VolumeMapper

Introduction

vtkVolumeMapper inherits from vtkMapper.
A volume mapper that performs ray casting on the GPU using fragment programs.

Methods

createRadonTransferFunction

Create an absorption transfer function to set to the mapper when blend mode is RADON.
The transfer function is a linear ramp between the lowest material with absorption and
the material with maximum absorption. Voxel values lower than the lowest material with
absorption will have no absorption associated. Voxel values higher than the maximum
absorbent material will have the same absorption than the max absorbent material.
The associated color transfer function is typically black to white between 0 and 1.
An alternative is to create your own transfer function with HU/absorption pairs. e.g.
const ofun = vtkPiecewiseFunction.newInstance();
ofun.addPointLong(-1000,0, 1, 1); // air, “1, 1)” to flatten the function
ofun.addPoint(-10, 0.01); // fat
ofun.addPoint(-10, 0.015); // water
ofun.addPointLong(1000, 0.03, 1, 1); // bone
ofun.addPoint(3000, 1); // silver

Argument Type Required Description
firstAbsorbentMaterialHounsfieldValue: number Yes Define minimum voxel value (in hounsfield unit) with non zero absorption (e.g. water (0), fat(-10)…). Any voxel value lower than this parameter will have no absorption (absorption === 0)
firstAbsorbentMaterialAbsorption: number Yes Absorption attributed to voxels with firstAbsorbentMaterialHounsfieldValue (e.g. 0 or 0.01)
maxAbsorbentMaterialHounsfieldValue: number Yes Define maximum voxel value (in hounsfield unit) with increasing absorption (e.g. bone (1000))
maxAbsorbentMaterialAbsorption: number Yes Absorption attributed to voxels >= maxAbsorbentMaterialHounsfieldValue (e.g. 0.03)
outputTransferFunction: vtkPiecewiseFunction Yes To provide optionally to avoid instantiating a new transfer function each time.

extend

Method use to decorate a given object (publicAPI+model) with vtkVolumeMapper characteristics.

Argument Type Required Description
publicAPI Yes object on which methods will be bounds (public)
model Yes object on which data structure will be bounds (protected)
initialValues IVolumeMapperInitialValues No (default: {})

getAutoAdjustSampleDistances

getBlendMode

getBlendModeAsString

getBounds

Get the bounds for this mapper as [xmin, xmax, ymin, ymax,zmin, zmax].

getColorTextureWidth

Get the color texture width.

getImageSampleDistance

Sampling distance in the XY image dimensions.
Default value of 1 meaning 1 ray cast per pixel. If set to 0.5, 4 rays will be cast per pixel.
If set to 2.0, 1 ray will be cast for every 4 (2 by 2) pixels. T

getInitialInteractionScale

Get at what scale the quality is reduced when interacting for the first time with the volume
It should should be set before any call to render for this volume
The higher the scale is, the lower the quality of rendering is during interaction

getInteractionSampleDistanceFactor

Get by how much the sample distance should be increased when interacting
This feature is only implemented in the OpenGL volume mapper

getLabelOutlineTextureWidth

Get the label outline texture width.

getMaximumSamplesPerRay

getOpacityTextureWidth

Get the opacity texture width.

getSampleDistance

Get the distance between samples used for rendering

getVolumeShadowSamplingDistFactor

Get the multipler for volume shadow sampling distance

newInstance

Method use to create a new instance of vtkVolumeMapper

setAutoAdjustSampleDistances

Argument Type Required Description
autoAdjustSampleDistances Yes

setBlendMode

Set blend mode to COMPOSITE_BLEND

Argument Type Required Description
blendMode BlendMode Yes

setBlendModeToAverageIntensity

Set blend mode to AVERAGE_INTENSITY_BLEND

setBlendModeToComposite

Set blend mode to COMPOSITE_BLEND

setBlendModeToMaximumIntensity

Set blend mode to MAXIMUM_INTENSITY_BLEND

setBlendModeToMinimumIntensity

Set blend mode to MINIMUM_INTENSITY_BLEND

setBlendModeToRadonTransform

Set blend mode to RADON_TRANSFORM_BLEND

setColorTextureWidth

Set the color texture width.

The default width (1024) should be fine in most instances.
Only set this property if your color transfer function range width is
larger than 1024.

