Z fighting issues
#1
Hello,
we are currently using Ab3d to display models for our BIM application and we have some problems with z-fighting on models, that is significantly changing based on camera angle.

Example 1:
[Image: https://ibb.co/cMs5Xk]
[Image: https://ibb.co/enHHdQ]

Example 2:
[Image: https://ibb.co/m09VyQ]
[Image: https://ibb.co/cdVQXk]

In Heading range about 46 to 280 everything is pretty much fine, but the rest is very bad.
Any idea on what could be the cause, and possible fix?

Thank you, Simon
#2
I see that the z-fighting is very bad on your screenshots.

I see that the camera in the A and B images is almost the same so I am wondering what is causing the change: I assume that in the B images you create new 3D models and position them on the same position as the original object or use just a very small offset to position the new objects slightly above the original objects.

In this case you will need to increase the offset of the new models so that they will be slightly above the original object - this will produce different z values (distance from the camera to the 3D position) for the top and original models. 

Another approach is to optimize the distribution of z values in the depth buffer (note that you still need to have slight offset between objects).

One of the most effective ways to optimize the distribution of z values is to switch to orthographic camera (from the first image I assume that you are using perspective camera). Orthographic camera is much better regarding z-fighting because there the resolution of z values is equal in the whole range from z-near to z-far. For perspective camera the resolution of z values is very good near the z-near value and much worse near the z-far value.  (in the depth buffer the points at the z-near plane have z depth value 0; the positions at the z-far plane have z depth value 1).

The standard approach to solve the z-fighting issue is to minimize the difference between z-near and z-far values.
By default Ab3d.DXEngine already tries to optimize this by automatically calculating the z-near and z-far values based on the bounding box of the whole scene. So z-far value is get as the distance from the camera to the farthest point on the scene's bounding box. The z-near value is the distance to the nearest point of the bounding box (in the look direction). If there are some objects behind the camera and you are using perspective camera, then z-near is not set to 0 (this would not work). In this case the z-near is calculated as 1 / 1000 of z-far value.

If you would like to manually control the z-near and z-far values, you need to set the DXScene's OptimizeNearAndFarCameraPlanes property to false. This can be done with the following code:

Code:
MainDXViewportView.DXSceneInitialized += delegate(object sender, EventArgs args)
{
   if (MainDXViewportView.DXScene == null) // When DXEngine falls back to WPF 3D rendering, the DXScene is null
       return;

   MainDXViewportView.DXScene.OptimizeNearAndFarCameraPlanes = false;
};

Then you can set the NearPlaneDistance and FarPlaneDistance on the camera and DXEngine will use those values.


As a final note I would like to mention that Ab3d.DXEngine is using 32 bit depth buffer so it can have the maximal resolution.


I hope that this will help you solve the problems. If not, then please explain in more details how you render yous scene (what changes you do from image A to image B).
Andrej Benedik
#3
(06-20-2017, 03:23 PM)abenedik Wrote: I see that the z-fighting is very bad on your screenshots.

I see that the camera in the A and B images is almost the same so I am wondering what is causing the change: I assume that in the B images you create new 3D models and position them on the same position as the original object or use just a very small offset to position the new objects slightly above the original objects.

...

Thank you for quick response!

I am aware that these models can be error prone  (layers on the road etc.). but there is not much that can be done about that. They are real measured representations, so they can't be moved. I was sure there would be some trouble, but they obviously shouldn't be this severe.

All that changes between A and B is just moving the camera, but now that you mention it, there might be a bug, that i put model in the scene twice, which would explain this behavior. I will check the code closely right away.

About the z-buffer distribution.
   I was actually wandering if there is a possibility to change it, because the models loaded can vary in size and detail a lot. But I didn't manage to find any specific information, how to do that using WPF 3D or Ab3D. Could you please point me in right direction?
   Also is there a way to dynamically change the distribution of z-buffer? Just switching between logarithmic and linear distribution depending on a distance would help in a lot of cases.

Thank you, Simon
#4
Hm, this is strange.

You said that the only change in the scene is that you change the camera, but if you look the second two image (2A and 2B) you will see that the camera is exactly the same (Heading, Attitude and Distance are the same to the 10th decimal).

Also, if you would add the same scene objects to the same position again, you would have z-fighting, but because the materials of both objects that "fight" would be the same, you would not see any problem with the rendered image - green fighting green is still green.

But on your images it is clearly seen that some red objects is drawn over the gray road edges.

It looks like you have added another copy of the objects to the same position but the second copy have different materials.


The distribution of z values in the depth buffer is determined with the projection matrix - in case of perspective camera, the distribution is logarithmic, in case of orthographic camera the distribution is linear.

But if you have objects at the same position and with different material then there is no way to prevent z-fighting regardless of the projection.
Andrej Benedik
#5
So after some testing it is definitely just problem with dynamic changing of Near and Far planes of the projection. I will either add option to switch between two or three camera settings (closeup, standard, far) or create my own algorithm to set the planes dynamically to fit our purposes.

Anyway thank you very much for quick and helpful assistance!

Best regards, Simon
#6
I am also very interested in any recommendations to improve the calculation of zNear and zFar values.
This is currently based on the scene's bounding box, but if you have any better recommendation, I would gladly implement that in the DXEngine.

Could you please share your findings - you may also send that as a private message or email (support at ab4d.com).
Andrej Benedik
#7
(06-21-2017, 10:55 AM)abenedik Wrote: I am also very interested in any recommendations to improve the calculation of zNear and zFar values.
This is currently based on the scene's bounding box, but if you have any better recommendation, I would gladly implement that in the DXEngine.

Could you please share your findings - you may also send that as a private message or email (support at ab4d.com).

I gave it some thought and honestly, don't see any better way. At least not efficient one.
Is the bounding box of the scene optimized? If not, it might help to calculate it and use that one instead.
Assuming we have a static scene, that is once initialized and no models are added/removed during runtime.

Also (again considering static scene), have you considered creating spatial octree of 2 or 3 levels and then move the zNear to the closest corner of the octree subdivision?

But what would most definitely help, would be a possibility to set bounds for the plane optimization algorithm. Perhaps as properties DXScene.minNearPlaneDistance and DXScene.maxFarPlaneDistance. The logarithmic distribution of z-buffer suffers from setting the Near plane too close to camera and in the cases I had the trouble with z-fighting it was set automatically below 1 (usually from 0.13 to 0.16).
If I could set minimum for Near plane to for example 2, that would prevent a lot of issues.

Best regards, Simon
#8
Simon, that is a good recommendation.

As you proposed, I have added MinNearPlaneDistance and MaxFarPlaneDistance properties to DXScene. This will allow you to have more control over the calculated near and far plane distance.


Currently the scene's bounds is calculating with simply calculating the union of the children axis oriented bounding boxes. This does not give perfect results but is very fast to calculate and gives quite good results. For now I would not change that.

This also gives good near and far values when the whole scene is shown. But the problems can happen when one part of the scene is behind the camera - in this case zNear is 1/1000 of zFar. But this might be too small in some cases. And in those cases you can set the MinNearPlaneDistance.



I am planning to release a beta version of new Ab3d.DXEngine (and Ab3d.PowerToys with tons of new features) tomorrow.
Andrej Benedik
#9
That is amazing! Thank you for the help.

Best regards, Simon
  


Forum Jump:


Users browsing this thread:
1 Guest(s)