Overlays ignore z-order

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


Post Reply
wuzz
Gnoblar
Posts: 10
Joined: Tue Mar 24, 2015 2:25 pm

Overlays ignore z-order

Post by wuzz »

Hey,
I've been messing with this for a long time now, Ogre2.1 somehow seems to ignore the z-order of my overlay elements.
I'm using this simple code to create 2 overlays overlapping each other:

Code: Select all

			Ogre::v1::OverlayManager* mOverlayMgr = Ogre::v1::OverlayManager::getSingletonPtr();

			Ogre::v1::PanelOverlayElement* control1 = static_cast<Ogre::v1::PanelOverlayElement*>(mOverlayMgr->createOverlayElement("Panel", "Panel1"));
			control1->setMetricsMode(Ogre::v1::GuiMetricsMode::GMM_PIXELS);
			control1->setMaterialName("material1");
			control1->setDimensions(200, 100);
			control1->setPosition(10, 10);
			Ogre::v1::Overlay* overlay1 = mOverlayMgr->create("Overlay1");
			overlay1->add2D(control1);
			overlay1->setZOrder(100);
			overlay1->show();

			Ogre::v1::PanelOverlayElement* control2 = static_cast<Ogre::v1::PanelOverlayElement*>(mOverlayMgr->createOverlayElement("Panel", "Panel2"));
			control2->setMetricsMode(Ogre::v1::GuiMetricsMode::GMM_PIXELS);
			control2->setMaterialName("material2");
			control2->setDimensions(200, 100);
			control2->setPosition(100, 10);
			Ogre::v1::Overlay* overlay2 = mOverlayMgr->create("Overlay2");
			overlay2->add2D(control2);
			overlay2->setZOrder(1);
			overlay2->show();
No matter what z order I set to the elements, the second panel is always drawn in front of the first one.
The hlms materials are one-liner:

Code: Select all

hlms material1 unlit
{
	diffuse_map		Texture1.png
}

hlms material2 unlit
{
	diffuse_map		Texture2.png
}
Either I'm not getting how the z-order is supposed to work or I messed something up horribly. I'm using the lasted repo of the 2.1 fork (4/8/2015).
What could be the issue of this problem?
Greetings!
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Overlays ignore z-order

Post by dark_sylinc »

Not all functionality is working in Ogre 2.1 and Z order parameter is likely to be one of them.
Calling RenderQueue::setSortRenderQueue( id, false ); [where id is the RenderQueue ID where the Overlays are living) can help or even fix the error.

Another workaround is that somewhere in the Overlay code the overlays are sorted alphabetically by name (probably an std::map somewhere), thus by controlling the name you may be able to control the order.
I agree this is a suboptimal solution.

I haven't looked much into this.
wuzz
Gnoblar
Posts: 10
Joined: Tue Mar 24, 2015 2:25 pm

Re: Overlays ignore z-order

Post by wuzz »

Thanks for your answer!
I tried setting the render queue sorting to false. However, that didn't fix the issue for me.
Also, trying to alphabetically sort the overlays or changing the order of instancing didn't change the order of how they are rendered.

EDIT: I'm using OpenGL3+.
EDIT2:
Turns out that the order of rendering has something to do with the order that the hlms materials are defined.
But it's not like "the first material defined is rendered first/last", but it's unpredictible.
Tried it with ~7 material definitions, and some of them are rendered on top only when they are defined somewhere in between. Behaviour changes also, when setting a scene_blend in the material definition.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Overlays ignore z-order

Post by dark_sylinc »

wuzz wrote:EDIT2:
Turns out that the order of rendering has something to do with the order that the hlms materials are defined.
But it's not like "the first material defined is rendered first/last", but it's unpredictible.
Tried it with ~7 material definitions, and some of them are rendered on top only when they are defined somewhere in between. Behaviour changes also, when setting a scene_blend in the material definition.
If this is happening, then you didn't successfully disable RenderQueue sorting for the overlays; because once you disable it, the only thing affecting the render order is the order of submission (which for v2 objects depends on the number of threads; but Overlays are v1 objects).