A reasonable max texture size would be either 2048 or 4096, as those
widths are supported by the vast majority of devices. Any width larger
than that will have issues with device support.

Specifying a width that is less than or equal to 0 will use the largest
possible texture width on the device. Use this with caution! The max texture
width of one device may not be the same for another device.

You can find more information about supported texture widths at the following link:
https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE

Argument Type Required Description
width Number Yes the texture width (defaults to 1024)

setImageSampleDistance

Argument Type Required Description
imageSampleDistance Yes

setInitialInteractionScale

Argument Type Required Description
initialInteractionScale Yes

setInteractionSampleDistanceFactor

Argument Type Required Description
interactionSampleDistanceFactor Yes

setLabelOutlineTextureWidth

Set the label outline texture width.

The default width (1024) should be fine in most instances.
Only set this property if you have more than 1024 labels
that you want to render with thickness.

A reasonable max texture size would be either 2048 or 4096, as those
widths are supported by the vast majority of devices. Any width larger
than that will have issues with device support.

Specifying a width that is less than or equal to 0 will use the largest
possible texture width on the device. Use this with caution! The max texture
width of one device may not be the same for another device.

You can find more information about supported texture widths at the following link:
https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE

Argument Type Required Description
width Number Yes the texture width (defaults to 1024)

setMaximumSamplesPerRay

Argument Type Required Description
maximumSamplesPerRay Yes

setOpacityTextureWidth

Set the opacity texture width.

The default width (1024) should be fine in most instances.
Only set this property if your opacity function range width is
larger than 1024.

Argument Type Required Description
width Number Yes the texture width (defaults to 1024)

setSampleDistance

Get the distance between samples used for rendering

Argument Type Required Description
sampleDistance Yes

setVolumeShadowSamplingDistFactor

Set the multipler for volume shadow sampling distance. This function is only effective when volumeScatterBlendCoef is greater than 0.
For VSSampleDistanceFactor >= 1.0, volume shadow sampling distance = VSSampleDistanceFactor * SampleDistance.

Argument Type Required Description
VSSampleDistanceFactor Yes

update

Source

Constants.d.ts
export declare enum BlendMode {
COMPOSITE_BLEND = 0,
MAXIMUM_INTENSITY_BLEND = 1,
MINIMUM_INTENSITY_BLEND = 2,
AVERAGE_INTENSITY_BLEND = 3,
ADDITIVE_INTENSITY_BLEND = 4,
RADON_TRANSFORM_BLEND = 5,
LABELMAP_EDGE_PROJECTION_BLEND = 6,
}

declare const _default: {
BlendMode: typeof BlendMode;
};
export default _default;
Constants.js
export const BlendMode = {
COMPOSITE_BLEND: 0,
MAXIMUM_INTENSITY_BLEND: 1,
MINIMUM_INTENSITY_BLEND: 2,
AVERAGE_INTENSITY_BLEND: 3,
ADDITIVE_INTENSITY_BLEND: 4,
RADON_TRANSFORM_BLEND: 5,
LABELMAP_EDGE_PROJECTION_BLEND: 6,
};

export default { BlendMode };
index.d.ts
import { vtkPiecewiseFunction } from '../../../Common/DataModel/PiecewiseFunction';
import { Bounds } from '../../../types';
import {
vtkAbstractMapper3D,
IAbstractMapper3DInitialValues,
} from '../AbstractMapper3D';
import { BlendMode } from './Constants';

/**
*
*/
export interface IVolumeMapperInitialValues
extends IAbstractMapper3DInitialValues {
autoAdjustSampleDistances?: boolean;
blendMode?: BlendMode;
bounds?: Bounds;
maximumSamplesPerRay?: number;
sampleDistance?: number;
volumeShadowSamplingDistFactor?: number;
}

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

/**
*
*/
getBlendMode(): BlendMode;

/**
*
*/
getBlendModeAsString(): string;

/**
* Get the distance between samples used for rendering
* @default 1.0
*/
getSampleDistance(): number;

/**
* Get the multipler for volume shadow sampling distance
* @default 5.0
*/
getVolumeShadowSamplingDistFactor(): number;

/**
* Sampling distance in the XY image dimensions.
* Default value of 1 meaning 1 ray cast per pixel. If set to 0.5, 4 rays will be cast per pixel.
* If set to 2.0, 1 ray will be cast for every 4 (2 by 2) pixels. T
* @default 1.0
*/
getImageSampleDistance(): number;

