Layered Renderers Do Not Render In Correct Order

When using VTK C++ I was able to establish the rendering order of layered renderers (3 separate renderers) by using the SetLayer function of the vtkRenderer objects and SetNumberOfLayers on the vtkRenderWindow object. When I tried this same approach with vtk.js the renderers were not being rendered in the order that I expected. They were always rendered in the order that I added the renderers to the renderwindow. I dug into the code and made some changes to the vtkForwardPass source code to make it work. I am not experienced in how to contribute correctly to the github project so I was hoping someone could contribute the changes for me, or point me to a resource that I can learn how to contribute correctly.

The changed ForwardPass code section (the full traverse() function) is below with bold lines showing my additions:

// this pass implements a forward rendering pipeline
// if both volumes and opaque geometry are present
// it will mix the two together by capturing a zbuffer
// first
publicAPI.traverse = (viewNode, parent = null) => {
if (model.deleted) {
return;
}
// we just render our delegates in order
model.currentParent = parent;
// build
publicAPI.setCurrentOperation(‘buildPass’);
viewNode.traverse(publicAPI);
const numlayers = viewNode.getRenderable().getNumberOfLayers();
// iterate over renderers
const renderers = viewNode.getChildren();
for (let i = 0; i < numlayers; i++) {
for (let index = 0; index < renderers.length; index++) {
const renNode = renderers[index];
const ren = viewNode.getRenderable().getRenderers()[index];
if (ren.getLayer() == i) {
// check for both opaque and volume actors
model.opaqueActorCount = 0;
model.translucentActorCount = 0;
model.volumeCount = 0;
publicAPI.setCurrentOperation(‘queryPass’);>
renNode.traverse(publicAPI);>
// do we need to capture a zbuffer?
if (
(model.opaqueActorCount > 0 && model.volumeCount > 0) ||
model.depthRequested
) {
const size = viewNode.getFramebufferSize();
// make sure the framebuffer is setup
if (model.framebuffer === null) {
model.framebuffer = vtkOpenGLFramebuffer.newInstance();
}
model.framebuffer.setOpenGLRenderWindow(viewNode);
model.framebuffer.saveCurrentBindingsAndBuffers();
const fbSize = model.framebuffer.getSize();
if (fbSize === null || fbSize[0] !== size[0] || fbSize[1] !== size[1]) {
model.framebuffer.create(size[0], size[1]);
model.framebuffer.populateFramebuffer();
}
model.framebuffer.bind();
publicAPI.setCurrentOperation(‘opaqueZBufferPass’);
renNode.traverse(publicAPI);
model.framebuffer.restorePreviousBindingsAndBuffers();
}>
publicAPI.setCurrentOperation(‘cameraPass’);
renNode.traverse(publicAPI);
if (model.opaqueActorCount > 0) {
publicAPI.setCurrentOperation(‘opaquePass’);
renNode.traverse(publicAPI);
}
if (model.translucentActorCount > 0) {
publicAPI.setCurrentOperation(‘translucentPass’);
renNode.traverse(publicAPI);
}
if (model.volumeCount > 0) {
publicAPI.setCurrentOperation(‘volumePass’);
renNode.traverse(publicAPI);
}
}
}
}
};

Thanks for helping make vtk.js better.

To streamline the contribution process, and retain your authorship.
You should follow those steps.

@ken-martin should review that contribution.

Thanks Seb,
I have created a new pull request following the guidelines you referenced. It feels good to be able to contribute to such a wonderful project.

1 Like