Co-planar surfaces rendered differently depending on depth peeling activation

Hello,

I often find myself in a situation where I have to deal with co-planar surfaces. The render differs depending whether or not I am using depth peeling.
Occlussion or composite change nothing in the result.

I am creating 2 cubes, that are slightly shifted in opposite directions, apply same opacity and some colors.
Left render is without depth peeling, right is with depth peeling. The central zone should be redish and it is strange that only the opposite face is colored.
comparison

Here is a python script:

#!/usr/bin/env python3
import vtk

# Grid
x = vtk.vtkFloatArray()
y = vtk.vtkFloatArray()
z = vtk.vtkFloatArray()

x_dim = y_dim = z_dim = 5

for v, dim in zip((x, y, z), (x_dim, y_dim, z_dim)):
  for i in range(dim):
    v.InsertNextValue(i)

grid = vtk.vtkRectilinearGrid()
grid.SetDimensions(x_dim, y_dim, z_dim)
grid.SetXCoordinates(x)
grid.SetYCoordinates(y)
grid.SetZCoordinates(z)

geometry_filter = vtk.vtkGeometryFilter()
geometry_filter.SetInputData(grid)
geometry_filter.Update()

# Cube1
translate_transform1 = vtk.vtkTransform()
translate_transform1.Translate(-1., 0., 0.)
translate_filter1 = vtk.vtkTransformPolyDataFilter()
translate_filter1.SetTransform(translate_transform1)
translate_filter1.SetInputConnection(geometry_filter.GetOutputPort())
translate_filter1.Update()
cube1 = geometry_filter.GetOutput()

# Cube2
translate_transform2 = vtk.vtkTransform()
translate_transform2.Translate(1., 0., 0.)
translate_filter2 = vtk.vtkTransformPolyDataFilter()
translate_filter2.SetTransform(translate_transform2)
translate_filter2.SetInputConnection(geometry_filter.GetOutputPort())
translate_filter2.Update()
cube2 = translate_filter2.GetOutput()

# Composite
composite = vtk.vtkMultiBlockDataSet()
composite.SetBlock(1, cube1)
composite.SetBlock(2, cube2)

# Display attributes
display_attributes = vtk.vtkCompositeDataDisplayAttributes()
display_attributes.SetBlockOpacity(cube1, 0.3)
display_attributes.SetBlockOpacity(cube2, 0.3)
display_attributes.SetBlockColor(cube1, (0.8, 0., 0.0))
display_attributes.SetBlockColor(cube2, (0.8, 0.8, 0.8))

# Pipeline
## Mapper
mapper = vtk.vtkCompositePolyDataMapper2()
mapper.SetCompositeDataDisplayAttributes(display_attributes)
mapper.SetInputDataObject(composite)

## Actor
actor = vtk.vtkActor()
actor.SetMapper(mapper)

## Renderer
renderer = vtk.vtkRenderer()
renderer.SetBackground(1., 1., 1.)
renderer.SetUseDepthPeeling(True)
#renderer.SetOcclusionRatio(0.)
renderer.AddActor(actor)

## RenderWindow
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)

## Interactor
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)

# Start
render_window.Render()
print('Depth peeling used:', renderer.GetLastRenderingUsedDepthPeeling())
interactor.Start()

I also tried VTK_USE_LEGACY_DEPTH_PEELING variable this seems to completely discard one of the cube regarding colors.
Is there any paramters I can tune in the dual depth peeling pass?

Thank you

Hi, friend,

I got translucency rendered correctly with this setup:

    # Prepare to render transparency/translucency adequately
    # See: https://stackoverflow.com/questions/47528086/problems-with-rendering-transparent-objects-in-vtk
    #      https://vtk.org/Wiki/VTK/Examples/Cxx/Visualization/CorrectlyRenderTranslucentGeometry
    renderer.SetUseDepthPeeling(1)
    renderer.SetOcclusionRatio(0.1)
    renderer.SetMaximumNumberOfPeels(4)
    render_window.SetMultiSamples(0)
    render_window.SetAlphaBitPlanes(1)

See if that helps. This is an untested translation from my C++ code to Python, so it is not assured to work without modifications for you case.

cheers,

Paulo

Hello,
Thank you for your answer.
Adding those settings did not change the result.

It seems that the last added block is the one rendered in the end. I was able to force the 1st cube to render on top of the second by creating another polydata instance, and using a shallowcopy. Basically I am creating a 3rd cube and discard the 1st one.
I am wondering if those block are stored in a map and thus the memory address is the thing that defines ordering (last is rendered on top).

Hi,

The final pixel color is decided in the rendering pipeline in the graphics card. The decision is made by using the Z-buffer (aka depth buffer). Coplanar surfaces get the same depth values when after rastering. For this reason, they invented depth peeling, which involves the usage of two z-buffers in order to correctly render intersecting, or coplanar, translucent surfaces. Anyway, it is a low level operation that is not aware of how the original objects are in the memory space of your program. The only way to modify the behavior of the graphics pipeline is by setting flags and parameters like you did. This does not solve your problem, but hopefuly casts some light on what is going on under the hood.

As for you problem, why don’t you simply disable depth peeling? The image on the left seems to be the expected result, right?

regards,

Paulo

Hello again,

Indeed the left image is correct for translucent cubes. But I need mapper.ScalarVisibilityOff() or I get artifacts.
So I tried deactivating the depth peeling. Sadly, if I set the opacity to 1.0, it seems the opaque pass is not done. I can force a correct render with actor.SetForceOpaque(True) but then translucent objects will have artifacts, like cells inside of them. If then I also force translucent, nothing changes, translucent render is not correct.

Hello,
I pushed more testing following you advices. Please discard the last reply, above.

I am using composite mapper for performance reasons and I tested alpha blending. Sadly I have an issue with alpha blending and 0D polydata: https://gitlab.kitware.com/vtk/vtk/-/issues/18192

So I am back to depth peeling for now. I produced the screenshots below using your settings. Could you maybe try the script at the end of this post and tell me if you get the same results as those?

I have a blue-green cube on the left; a translated red cube in the middle with vertices overlapping the 1st cube and finally; a translated/rotated grey cube with non-overlapping vertices but co-planar fragments.
I rendered this scene with alpha blending and depth peeling. I am more interested in the cube 1 and 2 color blending than the 3rd cube artefacts

  • Top-left alpha blending. I assumed that each cube is rendered separately and then everything is blended together. red+(blue+green) = dark grey. So we end up with a correct blending in this case
  • Top-right legacy depth peeling: I guess the last inserted fragment replaces the other one. Since the 2nd cube is instanciated after the first cube, the peel will only render the 2nd cube overlapping fragments? So red only
  • Bottom-left dual depth peeling: I cannot make sense of this one. Front peel should be red (see above), back peel should be red too, again see above. So we should have the same render as legacy depth peeling right?
  • Bottom-right dual depth peeling with a little z offset for cube1. We have something similar to alpha blending but with artifacts

In the session, you will notice how I use 0.8 values for color. It looks like coplanar surfaces have their colors simply summed giving values close to 1. (light grey) instead of darkening the result.

Here is the session. You can activate depth peeling, legacy or not at the top of the file. You can apply an offset to any of the cubes.

mini_coplanar.py (2.5 KB)

What do you think?