Skip to content

Commit

Permalink
Merge pull request #3157 from bruyeret/multi-component
Browse files Browse the repository at this point in the history
Add VolumeMapper multi component using multiple image data
  • Loading branch information
finetjul authored Oct 29, 2024
2 parents 3b86f71 + 6d54ca0 commit 4bb6513
Show file tree
Hide file tree
Showing 38 changed files with 2,894 additions and 3,262 deletions.
3 changes: 3 additions & 0 deletions BREAKING_CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## From 32.x to 33

- **vtkMapper**: many properties have moved to `vtkVolumeProperty`. The full list of changed methods is: `getAnisotropy`, `getComputeNormalFromOpacity`, `getFilterMode`, `getFilterModeAsString`, `getGlobalIlluminationReach`, `getIpScalarRange`, `getIpScalarRangeByReference`, `getLAOKernelRadius`, `getLAOKernelSize`, `getLocalAmbientOcclusion`, `getPreferSizeOverAccuracy`, `getVolumetricScatteringBlending`, `setAnisotropy`, `setAverageIPScalarRange`, `setComputeNormalFromOpacity`, `setFilterMode`, `setFilterModeToNormalized`, `setFilterModeToOff`, `setFilterModeToRaw`, `setGlobalIlluminationReach`, `setIpScalarRange`, `setIpScalarRangeFrom`, `setLAOKernelRadius`, `setLAOKernelSize`, `setLocalAmbientOcclusion`, `setPreferSizeOverAccuracy`, `setVolumetricScatteringBlending`.
## From 31.x to 32

- **vtkMapper**: remove `mapScalarsToTexture` from the public API. The function becomes protected and its API changes. This shouldn't cause any issue in most cases.
Expand Down
29 changes: 14 additions & 15 deletions Examples/Rendering/ManyRenderWindows/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,25 +44,24 @@ 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);
mapper.setInputData(imageData);

// 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(0.8);
actor.getProperty().setSpecular(1);
actor.getProperty().setSpecularPower(8);
const actorProperty = actor.getProperty();
actorProperty.setComputeNormalFromOpacity(true);
actorProperty.setLAOKernelRadius(5);
actorProperty.setLAOKernelSize(10);
actorProperty.setLocalAmbientOcclusion(0);
actorProperty.setVolumetricScatteringBlending(0);
actorProperty.setRGBTransferFunction(0, getRandomColorTransferFunction());
actorProperty.setScalarOpacity(0, sharedOpacityFunction);
actorProperty.setInterpolationTypeToLinear();
actorProperty.setShade(true);
actorProperty.setAmbient(0.3);
actorProperty.setDiffuse(0.8);
actorProperty.setSpecular(1);
actorProperty.setSpecularPower(8);
actor.setMapper(mapper);

return actor;
Expand Down
25 changes: 12 additions & 13 deletions Examples/Rendering/QuadView/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,28 +158,27 @@ function createVolumeView(renderer, source) {
.reduce((a, b) => a + b, 0)
);
mapper.setSampleDistance(sampleDistance / 2.5);
mapper.setComputeNormalFromOpacity(false);
mapper.setGlobalIlluminationReach(0.0);
mapper.setVolumetricScatteringBlending(0.5);
mapper.setVolumeShadowSamplingDistFactor(5.0);

// Set volume properties
const volProp = vtkVolumeProperty.newInstance();
volProp.setComputeNormalFromOpacity(false);
volProp.setGlobalIlluminationReach(0.0);
volProp.setVolumetricScatteringBlending(0.5);
volProp.setInterpolationTypeToLinear();
volume
.getProperty()
.setScalarOpacityUnitDistance(
0,
vtkBoundingBox.getDiagonalLength(source.getBounds()) /
Math.max(...source.getDimensions())
);
volProp.setScalarOpacityUnitDistance(
0,
vtkBoundingBox.getDiagonalLength(source.getBounds()) /
Math.max(...source.getDimensions())
);
volProp.setGradientOpacityMinimumValue(0, 0);
const dataArray =
source.getPointData().getScalars() || source.getPointData().getArrays()[0];
const dataRange = dataArray.getRange();
volume
.getProperty()
.setGradientOpacityMaximumValue(0, (dataRange[1] - dataRange[0]) * 0.05);
volProp.setGradientOpacityMaximumValue(
0,
(dataRange[1] - dataRange[0]) * 0.05
);
volProp.setShade(true);
volProp.setUseGradientOpacity(0, false);
volProp.setGradientOpacityMinimumOpacity(0, 0.0);
Expand Down
13 changes: 7 additions & 6 deletions Examples/Volume/VolumeMapperBlendModes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@ const reader = vtkHttpDataSetReader.newInstance({ fetchGzip: true });
const initialSampleDistance = 1.3;

