src/helpers/helpers.volumerendering.js
/** * Imports ***/
import ShadersUniform from '../shaders/shaders.vr.uniform';
import ShadersVertex from '../shaders/shaders.vr.vertex';
import ShadersFragment from '../shaders/shaders.vr.fragment';
import { helpersMaterialMixin } from '../helpers/helpers.material.mixin';
/**
* @module helpers/volumerendering
*/
const helpersVolumeRendering = (three = window.THREE) => {
if (three === undefined || three.Object3D === undefined) {
return null;
}
const Constructor = helpersMaterialMixin(three);
return class extends Constructor {
constructor(stack) {
//
super();
this._stack = stack;
this._textures = [];
this._shadersFragment = ShadersFragment;
this._shadersVertex = ShadersVertex;
this._uniforms = ShadersUniform.uniforms();
this._material = null;
this._geometry = null;
this._mesh = null;
this._algorithm = 0; // ray marching
this._alphaCorrection = 0.5; // default
this._interpolation = 1; // default to trilinear interpolation
this._shading = 1; // shading is on by default
this._shininess = 10.0;
this._steps = 256; // default
this._offset = 0;
this._windowCenter = 0.0;
this._windowWidth = 1.0;
this._create();
}
_create() {
this._prepareStack();
this._prepareTexture();
this._prepareMaterial();
this._prepareGeometry();
this._mesh = new three.Mesh(this._geometry, this._material);
this.add(this._mesh);
}
_prepareStack() {
if (!this._stack.prepared) {
this._stack.prepare();
}
if (!this._stack.packed) {
this._stack.pack();
}
// compensate for the offset to only pass > 0 values to shaders
// models > models.stack.js : _packTo8Bits
this._offset = Math.min(0, this._stack._minMax[0]);
this._windowCenter = this._stack.windowCenter;
this._windowWidth = this._stack.windowWidth * 0.8; // multiply for better default visualization
}
_prepareMaterial() {
// uniforms
this._uniforms = ShadersUniform.uniforms();
this._uniforms.uWorldBBox.value = this._stack.worldBoundingBox();
this._uniforms.uTextureSize.value = this._stack.textureSize;
this._uniforms.uTextureContainer.value = this._textures;
if (this._stack.textureUnits > 8) {
this._uniforms.uTextureContainer.length = 14;
}
this._uniforms.uWorldToData.value = this._stack.lps2IJK;
this._uniforms.uNumberOfChannels.value = this._stack.numberOfChannels;
this._uniforms.uPixelType.value = this._stack.pixelType;
this._uniforms.uBitsAllocated.value = this._stack.bitsAllocated;
this._uniforms.uPackedPerPixel.value = this._stack.packedPerPixel;
this._uniforms.uWindowCenterWidth.value = [
this._windowCenter - this._offset,
this._windowWidth,
];
this._uniforms.uRescaleSlopeIntercept.value = [
this._stack.rescaleSlope,
this._stack.rescaleIntercept,
];
this._uniforms.uDataDimensions.value = [
this._stack.dimensionsIJK.x,
this._stack.dimensionsIJK.y,
this._stack.dimensionsIJK.z,
];
this._uniforms.uAlphaCorrection.value = this._alphaCorrection;
this._uniforms.uInterpolation.value = this._interpolation;
this._uniforms.uShading.value = this._shading;
this._uniforms.uShininess.value = this._shininess;
this._uniforms.uSteps.value = this._steps;
this._uniforms.uAlgorithm.value = this._algorithm;
this._createMaterial({
side: three.BackSide,
transparent: true,
});
}
_prepareGeometry() {
let worldBBox = this._stack.worldBoundingBox();
let centerLPS = this._stack.worldCenter();
this._geometry = new three.BoxGeometry(
worldBBox[1] - worldBBox[0],
worldBBox[3] - worldBBox[2],
worldBBox[5] - worldBBox[4]
);
this._geometry.applyMatrix4(
new three.Matrix4().makeTranslation(centerLPS.x, centerLPS.y, centerLPS.z)
);
}
get uniforms() {
return this._uniforms;
}
set uniforms(uniforms) {
this._uniforms = uniforms;
}
set mesh(mesh) {
this._mesh = mesh;
}
get mesh() {
return this._mesh;
}
get stack() {
return this._stack;
}
set stack(stack) {
this._stack = stack;
}
get windowCenter() {
return this._windowCenter;
}
set windowCenter(windowCenter) {
this._windowCenter = windowCenter;
this._uniforms.uWindowCenterWidth.value[0] = this._windowCenter - this._offset;
}
get windowWidth() {
return this._windowWidth;
}
set windowWidth(windowWidth) {
this._windowWidth = Math.max(1, windowWidth);
this._uniforms.uWindowCenterWidth.value[1] = this._windowWidth;
}
get steps() {
return this._steps;
}
set steps(steps) {
this._steps = steps;
this._uniforms.uSteps.value = this._steps;
}
get alphaCorrection() {
return this._alphaCorrection;
}
set alphaCorrection(alphaCorrection) {
this._alphaCorrection = alphaCorrection;
this._uniforms.uAlphaCorrection.value = this._alphaCorrection;
}
get interpolation() {
return this._interpolation;
}
set interpolation(interpolation) {
this._interpolation = interpolation;
this._uniforms.uInterpolation.value = this._interpolation;
this._updateMaterial();
}
get shading() {
return this._shading;
}
set shading(shading) {
this._shading = shading;
this._uniforms.uShading.value = this._shading;
}
get shininess() {
return this._shininess;
}
set shininess(shininess) {
this._shininess = shininess;
this._uniforms.uShininess.value = this._shininess;
}
get algorithm() {
return this._algorithm;
}
set algorithm(algorithm) {
this._algorithm = algorithm;
this._uniforms.uAlgorithm.value = this._algorithm;
}
dispose() {
// Release memory
for (let j = 0; j < this._textures.length; j++) {
this._textures[j].dispose();
this._textures[j] = null;
}
this._textures = null;
this._shadersFragment = null;
this._shadersVertex = null;
this._uniforms.uTextureContainer = null;
this._uniforms.uTextureLUT = null;
this._uniforms = null;
// material, geometry and mesh
this.remove(this._mesh);
this._mesh.geometry.dispose();
this._mesh.geometry = null;
this._mesh.material.dispose();
this._mesh.material = null;
this._mesh = null;
this._geometry.dispose();
this._geometry = null;
this._material.vertexShader = null;
this._material.fragmentShader = null;
this._material.uniforms = null;
this._material.dispose();
this._material = null;
this._stack = null;
}
};
};
export { helpersVolumeRendering };
export default helpersVolumeRendering();