/**
*
* @default 1000
*/
getMaximumSamplesPerRay(): number;

/**
*
* @default true
*/
getAutoAdjustSampleDistances(): boolean;

/**
* Get at what scale the quality is reduced when interacting for the first time with the volume
* It should should be set before any call to render for this volume
* The higher the scale is, the lower the quality of rendering is during interaction
* @default 1
*/
getInitialInteractionScale(): number;

/**
* Get by how much the sample distance should be increased when interacting
* This feature is only implemented in the OpenGL volume mapper
* @default 1
*/
getInteractionSampleDistanceFactor(): number;

/**
* Set blend mode to COMPOSITE_BLEND
* @param {BlendMode} blendMode
*/
setBlendMode(blendMode: BlendMode): void;

/**
* Set blend mode to COMPOSITE_BLEND
*/
setBlendModeToComposite(): void;

/**
* Set blend mode to MAXIMUM_INTENSITY_BLEND
*/
setBlendModeToMaximumIntensity(): void;

/**
* Set blend mode to MINIMUM_INTENSITY_BLEND
*/
setBlendModeToMinimumIntensity(): void;

/**
* Set blend mode to AVERAGE_INTENSITY_BLEND
*/
setBlendModeToAverageIntensity(): void;

/**
* Set blend mode to RADON_TRANSFORM_BLEND
*/
setBlendModeToRadonTransform(): void;

/**
* Get the distance between samples used for rendering
* @param sampleDistance
*/
setSampleDistance(sampleDistance: number): boolean;

/**
* Set the multipler for volume shadow sampling distance. This function is only effective when volumeScatterBlendCoef is greater than 0.
* For VSSampleDistanceFactor >= 1.0, volume shadow sampling distance = VSSampleDistanceFactor * SampleDistance.
* @param VSSampleDistanceFactor
*/
setVolumeShadowSamplingDistFactor(VSSampleDistanceFactor: number): void;

/**
*
* @param imageSampleDistance
*/
setImageSampleDistance(imageSampleDistance: number): boolean;

/**
*
* @param maximumSamplesPerRay
*/
setMaximumSamplesPerRay(maximumSamplesPerRay: number): boolean;

/**
*
* @param autoAdjustSampleDistances
*/
setAutoAdjustSampleDistances(autoAdjustSampleDistances: boolean): boolean;

/**
*
* @param initialInteractionScale
*/
setInitialInteractionScale(initialInteractionScale: number): boolean;

/**
*
* @param interactionSampleDistanceFactor
*/
setInteractionSampleDistanceFactor(
interactionSampleDistanceFactor: number
): boolean;

/**
*
*/
update(): void;

/**
* Set the opacity texture width.
*
* The default width (1024) should be fine in most instances.
* Only set this property if your opacity function range width is
* larger than 1024.
*
* @param {Number} width the texture width (defaults to 1024)
*/
setOpacityTextureWidth(width: number): boolean;

/**
* Get the opacity texture width.
*/
getOpacityTextureWidth(): number;

/**
* Set the color texture width.
*
* The default width (1024) should be fine in most instances.
* Only set this property if your color transfer function range width is
* larger than 1024.
*
* A reasonable max texture size would be either 2048 or 4096, as those
* widths are supported by the vast majority of devices. Any width larger
* than that will have issues with device support.
*
* Specifying a width that is less than or equal to 0 will use the largest
* possible texture width on the device. Use this with caution! The max texture
* width of one device may not be the same for another device.
*
* You can find more information about supported texture widths at the following link:
* https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE
*
* @param {Number} width the texture width (defaults to 1024)
*/
setColorTextureWidth(width: number): boolean;

/**
* Get the color texture width.
*/
getColorTextureWidth(): number;

/**
* Set the label outline texture width.
*
* The default width (1024) should be fine in most instances.
* Only set this property if you have more than 1024 labels
* that you want to render with thickness.
*
* A reasonable max texture size would be either 2048 or 4096, as those
* widths are supported by the vast majority of devices. Any width larger
* than that will have issues with device support.
*
* Specifying a width that is less than or equal to 0 will use the largest
* possible texture width on the device. Use this with caution! The max texture
* width of one device may not be the same for another device.
*
* You can find more information about supported texture widths at the following link:
* https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE
*
* @param {Number} width the texture width (defaults to 1024)
*/
setLabelOutlineTextureWidth(width: number): boolean;

/**
* Get the label outline texture width.
*/
getLabelOutlineTextureWidth(): number;
}

/**
* Create an absorption transfer function to set to the mapper when blend mode is RADON.
* The transfer function is a linear ramp between the lowest material with absorption and
* the material with maximum absorption. Voxel values lower than the lowest material with
* absorption will have no absorption associated. Voxel values higher than the maximum
* absorbent material will have the same absorption than the max absorbent material.
* The associated color transfer function is typically black to white between 0 and 1.
* An alternative is to create your own transfer function with HU/absorption pairs. e.g.
* const ofun = vtkPiecewiseFunction.newInstance();
* ofun.addPointLong(-1000,0, 1, 1); // air, "1, 1)" to flatten the function
* ofun.addPoint(-10, 0.01); // fat
* ofun.addPoint(-10, 0.015); // water
* ofun.addPointLong(1000, 0.03, 1, 1); // bone
* ofun.addPoint(3000, 1); // silver
* @static
* @param {number} firstAbsorbentMaterialHounsfieldValue: Define minimum voxel value (in hounsfield unit) with non zero absorption (e.g. water (0), fat(-10)...).
* Any voxel value lower than this parameter will have no absorption (absorption === 0)
* @param {number} firstAbsorbentMaterialAbsorption: Absorption attributed to voxels with firstAbsorbentMaterialHounsfieldValue (e.g. 0 or 0.01)
* @param {number} maxAbsorbentMaterialHounsfieldValue: Define maximum voxel value (in hounsfield unit) with increasing absorption (e.g. bone (1000))
* @param {number} maxAbsorbentMaterialAbsorption: Absorption attributed to voxels >= maxAbsorbentMaterialHounsfieldValue (e.g. 0.03)
* @param {vtkPiecewiseFunction} outputTransferFunction: To provide optionally to avoid instantiating a new transfer function each time.
* @return {vtkPiecewiseFunction} the created absorption transfer function to set on VolumeMapper scalarOpacity.
*/
export function createRadonTransferFunction(
firstAbsorbentMaterialHounsfieldValue: number,
firstAbsorbentMaterialAbsorption: number,
maxAbsorbentMaterialHounsfieldValue: number,
maxAbsorbentMaterialAbsorption: number,
outputTransferFunction?: vtkPiecewiseFunction
): vtkPiecewiseFunction;

/**
* Method use to decorate a given object (publicAPI+model) with vtkVolumeMapper characteristics.
*
* @param publicAPI object on which methods will be bounds (public)
* @param model object on which data structure will be bounds (protected)
* @param {IVolumeMapperInitialValues} [initialValues] (default: {})
*/
export function extend(
publicAPI: object,
model: object,
initialValues?: IVolumeMapperInitialValues
): void;

/**
* Method use to create a new instance of vtkVolumeMapper
*/
export function newInstance(
initialValues?: IVolumeMapperInitialValues
): vtkVolumeMapper;

/**
* vtkVolumeMapper inherits from vtkMapper.
* A volume mapper that performs ray casting on the GPU using fragment programs.
*/
export declare const vtkVolumeMapper: {
newInstance: typeof newInstance;
extend: typeof extend;
BlendMode: typeof BlendMode;
};
export default vtkVolumeMapper;
index.js
import macro from 'vtk.js/Sources/macros';
import Constants from 'vtk.js/Sources/Rendering/Core/VolumeMapper/Constants';
import vtkAbstractMapper3D from 'vtk.js/Sources/Rendering/Core/AbstractMapper3D';
import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox';
import vtkPiecewiseFunction from 'vtk.js/Sources/Common/DataModel/PiecewiseFunction';

const { BlendMode } = Constants;

function createRadonTransferFunction(
firstAbsorbentMaterialHounsfieldValue,
firstAbsorbentMaterialAbsorption,
maxAbsorbentMaterialHounsfieldValue,
maxAbsorbentMaterialAbsorption,
outputTransferFunction
) {
let ofun = null;
if (outputTransferFunction) {
ofun = outputTransferFunction;
ofun.removeAllPoints();
} else {
ofun = vtkPiecewiseFunction.newInstance();
}
ofun.addPointLong(-1024, 0, 1, 1); // air (i.e. material with no absorption)
ofun.addPoint(
firstAbsorbentMaterialHounsfieldValue,
firstAbsorbentMaterialAbsorption
);
ofun.addPoint(
maxAbsorbentMaterialHounsfieldValue,
maxAbsorbentMaterialAbsorption
);

return ofun;
}

