import { mat4 } from 'gl-matrix'; import { ObjectType } from 'vtk.js/Sources/Rendering/OpenGL/BufferObject/Constants';
import * as macro from 'vtk.js/Sources/macros';
import vtkBufferObject from 'vtk.js/Sources/Rendering/OpenGL/BufferObject'; import * as vtkMath from 'vtk.js/Sources/Common/Core/Math';
import vtkShaderProgram from 'vtk.js/Sources/Rendering/OpenGL/ShaderProgram'; import vtkOpenGLPolyDataMapper from 'vtk.js/Sources/Rendering/OpenGL/PolyDataMapper';
import vtkSphereMapperVS from 'vtk.js/Sources/Rendering/OpenGL/glsl/vtkSphereMapperVS.glsl'; import vtkPolyDataFS from 'vtk.js/Sources/Rendering/OpenGL/glsl/vtkPolyDataFS.glsl';
import { registerOverride } from 'vtk.js/Sources/Rendering/OpenGL/ViewNodeFactory';
const { vtkErrorMacro } = macro;
function vtkOpenGLSphereMapper(publicAPI, model) { model.classHierarchy.push('vtkOpenGLSphereMapper');
const superClass = { ...publicAPI };
publicAPI.getShaderTemplate = (shaders, ren, actor) => { shaders.Vertex = vtkSphereMapperVS; shaders.Fragment = vtkPolyDataFS; shaders.Geometry = ''; };
publicAPI.replaceShaderValues = (shaders, ren, actor) => { let VSSource = shaders.Vertex; let FSSource = shaders.Fragment;
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Camera::Dec', [ 'uniform mat4 VCPCMatrix;\n', 'uniform mat4 MCVCMatrix;', ]).result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::PositionVC::Dec', [ 'varying vec4 vertexVCVSOutput;', ]).result;
FSSource = vtkShaderProgram.substitute( FSSource, '//VTK::PositionVC::Impl', ['vec4 vertexVC = vertexVCVSOutput;\n'] ).result;
const replacement = [ 'uniform float invertedDepth;\n', 'uniform int cameraParallel;\n', 'varying float radiusVCVSOutput;\n', 'varying vec3 centerVCVSOutput;\n', 'uniform mat4 VCPCMatrix;\n', ]; FSSource = vtkShaderProgram.substitute( FSSource, '//VTK::Normal::Dec', replacement ).result;
let fragString = ''; if (model.context.getExtension('EXT_frag_depth')) { fragString = 'gl_FragDepthEXT = (pos.z / pos.w + 1.0) / 2.0;\n'; } if (model._openGLRenderWindow.getWebgl2()) { fragString = 'gl_FragDepth = (pos.z / pos.w + 1.0) / 2.0;\n'; } FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Depth::Impl', [ ' vec3 EyePos;\n', ' vec3 EyeDir;\n', ' if (cameraParallel != 0) {\n', ' EyePos = vec3(vertexVC.x, vertexVC.y, vertexVC.z + 3.0*radiusVCVSOutput);\n', ' EyeDir = vec3(0.0,0.0,-1.0); }\n', ' else {\n', ' EyeDir = vertexVC.xyz;\n', ' EyePos = vec3(0.0,0.0,0.0);\n', ' float lengthED = length(EyeDir);\n', ' EyeDir = normalize(EyeDir);\n', ' if (lengthED > radiusVCVSOutput*3.0) {\n', ' EyePos = vertexVC.xyz - EyeDir*3.0*radiusVCVSOutput; }\n', ' }\n',
' EyePos = EyePos - centerVCVSOutput;\n', ' EyePos = EyePos/radiusVCVSOutput;\n', ' float b = 2.0*dot(EyePos,EyeDir);\n', ' float c = dot(EyePos,EyePos) - 1.0;\n', ' float d = b*b - 4.0*c;\n', ' vec3 normalVCVSOutput = vec3(0.0,0.0,1.0);\n', ' if (d < 0.0) { discard; }\n', ' else {\n', ' float t = (-b - invertedDepth*sqrt(d))*0.5;\n',
' normalVCVSOutput = invertedDepth*normalize(EyePos + t*EyeDir);\n', ' vertexVC.xyz = normalVCVSOutput*radiusVCVSOutput + centerVCVSOutput;\n', ' }\n', ' vec4 pos = VCPCMatrix * vertexVC;\n', fragString, ]).result;
FSSource = vtkShaderProgram.substitute( FSSource, '//VTK::Normal::Impl', '' ).result;
if (model.haveSeenDepthRequest) { FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ZBuffer::Impl', [ 'if (depthRequest == 1) {', 'float computedZ = (pos.z / pos.w + 1.0) / 2.0;', 'float iz = floor(computedZ * 65535.0 + 0.1);', 'float rf = floor(iz/256.0)/255.0;', 'float gf = mod(iz,256.0)/255.0;', 'gl_FragData[0] = vec4(rf, gf, 0.0, 1.0); }', ]).result; }
shaders.Vertex = VSSource; shaders.Fragment = FSSource;
superClass.replaceShaderValues(shaders, ren, actor); };
publicAPI.setMapperShaderParameters = (cellBO, ren, actor) => { if ( cellBO.getCABO().getElementCount() && (model.VBOBuildTime > cellBO.getAttributeUpdateTime().getMTime() || cellBO.getShaderSourceTime().getMTime() > cellBO.getAttributeUpdateTime().getMTime()) && cellBO.getProgram().isAttributeUsed('offsetMC') ) { if ( !cellBO.getVAO().addAttributeArray( cellBO.getProgram(), cellBO.getCABO(), 'offsetMC', 12, cellBO.getCABO().getStride(), model.context.FLOAT, 2, false ) ) { vtkErrorMacro("Error setting 'offsetMC' in shader VAO."); } }
if (cellBO.getProgram().isUniformUsed('invertedDepth')) { cellBO .getProgram() .setUniformf('invertedDepth', model.invert ? -1.0 : 1.0); } if (cellBO.getProgram().isUniformUsed('scaleFactor')) { const poly = model.currentInput; const pointData = poly.getPointData(); if ( model.renderable.getScaleArray() != null && pointData.hasArray(model.renderable.getScaleArray()) ) { cellBO .getProgram() .setUniformf('scaleFactor', model.renderable.getScaleFactor()); } else { cellBO.getProgram().setUniformf('scaleFactor', 1.0); } }
superClass.setMapperShaderParameters(cellBO, ren, actor); };
publicAPI.setCameraShaderParameters = (cellBO, ren, actor) => { const program = cellBO.getProgram();
const cam = ren.getActiveCamera(); const keyMats = model.openGLCamera.getKeyMatrices(ren);
if (program.isUniformUsed('VCPCMatrix')) { program.setUniformMatrix('VCPCMatrix', keyMats.vcpc); }
if (program.isUniformUsed('MCVCMatrix')) { if (!actor.getIsIdentity()) { const actMats = model.openGLActor.getKeyMatrices(); const tmp4 = new Float64Array(16); mat4.multiply(tmp4, keyMats.wcvc, actMats.mcwc); program.setUniformMatrix('MCVCMatrix', tmp4); } else { program.setUniformMatrix('MCVCMatrix', keyMats.wcvc); } }
if (program.isUniformUsed('cameraParallel')) { cellBO .getProgram() .setUniformi('cameraParallel', cam.getParallelProjection()); } };
publicAPI.getOpenGLMode = (rep, type) => model.context.TRIANGLES;
publicAPI.buildBufferObjects = (ren, actor) => { const poly = model.currentInput;
if (poly === null) { return; }
model.renderable.mapScalars(poly, 1.0); const c = model.renderable.getColorMapColors();
const vbo = model.primitives[model.primTypes.Tris].getCABO();
const pointData = poly.getPointData(); const points = poly.getPoints(); const numPoints = points.getNumberOfPoints(); const pointArray = points.getData();
const pointSize = 5; let scales = null;
if ( model.renderable.getScaleArray() != null && pointData.hasArray(model.renderable.getScaleArray()) ) { scales = pointData.getArray(model.renderable.getScaleArray()).getData(); }
let colorData = null; let colorComponents = 0; let packedUCVBO = null; if (c) { colorComponents = c.getNumberOfComponents(); vbo.setColorOffset(0); vbo.setColorBOStride(4); colorData = c.getData(); packedUCVBO = new Uint8Array(3 * numPoints * 4); if (!vbo.getColorBO()) { vbo.setColorBO(vtkBufferObject.newInstance()); } vbo.getColorBO().setOpenGLRenderWindow(model._openGLRenderWindow); } else if (vbo.getColorBO()) { vbo.setColorBO(null); } vbo.setColorComponents(colorComponents);
const packedVBO = new Float32Array(pointSize * numPoints * 3);
vbo.setStride(pointSize * 4);
const cos30 = Math.cos(vtkMath.radiansFromDegrees(30.0)); let pointIdx = 0; let colorIdx = 0;
let vboIdx = 0; let ucIdx = 0; for (let i = 0; i < numPoints; ++i) { let radius = model.renderable.getRadius(); if (scales) { radius = scales[i]; }
pointIdx = i * 3; packedVBO[vboIdx++] = pointArray[pointIdx++]; packedVBO[vboIdx++] = pointArray[pointIdx++]; packedVBO[vboIdx++] = pointArray[pointIdx++]; packedVBO[vboIdx++] = -2.0 * radius * cos30; packedVBO[vboIdx++] = -radius; if (colorData) { colorIdx = i * colorComponents; packedUCVBO[ucIdx++] = colorData[colorIdx]; packedUCVBO[ucIdx++] = colorData[colorIdx + 1]; packedUCVBO[ucIdx++] = colorData[colorIdx + 2]; packedUCVBO[ucIdx++] = colorData[colorIdx + 3]; }
pointIdx = i * 3; packedVBO[vboIdx++] = pointArray[pointIdx++]; packedVBO[vboIdx++] = pointArray[pointIdx++]; packedVBO[vboIdx++] = pointArray[pointIdx++]; packedVBO[vboIdx++] = 2.0 * radius * cos30; packedVBO[vboIdx++] = -radius; if (colorData) { packedUCVBO[ucIdx++] = colorData[colorIdx]; packedUCVBO[ucIdx++] = colorData[colorIdx + 1]; packedUCVBO[ucIdx++] = colorData[colorIdx + 2]; packedUCVBO[ucIdx++] = colorData[colorIdx + 3]; }
pointIdx = i * 3; packedVBO[vboIdx++] = pointArray[pointIdx++]; packedVBO[vboIdx++] = pointArray[pointIdx++]; packedVBO[vboIdx++] = pointArray[pointIdx++]; packedVBO[vboIdx++] = 0.0; packedVBO[vboIdx++] = 2.0 * radius; if (colorData) { packedUCVBO[ucIdx++] = colorData[colorIdx]; packedUCVBO[ucIdx++] = colorData[colorIdx + 1]; packedUCVBO[ucIdx++] = colorData[colorIdx + 2]; packedUCVBO[ucIdx++] = colorData[colorIdx + 3]; } }
vbo.setElementCount(vboIdx / pointSize); vbo.upload(packedVBO, ObjectType.ARRAY_BUFFER); if (c) { vbo.getColorBO().upload(packedUCVBO, ObjectType.ARRAY_BUFFER); }
model.VBOBuildTime.modified(); }; }
const DEFAULT_VALUES = {};
export function extend(publicAPI, model, initialValues = {}) { Object.assign(model, DEFAULT_VALUES, initialValues);
vtkOpenGLPolyDataMapper.extend(publicAPI, model, initialValues);
vtkOpenGLSphereMapper(publicAPI, model); }
export const newInstance = macro.newInstance(extend, 'vtkOpenGLSphereMapper');
export default { newInstance, extend };
registerOverride('vtkSphereMapper', newInstance);
|