[fixed]Transparent objects sorting error bug/improvement
[fixed]Transparent objects sorting error bug/improvement
Hello,
I posted this originally to the Irrlicht .NET forum, before I realized I was in the wrong place. Posting it here. After reading some of the posts here, this may be related to some of the transparency issues other people were reporting.
I have a bunch of transparent and partially transparent images that I am moving in 3D space. I have made my own custom node to orient them towards the camera (billboard didn't quite work). I ran into one problem, and have figured out a work-around, but it involves changing Irrlicht. I'm wondering if this was noticed before, if there is a different work-around, or if my fix is interesting to anyone.
In the CSceneManager::drawAll() function
Transparent nodes are drawn after all the solid objects, and are sorted by their distance from the camera. The sorting distance is set in the constructor for TransparentNodeEntry, and is a squared distance from the node's absolute location from the camera node.
The problem is that this sorting distance should be the 'Z' coordinate in camera space, and sorting problems are preventing my scene nodes from being drawn in the correct order. On my system (OpenGL, Ubuntu 9.04), this is further complicated by what appears to be zbuffer writes being turned on when rendering the same material twice in succession, regardless of the setting of scene::ALLOW_ZWRITE_ON_TRANSPARENT, but that's a different issue and isn't concerning me at the moment.
How I've worked around this is creating a new constructor for TransparentNodeEntry that takes a camera view matrix reference instead of a camera position reference as a parameter. I then store my sorting distance based on the 'Z' coordinate of the object position transformed to camera space, and my scene renders in the correct order.
Are any of my observations/changes relevant? Thanks for reading this long-winded post. I'm fairly new to Irrlicht, and I'm in the middle of porting a graohics interface to run on top of Irrlicht, and like it so far.
Thanks
Mark Penacho
I posted this originally to the Irrlicht .NET forum, before I realized I was in the wrong place. Posting it here. After reading some of the posts here, this may be related to some of the transparency issues other people were reporting.
I have a bunch of transparent and partially transparent images that I am moving in 3D space. I have made my own custom node to orient them towards the camera (billboard didn't quite work). I ran into one problem, and have figured out a work-around, but it involves changing Irrlicht. I'm wondering if this was noticed before, if there is a different work-around, or if my fix is interesting to anyone.
In the CSceneManager::drawAll() function
Transparent nodes are drawn after all the solid objects, and are sorted by their distance from the camera. The sorting distance is set in the constructor for TransparentNodeEntry, and is a squared distance from the node's absolute location from the camera node.
The problem is that this sorting distance should be the 'Z' coordinate in camera space, and sorting problems are preventing my scene nodes from being drawn in the correct order. On my system (OpenGL, Ubuntu 9.04), this is further complicated by what appears to be zbuffer writes being turned on when rendering the same material twice in succession, regardless of the setting of scene::ALLOW_ZWRITE_ON_TRANSPARENT, but that's a different issue and isn't concerning me at the moment.
How I've worked around this is creating a new constructor for TransparentNodeEntry that takes a camera view matrix reference instead of a camera position reference as a parameter. I then store my sorting distance based on the 'Z' coordinate of the object position transformed to camera space, and my scene renders in the correct order.
Are any of my observations/changes relevant? Thanks for reading this long-winded post. I'm fairly new to Irrlicht, and I'm in the middle of porting a graohics interface to run on top of Irrlicht, and like it so far.
Thanks
Mark Penacho
Here is an example that shows what I am talking about
I have a camera positioned at (0,0,-330) and pointing towards (0.0.0).
I have a semi transparent object (OBJ1) positioned at (0,0,0)
I have a semi transparent object (OBJ2) positioned at (50,0,-1)
OBJ1 and OBJ2 are big enough, that they overlap each other in the camera view.
The constructor for the TransparentNodeEntry computes the values that will be used by the list sorting algorithm, based on dx^2 +dy^2 + dz^2 from the camera or:
OBJ1 sorting distance = (0 - 0) ^ 2 + (0 - 0) ^ 2 + (-330 - 0) ^ 2 = 108900
OBJ2 sorting distance = (0 - 50) ^ 2 + (0 - 0) ^ 2 + (-330 - (-1)) ^ 2 = 110741
so the sorting values are computed showing OBJ2 farther away the camera than OBJ1 and OBJ2 is drawn before OBJ1.
The problem: OBJ2 is further from the camera than OBJ1, but given the camera's orientation, OBJ2 is closer to the camera's view plane (which in this simple case, the distance is simply the Z delta).
So, to draw them in the correct order, the sorting distance should not be the xyz squared distance, but instead be the distance from the view plane after the object position is transformed to camera space. I accomplished this by making a new constructor for TransparentNodeEntry that takes the camera view matrix as a parameter instead of the camera position, and computes a sorting distance by transforming the object position into camera space, and then using the resulting, post-transformed, Z coordinate
I have a camera positioned at (0,0,-330) and pointing towards (0.0.0).
I have a semi transparent object (OBJ1) positioned at (0,0,0)
I have a semi transparent object (OBJ2) positioned at (50,0,-1)
OBJ1 and OBJ2 are big enough, that they overlap each other in the camera view.
The constructor for the TransparentNodeEntry computes the values that will be used by the list sorting algorithm, based on dx^2 +dy^2 + dz^2 from the camera or:
OBJ1 sorting distance = (0 - 0) ^ 2 + (0 - 0) ^ 2 + (-330 - 0) ^ 2 = 108900
OBJ2 sorting distance = (0 - 50) ^ 2 + (0 - 0) ^ 2 + (-330 - (-1)) ^ 2 = 110741
so the sorting values are computed showing OBJ2 farther away the camera than OBJ1 and OBJ2 is drawn before OBJ1.
The problem: OBJ2 is further from the camera than OBJ1, but given the camera's orientation, OBJ2 is closer to the camera's view plane (which in this simple case, the distance is simply the Z delta).
So, to draw them in the correct order, the sorting distance should not be the xyz squared distance, but instead be the distance from the view plane after the object position is transformed to camera space. I accomplished this by making a new constructor for TransparentNodeEntry that takes the camera view matrix as a parameter instead of the camera position, and computes a sorting distance by transforming the object position into camera space, and then using the resulting, post-transformed, Z coordinate
Last edited by mpenacho on Thu Apr 30, 2009 10:36 pm, edited 1 time in total.
I have another bug that is quite similar to this one, yet not quite the same- but it involves changes to almost the exact same piece of code.
The issue is with when you have an orthogonal camera, and you're positioning (semi-)transparent objects to be visible. The distance sorting is done via the distance between the ISceneNode in question and the ICameraSceneNode that is the ActiveCamera in the ISceneManager, but in the case of an orthogonal camera, shouldn't the distance be calculated base on the distance between the ISceneNode in question, and a plane perpendicular to the direction the ActiveCamera is pointing, and passing thru the ActiveCamera?
For example: If your orthogonal ActiveCamera is at (0, 0, 10), and targetting (0, 0, 0), then an object at (0, 0, -10) should always be in front of an object at (0, 10, -11), yet depending on where the camera is positioned, either object could appear to be in front of the other.
Unfortunately, I need my project to be easily usable by other Irrlicht coders, so I can't be going and modifying the Irrlicht code from what's in the 1.5 code, and thus I don't have a patch or anything prepared, and only my theory above on how to make it work.
EDIT: My workaround in my own code was to completely exaggerate my "depth" values- making them 500 times bigger than my "X" and "Y" values, resulting in the "layers" you would see via an orthogonal camera to be 100s of units apart on the Z axis, and I'm only moving the objects around by 0-30 units on the X and Y axes.
The issue is with when you have an orthogonal camera, and you're positioning (semi-)transparent objects to be visible. The distance sorting is done via the distance between the ISceneNode in question and the ICameraSceneNode that is the ActiveCamera in the ISceneManager, but in the case of an orthogonal camera, shouldn't the distance be calculated base on the distance between the ISceneNode in question, and a plane perpendicular to the direction the ActiveCamera is pointing, and passing thru the ActiveCamera?
For example: If your orthogonal ActiveCamera is at (0, 0, 10), and targetting (0, 0, 0), then an object at (0, 0, -10) should always be in front of an object at (0, 10, -11), yet depending on where the camera is positioned, either object could appear to be in front of the other.
Unfortunately, I need my project to be easily usable by other Irrlicht coders, so I can't be going and modifying the Irrlicht code from what's in the 1.5 code, and thus I don't have a patch or anything prepared, and only my theory above on how to make it work.
EDIT: My workaround in my own code was to completely exaggerate my "depth" values- making them 500 times bigger than my "X" and "Y" values, resulting in the "layers" you would see via an orthogonal camera to be 100s of units apart on the Z axis, and I'm only moving the objects around by 0-30 units on the X and Y axes.
-
- Posts: 1638
- Joined: Mon Apr 30, 2007 3:24 am
- Location: Montreal, CANADA
- Contact:
Hi, I've downloaded official release 1.6 and this can be observed with the particle billboards in the Quake Explorer and Demo. Their Z order with the 3D background is ok, but if multiples billboards are overlapping (as in the particles coming from the wall) the Z Depth of the billboard are not properly drawn for their alphas.
Re:
This bug is still in irrlicht 1.8.1.mpenacho wrote: So, to draw them in the correct order, the sorting distance should not be the xyz squared distance, but instead be the distance from the view plane after the object position is transformed to camera space. I accomplished this by making a new constructor for TransparentNodeEntry that takes the camera view matrix as a parameter instead of the camera position, and computes a sorting distance by transforming the object position into camera space, and then using the resulting, post-transformed, Z coordinate
I've just fixed it for myself:
In CSceneManager.cpp replace:
Code: Select all
TransparentNodeEntry e(node, camWorldPos);
Code: Select all
TransparentNodeEntry e(node, ActiveCamera->getAbsoluteTransformation());
Code: Select all
TransparentNodeEntry(ISceneNode* n, const core::matrix4& cameraViewMatrix)
: Node(n)
{
core::vector3df out;
cameraViewMatrix.transformVect(out, n->getPosition());
Distance = out.Z;
}
Re: Transparent objects sorting error bug/improvement
That massively increases the cpu overhead. Consider a hundred or a thousand units.
Re: Transparent objects sorting error bug/improvement
Very true. That sort of transformation should be done in a shader, however i still think a slow fix on the CPU is better than broken functionality, and someone more acquainted with irrlicht conventions and architecture can make a GPU-based fixed when they have time.hendu wrote:That massively increases the cpu overhead. Consider a hundred or a thousand units.
-
- Competition winner
- Posts: 688
- Joined: Mon Sep 10, 2012 8:51 am
Re: Transparent objects sorting error bug/improvement
I just saved a CSceneManager class member vector3df of camToTarget (camToTarget = ActiveCamera->getTarget() - camWorldPos), set at the same time as camWorldPos. Then I passed this into the TransparentNodeEntry as a parameter ( const core::vector3df& cameraToTarget ) and set the distance based on the dot product:
Another thing:
Transparent mesh buffers are not sorted in CMeshSceneNode, causing this same z-order problem. Mesh buffers are simply drawn in-order. This results in the first buffer always causing the other buffers to be invisible when they are behind it. And of course, each buffer drawn next causes the one after it to be hidden.
Code: Select all
Distance = cameraToTarget.dotProduct( Node->getAbsolutePosition() - camera );
Transparent mesh buffers are not sorted in CMeshSceneNode, causing this same z-order problem. Mesh buffers are simply drawn in-order. This results in the first buffer always causing the other buffers to be invisible when they are behind it. And of course, each buffer drawn next causes the one after it to be hidden.
Re: [fixed]Transparent objects sorting error bug/improvement
Fixed in svn trunk r6573. Can now be set with ISceneManager::setTransparentNodeSorting
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm