Skip to content

Commit

Permalink
docs(ManyRenderWindows): Add image reslice to the example
Browse files Browse the repository at this point in the history
Also add `addView` call (this didn't cause any bug, but it is better for the example)
  • Loading branch information
bruyeret authored and floryst committed May 30, 2024
1 parent 60d3608 commit ac4d712
Showing 1 changed file with 79 additions and 21 deletions.
100 changes: 79 additions & 21 deletions Examples/Rendering/ManyRenderWindows/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,50 +14,107 @@ import vtkRenderWindowInteractor from '@kitware/vtk.js/Rendering/Core/RenderWind
import vtkVolume from '@kitware/vtk.js/Rendering/Core/Volume';
import vtkVolumeMapper from '@kitware/vtk.js/Rendering/Core/VolumeMapper';

import vtkImageSlice from '@kitware/vtk.js/Rendering/Core/ImageSlice';
import vtkImageResliceMapper from '@kitware/vtk.js/Rendering/Core/ImageResliceMapper';
import vtkPlane from '@kitware/vtk.js/Common/DataModel/Plane';
import { SlabTypes } from '@kitware/vtk.js/Rendering/Core/ImageResliceMapper/Constants';
import vtkMath from '@kitware/vtk.js/Common/Core/Math';

// Force the loading of HttpDataAccessHelper to support gzip decompression
import '@kitware/vtk.js/IO/Core/DataAccessHelper/HttpDataAccessHelper';

// ----------------------------------------------------------------------------
// Background colors
// ----------------------------------------------------------------------------

async function createActor() {
const actor = vtkVolume.newInstance();
const sharedOpacityFunction = vtkPiecewiseFunction.newInstance();
sharedOpacityFunction.addPoint(100.0, 0.0);
sharedOpacityFunction.addPoint(255.0, 1.0);

function getRandomColorTransferFunction() {
const ctfun = vtkColorTransferFunction.newInstance();
ctfun.addRGBPoint(0, 0, 0, 0);
ctfun.addRGBPoint(95, Math.random(), Math.random(), Math.random());
ctfun.addRGBPoint(225, 0.66, 0.66, 0.5);
ctfun.addRGBPoint(255, 0.3, 0.3, 0.5);
return ctfun;
}

function createVolumeActor(imageData) {
// Create and setup the mapper
const mapper = vtkVolumeMapper.newInstance();
mapper.setSampleDistance(0.7);
mapper.setVolumetricScatteringBlending(0);
mapper.setLocalAmbientOcclusion(0);
mapper.setLAOKernelSize(10);
mapper.setLAOKernelRadius(5);
mapper.setComputeNormalFromOpacity(true);
actor.setMapper(mapper);
mapper.setInputData(imageData);

const ctfun = vtkColorTransferFunction.newInstance();
ctfun.addRGBPoint(0, 0, 0, 0);
ctfun.addRGBPoint(95, 1.0, 1.0, 1.0);
ctfun.addRGBPoint(225, 0.66, 0.66, 0.5);
ctfun.addRGBPoint(255, 0.3, 0.3, 0.5);
const ofun = vtkPiecewiseFunction.newInstance();
ofun.addPoint(100.0, 0.0);
ofun.addPoint(255.0, 1.0);
actor.getProperty().setRGBTransferFunction(0, ctfun);
actor.getProperty().setScalarOpacity(0, ofun);
// Create and setup the actor
const actor = vtkVolume.newInstance();
actor
.getProperty()
.setRGBTransferFunction(0, getRandomColorTransferFunction());
actor.getProperty().setScalarOpacity(0, sharedOpacityFunction);
actor.getProperty().setInterpolationTypeToLinear();
actor.getProperty().setShade(true);
actor.getProperty().setAmbient(0.3);
actor.getProperty().setDiffuse(1);
actor.getProperty().setDiffuse(0.8);
actor.getProperty().setSpecular(1);
actor.setScale(0.003, 0.003, 0.003);
actor.setPosition(1, 1, -1.1);
actor.getProperty().setSpecularPower(8);
actor.setMapper(mapper);

return actor;
}

function createImageActor(imageData) {
// Random plane normal
const randomQuat = [
Math.random(),
Math.random(),
Math.random(),
Math.random(),
];
const randomMat = new Float32Array(9);
vtkMath.quaternionToMatrix3x3(randomQuat, randomMat); // No need to normalize the quaternion
const randomNormal = [randomMat[0], randomMat[1], randomMat[2]];

// Create and setup the plane
const slicePlane = vtkPlane.newInstance();
slicePlane.setNormal(...randomNormal);
slicePlane.setOrigin(imageData.getCenter());

// Create and setup mapper
const mapper = vtkImageResliceMapper.newInstance();
mapper.setSlicePlane(slicePlane);
mapper.setSlabType(SlabTypes.MAX);
mapper.setInputData(imageData);

// Create and setup actor
const actor = vtkImageSlice.newInstance();
actor.getProperty().setRGBTransferFunction(getRandomColorTransferFunction());
actor.setMapper(mapper);

return actor;
}

async function createActors(numberOfActors) {
const reader = vtkHttpDataSetReader.newInstance({ fetchGzip: true });
await reader.setUrl(`${__BASE_PATH__}/data/volume/LIDC2.vti`);
await reader.loadData();
const imageData = reader.getOutputData();

mapper.setInputData(imageData);
const actors = [];
for (let i = 0; i < numberOfActors; ++i) {
if (Math.random() > 0.5) {
actors.push(createVolumeActor(imageData));
} else {
actors.push(createImageActor(imageData));
}
}

return actor;
return actors;
}

const mainRenderWindow = vtkRenderWindow.newInstance();
Expand Down Expand Up @@ -88,6 +145,7 @@ function addRenderWindow() {

// Create the corresponding view
const renderWindowView = mainRenderWindowView.addMissingNode(renderWindow);
renderWindow.addView(renderWindowView);

// Create a container for the view
const container = applyStyle(document.createElement('div'));
Expand Down Expand Up @@ -125,12 +183,12 @@ function addRenderWindow() {
// ----------------------------------------------------------------------------

const childRenderWindows = [];
createActor().then((actor) => {
createActors(64).then((actors) => {
// Main view has to be initialized before the first "render" from a child render window
// We initialize before creating the child render windows because the interactor initialization calls "render" on them
mainRenderWindowView.initialize();

for (let i = 0; i < 64; i++) {
actors.forEach((actor) => {
const childRenderWindow = addRenderWindow();

// Create the corresponding renderer
Expand All @@ -151,7 +209,7 @@ createActor().then((actor) => {
renderer.resetCamera();

childRenderWindows.push(childRenderWindow);
}
});

mainRenderWindowView.resizeFromChildRenderWindows();
mainRenderWindow.render();
Expand Down

0 comments on commit ac4d712

Please sign in to comment.