Edit:Placing breakpoints inside RenderQueue::renderGL3V1 should help you determine what is being rendered, and which RenderQueue IDs are used. The ones to enter the "if( !mRenderQueues.mSorted )" in RenderQueue::render are being sorted in a way that Hlms materials affect render order.
wuzz
Gnoblar
Posts: 10
Joined: Tue Mar 24, 2015 2:25 pm

Re: Overlays ignore z-order

Post by wuzz »

You're right, I enabled the sorting again when trying to alphabetically sort the overlays.
To disable sorting, I called RenderQueue::setSortRenderQueue(254, false) after initializing root, because my overlays were inserted into this render queue.
When debugging I see that mDoSort and mSorted are false (which should be correct I guess?).

Where should the actual sorting of the overlays by their z-order happen? In the OverlayManager::_updateOverlaysForRendering method? From what I saw, the z-order is stored in the mObjectData.distanceToCamera attribute, but I couldn't locate the code where they are actually sorted. Should overlays be already inserted into the render queue depending of their z-order, or does the render queue sort the overlays itself?
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Overlays ignore z-order

Post by dark_sylinc »

wuzz wrote:Should overlays be already inserted into the render queue depending of their z-order, or does the render queue sort the overlays itself?
The former.
zxz
Gremlin
Posts: 184
Joined: Sat Apr 16, 2016 9:25 pm
x 19

Re: Overlays ignore z-order

Post by zxz »

Did you ever find a workaround for the z-order issue, wuzz?

It doesn't seem to be working in the latest v2-1 branch.

Edit: A quick workaround seems to be to insert some code to sort the overlays in OverlayManager::_queueOverlaysForRendering
farrer
Halfling
Posts: 64
Joined: Mon Sep 12, 2011 7:35 pm
x 13

Re: Overlays ignore z-order

Post by farrer »

Use Overlay::setRenderQueueGroup or OverlayContainer::setRenderQueueSubGroup (depending on your case).

Try to keep to a very few groups if a single one didn't suffice (subgroups would be from 0 to 6 btw).

My suggestion is that if you can, try not using overlays at all and use or implement something else.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Overlays ignore z-order

Post by dark_sylinc »

@zxz
I realized we were already trying to sort by Z Order, but there was a bug. This bug has just been fixed. Could you confirm it fixes your issue?

Note that for this to work correctly, RenderQueue's sorting must not be disabled (as I suggested in my last post from this thread).


PS. The idea is that by writing the Z Order to mObjectData.mDistanceToCamera, then this snippet in RenderQueue::addRenderable:

Code: Select all

uint32 quantizedDepth = static_cast<uint32>( depth ) >> (32 - RqBits::DepthBits);
...
if( !transparent )
{
...
}
else
{
quantizedDepth = quantizedDepth ^ 0xffffffff;
            hash =
            OGRE_RQ_HASH( subId,            RqBits::SubRqIdBits,        RqBits::SubRqIdShift )          |
            OGRE_RQ_HASH( transparent,      RqBits::TransparencyBits,   RqBits::TransparencyShift ) ...;
}
Should take care of it. If it still does not work then I did a mistake and possibly we should be doing:

Code: Select all

void Overlay::setZOrder( uint16 zorder )
{
    mObjectData.mDistanceToCamera[mObjectData.mIndex] = (zorder ^ 0xffff) << (32u - RqBits::DepthBits);
}
//---------------------------------------------------------------------
uint16 Overlay::getZOrder(void) const
{
    return (uint16)(mObjectData.mDistanceToCamera[mObjectData.mIndex] >> (32u - RqBits::DepthBits))^0xffff;
}
Edit: I pushed the 0xffff xor too; I believe it's necessary. Let me know if I made a mistake and testing indicates I am wrong and such ^0xffff does exactly the opposite.
zxz
Gremlin
Posts: 184
Joined: Sat Apr 16, 2016 9:25 pm
x 19