const methodNamesMovedToVolumeProperties = [
'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',
];

// ----------------------------------------------------------------------------
// Static API
// ----------------------------------------------------------------------------

export const STATIC = {
createRadonTransferFunction,
};

// ----------------------------------------------------------------------------
// vtkVolumeMapper methods
// ----------------------------------------------------------------------------

function vtkVolumeMapper(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkVolumeMapper');

const superClass = { ...publicAPI };

publicAPI.getBounds = () => {
if (!model.static) {
publicAPI.update();
}
model.bounds = [...publicAPI.getInputData().getBounds()];
return model.bounds;
};

publicAPI.setBlendModeToComposite = () => {
publicAPI.setBlendMode(BlendMode.COMPOSITE_BLEND);
};

publicAPI.setBlendModeToMaximumIntensity = () => {
publicAPI.setBlendMode(BlendMode.MAXIMUM_INTENSITY_BLEND);
};

publicAPI.setBlendModeToMinimumIntensity = () => {
publicAPI.setBlendMode(BlendMode.MINIMUM_INTENSITY_BLEND);
};

publicAPI.setBlendModeToAverageIntensity = () => {
publicAPI.setBlendMode(BlendMode.AVERAGE_INTENSITY_BLEND);
};

publicAPI.setBlendModeToAdditiveIntensity = () => {
publicAPI.setBlendMode(BlendMode.ADDITIVE_INTENSITY_BLEND);
};

publicAPI.setBlendModeToRadonTransform = () => {
publicAPI.setBlendMode(BlendMode.RADON_TRANSFORM_BLEND);
};

publicAPI.getBlendModeAsString = () =>
macro.enumToString(BlendMode, model.blendMode);

publicAPI.setVolumeShadowSamplingDistFactor = (vsdf) =>
superClass.setVolumeShadowSamplingDistFactor(vsdf >= 1.0 ? vsdf : 1.0);

// Instead of a "undefined is not a function" error, give more context and advice for these widely used methods
methodNamesMovedToVolumeProperties.forEach((removedMethodName) => {
const removedMethod = () => {
throw new Error(
`The method "volumeMapper.${removedMethodName}()" doesn't exist anymore. ` +
`It is a rendering property that has been moved to the volume property. ` +
`Replace your code with:\n` +
`volumeActor.getProperty().${removedMethodName}()\n`
);
};
publicAPI[removedMethodName] = removedMethod;
});
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

// TODO: what values to use for averageIPScalarRange to get GLSL to use max / min values like [-Math.inf, Math.inf]?
const defaultValues = (initialValues) => ({
bounds: [...vtkBoundingBox.INIT_BOUNDS],
sampleDistance: 1.0,
imageSampleDistance: 1.0,
maximumSamplesPerRay: 1000,
autoAdjustSampleDistances: true,
initialInteractionScale: 1.0,
interactionSampleDistanceFactor: 1.0,
blendMode: BlendMode.COMPOSITE_BLEND,
volumeShadowSamplingDistFactor: 5.0,
colorTextureWidth: 1024,
opacityTextureWidth: 1024,
labelOutlineTextureWidth: 1024,
...initialValues,
});

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, defaultValues(initialValues));

vtkAbstractMapper3D.extend(publicAPI, model, initialValues);

macro.setGet(publicAPI, model, [
'sampleDistance',
'imageSampleDistance',
'maximumSamplesPerRay',
'autoAdjustSampleDistances',
'initialInteractionScale',
'interactionSampleDistanceFactor',
'blendMode',
'volumeShadowSamplingDistFactor',
'colorTextureWidth',
'opacityTextureWidth',
'labelOutlineTextureWidth',
]);

macro.event(publicAPI, model, 'lightingActivated');

// Object methods
vtkVolumeMapper(publicAPI, model);
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(extend, 'vtkVolumeMapper');

// ----------------------------------------------------------------------------

export default { newInstance, extend, ...STATIC };