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: {})

getAnisotropy

Get anisotropy of volume shadow scatter

getAutoAdjustSampleDistances

getAverageIPScalarRange

getAverageIPScalarRangeByReference

getBlendMode

getBlendModeAsString

getBounds

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

getGlobalIlluminationReach

Get the global illumination reach of volume shadow

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

getLAOKernelRadius

Get kernel radius for local ambient occlusion

getLAOKernelSize

Get kernel size for local ambient occlusion

getLocalAmbientOcclusion

Get local ambient occlusion flag

getMaximumSamplesPerRay

getSampleDistance

Get the distance between samples used for rendering

getVolumeShadowSamplingDistFactor

Get the multipler for volume shadow sampling distance

getVolumetricScatteringBlending

Get the blending coefficient that interpolates between surface and volume rendering

newInstance

Method use to create a new instance of vtkVolumeMapper

setAnisotropy

Set anisotropy of volume shadow scatter. This function is only effective when volumeScatterBlendCoef is greater than 0.
Default value of 0.0 means light scatters uniformly in all directions.
Value of -1.0 means light scatters backward, value of 1.0 means light scatters forward.

Argument Type Required Description
anisotropy Yes

setAutoAdjustSampleDistances

Argument Type Required Description
autoAdjustSampleDistances Yes

setAverageIPScalarRange

Argument Type Required Description
x Yes
y Yes

setAverageIPScalarRangeFrom

Argument Type Required Description
averageIPScalarRange Range 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

setGlobalIlluminationReach

Set the global illumination reach of volume shadow. This function is only effective when volumeScatterBlendCoef is greater than 0.
Default value of 0.0 means only the neighboring voxel is considered when creating global shadow.
Value of 1.0 means the shadow ray traverses through the entire volume.

Argument Type Required Description
globalIlluminationReach Yes

setImageSampleDistance

Argument Type Required Description
imageSampleDistance Yes

setLAOKernelRadius

Set kernel radius for local ambient occlusion. It specifies the number of samples that are considered on each random ray.
Value must be greater than or equal to 1.

Argument Type Required Description
LAOKernelRadius Yes

setLAOKernelSize

Set kernel size for local ambient occlusion. It specifies the number of rays that are randomly sampled in the hemisphere.
Value is clipped between 1 and 32.

Argument Type Required Description
LAOKernelSize Yes

setLocalAmbientOcclusion

Set whether to turn on local ambient occlusion (LAO). LAO is only effective if shading is on and volumeScatterBlendCoef is set to 0.
LAO effect is added to ambient lighting, so the ambient component of the actor needs to be great than 0.

Argument Type Required Description
localAmbientOcclusion Yes

setMaximumSamplesPerRay

Argument Type Required Description
maximumSamplesPerRay Yes

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

setVolumetricScatteringBlending

Set the blending coefficient that determines the interpolation between surface and volume rendering.
Default value of 0.0 means shadow effect is computed with phong model.
Value of 1.0 means shadow is created by volume occlusion.

Argument Type Required Description
volumeScatterBlendCoef 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,
}

export declare enum FilterMode {
OFF = 0,
NORMALIZED = 1,
RAW = 2,
}

declare const _default: {
BlendMode: typeof BlendMode;
FilterMode: typeof FilterMode;
};
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,
};

export const FilterMode = {
OFF: 0,
NORMALIZED: 1,
RAW: 2,
};

export default {
BlendMode,
FilterMode,
};
index.d.ts
import vtkPiecewiseFunction from "../../../Common/DataModel/PiecewiseFunction";
import { Bounds, Range } from "../../../types";
import vtkAbstractMapper, { IAbstractMapperInitialValues } from "../AbstractMapper";
import { BlendMode, FilterMode } from "./Constants";

/**
*
*/
export interface IVolumeMapperInitialValues extends IAbstractMapperInitialValues {
bounds?: Bounds;
blendMode?: BlendMode;
sampleDistance?: number;
imageSampleDistance?: number;
maximumSamplesPerRay?: number;
autoAdjustSampleDistances?: boolean;
averageIPScalarRange?: Range;
}