Re: Overlays ignore z-order

Post by zxz »

This works.

Though I'm not sure which sorting order should be used. With your fix, a higher z-order means drawing earlier, so overlays with a higher z-order ends up below those with lower z-order. This feels a bit counter-intuitive to me, but it isn't a big deal. I don't remember how it used to work in order Ogre versions.

Thanks for the fix
zxz
Gremlin
Posts: 184
Joined: Sat Apr 16, 2016 9:25 pm
x 19

Re: Overlays ignore z-order

Post by zxz »

Hello again,

Unless this sorting behaviour has changed since the Ogre 2.1 commit we are running at, the current sorting order appears to be opposite of the one used in Ogre 1.8 (see attached image). I think it would be best if 2.1 matches 1.8 behaviour in this case.
Attachments
ogre-overlay-zorder.png
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Overlays ignore z-order

Post by dark_sylinc »

If I did it wrong, flip the snippet from a few posts above:
void Overlay::setZOrder( uint16 zorder )
{
mObjectData.mDistanceToCamera[mObjectData.mIndex] = (zorder ^ 0xffff) << (32u - RqBits::DepthBits);
}
//---------------------------------------------------------------------
uint16 Overlay::getZOrder(void) const
{
return (uint16)(mObjectData.mDistanceToCamera[mObjectData.mIndex] >> (32u - RqBits::DepthBits))^0xffff;
}
If flipping works as expected (remove the "^ 0xffff" part), then we'll push the change.
If it is still wrong, then we're dealing with a different kind of bug.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Overlays ignore z-order

Post by dark_sylinc »

Today I noticed that Overlays were very wrong while working on restoring the profiling module, and pushed a fix.

Maybe this is the issue that was driving you nuts?

PS: Note that you have to manually call:

Code: Select all

mSceneManager->getRenderQueue()->setSortRenderQueue(
            Ogre::v1::OverlayManager::getSingleton().mDefaultRenderQueueId,
            Ogre::RenderQueue::StableSort );
zxz
Gremlin
Posts: 184
Joined: Sat Apr 16, 2016 9:25 pm
x 19

Re: Overlays ignore z-order

Post by zxz »

Hi!

I haven't had issues with the sorting being stable or not. Wouldn't this only be a problem for overlays with same z-order?

I finally had a little bit of time to take a look at this sorting issue. The current code appears to be broken, not just different from 1.8. Also, removing the XOR still results in wrong overlay order.

Example inputs:

Current implementation with XOR:
zorder = 100, masked quantized depth in RQ = 100
zorder = 600, masked quantized depth in RQ = 600

Without XOR:
zorder = 100, masked quantized depth in RQ = 16484
zorder = 600, masked quantized depth in RQ = 16984

Note that the above two examples give the same final relative ordering (also observed in renderings on-screen).

Upon closer inspection, the current implementation contains an integer shift overflow at the following line:

Code: Select all

 mObjectData.mDistanceToCamera[mObjectData.mIndex] = (zorder ^ 0xffff) << (32u - RqBits::DepthBits);
For example, with zorder = 100, this becomes (100 ^ 0xffff) << 17, which triggers undefined behaviour due to the shift overflowing. To avoid this overflow, I tested around a bit without the XOR so that the values will fit in the 15 upper bits of mDistanceToCamera.

Without the XOR, the maximum masked quantized depth (2^DepthBits-1) occurs at zorder = 16383. At zorder = 0 the quantized depth is then 16384. Thus, in order to achieve opposite sorting order, I can do zorder = 16383 - zorder. I then get 2^14 values with the expected sorting order (same as order as in 1.8 ).

That doesn't appear to be a proper solution as it won't make use of all bits in the sorting hash, but it is what I could get through from setZOrder to the final sorting hash without modifying the render queue bit operations.
Post Reply