UNPKG

@thewtex/vtk.js-esm

Version:

Visualization Toolkit for the Web

506 lines (421 loc) 21.8 kB
import _defineProperty from '@babel/runtime/helpers/defineProperty'; import { obj, newInstance as newInstance$1, vtkErrorMacro as vtkErrorMacro$1 } from '../../macro.js'; import vtkBufferObject from './BufferObject.js'; import vtkHardwareSelector from './HardwareSelector.js'; import vtkProperty from '../Core/Property.js'; import vtkOpenGLPolyDataMapper from './PolyDataMapper.js'; import vtkShaderProgram from './ShaderProgram.js'; import { registerOverride } from './ViewNodeFactory.js'; import { i as identity, m as multiply } from '../../vendor/gl-matrix/esm/mat3.js'; import { i as identity$1, m as multiply$1 } from '../../vendor/gl-matrix/esm/mat4.js'; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } var vtkErrorMacro = vtkErrorMacro$1; var Representation = vtkProperty.Representation; var ObjectType = vtkBufferObject.ObjectType; var PassTypes = vtkHardwareSelector.PassTypes; var StartEvent = { type: 'StartEvent' }; var EndEvent = { type: 'EndEvent' }; // ---------------------------------------------------------------------------- // vtkOpenGLSphereMapper methods // ---------------------------------------------------------------------------- function vtkOpenGLGlyph3DMapper(publicAPI, model) { // Set our className model.classHierarchy.push('vtkOpenGLGlyph3DMapper'); // Capture 'parentClass' api for internal use var superClass = _objectSpread({}, publicAPI); publicAPI.renderPiece = function (ren, actor) { publicAPI.invokeEvent(StartEvent); if (!model.renderable.getStatic()) { model.renderable.update(); } model.currentInput = model.renderable.getInputData(1); publicAPI.invokeEvent(EndEvent); if (!model.currentInput) { vtkErrorMacro('No input!'); return; } // if there are no points then we are done if (!model.currentInput.getPoints || !model.currentInput.getPoints().getNumberOfValues()) { return; } // apply faceCulling var gl = model.context; if (model.openGLRenderWindow.getWebgl2()) { model.hardwareSupport = true; model.extension = null; } else if (!model.extension) { model.extension = model.context.getExtension('ANGLE_instanced_arrays'); model.hardwareSupport = !!model.extension; } // to test without extension support uncomment the next two lines // model.extension = null; // model.hardwareSupport = !!model.extension; var backfaceCulling = actor.getProperty().getBackfaceCulling(); var frontfaceCulling = actor.getProperty().getFrontfaceCulling(); if (!backfaceCulling && !frontfaceCulling) { model.openGLRenderWindow.disableCullFace(); } else if (frontfaceCulling) { model.openGLRenderWindow.enableCullFace(); gl.cullFace(gl.FRONT); } else { model.openGLRenderWindow.enableCullFace(); gl.cullFace(gl.BACK); } publicAPI.renderPieceStart(ren, actor); publicAPI.renderPieceDraw(ren, actor); publicAPI.renderPieceFinish(ren, actor); }; publicAPI.multiply4x4WithOffset = function (out, a, b, off) { var a00 = a[0]; var a01 = a[1]; var a02 = a[2]; var a03 = a[3]; var a10 = a[4]; var a11 = a[5]; var a12 = a[6]; var a13 = a[7]; var a20 = a[8]; var a21 = a[9]; var a22 = a[10]; var a23 = a[11]; var a30 = a[12]; var a31 = a[13]; var a32 = a[14]; var a33 = a[15]; // Cache only the current line of the second matrix var b0 = b[off]; var b1 = b[off + 1]; var b2 = b[off + 2]; var b3 = b[off + 3]; out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[off + 4]; b1 = b[off + 5]; b2 = b[off + 6]; b3 = b[off + 7]; out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[off + 8]; b1 = b[off + 9]; b2 = b[off + 10]; b3 = b[off + 11]; out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[off + 12]; b1 = b[off + 13]; b2 = b[off + 14]; b3 = b[off + 15]; out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; }; publicAPI.replaceShaderNormal = function (shaders, ren, actor) { if (model.hardwareSupport) { var lastLightComplexity = model.lastBoundBO.getReferenceByName('lastLightComplexity'); if (lastLightComplexity > 0) { var VSSource = shaders.Vertex; if (model.lastBoundBO.getCABO().getNormalOffset()) { VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Normal::Dec', ['attribute vec3 normalMC;', 'attribute mat3 gNormal;', 'uniform mat3 normalMatrix;', 'varying vec3 normalVCVSOutput;']).result; VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Normal::Impl', ['normalVCVSOutput = normalMatrix * gNormal * normalMC;']).result; } shaders.Vertex = VSSource; } } superClass.replaceShaderNormal(shaders, ren, actor); }; publicAPI.replaceShaderColor = function (shaders, ren, actor) { if (model.hardwareSupport && model.renderable.getColorArray()) { var VSSource = shaders.Vertex; var GSSource = shaders.Geometry; var FSSource = shaders.Fragment; var lastLightComplexity = model.lastBoundBO.getReferenceByName('lastLightComplexity'); // create the material/color property declarations, and VS implementation // these are always defined var colorDec = ['uniform float ambient;', 'uniform float diffuse;', 'uniform float specular;', 'uniform float opacityUniform; // the fragment opacity']; // add more for specular if (lastLightComplexity) { colorDec = colorDec.concat(['uniform vec3 specularColorUniform;', 'uniform float specularPowerUniform;']); } // now handle the more complex fragment shader implementation // the following are always defined variables. We start // by assigning a default value from the uniform var colorImpl = ['vec3 ambientColor;', ' vec3 diffuseColor;', ' float opacity;']; if (lastLightComplexity) { colorImpl = colorImpl.concat([' vec3 specularColor;', ' float specularPower;']); } colorImpl = colorImpl.concat([' opacity = opacityUniform;']); if (lastLightComplexity) { colorImpl = colorImpl.concat([' specularColor = specularColorUniform;', ' specularPower = specularPowerUniform;']); } if (!model.drawingEdges) { colorDec = colorDec.concat(['varying vec4 vertexColorVSOutput;']); VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Color::Dec', ['attribute vec4 gColor;', 'varying vec4 vertexColorVSOutput;']).result; VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Color::Impl', ['vertexColorVSOutput = gColor;']).result; GSSource = vtkShaderProgram.substitute(GSSource, '//VTK::Color::Dec', ['in vec4 vertexColorVSOutput[];', 'out vec4 vertexColorGSOutput;']).result; GSSource = vtkShaderProgram.substitute(GSSource, '//VTK::Color::Impl', ['vertexColorGSOutput = vertexColorVSOutput[i];']).result; colorImpl = colorImpl.concat([' diffuseColor = vertexColorVSOutput.rgb;', ' ambientColor = vertexColorVSOutput.rgb;', ' opacity = opacity*vertexColorVSOutput.a;']); } FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Color::Impl', colorImpl).result; FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Color::Dec', colorDec).result; shaders.Vertex = VSSource; shaders.Geometry = GSSource; shaders.Fragment = FSSource; } superClass.replaceShaderColor(shaders, ren, actor); }; publicAPI.replaceShaderPositionVC = function (shaders, ren, actor) { if (model.hardwareSupport) { var VSSource = shaders.Vertex; // do we need the vertex in the shader in View Coordinates var lastLightComplexity = model.lastBoundBO.getReferenceByName('lastLightComplexity'); if (lastLightComplexity > 0) { VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::PositionVC::Impl', ['vec4 gVertexMC = gMatrix * vertexMC;', 'vertexVCVSOutput = MCVCMatrix * gVertexMC;', ' gl_Position = MCPCMatrix * gVertexMC;']).result; VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Camera::Dec', ['attribute mat4 gMatrix;', 'uniform mat4 MCPCMatrix;', 'uniform mat4 MCVCMatrix;']).result; } else { VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Camera::Dec', ['attribute mat4 gMatrix;', 'uniform mat4 MCPCMatrix;']).result; VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::PositionVC::Impl', ['vec4 gVertexMC = gMatrix * vertexMC;', ' gl_Position = MCPCMatrix * gVertexMC;']).result; } shaders.Vertex = VSSource; } superClass.replaceShaderPositionVC(shaders, ren, actor); }; publicAPI.replaceShaderPicking = function (shaders, ren, actor) { if (model.hardwareSupport) { var FSSource = shaders.Fragment; var VSSource = shaders.Vertex; VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Picking::Dec', ['attribute vec3 mapperIndexVS;', 'varying vec3 mapperIndexVSOutput;']).result; VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Picking::Impl', ' mapperIndexVSOutput = mapperIndexVS;').result; shaders.Vertex = VSSource; FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Picking::Dec', ['varying vec3 mapperIndexVSOutput;', 'uniform vec3 mapperIndex;', 'uniform int picking;']).result; FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Picking::Impl', [' vec4 pickColor = picking == 2 ? vec4(mapperIndexVSOutput,1.0) : vec4(mapperIndex,1.0);', ' gl_FragData[0] = picking != 0 ? pickColor : gl_FragData[0];']).result; shaders.Fragment = FSSource; } else { superClass.replaceShaderPicking(shaders, ren, actor); } }; publicAPI.updateGlyphShaderParameters = function (normalMatrixUsed, mcvcMatrixUsed, cellBO, carray, garray, narray, p, selector) { var program = cellBO.getProgram(); if (normalMatrixUsed) { var a = model.normalMatrix; var b = narray; var ofs = p * 9; var out = model.tmpMat3; var a00 = a[0]; var a01 = a[1]; var a02 = a[2]; var a10 = a[3]; var a11 = a[4]; var a12 = a[5]; var a20 = a[6]; var a21 = a[7]; var a22 = a[8]; var b00 = b[ofs]; var b01 = b[ofs + 1]; var b02 = b[ofs + 2]; var b10 = b[ofs + 3]; var b11 = b[ofs + 4]; var b12 = b[ofs + 5]; var b20 = b[ofs + 6]; var b21 = b[ofs + 7]; var b22 = b[ofs + 8]; out[0] = b00 * a00 + b01 * a10 + b02 * a20; out[1] = b00 * a01 + b01 * a11 + b02 * a21; out[2] = b00 * a02 + b01 * a12 + b02 * a22; out[3] = b10 * a00 + b11 * a10 + b12 * a20; out[4] = b10 * a01 + b11 * a11 + b12 * a21; out[5] = b10 * a02 + b11 * a12 + b12 * a22; out[6] = b20 * a00 + b21 * a10 + b22 * a20; out[7] = b20 * a01 + b21 * a11 + b22 * a21; out[8] = b20 * a02 + b21 * a12 + b22 * a22; program.setUniformMatrix3x3('normalMatrix', model.tmpMat3); } publicAPI.multiply4x4WithOffset(model.tmpMat4, model.mcpcMatrix, garray, p * 16); program.setUniformMatrix('MCPCMatrix', model.tmpMat4); if (mcvcMatrixUsed) { publicAPI.multiply4x4WithOffset(model.tmpMat4, model.mcvcMatrix, garray, p * 16); program.setUniformMatrix('MCVCMatrix', model.tmpMat4); } // set color if (carray) { var cdata = carray.getData(); model.tmpColor[0] = cdata[p * 4] / 255.0; model.tmpColor[1] = cdata[p * 4 + 1] / 255.0; model.tmpColor[2] = cdata[p * 4 + 2] / 255.0; program.setUniform3fArray('ambientColorUniform', model.tmpColor); program.setUniform3fArray('diffuseColorUniform', model.tmpColor); } if (selector) { program.setUniform3fArray('mapperIndex', selector.getPropColorValue()); } }; publicAPI.renderPieceDraw = function (ren, actor) { var representation = actor.getProperty().getRepresentation(); var gl = model.context; var drawSurfaceWithEdges = actor.getProperty().getEdgeVisibility() && representation === Representation.SURFACE; // [WMVP]C == {world, model, view, projection} coordinates // E.g., WCPC == world to projection coordinate transformation var keyMats = model.openGLCamera.getKeyMatrices(ren); var actMats = model.openGLActor.getKeyMatrices(); // precompute the actor+camera mats once multiply(model.normalMatrix, keyMats.normalMatrix, actMats.normalMatrix); multiply$1(model.mcpcMatrix, keyMats.wcpc, actMats.mcwc); multiply$1(model.mcvcMatrix, keyMats.wcvc, actMats.mcwc); var garray = model.renderable.getMatrixArray(); var narray = model.renderable.getNormalArray(); var carray = model.renderable.getColorArray(); var numPts = garray.length / 16; var compositePass = false; if (model.openGLRenderer.getSelector()) { if (model.openGLRenderer.getSelector().getCurrentPass() === PassTypes.COMPOSITE_INDEX_PASS) { compositePass = true; } } // for every primitive type for (var i = model.primTypes.Start; i < model.primTypes.End; i++) { // if there are entries var cabo = model.primitives[i].getCABO(); if (cabo.getElementCount()) { // are we drawing edges model.drawingEdges = drawSurfaceWithEdges && (i === model.primTypes.TrisEdges || i === model.primTypes.TriStripsEdges); publicAPI.updateShaders(model.primitives[i], ren, actor); var program = model.primitives[i].getProgram(); var mode = publicAPI.getOpenGLMode(representation, i); var normalMatrixUsed = program.isUniformUsed('normalMatrix'); var mcvcMatrixUsed = program.isUniformUsed('MCVCMatrix'); if (model.hardwareSupport) { if (model.extension) { model.extension.drawArraysInstancedANGLE(mode, 0, cabo.getElementCount(), numPts); } else { gl.drawArraysInstanced(mode, 0, cabo.getElementCount(), numPts); } } else { // draw the array multiple times with different cam matrix for (var p = 0; p < numPts; ++p) { if (compositePass) { model.openGLRenderer.getSelector().renderCompositeIndex(p); } publicAPI.updateGlyphShaderParameters(normalMatrixUsed, mcvcMatrixUsed, model.primitives[i], carray, garray, narray, p, compositePass ? model.openGLRenderer.getSelector() : null); gl.drawArrays(mode, 0, cabo.getElementCount()); } } } } }; publicAPI.setMapperShaderParameters = function (cellBO, ren, actor) { if (cellBO.getCABO().getElementCount() && (model.glyphBOBuildTime.getMTime() > cellBO.getAttributeUpdateTime().getMTime() || cellBO.getShaderSourceTime().getMTime() > cellBO.getAttributeUpdateTime().getMTime())) { if (cellBO.getProgram().isAttributeUsed('gMatrix')) { if (!cellBO.getVAO().addAttributeMatrixWithDivisor(cellBO.getProgram(), model.matrixBuffer, 'gMatrix', 0, 64, model.context.FLOAT, 4, false, 1)) { vtkErrorMacro('Error setting gMatrix in shader VAO.'); } } else { cellBO.getVAO().removeAttributeArray('gMatrix'); } if (cellBO.getProgram().isAttributeUsed('gNormal')) { if (!cellBO.getVAO().addAttributeMatrixWithDivisor(cellBO.getProgram(), model.normalBuffer, 'gNormal', 0, 36, model.context.FLOAT, 3, false, 1)) { vtkErrorMacro('Error setting gNormal in shader VAO.'); } } else { cellBO.getVAO().removeAttributeArray('gNormal'); } if (cellBO.getProgram().isAttributeUsed('gColor')) { if (!cellBO.getVAO().addAttributeArrayWithDivisor(cellBO.getProgram(), model.colorBuffer, 'gColor', 0, 4, model.context.UNSIGNED_BYTE, 4, true, 1, false)) { vtkErrorMacro('Error setting gColor in shader VAO.'); } } else { cellBO.getVAO().removeAttributeArray('gColor'); } if (cellBO.getProgram().isAttributeUsed('mapperIndexVS')) { if (!cellBO.getVAO().addAttributeArrayWithDivisor(cellBO.getProgram(), model.pickBuffer, 'mapperIndexVS', 0, 4, model.context.UNSIGNED_BYTE, 4, true, 1, false)) { vtkErrorMacro('Error setting mapperIndexVS in shader VAO.'); } } else { cellBO.getVAO().removeAttributeArray('mapperIndexVS'); } superClass.setMapperShaderParameters(cellBO, ren, actor); cellBO.getAttributeUpdateTime().modified(); return; } superClass.setMapperShaderParameters(cellBO, ren, actor); }; publicAPI.getNeedToRebuildBufferObjects = function (ren, actor) { model.renderable.buildArrays(); // first do a coarse check // Note that the actor's mtime includes it's properties mtime var vmtime = model.VBOBuildTime.getMTime(); if (vmtime < model.renderable.getBuildTime().getMTime()) { return true; } return superClass.getNeedToRebuildBufferObjects(ren, actor); }; publicAPI.buildBufferObjects = function (ren, actor) { if (model.hardwareSupport) { // update the buffer objects if needed var garray = model.renderable.getMatrixArray(); var narray = model.renderable.getNormalArray(); var carray = model.renderable.getColorArray(); if (!model.matrixBuffer) { model.matrixBuffer = vtkBufferObject.newInstance(); model.matrixBuffer.setOpenGLRenderWindow(model.openGLRenderWindow); model.normalBuffer = vtkBufferObject.newInstance(); model.normalBuffer.setOpenGLRenderWindow(model.openGLRenderWindow); model.colorBuffer = vtkBufferObject.newInstance(); model.colorBuffer.setOpenGLRenderWindow(model.openGLRenderWindow); model.pickBuffer = vtkBufferObject.newInstance(); model.pickBuffer.setOpenGLRenderWindow(model.openGLRenderWindow); } if (model.renderable.getBuildTime().getMTime() > model.glyphBOBuildTime.getMTime()) { model.matrixBuffer.upload(garray, ObjectType.ARRAY_BUFFER); model.normalBuffer.upload(narray, ObjectType.ARRAY_BUFFER); if (carray) { model.colorBuffer.upload(carray.getData(), ObjectType.ARRAY_BUFFER); } else { model.colorBuffer.releaseGraphicsResources(); } var numPts = garray.length / 16; var parray = new Uint8Array(4 * numPts); for (var i = 0; i < numPts; ++i) { var value = i + 1; var offset = i * 4; parray[offset] = value % 256; value -= parray[offset]; value /= 256; parray[offset + 1] = value % 256; value -= parray[offset + 1]; value /= 256; parray[offset + 2] = value % 256; parray[offset + 3] = 255; } model.pickBuffer.upload(parray, ObjectType.ARRAY_BUFFER); model.glyphBOBuildTime.modified(); } } return superClass.buildBufferObjects(ren, actor); }; } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- var DEFAULT_VALUES = { normalMatrix: null, mcpcMatrix: null, mcwcMatrix: null }; // ---------------------------------------------------------------------------- function extend(publicAPI, model) { var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance vtkOpenGLPolyDataMapper.extend(publicAPI, model, initialValues); model.tmpMat3 = identity(new Float64Array(9)); model.normalMatrix = identity(new Float64Array(9)); model.mcpcMatrix = identity$1(new Float64Array(16)); model.mcvcMatrix = identity$1(new Float64Array(16)); model.tmpColor = []; model.glyphBOBuildTime = {}; obj(model.glyphBOBuildTime, { mtime: 0 }); // Object methods vtkOpenGLGlyph3DMapper(publicAPI, model); } // ---------------------------------------------------------------------------- var newInstance = newInstance$1(extend, 'vtkOpenGLGlyph3DMapper'); // ---------------------------------------------------------------------------- var vtkGlyph3DMapper = { newInstance: newInstance, extend: extend }; // Register ourself to OpenGL backend if imported registerOverride('vtkGlyph3DMapper', newInstance); export default vtkGlyph3DMapper; export { extend, newInstance };