VolumeProperty

Introduction

vtkVolumeProperty is used to represent common properties associated
with volume rendering. This includes properties for determining the type
of interpolation to use when sampling a volume, the color of a volume,
the scalar opacity of a volume, the gradient opacity of a volume, and the
shading parameters of a volume.

When the scalar opacity or the gradient opacity of a volume is not set,
then the function is defined to be a constant value of 1.0. When a
scalar and gradient opacity are both set simultaneously, then the opacity
is defined to be the product of the scalar opacity and gradient opacity
transfer functions.

Most properties can be set per “component” for volume mappers that
support multiple independent components. If you are using 2 component
data as LV or 4 component data as RGBV (as specified in the mapper)
only the first scalar opacity and gradient opacity transfer functions
will be used (and all color functions will be ignored). Omitting the
index parameter on the Set/Get methods will access index = 0.

vtkColorTransferFunction is a color mapping in RGB or HSV space that
uses piecewise hermite functions to allow interpolation that can be
piecewise constant, piecewise linear, or somewhere in-between
(a modified piecewise hermite function that squishes the function
according to a sharpness parameter). The function also allows for
the specification of the midpoint (the place where the function
reaches the average of the two bounding nodes) as a normalize distance
between nodes.

See the description of class vtkPiecewiseFunction for an explanation of
midpoint and sharpness.

Usage


// create color and opacity transfer functions
const ctfun = vtkColorTransferFunction.newInstance();
ctfun.addRGBPoint(200.0, 1.0, 1.0, 1.0);
ctfun.addRGBPoint(2000.0, 0.0, 0.0, 0.0);
const ofun = vtkPiecewiseFunction.newInstance();
ofun.addPoint(200.0, 0.0);
ofun.addPoint(1200.0, 0.2);
ofun.addPoint(4000.0, 0.4);

// set them on the property
volume.getProperty().setRGBTransferFunction(0, ctfun);
volume.getProperty().setScalarOpacity(0, ofun);
volume.getProperty().setScalarOpacityUnitDistance(0, 4.5);
volume.getProperty().setInterpolationTypeToLinear();

See Also

vtkColorTransferFunction
vtkPiecewiseFunction
vtkVolume

Methods

getInterpolationType

getInterpolationTypeAsString

setInterpolationTypeToNearest

setInterpolationTypeToFastLinear

setInterpolationTypeToLinear

Set/Get the interpolation type for sampling a volume. The initial
value is FAST_LINEAR. NEAREST interpolation will snap to the closest
voxel, LINEAR will perform trilinear interpolation to compute a
scalar value from surrounding voxels. FAST_LINEAR under WebGL 1
will perform bilinear interpolation on X and Y but use nearest
for Z. This is slightly faster than full linear at the cost of
no Z axis linear interpolation.

setScalarOpacityUnitDistance

Set/Get the unit distance on which the scalar opacity transfer function
is defined. By default this is 1.0, meaning that over a distance of
1.0 units, a given opacity (from the transfer function) is accumulated.
This is adjusted for the actual sampling distance during rendering.

Source

Constants.js
export const InterpolationType = {
NEAREST: 0,
LINEAR: 1,
FAST_LINEAR: 2,
};

export default {
InterpolationType,
};
index.js
import macro from 'vtk.js/Sources/macro';
import vtkColorTransferFunction from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction';
import vtkPiecewiseFunction from 'vtk.js/Sources/Common/DataModel/PiecewiseFunction';
import Constants from 'vtk.js/Sources/Rendering/Core/VolumeProperty/Constants';

const { InterpolationType } = Constants;
const { vtkErrorMacro } = macro;

const VTK_MAX_VRCOMP = 4;

// ----------------------------------------------------------------------------
// vtkVolumeProperty methods
// ----------------------------------------------------------------------------

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

publicAPI.getMTime = () => {
let mTime = model.mtime;
let time;

for (let index = 0; index < VTK_MAX_VRCOMP; index++) {
// Color MTimes
if (model.componentData[index].colorChannels === 1) {
if (model.componentData[index].grayTransferFunction) {
// time that Gray transfer function was last modified
time = model.componentData[index].grayTransferFunction.getMTime();
mTime = mTime > time ? mTime : time;
}
} else if (model.componentData[index].colorChannels === 3) {
if (model.componentData[index].rGBTransferFunction) {
// time that RGB transfer function was last modified
time = model.componentData[index].rGBTransferFunction.getMTime();
mTime = mTime > time ? mTime : time;
}
}

// Opacity MTimes
if (model.componentData[index].scalarOpacity) {
// time that Scalar opacity transfer function was last modified
time = model.componentData[index].scalarOpacity.getMTime();
mTime = mTime > time ? mTime : time;
}

if (model.componentData[index].gradientOpacity) {
if (!model.componentData[index].disableGradientOpacity) {
// time that Gradient opacity transfer function was last modified
time = model.componentData[index].gradientOpacity.getMTime();
mTime = mTime > time ? mTime : time;
}
}
}

return mTime;
};

publicAPI.getColorChannels = (index) => {
if (index < 0 || index > 3) {
vtkErrorMacro('Bad index - must be between 0 and 3');
return 0;
}

return model.componentData[index].colorChannels;
};

// Set the color of a volume to a gray transfer function
publicAPI.setGrayTransferFunction = (index, func) => {
if (model.componentData[index].grayTransferFunction !== func) {
model.componentData[index].grayTransferFunction = func;
publicAPI.modified();
}

if (model.componentData[index].colorChannels !== 1) {
model.componentData[index].colorChannels = 1;
publicAPI.modified();
}
};

