AB4D Forum

Full Version: Transparent triangle sorting
You're currently viewing a stripped down version of our content. View the full version with proper formatting.

I've ran into an issue while rendering non-convex transparent object. Some triangles were wrongly shaded as shown in the attached image. The model is also attached (it's an fbx wrapped in zip, since fbx was not allowed to be uploaded). and it's an approximation of a glass. To achieve this in the PBR model viewer demo, it is enough to manually set the color to some semitransparent and set HasTransparency in the method UpdateMaterials.

I think the issue is in the order the triangles are drawn (some tringles in front are drawn first and then the ones in the back). It can be solved by splitting this concave shape into two convex shapes with different materials. Does DXEngine provide some triangle sorting (per-mesh) based on the distance from camera (there is at least for different meshes).

I've thought about drawing the objects in the transparent queue to depth buffer first and then write only the pixels that pass depth test equal (basically only the first triangles visible). But I had no idea how to set this up. The closest I've got is to get the current Depth/Stencil buffer - MainDXViewportView.DXScene.DXDevice.ImmediateContextStatesManager.DepthStencilState.

Thank you.
Best regards,
Janovsky Roman
You are right. Those problems are caused because some triangles are rendered before others and because the object is rendered with DepthReadWrite mode the triangles that are closer to the camera may prevent rendering triangles that are farther to the camera (if they are rendered first).

This can be prevented by using DepthRead DepthStencilState.
The following code does the trick:

MainDXViewportView.DXSceneInitialized += delegate (object sender, EventArgs args)
    var dxScene = MainDXViewportView.DXScene;
    var transparentRenderingQueue = dxScene.TransparentRenderingQueue;

    var renderTransparentObjectsRenderingStep = new RenderObjectsRenderingStep("RenderTransparentObjects");

    // Render only objects in transparent rendering queue
    renderTransparentObjectsRenderingStep.FilterRenderingQueuesFunction = queue => queue == transparentRenderingQueue;
    renderTransparentObjectsRenderingStep.OverrideDepthStencilState = dxScene.DXDevice.CommonStates.DepthRead;

    dxScene.RenderingSteps.AddAfter(dxScene.DefaultRenderObjectsRenderingStep, renderTransparentObjectsRenderingStep);

    // DefaultRenderObjectsRenderingStep should render all objects except objects in transparent rendering queue
    dxScene.DefaultRenderObjectsRenderingStep.FilterRenderingQueuesFunction = queue => queue != transparentRenderingQueue;

For the next version that will be released in November (after the .Net 6 release) I am preparing a few improvements for rendering transparent objects. The following two are already implemented:

  • easy way to render transparent objects without writing to depth buffer (using DepthRead; this prevents occluding triangles that are behind other triangles). You will only need to use the following to enable that: "MainDXViewportView.DXScene.DXDevice.CommonStates.DefaultTransparentDepthStencilState = MainDXViewportView.DXScene.DXDevice.CommonStates.DepthRead;"

  • support for two sided materials (render two sided material with one render pass; this works very well with DepthRead only mode for transparent objects).

I have also a working version of the triangles sorting mechanism, but this still needs a little polishing and testing. I will send you a pre-release version when this is ready.

I don't think that rendering with only DepthRead is enough (I made a test for it and it does not change the result - the pixels are simply blended in a wrong order).

For this to work I would need to render depth only first. And then I could render with DepthRead and DepthComparison.LessEqual. These steps should result in rendering only the closest faces of an (even concave) object. 

Right now I have a workaround:
1. I have created a RenderingStepsGroup.
2. Added RenderObjectsRenderingStep with filter as suggested.
3. Then I've enabled the blend state - zero for source, one for destination, and add as the operation.
4. Set depth write (this concludes the depth-only rendering step).
5. Create DepthRead as suggested.

Is there an efficient way in DXEngine to render only depth?

You mentioned, that in the new version, sorting triangles will be available. If I want to write something like this on my own, which callbacks can be used? For example, slice-render the object (you have a set of planes and you render based on the distance. these planes are view dependent.).

Janovsky Roman