@kitware/vtk.js
Version:
Visualization Toolkit for the Web
871 lines (841 loc) • 62.4 kB
JavaScript
import { mat3, mat4, vec3 } from 'gl-matrix';
import { n as newInstance$1, e as setGet, o as obj, c as macro } from '../../macros2.js';
import vtkHelper from './Helper.js';
import vtkMapper from '../Core/Mapper.js';
import { l as normalize } from '../../Common/Core/Math/index.js';
import vtkOpenGLTexture from './Texture.js';
import vtkProp from '../Core/Prop.js';
import vtkProperty from '../Core/Property.js';
import vtkShaderProgram from './ShaderProgram.js';
import vtkViewNode from '../SceneGraph/ViewNode.js';
import { v as vtkPolyDataVS } from './glsl/vtkPolyDataVS.glsl.js';
import { v as vtkPolyDataFS } from './glsl/vtkPolyDataFS.glsl.js';
import vtkReplacementShaderMapper from './ReplacementShaderMapper.js';
import { registerOverride } from './ViewNodeFactory.js';
import { PassTypes } from './HardwareSelector/Constants.js';
import vtkDataSet from '../../Common/DataModel/DataSet.js';
import '../Core/Mapper/CoincidentTopologyHelper.js';
import { Resolve } from '../Core/Mapper/Static.js';
const {
FieldAssociations
} = vtkDataSet;
/* eslint-disable no-lonely-if */
const {
primTypes
} = vtkHelper;
const {
Representation,
Shading
} = vtkProperty;
const {
ScalarMode
} = vtkMapper;
const {
Filter,
Wrap
} = vtkOpenGLTexture;
const {
vtkErrorMacro
} = macro;
const StartEvent = {
type: 'StartEvent'
};
const EndEvent = {
type: 'EndEvent'
};
const {
CoordinateSystem
} = vtkProp;
// ----------------------------------------------------------------------------
// vtkOpenGLPolyDataMapper methods
// ----------------------------------------------------------------------------
function getPickState(renderer) {
const selector = renderer.getSelector();
if (selector) {
return selector.getCurrentPass();
}
return PassTypes.MIN_KNOWN_PASS - 1;
}
function vtkOpenGLPolyDataMapper(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkOpenGLPolyDataMapper');
publicAPI.buildPass = prepass => {
if (prepass) {
model.currentRenderPass = null;
model.openGLActor = publicAPI.getFirstAncestorOfType('vtkOpenGLActor');
model._openGLRenderer = model.openGLActor.getFirstAncestorOfType('vtkOpenGLRenderer');
model._openGLRenderWindow = model._openGLRenderer.getLastAncestorOfType('vtkOpenGLRenderWindow');
model.openGLCamera = model._openGLRenderer.getViewNodeFor(model._openGLRenderer.getRenderable().getActiveCamera(), model.openGLCamera);
}
};
// Renders myself
publicAPI.translucentPass = (prepass, renderPass) => {
if (prepass) {
model.currentRenderPass = renderPass;
publicAPI.render();
}
};
publicAPI.zBufferPass = prepass => {
if (prepass) {
model.haveSeenDepthRequest = true;
model.renderDepth = true;
publicAPI.render();
model.renderDepth = false;
}
};
publicAPI.opaqueZBufferPass = prepass => publicAPI.zBufferPass(prepass);
publicAPI.opaquePass = prepass => {
if (prepass) {
publicAPI.render();
}
};
publicAPI.render = () => {
const ctx = model._openGLRenderWindow.getContext();
if (model.context !== ctx) {
model.context = ctx;
for (let i = primTypes.Start; i < primTypes.End; i++) {
model.primitives[i].setOpenGLRenderWindow(model._openGLRenderWindow);
}
}
const actor = model.openGLActor.getRenderable();
const ren = model._openGLRenderer.getRenderable();
publicAPI.renderPiece(ren, actor);
};
publicAPI.getShaderTemplate = (shaders, ren, actor) => {
shaders.Vertex = vtkPolyDataVS;
shaders.Fragment = vtkPolyDataFS;
shaders.Geometry = '';
};
publicAPI.replaceShaderColor = (shaders, ren, actor) => {
let VSSource = shaders.Vertex;
let GSSource = shaders.Geometry;
let FSSource = shaders.Fragment;
const lastLightComplexity = model.lastBoundBO.getReferenceByName('lastLightComplexity');
// create the material/color property declarations, and VS implementation
// these are always defined
let colorDec = ['uniform float ambient;', 'uniform float diffuse;', 'uniform float specular;', 'uniform float opacityUniform; // the fragment opacity', 'uniform vec3 ambientColorUniform;', 'uniform vec3 diffuseColorUniform;'];
// 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
let colorImpl = ['vec3 ambientColor;', ' vec3 diffuseColor;', ' float opacity;'];
if (lastLightComplexity) {
colorImpl = colorImpl.concat([' vec3 specularColor;', ' float specularPower;']);
}
colorImpl = colorImpl.concat([' ambientColor = ambientColorUniform;', ' diffuseColor = diffuseColorUniform;', ' opacity = opacityUniform;']);
if (lastLightComplexity) {
colorImpl = colorImpl.concat([' specularColor = specularColorUniform;', ' specularPower = specularPowerUniform;']);
}
// add scalar vertex coloring
if (model.lastBoundBO.getCABO().getColorComponents() !== 0 && !model.drawingEdges) {
colorDec = colorDec.concat(['varying vec4 vertexColorVSOutput;']);
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Color::Dec', ['attribute vec4 scalarColor;', 'varying vec4 vertexColorVSOutput;']).result;
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Color::Impl', ['vertexColorVSOutput = scalarColor;']).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;
}
if (model.lastBoundBO.getCABO().getColorComponents() !== 0 && !model.drawingEdges) {
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Color::Impl', colorImpl.concat([' diffuseColor = vertexColorVSOutput.rgb;', ' ambientColor = vertexColorVSOutput.rgb;', ' opacity = opacity*vertexColorVSOutput.a;'])).result;
} else {
if ((model.renderable.getAreScalarsMappedFromCells() || model.renderable.getInterpolateScalarsBeforeMapping()) && model.renderable.getColorCoordinates() && !model.drawingEdges) {
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Color::Impl', colorImpl.concat([' vec4 texColor = texture2D(texture1, tcoordVCVSOutput.st);', ' diffuseColor = texColor.rgb;', ' ambientColor = texColor.rgb;', ' opacity = opacity*texColor.a;'])).result;
} else {
if (actor.getBackfaceProperty() && !model.drawingEdges) {
colorDec = colorDec.concat(['uniform float opacityUniformBF; // the fragment opacity', 'uniform float ambientIntensityBF; // the material ambient', 'uniform float diffuseIntensityBF; // the material diffuse', 'uniform vec3 ambientColorUniformBF; // ambient material color', 'uniform vec3 diffuseColorUniformBF; // diffuse material color']);
if (lastLightComplexity) {
colorDec = colorDec.concat(['uniform float specularIntensityBF; // the material specular intensity', 'uniform vec3 specularColorUniformBF; // intensity weighted color', 'uniform float specularPowerUniformBF;']);
colorImpl = colorImpl.concat(['if (gl_FrontFacing == false) {', ' ambientColor = ambientIntensityBF * ambientColorUniformBF;', ' diffuseColor = diffuseIntensityBF * diffuseColorUniformBF;', ' specularColor = specularIntensityBF * specularColorUniformBF;', ' specularPower = specularPowerUniformBF;', ' opacity = opacityUniformBF; }']);
} else {
colorImpl = colorImpl.concat(['if (gl_FrontFacing == false) {', ' ambientColor = ambientIntensityBF * ambientColorUniformBF;', ' diffuseColor = diffuseIntensityBF * diffuseColorUniformBF;', ' opacity = opacityUniformBF; }']);
}
}
if (model.haveCellScalars && !model.drawingEdges) {
colorDec = colorDec.concat(['uniform samplerBuffer texture1;']);
}
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;
};
publicAPI.replaceShaderLight = (shaders, ren, actor) => {
let FSSource = shaders.Fragment;
// check for shadow maps
const shadowFactor = '';
const lastLightComplexity = model.lastBoundBO.getReferenceByName('lastLightComplexity');
const lastLightCount = model.lastBoundBO.getReferenceByName('lastLightCount');
let sstring = [];
switch (lastLightComplexity) {
case 0:
// no lighting or RENDER_VALUES
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Light::Impl', [' gl_FragData[0] = vec4(ambientColor * ambient + diffuseColor * diffuse, opacity);', ' //VTK::Light::Impl'], false).result;
break;
case 1:
// headlight
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Light::Impl', [' float df = max(0.0, normalVCVSOutput.z);', ' float sf = pow(df, specularPower);', ' vec3 diffuseL = df * diffuseColor;', ' vec3 specularL = sf * specularColor;', ' gl_FragData[0] = vec4(ambientColor * ambient + diffuseL * diffuse + specularL * specular, opacity);', ' //VTK::Light::Impl'], false).result;
break;
case 2:
// light kit
for (let lc = 0; lc < lastLightCount; ++lc) {
sstring = sstring.concat([`uniform vec3 lightColor${lc};`, `uniform vec3 lightDirectionVC${lc}; // normalized`, `uniform vec3 lightHalfAngleVC${lc}; // normalized`]);
}
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Light::Dec', sstring).result;
sstring = ['vec3 diffuseL = vec3(0,0,0);', ' vec3 specularL = vec3(0,0,0);', ' float df;'];
for (let lc = 0; lc < lastLightCount; ++lc) {
sstring = sstring.concat([` df = max(0.0, dot(normalVCVSOutput, -lightDirectionVC${lc}));`, ` diffuseL += ((df${shadowFactor}) * lightColor${lc});`, ` if (dot(normalVCVSOutput, lightDirectionVC${lc}) < 0.0)`, ' {', ` float sf = sign(df)*pow(max(1e-5,
dot(reflect(lightDirectionVC${lc},normalVCVSOutput),
normalize(-vertexVC.xyz))),
specularPower);`, ` specularL += (sf${shadowFactor} * lightColor${lc});`, ' }']);
}
sstring = sstring.concat([' diffuseL = diffuseL * diffuseColor;', ' specularL = specularL * specularColor;', ' gl_FragData[0] = vec4(ambientColor * ambient + diffuseL * diffuse + specularL * specular, opacity);', ' //VTK::Light::Impl']);
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Light::Impl', sstring, false).result;
break;
case 3:
// positional
for (let lc = 0; lc < lastLightCount; ++lc) {
sstring = sstring.concat([`uniform vec3 lightColor${lc};`, `uniform vec3 lightDirectionVC${lc}; // normalized`, `uniform vec3 lightHalfAngleVC${lc}; // normalized`, `uniform vec3 lightPositionVC${lc};`, `uniform vec3 lightAttenuation${lc};`, `uniform float lightConeAngle${lc};`, `uniform float lightExponent${lc};`, `uniform int lightPositional${lc};`]);
}
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Light::Dec', sstring).result;
sstring = ['vec3 diffuseL = vec3(0,0,0);', ' vec3 specularL = vec3(0,0,0);', ' vec3 vertLightDirectionVC;', ' float attenuation;', ' float df;'];
for (let lc = 0; lc < lastLightCount; ++lc) {
sstring = sstring.concat([' attenuation = 1.0;', ` if (lightPositional${lc} == 0)`, ' {', ` vertLightDirectionVC = lightDirectionVC${lc};`, ' }', ' else', ' {', ` vertLightDirectionVC = vertexVC.xyz - lightPositionVC${lc};`, ' float distanceVC = length(vertLightDirectionVC);', ' vertLightDirectionVC = normalize(vertLightDirectionVC);', ' attenuation = 1.0 /', ` (lightAttenuation${lc}.x`, ` + lightAttenuation${lc}.y * distanceVC`, ` + lightAttenuation${lc}.z * distanceVC * distanceVC);`, ' // per OpenGL standard cone angle is 90 or less for a spot light', ` if (lightConeAngle${lc} <= 90.0)`, ' {', ` float coneDot = dot(vertLightDirectionVC, lightDirectionVC${lc});`, ' // if inside the cone', ` if (coneDot >= cos(radians(lightConeAngle${lc})))`, ' {', ` attenuation = attenuation * pow(coneDot, lightExponent${lc});`, ' }', ' else', ' {', ' attenuation = 0.0;', ' }', ' }', ' }', ' df = max(0.0, attenuation*dot(normalVCVSOutput, -vertLightDirectionVC));', ` diffuseL += ((df${shadowFactor}) * lightColor${lc});`, ' if (dot(normalVCVSOutput, vertLightDirectionVC) < 0.0)', ' {', ` float sf = sign(df)*attenuation*pow(max(1e-5,
dot(reflect(lightDirectionVC${lc},
normalVCVSOutput),
normalize(-vertexVC.xyz))),
specularPower);`, ` specularL += ((sf${shadowFactor}) * lightColor${lc});`, ' }']);
}
sstring = sstring.concat([' diffuseL = diffuseL * diffuseColor;', ' specularL = specularL * specularColor;', ' gl_FragData[0] = vec4(ambientColor * ambient + diffuseL * diffuse + specularL * specular, opacity);', ' //VTK::Light::Impl']);
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Light::Impl', sstring, false).result;
break;
default:
vtkErrorMacro('bad light complexity');
}
shaders.Fragment = FSSource;
};
publicAPI.replaceShaderNormal = (shaders, ren, actor) => {
const lastLightComplexity = model.lastBoundBO.getReferenceByName('lastLightComplexity');
if (lastLightComplexity > 0) {
let VSSource = shaders.Vertex;
let GSSource = shaders.Geometry;
let FSSource = shaders.Fragment;
if (model.lastBoundBO.getCABO().getNormalOffset()) {
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Normal::Dec', ['attribute vec3 normalMC;', 'uniform mat3 normalMatrix;', 'varying vec3 normalVCVSOutput;']).result;
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Normal::Impl', ['normalVCVSOutput = normalMatrix * normalMC;']).result;
GSSource = vtkShaderProgram.substitute(GSSource, '//VTK::Normal::Dec', ['in vec3 normalVCVSOutput[];', 'out vec3 normalVCGSOutput;']).result;
GSSource = vtkShaderProgram.substitute(GSSource, '//VTK::Normal::Impl', ['normalVCGSOutput = normalVCVSOutput[i];']).result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Normal::Dec', ['varying vec3 normalVCVSOutput;']).result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Normal::Impl', ['vec3 normalVCVSOutput = normalize(normalVCVSOutput);',
// if (!gl_FrontFacing) does not work in intel hd4000 mac
// if (int(gl_FrontFacing) == 0) does not work on mesa
' if (gl_FrontFacing == false) { normalVCVSOutput = -normalVCVSOutput; }']).result;
} else {
if (model.haveCellNormals) {
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Normal::Dec', ['uniform mat3 normalMatrix;', 'uniform samplerBuffer textureN;']).result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Normal::Impl', ['vec3 normalVCVSOutput = normalize(normalMatrix *', ' texelFetchBuffer(textureN, gl_PrimitiveID + PrimitiveIDOffset).xyz);', ' if (gl_FrontFacing == false) { normalVCVSOutput = -normalVCVSOutput; }']).result;
} else {
if (model.lastBoundBO.getOpenGLMode(actor.getProperty().getRepresentation()) === model.context.LINES) {
// generate a normal for lines, it will be perpendicular to the line
// and maximally aligned with the camera view direction
// no clue if this is the best way to do this.
// the code below has been optimized a bit so what follows is
// an explanation of the basic approach. Compute the gradient of the line
// with respect to x and y, the the larger of the two
// cross that with the camera view direction. That gives a vector
// orthogonal to the camera view and the line. Note that the line and the camera
// view are probably not orthogonal. Which is why when we cross result that with
// the line gradient again we get a reasonable normal. It will be othogonal to
// the line (which is a plane but maximally aligned with the camera view.
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::UniformFlow::Impl', [' vec3 fdx = dFdx(vertexVC.xyz);', ' vec3 fdy = dFdy(vertexVC.xyz);', ' //VTK::UniformFlow::Impl'] // For further replacements
).result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Normal::Impl', ['vec3 normalVCVSOutput;', ' if (abs(fdx.x) > 0.0)', ' { fdx = normalize(fdx); normalVCVSOutput = normalize(cross(vec3(fdx.y, -fdx.x, 0.0), fdx)); }', ' else { fdy = normalize(fdy); normalVCVSOutput = normalize(cross(vec3(fdy.y, -fdy.x, 0.0), fdy));}']).result;
} else {
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Normal::Dec', ['uniform int cameraParallel;']).result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::UniformFlow::Impl', [
// ' vec3 fdx = vec3(dFdx(vertexVC.x),dFdx(vertexVC.y),dFdx(vertexVC.z));',
// ' vec3 fdy = vec3(dFdy(vertexVC.x),dFdy(vertexVC.y),dFdy(vertexVC.z));',
' vec3 fdx = dFdx(vertexVC.xyz);', ' vec3 fdy = dFdy(vertexVC.xyz);', ' //VTK::UniformFlow::Impl'] // For further replacements
).result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Normal::Impl', [' fdx = normalize(fdx);', ' fdy = normalize(fdy);', ' vec3 normalVCVSOutput = normalize(cross(fdx,fdy));',
// the code below is faster, but does not work on some devices
// 'vec3 normalVC = normalize(cross(dFdx(vertexVC.xyz), dFdy(vertexVC.xyz)));',
' if (cameraParallel == 1 && normalVCVSOutput.z < 0.0) { normalVCVSOutput = -1.0*normalVCVSOutput; }', ' if (cameraParallel == 0 && dot(normalVCVSOutput,vertexVC.xyz) > 0.0) { normalVCVSOutput = -1.0*normalVCVSOutput; }']).result;
}
}
}
shaders.Vertex = VSSource;
shaders.Geometry = GSSource;
shaders.Fragment = FSSource;
}
};
publicAPI.replaceShaderPositionVC = (shaders, ren, actor) => {
// replace common shader code
model.lastBoundBO.replaceShaderPositionVC(shaders, ren, actor);
let VSSource = shaders.Vertex;
let GSSource = shaders.Geometry;
let FSSource = shaders.Fragment;
// do we need the vertex in the shader in View Coordinates
const lastLightComplexity = model.lastBoundBO.getReferenceByName('lastLightComplexity');
if (lastLightComplexity > 0) {
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::PositionVC::Dec', ['varying vec4 vertexVCVSOutput;']).result;
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::PositionVC::Impl', ['vertexVCVSOutput = MCVCMatrix * vertexMC;', ' gl_Position = MCPCMatrix * vertexMC;']).result;
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Camera::Dec', ['uniform mat4 MCPCMatrix;', 'uniform mat4 MCVCMatrix;']).result;
GSSource = vtkShaderProgram.substitute(GSSource, '//VTK::PositionVC::Dec', ['in vec4 vertexVCVSOutput[];', 'out vec4 vertexVCGSOutput;']).result;
GSSource = vtkShaderProgram.substitute(GSSource, '//VTK::PositionVC::Impl', ['vertexVCGSOutput = vertexVCVSOutput[i];']).result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::PositionVC::Dec', ['varying vec4 vertexVCVSOutput;']).result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::PositionVC::Impl', ['vec4 vertexVC = vertexVCVSOutput;']).result;
} else {
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Camera::Dec', ['uniform mat4 MCPCMatrix;']).result;
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::PositionVC::Impl', [' gl_Position = MCPCMatrix * vertexMC;']).result;
}
shaders.Vertex = VSSource;
shaders.Geometry = GSSource;
shaders.Fragment = FSSource;
};
publicAPI.replaceShaderTCoord = (shaders, ren, actor) => {
if (model.lastBoundBO.getCABO().getTCoordOffset()) {
let VSSource = shaders.Vertex;
let GSSource = shaders.Geometry;
let FSSource = shaders.Fragment;
if (model.drawingEdges) {
return;
}
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Impl', 'tcoordVCVSOutput = tcoordMC;').result;
// we only handle the first texture by default
// additional textures are activated and we set the uniform
// for the texture unit they are assigned to, but you have to
// add in the shader code to do something with them
const tus = model.openGLActor.getActiveTextures();
let tNumComp = 2;
let tcdim = 2;
if (tus && tus.length > 0) {
tNumComp = tus[0].getComponents();
if (tus[0].getTarget() === model.context.TEXTURE_CUBE_MAP) {
tcdim = 3;
}
}
if (model.renderable.getColorTextureMap()) {
tNumComp = model.renderable.getColorTextureMap().getPointData().getScalars().getNumberOfComponents();
tcdim = 2;
}
if (tcdim === 2) {
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Dec', 'attribute vec2 tcoordMC; varying vec2 tcoordVCVSOutput;').result;
GSSource = vtkShaderProgram.substitute(GSSource, '//VTK::TCoord::Dec', ['in vec2 tcoordVCVSOutput[];', 'out vec2 tcoordVCGSOutput;']).result;
GSSource = vtkShaderProgram.substitute(GSSource, '//VTK::TCoord::Impl', 'tcoordVCGSOutput = tcoordVCVSOutput[i];').result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Dec', ['varying vec2 tcoordVCVSOutput;', 'uniform sampler2D texture1;']).result;
if (tus && tus.length >= 1) {
switch (tNumComp) {
case 1:
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Impl', [' vec4 tcolor = texture2D(texture1, tcoordVCVSOutput);', ' ambientColor = ambientColor*tcolor.r;', ' diffuseColor = diffuseColor*tcolor.r;']).result;
break;
case 2:
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Impl', [' vec4 tcolor = texture2D(texture1, tcoordVCVSOutput);', ' ambientColor = ambientColor*tcolor.r;', ' diffuseColor = diffuseColor*tcolor.r;', ' opacity = opacity * tcolor.g;']).result;
break;
default:
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Impl', [' vec4 tcolor = texture2D(texture1, tcoordVCVSOutput);', ' ambientColor = ambientColor*tcolor.rgb;', ' diffuseColor = diffuseColor*tcolor.rgb;', ' opacity = opacity * tcolor.a;']).result;
}
}
} else {
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Dec', 'attribute vec3 tcoordMC; varying vec3 tcoordVCVSOutput;').result;
GSSource = vtkShaderProgram.substitute(GSSource, '//VTK::TCoord::Dec', ['in vec3 tcoordVCVSOutput[];', 'out vec3 tcoordVCGSOutput;']).result;
GSSource = vtkShaderProgram.substitute(GSSource, '//VTK::TCoord::Impl', 'tcoordVCGSOutput = tcoordVCVSOutput[i];').result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Dec', ['varying vec3 tcoordVCVSOutput;', 'uniform samplerCube texture1;']).result;
switch (tNumComp) {
case 1:
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Impl', [' vec4 tcolor = textureCube(texture1, tcoordVCVSOutput);', ' ambientColor = ambientColor*tcolor.r;', ' diffuseColor = diffuseColor*tcolor.r;']).result;
break;
case 2:
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Impl', [' vec4 tcolor = textureCube(texture1, tcoordVCVSOutput);', ' ambientColor = ambientColor*tcolor.r;', ' diffuseColor = diffuseColor*tcolor.r;', ' opacity = opacity * tcolor.g;']).result;
break;
default:
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Impl', [' vec4 tcolor = textureCube(texture1, tcoordVCVSOutput);', ' ambientColor = ambientColor*tcolor.rgb;', ' diffuseColor = diffuseColor*tcolor.rgb;', ' opacity = opacity * tcolor.a;']).result;
}
}
shaders.Vertex = VSSource;
shaders.Geometry = GSSource;
shaders.Fragment = FSSource;
}
};
publicAPI.replaceShaderClip = (shaders, ren, actor) => {
let VSSource = shaders.Vertex;
let FSSource = shaders.Fragment;
if (model.renderable.getNumberOfClippingPlanes()) {
const numClipPlanes = model.renderable.getNumberOfClippingPlanes();
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Clip::Dec', ['uniform int numClipPlanes;', `uniform vec4 clipPlanes[${numClipPlanes}];`, `varying float clipDistancesVSOutput[${numClipPlanes}];`]).result;
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Clip::Impl', [`for (int planeNum = 0; planeNum < ${numClipPlanes}; planeNum++)`, ' {', ' if (planeNum >= numClipPlanes)', ' {', ' break;', ' }', ' clipDistancesVSOutput[planeNum] = dot(clipPlanes[planeNum], vertexMC);', ' }']).result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Clip::Dec', ['uniform int numClipPlanes;', `varying float clipDistancesVSOutput[${numClipPlanes}];`]).result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Clip::Impl', [`for (int planeNum = 0; planeNum < ${numClipPlanes}; planeNum++)`, ' {', ' if (planeNum >= numClipPlanes)', ' {', ' break;', ' }', ' if (clipDistancesVSOutput[planeNum] < 0.0) discard;', ' }']).result;
}
shaders.Vertex = VSSource;
shaders.Fragment = FSSource;
};
publicAPI.getCoincidentParameters = (ren, actor) => {
// 1. ResolveCoincidentTopology is On and non zero for this primitive
// type
let cp = {
factor: 0.0,
offset: 0.0
};
const prop = actor.getProperty();
if (
// backwards compat with code that (errorneously) set this to boolean
// eslint-disable-next-line eqeqeq
model.renderable.getResolveCoincidentTopology() == Resolve.PolygonOffset || prop.getEdgeVisibility() && prop.getRepresentation() === Representation.SURFACE) {
const primType = model.lastBoundBO.getPrimitiveType();
if (primType === primTypes.Points || prop.getRepresentation() === Representation.POINTS) {
cp = model.renderable.getCoincidentTopologyPointOffsetParameter();
} else if (primType === primTypes.Lines || prop.getRepresentation() === Representation.WIREFRAME) {
cp = model.renderable.getCoincidentTopologyLineOffsetParameters();
} else if (primType === primTypes.Tris || primType === primTypes.TriStrips) {
cp = model.renderable.getCoincidentTopologyPolygonOffsetParameters();
}
if (primType === primTypes.TrisEdges || primType === primTypes.TriStripsEdges) {
cp = model.renderable.getCoincidentTopologyPolygonOffsetParameters();
cp.factor /= 2.0;
cp.offset /= 2.0;
}
}
// hardware picking always offset due to saved zbuffer
// This gets you above the saved surface depth buffer.
const selector = model._openGLRenderer.getSelector();
if (selector && selector.getFieldAssociation() === FieldAssociations.FIELD_ASSOCIATION_POINTS) {
cp.offset -= 2.0;
}
return cp;
};
publicAPI.replaceShaderPicking = (shaders, ren, actor) => {
let FSSource = shaders.Fragment;
let VSSource = shaders.Vertex;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Picking::Dec', ['uniform int picking;', '//VTK::Picking::Dec']).result;
if (!model._openGLRenderer.getSelector()) {
return;
}
if (model.lastSelectionState === PassTypes.ID_LOW24 || model.lastSelectionState === PassTypes.ID_HIGH24) {
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Picking::Dec', ['flat out int vertexIDVSOutput;\n', 'uniform int VertexIDOffset;\n']).result;
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Picking::Impl', ' vertexIDVSOutput = gl_VertexID + VertexIDOffset;\n').result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Picking::Dec', 'flat in int vertexIDVSOutput;\n').result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Picking::Impl', [' int idx = vertexIDVSOutput;', '//VTK::Picking::Impl']).result;
}
switch (model.lastSelectionState) {
case PassTypes.ID_LOW24:
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Picking::Impl', ' gl_FragData[0] = vec4(float(idx%256)/255.0, float((idx/256)%256)/255.0, float((idx/65536)%256)/255.0, 1.0);').result;
break;
case PassTypes.ID_HIGH24:
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Picking::Impl', ' gl_FragData[0] = vec4(float((idx/16777216)%256)/255.0, 0.0, 0.0, 1.0);').result;
break;
default:
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Picking::Dec', 'uniform vec3 mapperIndex;').result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Picking::Impl', ' gl_FragData[0] = picking != 0 ? vec4(mapperIndex,1.0) : gl_FragData[0];').result;
}
shaders.Fragment = FSSource;
shaders.Vertex = VSSource;
};
publicAPI.replaceShaderValues = (shaders, ren, actor) => {
publicAPI.replaceShaderColor(shaders, ren, actor);
publicAPI.replaceShaderNormal(shaders, ren, actor);
publicAPI.replaceShaderLight(shaders, ren, actor);
publicAPI.replaceShaderTCoord(shaders, ren, actor);
publicAPI.replaceShaderPicking(shaders, ren, actor);
publicAPI.replaceShaderClip(shaders, ren, actor);
publicAPI.replaceShaderCoincidentOffset(shaders, ren, actor);
publicAPI.replaceShaderPositionVC(shaders, ren, actor);
if (model.haveSeenDepthRequest) {
let FSSource = shaders.Fragment;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ZBuffer::Dec', 'uniform int depthRequest;').result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ZBuffer::Impl', ['if (depthRequest == 1) {', 'float iz = floor(gl_FragCoord.z*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.Fragment = FSSource;
}
};
publicAPI.getNeedToRebuildShaders = (cellBO, ren, actor) => {
let lightComplexity = 0;
let numberOfLights = 0;
const primType = cellBO.getPrimitiveType();
const poly = model.currentInput;
// different algo from C++ as of 5/2019
let needLighting = false;
const pointNormals = poly.getPointData().getNormals();
const cellNormals = poly.getCellData().getNormals();
const flat = actor.getProperty().getInterpolation() === Shading.FLAT;
const representation = actor.getProperty().getRepresentation();
const mode = cellBO.getOpenGLMode(representation, primType);
// 1) all surfaces need lighting
if (mode === model.context.TRIANGLES) {
needLighting = true;
// 2) all cell normals without point normals need lighting
} else if (cellNormals && !pointNormals) {
needLighting = true;
// 3) Phong + pointNormals need lighting
} else if (!flat && pointNormals) {
needLighting = true;
// 4) Phong Lines need lighting
} else if (!flat && mode === model.context.LINES) {
needLighting = true;
}
// 5) everything else is unlit
// do we need lighting?
if (actor.getProperty().getLighting() && needLighting) {
// consider the lighting complexity to determine which case applies
// simple headlight, Light Kit, the whole feature set of VTK
lightComplexity = 0;
const lights = ren.getLightsByReference();
for (let index = 0; index < lights.length; ++index) {
const light = lights[index];
const status = light.getSwitch();
if (status > 0) {
numberOfLights++;
if (lightComplexity === 0) {
lightComplexity = 1;
}
}
if (lightComplexity === 1 && (numberOfLights > 1 || light.getIntensity() !== 1.0 || !light.lightTypeIsHeadLight())) {
lightComplexity = 2;
}
if (lightComplexity < 3 && light.getPositional()) {
lightComplexity = 3;
}
}
}
let needRebuild = false;
const lastLightComplexity = model.lastBoundBO.getReferenceByName('lastLightComplexity');
const lastLightCount = model.lastBoundBO.getReferenceByName('lastLightCount');
if (lastLightComplexity !== lightComplexity || lastLightCount !== numberOfLights) {
model.lastBoundBO.set({
lastLightComplexity: lightComplexity
}, true);
model.lastBoundBO.set({
lastLightCount: numberOfLights
}, true);
needRebuild = true;
}
// has the render pass shader replacement changed? Two options
if (!model.currentRenderPass && model.lastRenderPassShaderReplacement || model.currentRenderPass && model.currentRenderPass.getShaderReplacement() !== model.lastRenderPassShaderReplacement) {
needRebuild = true;
}
// has something changed that would require us to recreate the shader?
// candidates are
// property modified (representation interpolation and lighting)
// input modified
// light complexity changed
// render pass shader replacement changed
if (model.lastHaveSeenDepthRequest !== model.haveSeenDepthRequest || cellBO.getShaderSourceTime().getMTime() < model.renderable.getMTime() || cellBO.getShaderSourceTime().getMTime() < model.currentInput.getMTime() || cellBO.getShaderSourceTime().getMTime() < model.selectionStateChanged.getMTime() || needRebuild) {
model.lastHaveSeenDepthRequest = model.haveSeenDepthRequest;
return true;
}
return false;
};
publicAPI.invokeShaderCallbacks = (cellBO, ren, actor) => {
const listCallbacks = model.renderable.getViewSpecificProperties().ShadersCallbacks;
if (listCallbacks) {
listCallbacks.forEach(object => {
object.callback(object.userData, cellBO, ren, actor);
});
}
};
publicAPI.setMapperShaderParameters = (cellBO, ren, actor) => {
// Now to update the VAO too, if necessary.
if (cellBO.getProgram().isUniformUsed('PrimitiveIDOffset')) {
cellBO.getProgram().setUniformi('PrimitiveIDOffset', model.primitiveIDOffset);
}
if (cellBO.getProgram().isUniformUsed('VertexIDOffset')) {
cellBO.getProgram().setUniformi('VertexIDOffset', model.vertexIDOffset);
}
if (cellBO.getCABO().getElementCount() && (model.VBOBuildTime.getMTime() > cellBO.getAttributeUpdateTime().getMTime() || cellBO.getShaderSourceTime().getMTime() > cellBO.getAttributeUpdateTime().getMTime())) {
const lastLightComplexity = model.lastBoundBO.getReferenceByName('lastLightComplexity');
if (cellBO.getProgram().isAttributeUsed('vertexMC')) {
if (!cellBO.getVAO().addAttributeArray(cellBO.getProgram(), cellBO.getCABO(), 'vertexMC', cellBO.getCABO().getVertexOffset(), cellBO.getCABO().getStride(), model.context.FLOAT, 3, false)) {
vtkErrorMacro('Error setting vertexMC in shader VAO.');
}
}
if (cellBO.getProgram().isAttributeUsed('normalMC') && cellBO.getCABO().getNormalOffset() && lastLightComplexity > 0) {
if (!cellBO.getVAO().addAttributeArray(cellBO.getProgram(), cellBO.getCABO(), 'normalMC', cellBO.getCABO().getNormalOffset(), cellBO.getCABO().getStride(), model.context.FLOAT, 3, false)) {
vtkErrorMacro('Error setting normalMC in shader VAO.');
}
} else {
cellBO.getVAO().removeAttributeArray('normalMC');
}
model.renderable.getCustomShaderAttributes().forEach((attrName, idx) => {
if (cellBO.getProgram().isAttributeUsed(`${attrName}MC`)) {
if (!cellBO.getVAO().addAttributeArray(cellBO.getProgram(), cellBO.getCABO(), `${attrName}MC`, cellBO.getCABO().getCustomData()[idx].offset, cellBO.getCABO().getStride(), model.context.FLOAT, cellBO.getCABO().getCustomData()[idx].components, false)) {
vtkErrorMacro(`Error setting ${attrName}MC in shader VAO.`);
}
}
});
if (cellBO.getProgram().isAttributeUsed('tcoordMC') && cellBO.getCABO().getTCoordOffset()) {
if (!cellBO.getVAO().addAttributeArray(cellBO.getProgram(), cellBO.getCABO(), 'tcoordMC', cellBO.getCABO().getTCoordOffset(), cellBO.getCABO().getStride(), model.context.FLOAT, cellBO.getCABO().getTCoordComponents(), false)) {
vtkErrorMacro('Error setting tcoordMC in shader VAO.');
}
} else {
cellBO.getVAO().removeAttributeArray('tcoordMC');
}
if (cellBO.getProgram().isAttributeUsed('scalarColor') && cellBO.getCABO().getColorComponents()) {
if (!cellBO.getVAO().addAttributeArray(cellBO.getProgram(), cellBO.getCABO().getColorBO(), 'scalarColor', cellBO.getCABO().getColorOffset(), cellBO.getCABO().getColorBOStride(), model.context.UNSIGNED_BYTE, 4, true)) {
vtkErrorMacro('Error setting scalarColor in shader VAO.');
}
} else {
cellBO.getVAO().removeAttributeArray('scalarColor');
}
cellBO.getAttributeUpdateTime().modified();
}
if (model.renderable.getNumberOfClippingPlanes()) {
// add all the clipping planes
const numClipPlanes = model.renderable.getNumberOfClippingPlanes();
const planeEquations = [];
const shiftScaleEnabled = cellBO.getCABO().getCoordShiftAndScaleEnabled();
const inverseShiftScaleMatrix = shiftScaleEnabled ? cellBO.getCABO().getInverseShiftAndScaleMatrix() : null;
const mat = inverseShiftScaleMatrix ? mat4.copy(model.tmpMat4, actor.getMatrix()) : actor.getMatrix();
if (inverseShiftScaleMatrix) {
mat4.transpose(mat, mat);
mat4.multiply(mat, mat, inverseShiftScaleMatrix);
mat4.transpose(mat, mat);
}
for (let i = 0; i < numClipPlanes; i++) {
const planeEquation = [];
model.renderable.getClippingPlaneInDataCoords(mat, i, planeEquation);
for (let j = 0; j < 4; j++) {
planeEquations.push(planeEquation[j]);
}
}
cellBO.getProgram().setUniformi('numClipPlanes', numClipPlanes);
cellBO.getProgram().setUniform4fv('clipPlanes', planeEquations);
}
if (model.internalColorTexture && cellBO.getProgram().isUniformUsed('texture1')) {
cellBO.getProgram().setUniformi('texture1', model.internalColorTexture.getTextureUnit());
}
const tus = model.openGLActor.getActiveTextures();
if (tus) {
for (let index = 0; index < tus.length; ++index) {
const tex = tus[index];
const texUnit = tex.getTextureUnit();
const tname = `texture${texUnit + 1}`;
if (cellBO.getProgram().isUniformUsed(tname)) {
cellBO.getProgram().setUniformi(tname, texUnit);
}
}
}
// handle depth requests
if (model.haveSeenDepthRequest) {
cellBO.getProgram().setUniformi('depthRequest', model.renderDepth ? 1 : 0);
}
// handle coincident
if (cellBO.getProgram().isUniformUsed('coffset')) {
const cp = publicAPI.getCoincidentParameters(ren, actor);
cellBO.getProgram().setUniformf('coffset', cp.offset);
// cfactor isn't always used when coffset is.
if (cellBO.getProgram().isUniformUsed('cfactor')) {
cellBO.getProgram().setUniformf('cfactor', cp.factor);
}
}
// handle wide lines
cellBO.setMapperShaderParameters(ren, actor, model._openGLRenderer.getTiledSizeAndOrigin());
const selector = model._openGLRenderer.getSelector();
cellBO.getProgram().setUniform3fArray('mapperIndex', selector ? selector.getPropColorValue() : [0.0, 0.0, 0.0]);
cellBO.getProgram().setUniformi('picking', selector ? selector.getCurrentPass() + 1 : 0);
};
publicAPI.setLightingShaderParameters = (cellBO, ren, actor) => {
// for unlit and headlight there are no lighting parameters
const lastLightComplexity = model.lastBoundBO.getReferenceByName('lastLightComplexity');
if (lastLightComplexity < 2) {
return;
}
const program = cellBO.getProgram();
// bind some light settings
let numberOfLights = 0;
const lights = ren.getLightsByReference();
for (let index = 0; index < lights.length; ++index) {
const light = lights[index];
const status = light.getSwitch();
if (status > 0.0) {
const dColor = light.getColorByReference();
const intensity = light.getIntensity();
model.lightColor[0] = dColor[0] * intensity;
model.lightColor[1] = dColor[1] * intensity;
model.lightColor[2] = dColor[2] * intensity;
// get required info from light
const ld = light.getDirection();
const transform = ren.getActiveCamera().getViewMatrix();
const newLightDirection = [...ld];
if (light.lightTypeIsSceneLight()) {
newLightDirection[0] = transform[0] * ld[0] + transform[1] * ld[1] + transform[2] * ld[2];
newLightDirection[1] = transform[4] * ld[0] + transform[5] * ld[1] + transform[6] * ld[2];
newLightDirection[2] = transform[8] * ld[0] + transform[9] * ld[1] + transform[10] * ld[2];
normalize(newLightDirection);
}
model.lightDirection[0] = newLightDirection[0];
model.lightDirection[1] = newLightDirection[1];
model.lightDirection[2] = newLightDirection[2];
normalize(model.lightDirection);
program.setUniform3fArray(`lightColor${numberOfLights}`, model.lightColor);
program.setUniform3fArray(`lightDirectionVC${numberOfLights}`, model.lightDirection);
numberOfLights++;
}
}
// we are done unless we have positional lights
if (lastLightComplexity < 3) {
return;
}
// for lightkit case there are some parameters to set
const cam = ren.getActiveCamera();
const viewTF = cam.getViewMatrix();
mat4.transpose(viewTF, viewTF);
numberOfLights = 0;
for (let index = 0; index < lights.length; ++index) {
const light = lights[index];
const status = light.getSwitch();
if (status > 0.0) {
const lp = light.getTransformedPosition();
const np = new Float64Array(3);
vec3.transformMat4(np, lp, viewTF);
program.setUniform3fArray(`lightAttenuation${numberOfLights}`, light.getAttenuationValuesByReference());
program.setUniformi(`lightPositional${numberOfLights}`, light.getPositional());
program.setUniformf(`lightExponent${numberOfLights}`, light.getExponent());
program.setUniformf(`lightConeAngle${numberOfLights}`, light.getConeAngle());
program.setUniform3fArray(`lightPositionVC${numberOfLights}`, [np[0], np[1], np[2]]);
numberOfLights++;
}
}
};
function safeMatrixMultiply(matrixArray, matrixType, tmpMat) {
matrixType.identity(tmpMat);
return matrixArray.reduce((res, matrix, index) => {
if (index === 0) {
return matrix ? matrixType.copy(res, matrix) : matrixType.identity(res);
}
return matrix ? matrixType.multiply(res, res, matrix) : res;
}, tmpMat);
}
publicAPI.setCameraShaderParameters = (cellBO, ren, actor) => {
const program = cellBO.getProgram();
// [WMVP]C == {world, model, view, projection} coordinates
// E.g., WCPC == world to projection coordinate transformation
const keyMats = model.openGLCamera.getKeyMatrices(ren);
const cam = ren.getActiveCamera();
const camm = model.openGLCamera.getKeyMatrixTime().getMTime();
const progm = program.getLastCameraMTime();
const shiftScaleEnabled = cellBO.getCABO().getCoordShiftAndScaleEnabled();
const inverseShiftScaleMatrix = shiftScaleEnabled ? cellBO.getCABO().getInverseShiftAndScaleMatrix() : null;
const actorIsIdentity = actor.getIsIdentity();
const actMats = actorIsIdentity ? {
mcwc: null,
normalMatrix: null
} : model.openGLActor.getKeyMatrices();
if (actor.getCoordinateSystem() === CoordinateSystem.DISPLAY) {
const size = model._openGLRenderer.getTiledSizeAndOrigin();
mat4.identity(model.tmpMat4);
model.tmpMat4[0] = 2.0 / size.usize;
model.tmpMat4[12] = -1.0;
model.tmpMat4[5] = 2.0 / size.vsize;
model.tmpMat4[13] = -1.0;
mat4.multiply(model.tmpMat4, model.tmpMat4, inverseShiftScaleMatrix);
program.setUniformMatrix('MCPCMatrix', model.tmpMat4);
} else {
program.setUniformMatrix('MCPCMatrix', safeMatrixMultiply([keyMats.wcpc, actMats.mcwc, inverseShiftScaleMatrix], mat4, model.tmpMat4));
}
if (program.isUniformUsed('MCVCMatrix')) {
program.setUniformMatrix('MCVCMatrix', safeMatrixMultiply([keyMats.wcvc, actMats.mcwc, inverseShiftScaleMatrix], mat4, model.tmpMat4));
}
if (program.isUniformUsed('normalMatrix')) {
program.setUniformMatrix3x3('normalMatrix', safeMatrixMultiply([keyMats.normalMatrix, actMats.normalMatrix], mat3, model.tmpMat3));
}
if (progm !== camm) {
if (program.isUniformUsed('cameraParallel')) {
program.setUniformi('cameraParallel', cam.getParallelProjection());
}
program.setLastCameraMTime(camm);
}
if (!actorIsIdentity) {
// reset the cam mtime as actor modified the shader values
program.setLastCameraMTime(0);
}
};
publicAPI.setPropertyShaderParameters = (cellBO, ren, actor) => {
const program = cellBO.getProgram();
let ppty = actor.getProperty();
let opacity = ppty.getOpacity();
let aColor = model.drawingEdges ? ppty.getEdgeColorByReference() : ppty.getAmbientColorByReference();
let dColor = model.drawingEdges ? ppty.getEdgeColorByReference() : ppty.getDiffuseColorByReference();
let aIntensity = model.drawingEdges ? 1.0 : ppty.getAmbient();
let dIntensity = model.drawingEdges ? 0.0 : ppty.getDiffuse();
let sIntensity = model.drawingEdges ? 0.0 : ppty.getSpecular();
const specularPower = ppty.getSpecularPower();
program.setUniformf('opacityUniform', opacity);
program.setUniform3fArray('ambientColorUniform', aColor);
program.setUniform3fArray('diffuseColorUniform', dColor);
program.setUniformf('ambient', aIntensity);
program.setUniformf('diffuse', dIntensity);
// we are done unless we have lighting
const lastLightComplexity = model.lastBoundBO.getReferenceByName('lastLightComplexity');
if (lastLightComplexity < 1) {
return;
}
let sColor = ppty.getSpecularColorByReference();
program.setUniform3fArray('specularColorUniform', sColor);
program.setUniformf('specularPowerUniform', specularPower);
program.setUniformf('specular', sIntensity);
// now set the backface properties if we have them
if (program.isUniformUsed('ambientIntensityBF')) {
ppty = actor.getBackfaceProperty();
opacity = ppty.getOpacity();
aColor = ppty.getAmbientColor();
aIntensity = ppty.getAmbient();
dColor = ppty.getDiffuseColor();
dIntensity = ppty.getDiffuse();
sColor = ppty.getSpecularColor();
sIntensity = ppty.getSpecular();
program.setUniformf('ambientIntensityBF', aIntensity);
program.setUniformf('diffuseIntensityBF', dIntensity);
program.setUniformf('opacityUniformBF', opacity);
program.setUniform3fArray('ambientColorUniformBF', aColor);
program.setUniform3fArray('diffuseColorUniformBF', dColor);
// we are done unless we have lighting
if (lastLightComplexity < 1) {
return;
}
program.setUniformf('specularIntensityBF', sIntensity);
program.setUniform3fArray('specularColorUniformBF', sColor);
program.setUniformf('specularPowerUniformBF', specularPower);
}
};
publicAPI.updateMaximumPointCellIds = (ren, actor) => {
const selector = model._openGLRenderer.getSelector();
if (!selector) {
return;
}
if (model.selectionWebGLIdsToVTKIds?.points?.length) {
const length = model.selectionWebGLIdsToVTKIds.points.length;
selector.setMaximumPointId(length - 1);
}
if (model.selectionWebGLIdsToVTKIds?.cells?.length) {
const length = model.selectionWebGLIdsToVTKIds.cells.length;
selector.setMaximumCellId(length - 1);
}
const fieldAssociation = selector.getFieldAssociation();
if (fieldAssociation === FieldAssociations.FIELD_ASSOCIATION_POINTS) {
model.pointPicking = true;
}
};
publicAPI.renderPieceStart = (ren, actor) => {
model.primitiveIDOffset = 0;
model.vertexIDOffset = 0;
const picking = getPickState(model._openGLRenderer);
if (model.lastSelectionState !== picking) {
model.selectionStateChanged.modified();
model.lastSelectionState = picking;
}
if (model._openGLRenderer.getSelector()) {
switch (picking) {
default:
model._openGLRenderer.getSelector().renderProp(actor);
}
}
// make sure the BOs are up to date
publicAPI.updateBufferObjects(ren, actor);
// If we are coloring by texture, then load the texture map.
// Use Map as indicator, because texture hangs around.
if (model.renderable.getColorTextureMap()) {
model.internalColorTexture.activate();
}
// Bind the OpenGL, this is shared between