// Get the currently set gray transfer function. Create one if none set.
publicAPI.getGrayTransferFunction = (index) => {
if (model.componentData[index].grayTransferFunction === null) {
model.componentData[
index
].grayTransferFunction = vtkPiecewiseFunction.newInstance();
model.componentData[index].grayTransferFunction.addPoint(0, 0.0);
model.componentData[index].grayTransferFunction.addPoint(1024, 1.0);
if (model.componentData[index].colorChannels !== 1) {
model.componentData[index].colorChannels = 1;
}
publicAPI.modified();
}

return model.componentData[index].grayTransferFunction;
};

// Set the color of a volume to an RGB transfer function
publicAPI.setRGBTransferFunction = (index, func) => {
if (model.componentData[index].rGBTransferFunction !== func) {
model.componentData[index].rGBTransferFunction = func;
publicAPI.modified();
}

if (model.componentData[index].colorChannels !== 3) {
model.componentData[index].colorChannels = 3;
publicAPI.modified();
}
};

// Get the currently set RGB transfer function. Create one if none set.
publicAPI.getRGBTransferFunction = (index) => {
if (model.componentData[index].rGBTransferFunction === null) {
model.componentData[
index
].rGBTransferFunction = vtkColorTransferFunction.newInstance();
model.componentData[index].rGBTransferFunction.addRGBPoint(
0,
0.0,
0.0,
0.0
);
model.componentData[index].rGBTransferFunction.addRGBPoint(
1024,
1.0,
1.0,
1.0
);
if (model.componentData[index].colorChannels !== 3) {
model.componentData[index].colorChannels = 3;
}
publicAPI.modified();
}

return model.componentData[index].rGBTransferFunction;
};

// Set the scalar opacity of a volume to a transfer function
publicAPI.setScalarOpacity = (index, func) => {
if (model.componentData[index].scalarOpacity !== func) {
model.componentData[index].scalarOpacity = func;
publicAPI.modified();
}
};

// Get the scalar opacity transfer function. Create one if none set.
publicAPI.getScalarOpacity = (index) => {
if (model.componentData[index].scalarOpacity === null) {
model.componentData[
index
].scalarOpacity = vtkPiecewiseFunction.newInstance();
model.componentData[index].scalarOpacity.addPoint(0, 1.0);
model.componentData[index].scalarOpacity.addPoint(1024, 1.0);
publicAPI.modified();
}

return model.componentData[index].scalarOpacity;
};

publicAPI.setComponentWeight = (index, value) => {
if (index < 0 || index >= VTK_MAX_VRCOMP) {
vtkErrorMacro('Invalid index');
return;
}

const val = Math.min(1, Math.max(0, value));
if (model.componentData[index].componentWeight !== val) {
model.componentData[index].componentWeight = val;
publicAPI.modified();
}
};

publicAPI.getComponentWeight = (index) => {
if (index < 0 || index >= VTK_MAX_VRCOMP) {
vtkErrorMacro('Invalid index');
return 0.0;
}

return model.componentData[index].componentWeight;
};

publicAPI.setInterpolationTypeToNearest = () => {
publicAPI.setInterpolationType(InterpolationType.NEAREST);
};

publicAPI.setInterpolationTypeToLinear = () => {
publicAPI.setInterpolationType(InterpolationType.LINEAR);
};

publicAPI.setInterpolationTypeToFastLinear = () => {
publicAPI.setInterpolationType(InterpolationType.FAST_LINEAR);
};

publicAPI.getInterpolationTypeAsString = () =>
macro.enumToString(InterpolationType, model.interpolationType);

const sets = [
'useGradientOpacity',
'scalarOpacityUnitDistance',
'gradientOpacityMinimumValue',
'gradientOpacityMinimumOpacity',
'gradientOpacityMaximumValue',
'gradientOpacityMaximumOpacity',
];
sets.forEach((val) => {
const cap = macro.capitalize(val);
publicAPI[`set${cap}`] = (index, value) => {
if (model.componentData[index][`${val}`] !== value) {
model.componentData[index][`${val}`] = value;
publicAPI.modified();
}
};
});

const gets = [
'useGradientOpacity',
'scalarOpacityUnitDistance',
'gradientOpacityMinimumValue',
'gradientOpacityMinimumOpacity',
'gradientOpacityMaximumValue',
'gradientOpacityMaximumOpacity',
];
gets.forEach((val) => {
const cap = macro.capitalize(val);
publicAPI[`get${cap}`] = (index) => model.componentData[index][`${val}`];
});
}

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

const DEFAULT_VALUES = {
independentComponents: 1,
interpolationType: InterpolationType.FAST_LINEAR,
shade: 0,
ambient: 0.1,
diffuse: 0.7,
specular: 0.2,
specularPower: 10.0,
};

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

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

// Build VTK API
macro.obj(publicAPI, model);

if (!model.componentData) {
model.componentData = [];
for (let i = 0; i < VTK_MAX_VRCOMP; ++i) {
model.componentData.push({
colorChannels: 1,
grayTransferFunction: null,
rGBTransferFunction: null,
scalarOpacity: null,
scalarOpacityUnitDistance: 1.0,

gradientOpacityMinimumValue: 0,
gradientOpacityMinimumOpacity: 0.0,
gradientOpacityMaximumValue: 1.0,
gradientOpacityMaximumOpacity: 1.0,
useGradientOpacity: false,

componentWeight: 1.0,
});
}
}

macro.setGet(publicAPI, model, [
'independentComponents',
'interpolationType',
'shade',
'ambient',
'diffuse',
'specular',
'specularPower',
]);

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

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

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

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

export default Object.assign({ newInstance, extend }, Constants);