const actor = vtkVolume.newInstance();
const actorProperty = actor.getProperty();
const mapper = vtkVolumeMapper.newInstance();
mapper.setSampleDistance(initialSampleDistance);

// use half float at the cost of precision to save memory
mapper.setPreferSizeOverAccuracy(true);
actorProperty.setPreferSizeOverAccuracy(true);

actor.setMapper(mapper);

Expand Down Expand Up @@ -125,16 +126,16 @@ function updateSampleDistance(event) {
}

function updateScalarMin(event) {
mapper.setIpScalarRange(
actorProperty.setIpScalarRange(
event.target.valueAsNumber,
mapper.getIpScalarRange()[1]
actorProperty.getIpScalarRange()[1]
);
renderWindow.render();
}

function updateScalarMax(event) {
mapper.setIpScalarRange(
mapper.getIpScalarRange()[0],
actorProperty.setIpScalarRange(
actorProperty.getIpScalarRange()[0],
event.target.valueAsNumber
);
renderWindow.render();
Expand All @@ -146,7 +147,7 @@ function updateBlendMode(event) {
const radonScalars = document.querySelectorAll('.radonScalar');

mapper.setBlendMode(currentBlendMode);
mapper.setIpScalarRange(0.0, 1.0);
actorProperty.setIpScalarRange(0.0, 1.0);

// if average or additive blend mode
for (let i = 0; i < ipScalarEls.length; i += 1) {
Expand Down
88 changes: 36 additions & 52 deletions Examples/Volume/VolumeMapperLightAndShadow/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import '@kitware/vtk.js/favicon';

import '@kitware/vtk.js/Rendering/Profiles/Volume';
import '@kitware/vtk.js/Rendering/Profiles/Geometry';
import macro from '@kitware/vtk.js/macros';
import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction';
import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow';
import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunction';
Expand Down Expand Up @@ -31,19 +30,6 @@ const fpsMonitor = vtkFPSMonitor.newInstance();
const progressContainer = document.createElement('div');
myContainer.appendChild(progressContainer);

const progressCallback = (progressEvent) => {
if (progressEvent.lengthComputable) {
const percent = Math.floor(
(100 * progressEvent.loaded) / progressEvent.total
);
progressContainer.innerHTML = `Loading ${percent}%`;
} else {
progressContainer.innerHTML = macro.formatBytesToProperUnit(
progressEvent.loaded
);
}
};

// ----------------------------------------------------------------------------
// Main function to set up and render volume
// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -94,10 +80,11 @@ function createVolumeShadowViewer(rootContainer, fileContents) {
const source = vtiReader.getOutputData(0);

const actor = vtkVolume.newInstance();
const actorProperty = actor.getProperty(0);
const mapper = vtkVolumeMapper.newInstance();

actor.setMapper(mapper);
mapper.setInputData(source);
mapper.addInputData(source);

// Add one positional light
const bounds = actor.getBounds();
Expand All @@ -124,44 +111,42 @@ function createVolumeShadowViewer(rootContainer, fileContents) {
.reduce((a, b) => a + b, 0)
);
mapper.setSampleDistance(sampleDistance / 2.5);
mapper.setComputeNormalFromOpacity(false);
mapper.setGlobalIlluminationReach(0.0);
mapper.setVolumetricScatteringBlending(0.0);
mapper.setVolumeShadowSamplingDistFactor(5.0);

// Add transfer function
const lookupTable = vtkColorTransferFunction.newInstance();
const piecewiseFunction = vtkPiecewiseFunction.newInstance();
actor.getProperty().setRGBTransferFunction(0, lookupTable);
actor.getProperty().setScalarOpacity(0, piecewiseFunction);
actorProperty.setRGBTransferFunction(0, lookupTable);
actorProperty.setScalarOpacity(0, piecewiseFunction);

// Set actor properties
actor.getProperty().setInterpolationTypeToLinear();
actor
.getProperty()
.setScalarOpacityUnitDistance(
0,
vtkBoundingBox.getDiagonalLength(source.getBounds()) /
Math.max(...source.getDimensions())
);
actor.getProperty().setGradientOpacityMinimumValue(0, 0);
actorProperty.setComputeNormalFromOpacity(false);
actorProperty.setGlobalIlluminationReach(0.0);
actorProperty.setVolumetricScatteringBlending(0.0);
actorProperty.setInterpolationTypeToLinear();
actorProperty.setScalarOpacityUnitDistance(
0,
vtkBoundingBox.getDiagonalLength(source.getBounds()) /
Math.max(...source.getDimensions())
);
actorProperty.setGradientOpacityMinimumValue(0, 0);
const dataArray =
source.getPointData().getScalars() || source.getPointData().getArrays()[0];
const dataRange = dataArray.getRange();
actor
.getProperty()
.setGradientOpacityMaximumValue(0, (dataRange[1] - dataRange[0]) * 0.05);
actor.getProperty().setShade(true);
actor.getProperty().setUseGradientOpacity(0, false);
actor.getProperty().setGradientOpacityMinimumOpacity(0, 0.0);
actor.getProperty().setGradientOpacityMaximumOpacity(0, 1.0);
actor.getProperty().setAmbient(0.0);
actor.getProperty().setDiffuse(2.0);
actor.getProperty().setSpecular(0.0);
actor.getProperty().setSpecularPower(0.0);
actor.getProperty().setUseLabelOutline(false);
actor.getProperty().setLabelOutlineThickness(2);
renderer.addActor(actor);
actorProperty.setGradientOpacityMaximumValue(
0,
(dataRange[1] - dataRange[0]) * 0.05
);
actorProperty.setShade(true);
actorProperty.setUseGradientOpacity(0, false);
actorProperty.setGradientOpacityMinimumOpacity(0, 0.0);
actorProperty.setGradientOpacityMaximumOpacity(0, 1.0);
actorProperty.setAmbient(0.0);
actorProperty.setDiffuse(2.0);
actorProperty.setSpecular(0.0);
actorProperty.setSpecularPower(0.0);
actorProperty.setUseLabelOutline(false);
actorProperty.setLabelOutlineThickness(2);

// Control UI for sample distance, transfer function, and shadow on/off
const controllerWidget = vtkVolumeController.newInstance({
Expand Down Expand Up @@ -191,12 +176,12 @@ function createVolumeShadowViewer(rootContainer, fileContents) {
// Add sliders to tune volume shadow effect
function updateVSB(e) {
const vsb = Number(e.target.value);
mapper.setVolumetricScatteringBlending(vsb);
actorProperty.setVolumetricScatteringBlending(vsb);
renderWindow.render();
}
function updateGlobalReach(e) {
const gir = Number(e.target.value);
mapper.setGlobalIlluminationReach(gir);
actorProperty.setGlobalIlluminationReach(gir);
renderWindow.render();
}
function updateSD(e) {
Expand All @@ -206,7 +191,7 @@ function createVolumeShadowViewer(rootContainer, fileContents) {
}
function updateAT(e) {
const at = Number(e.target.value);
mapper.setAnisotropy(at);
actorProperty.setAnisotropy(at);
renderWindow.render();
}
const el = document.querySelector('.volumeBlending');
Expand Down Expand Up @@ -235,7 +220,7 @@ function createVolumeShadowViewer(rootContainer, fileContents) {
const buttonID = document.querySelector('.text2');
function toggleDensityNormal() {
isDensity = !isDensity;
mapper.setComputeNormalFromOpacity(isDensity);
actorProperty.setComputeNormalFromOpacity(isDensity);
buttonID.innerText = `(${isDensity ? 'on' : 'off'})`;
renderWindow.render();
}
Expand All @@ -257,6 +242,9 @@ function createVolumeShadowViewer(rootContainer, fileContents) {
renderer.addActor(actorSphere);
}

// Add the volume actor here to avoid compiling the shader twice
renderer.addActor(actor);

// Camera and first render
renderer.resetCamera();
renderWindow.render();
Expand All @@ -279,11 +267,7 @@ function createVolumeShadowViewer(rootContainer, fileContents) {
// Read volume and render
// ----------------------------------------------------------------------------
HttpDataAccessHelper.fetchBinary(
'https://data.kitware.com/api/v1/item/59de9dc98d777f31ac641dc1/download',
{
progressCallback,
}
`${__BASE_PATH__}/data/volume/head-binary.vti`
).then((binary) => {
myContainer.removeChild(progressContainer);
createVolumeShadowViewer(myContainer, binary);
});
4 changes: 2 additions & 2 deletions Examples/Volume/WebXRChestCTBlendedCVR/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ HttpDataAccessHelper.fetchBinary(fileURL).then((fileContents) => {
actor.getProperty().setAmbient(0.2);
actor.getProperty().setDiffuse(1.3);
actor.getProperty().setSpecular(0.0);
mapper.setGlobalIlluminationReach(0.1);
mapper.setVolumetricScatteringBlending(0.5);
actor.getProperty().setGlobalIlluminationReach(0.1);
actor.getProperty().setVolumetricScatteringBlending(0.5);
mapper.setVolumeShadowSamplingDistFactor(1.0);
mapper.setAutoAdjustSampleDistances(false);

Expand Down
4 changes: 2 additions & 2 deletions Examples/Volume/WebXRHeadFullVolumeCVR/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ HttpDataAccessHelper.fetchBinary(fileURL).then((fileContents) => {
actor.getProperty().setAmbient(0.0);
actor.getProperty().setDiffuse(2.0);
actor.getProperty().setSpecular(0.0);
mapper.setGlobalIlluminationReach(1.0);
mapper.setVolumetricScatteringBlending(1.0);
actor.getProperty().setGlobalIlluminationReach(1.0);
actor.getProperty().setVolumetricScatteringBlending(1.0);
mapper.setVolumeShadowSamplingDistFactor(1.0);
mapper.setAutoAdjustSampleDistances(false);

Expand Down
4 changes: 2 additions & 2 deletions Examples/Volume/WebXRHeadGradientCVR/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ HttpDataAccessHelper.fetchBinary(fileURL).then((fileContents) => {

// CVR
actor.getProperty().setShade(true);
mapper.setGlobalIlluminationReach(0.0);
mapper.setVolumetricScatteringBlending(0.0);
actor.getProperty().setGlobalIlluminationReach(0.0);
actor.getProperty().setVolumetricScatteringBlending(0.0);
mapper.setVolumeShadowSamplingDistFactor(1.0);
mapper.setAutoAdjustSampleDistances(false);

Expand Down
25 changes: 5 additions & 20 deletions Sources/Rendering/Core/Actor/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,6 @@ export interface vtkActor extends vtkProp3D {
*/
getBackfaceProperty(): vtkProperty;

/**
* Get the bounds for this mapper as [xmin, xmax, ymin, ymax,zmin, zmax].
* @return {Bounds} The bounds for the mapper.
*/
getBounds(): Bounds;

/**
* Check whether the opaque is forced or not.
*/
Expand All @@ -63,16 +57,6 @@ export interface vtkActor extends vtkProp3D {
*/
getMapper(): Nullable<vtkMapper>;

/**
* Get the property object that controls this actors surface
* properties. This should be an instance of a vtkProperty object. Every
* actor must have a property associated with it. If one isn’t specified,
* then one will be generated automatically. Multiple actors can share one
* property object.
* @return {vtkProperty} The property object
*/
getProperty(): vtkProperty;

/**
* Check whether if the actor supports selection
* @return {Boolean} true if the actor support selection.
Expand Down Expand Up @@ -111,11 +95,12 @@ export interface vtkActor extends vtkProp3D {
*/
setMapper(mapper: vtkMapper): boolean;

/**
* Set the property object that controls this actors surface properties.
* @param {vtkProperty} property The vtkProperty instance.
*/
// Inherited from vtkProp3D, but takes a vtkProperty instead of a generic vtkObject
getProperty(mapperInputPort?: number): vtkProperty;
getProperties(): vtkProperty[];
setProperty(mapperInputPort: number, property: vtkProperty): boolean;
setProperty(property: vtkProperty): boolean;
setProperties(properties: vtkProperty[]): boolean;
}

/**
Expand Down
Loading

0 comments on commit 4bb6513

Please sign in to comment.