Hello,
Recently I tried using multiple renderers within the same renderWindow
: one for displaying a volume in the background and another for displaying polydata elements in the foreground. However, I encountered some issues:
- The lighting doesn’t seem to follow the camera correctly in the scene.
- The camera’s clipping range appears to only take the foreground elements into account, ignoring the volume in the background.
Here is how I create the renderers:
// Create render window
const genericRenderWindow = vtkGenericRenderWindow.newInstance();
genericRenderWindow.setContainer(containerRef.current);
genericRenderWindow.resize();
const renderWindow = genericRenderWindow.getRenderWindow();
// Use default renderer as background renderer (layer 0)
const backgroundRenderer = genericRenderWindow.getRenderer();
backgroundRenderer.setLayer(0);
backgroundRenderer.setBackground(0.341, 0.325, 0.306);
backgroundRenderer.setBackingStore(true);
// Create additional renderer for foreground layer
const foregroundRenderer = vtkRenderer.newInstance();
const interactor = renderWindow.getInteractor();
// Add foreground renderer to render window
renderWindow.addRenderer(foregroundRenderer);
interactor.getInteractorStyle().setFocusedRenderer(backgroundRenderer);
foregroundRenderer.setLayer(1);
renderWindow.setNumberOfLayers(2);
foregroundRenderer.setPreserveDepthBuffer(true);
foregroundRenderer.setPreserveColorBuffer(true);
// Share the same camera between renderers
foregroundRenderer.setActiveCamera(backgroundRenderer.getActiveCamera());
rendererRef.current = {
background: backgroundRenderer,
foreground: foregroundRenderer,
};
To add the volume to the background renderer:
// Create volume and mapper
const volume = vtkVolume.newInstance();
const mapper = vtkVolumeMapper.newInstance();
mapper.setInputData(maskedVtkImage);
volume.setMapper(mapper);
const volumeProperty = volume.getProperty();
// Apply transfer functions
const transferFunctions = createTransferFunctions3D();
volumeProperty.setScalarOpacity(0, transferFunctions.opacityFunction);
volumeProperty.setRGBTransferFunction(0, transferFunctions.colorFunction);
rendererRef.current.background.addVolume(volume);
To add an actor to the foreground renderer:
const sphereSource = vtkSphereSource.newInstance({
center: [0, 0, 0],
radius: 2.2,
});
const sphereMapper = vtkMapper.newInstance();
sphereMapper.setInputConnection(sphereSource.getOutputPort());
const sphereActor = vtkActor.newInstance();
sphereActor.setMapper(sphereMapper);
sphereActor.getProperty().setColor(0, 1, 0); // Green
if (position) {
sphereActor.setPosition(position.x, position.y, position.z);
}
rendererCurrentRef.addActor(sphereActor);
Interestingly, when I add the following code using the orientation widget, it seems to fix the issues:
import {
createInteractiveOrientationMarkerWidget,
alignCameraOnViewWidgetOrientationChange,
} from '@kitware/vtk.js/Widgets/Widgets3D/InteractiveOrientationWidget/helpers';
const { interactiveOrientationWidget, orientationMarkerWidget } =
createInteractiveOrientationMarkerWidget(
globalWidgetManager,
renderWindowInteractor,
renderer
);