export interface vtkVolumeMapper extends vtkAbstractMapper {

/**
* 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;

/**
* 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;

/**
*
*/
getAverageIPScalarRange(): Range;

/**
*
*/
getAverageIPScalarRangeByReference(): Range;

/**
* Get the blending coefficient that interpolates between surface and volume rendering
* @default 0.0
*/
getVolumetricScatteringBlending(): number;

/**
* Get the global illumination reach of volume shadow
* @default 0.0
*/
getGlobalIlluminationReach(): number;

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

/**
* Get anisotropy of volume shadow scatter
* @default 0.0
*/
getAnisotropy(): number;

/**
* Get local ambient occlusion flag
* @default false
*/
getLocalAmbientOcclusion(): boolean;

/**
* Get kernel size for local ambient occlusion
* @default 15
*/
getLAOKernelSize(): number;

/**
* Get kernel radius for local ambient occlusion
* @default 7
*/
getLAOKernelRadius(): number;

/**
*
* @param x
* @param y
*/
setAverageIPScalarRange(x: number, y: number): boolean;

/**
*
* @param {Range} averageIPScalarRange
*/
setAverageIPScalarRangeFrom(averageIPScalarRange: Range): boolean;

/**
* 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;

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

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

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

/**
* Set the blending coefficient that determines the interpolation between surface and volume rendering.
* Default value of 0.0 means shadow effect is computed with phong model.
* Value of 1.0 means shadow is created by volume occlusion.
* @param volumeScatterBlendCoef
*/
setVolumetricScatteringBlending(volumeScatterBlendCoef: number): void;

/**
* Set the global illumination reach of volume shadow. This function is only effective when volumeScatterBlendCoef is greater than 0.
* Default value of 0.0 means only the neighboring voxel is considered when creating global shadow.
* Value of 1.0 means the shadow ray traverses through the entire volume.
* @param globalIlluminationReach
*/
setGlobalIlluminationReach(globalIlluminationReach: number): void;

/**
* 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;

/**
* Set anisotropy of volume shadow scatter. This function is only effective when volumeScatterBlendCoef is greater than 0.
* Default value of 0.0 means light scatters uniformly in all directions.
* Value of -1.0 means light scatters backward, value of 1.0 means light scatters forward.
* @param anisotropy
*/
setAnisotropy(anisotropy: number): void;

/**
* Set whether to turn on local ambient occlusion (LAO). LAO is only effective if shading is on and volumeScatterBlendCoef is set to 0.
* LAO effect is added to ambient lighting, so the ambient component of the actor needs to be great than 0.
* @param localAmbientOcclusion
*/
setLocalAmbientOcclusion(localAmbientOcclusion: boolean): void;

/**
* Set kernel size for local ambient occlusion. It specifies the number of rays that are randomly sampled in the hemisphere.
* Value is clipped between 1 and 32.
* @param LAOKernelSize
*/
setLAOKernelSize(LAOKernelSize: number): void;

/**
* Set kernel radius for local ambient occlusion. It specifies the number of samples that are considered on each random ray.
* Value must be greater than or equal to 1.
* @param LAOKernelRadius
*/
setLAOKernelRadius(LAOKernelRadius: number): void;

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

/**
* 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;
FilterMode: typeof FilterMode;
};
export default vtkVolumeMapper;
index.js
import macro from 'vtk.js/Sources/macros';
import * as vtkMath from 'vtk.js/Sources/Common/Core/Math';
import Constants from 'vtk.js/Sources/Rendering/Core/VolumeMapper/Constants';
import vtkAbstractMapper from 'vtk.js/Sources/Rendering/Core/AbstractMapper';
import vtkPiecewiseFunction from 'vtk.js/Sources/Common/DataModel/PiecewiseFunction';

const { BlendMode, FilterMode } = 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;
}

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

export const STATIC = {
createRadonTransferFunction,
};

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

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

const superClass = { ...publicAPI };

publicAPI.getBounds = () => {
const input = publicAPI.getInputData();
if (!input) {
model.bounds = vtkMath.createUninitializedBounds();
} else {
if (!model.static) {
publicAPI.update();
}
model.bounds = input.getBounds();
}
return model.bounds;
};

publicAPI.update = () => {
publicAPI.getInputData();
};

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.setAverageIPScalarRange = (min, max) => {
console.warn('setAverageIPScalarRange is deprecated use setIpScalarRange');
publicAPI.setIpScalarRange(min, max);
};

publicAPI.getFilterModeAsString = () =>
macro.enumToString(FilterMode, model.filterMode);

publicAPI.setFilterModeToOff = () => {
publicAPI.setFilterMode(FilterMode.OFF);
};

publicAPI.setFilterModeToNormalized = () => {
publicAPI.setFilterMode(FilterMode.NORMALIZED);
};

publicAPI.setFilterModeToRaw = () => {
publicAPI.setFilterMode(FilterMode.RAW);
};

publicAPI.setGlobalIlluminationReach = (gl) =>
superClass.setGlobalIlluminationReach(vtkMath.clampValue(gl, 0.0, 1.0));

publicAPI.setVolumetricScatteringBlending = (vsb) =>
superClass.setVolumetricScatteringBlending(
vtkMath.clampValue(vsb, 0.0, 1.0)
);

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

publicAPI.setAnisotropy = (at) =>
superClass.setAnisotropy(vtkMath.clampValue(at, -0.99, 0.99));

publicAPI.setLAOKernelSize = (ks) =>
superClass.setLAOKernelSize(vtkMath.floor(vtkMath.clampValue(ks, 1, 32)));

publicAPI.setLAOKernelRadius = (kr) =>
superClass.setLAOKernelRadius(kr >= 1 ? kr : 1);
}

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

// TODO: what values to use for averageIPScalarRange to get GLSL to use max / min values like [-Math.inf, Math.inf]?
const DEFAULT_VALUES = {
bounds: [1, -1, 1, -1, 1, -1],
sampleDistance: 1.0,
imageSampleDistance: 1.0,
maximumSamplesPerRay: 1000,
autoAdjustSampleDistances: true,
blendMode: BlendMode.COMPOSITE_BLEND,
ipScalarRange: [-1000000.0, 1000000.0],
filterMode: FilterMode.OFF, // ignored by WebGL so no behavior change
preferSizeOverAccuracy: false, // Whether to use halfFloat representation of float, when it is inaccurate
computeNormalFromOpacity: false,
// volume shadow parameters
volumetricScatteringBlending: 0.0,
globalIlluminationReach: 0.0,
volumeShadowSamplingDistFactor: 5.0,
anisotropy: 0.0,
// local ambient occlusion
localAmbientOcclusion: false,
LAOKernelSize: 15,
LAOKernelRadius: 7,
};

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

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

vtkAbstractMapper.extend(publicAPI, model, initialValues);

macro.setGet(publicAPI, model, [
'sampleDistance',
'imageSampleDistance',
'maximumSamplesPerRay',
'autoAdjustSampleDistances',
'blendMode',
'filterMode',
'preferSizeOverAccuracy',
'computeNormalFromOpacity',
'volumetricScatteringBlending',
'globalIlluminationReach',
'volumeShadowSamplingDistFactor',
'anisotropy',
'localAmbientOcclusion',
'LAOKernelSize',
'LAOKernelRadius',
]);

macro.setGetArray(publicAPI, model, ['ipScalarRange'], 2);

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

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

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

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

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

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