@thewtex/vtk.js-esm
Version:
Visualization Toolkit for the Web
242 lines (187 loc) • 11.5 kB
JavaScript
import { newInstance as newInstance$1, vtkErrorMacro as vtkErrorMacro$1 } from '../../macro.js';
import { r as radiansFromDegrees } from '../../Common/Core/Math/index.js';
import vtkWebGPUPolyDataMapper from './PolyDataMapper.js';
import vtkWebGPUBufferManager from './BufferManager.js';
import vtkWebGPUShaderCache from './ShaderCache.js';
import { registerOverride } from './ViewNodeFactory.js';
var BufferUsage = vtkWebGPUBufferManager.BufferUsage,
PrimitiveTypes = vtkWebGPUBufferManager.PrimitiveTypes;
var vtkErrorMacro = vtkErrorMacro$1;
var vtkWebGPUSphereMapperVS = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::Color::Dec\n\n//VTK::IOStructs::Dec\n\n[[stage(vertex)]]\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : vertexOutput;\n\n var vertexVC: vec4<f32> = rendererUBO.SCVCMatrix * mapperUBO.BCSCMatrix * vec4<f32>(vertexBC.x, vertexBC.y, vertexBC.z, 1.0);\n\n //VTK::Color::Impl\n\n // compute the projected vertex position\n output.centerVC = vertexVC.xyz;\n output.radiusVC = length(offsetMC)*0.5;\n\n // make the triangle face the camera\n if (rendererUBO.cameraParallel == 0u)\n {\n var dir: vec3<f32> = normalize(-vertexVC.xyz);\n var base2: vec3<f32> = normalize(cross(dir,vec3<f32>(1.0,0.0,0.0)));\n var base1: vec3<f32> = cross(base2,dir);\n dir = vertexVC.xyz + offsetMC.x*base1 + offsetMC.y*base2;\n vertexVC = vec4<f32>(dir, 1.0);\n }\n else\n {\n // add in the offset\n var tmp2: vec2<f32> = vertexVC.xy + offsetMC;\n vertexVC = vec4<f32>(tmp2, vertexVC.zw);\n }\n\n output.vertexVC = vertexVC.xyz;\n\n //VTK::Position::Impl\n\n return output;\n}\n"; // ----------------------------------------------------------------------------
// vtkWebGPUSphereMapper methods
// ----------------------------------------------------------------------------
function vtkWebGPUSphereMapper(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkWebGPUSphereMapper');
publicAPI.replaceShaderNormal = function (hash, pipeline, vertexInput) {
var vDesc = pipeline.getShaderDescription('vertex');
vDesc.addOutput('vec3<f32>', 'vertexVC');
vDesc.addOutput('vec3<f32>', 'centerVC');
vDesc.addOutput('f32', 'radiusVC');
var fDesc = pipeline.getShaderDescription('fragment');
fDesc.addBuiltinOutput('f32', '[[builtin(frag_depth)]] fragDepth');
var sphereFrag = "\n // compute the eye position and unit direction\n var vertexVC: vec4<f32>;\n var EyePos: vec3<f32>;\n var EyeDir: vec3<f32>;\n var invertedDepth: f32 = 1.0;\n if (rendererUBO.cameraParallel != 0u) {\n EyePos = vec3<f32>(input.vertexVC.x, input.vertexVC.y, input.vertexVC.z + 3.0*input.radiusVC);\n EyeDir = vec3<f32>(0.0, 0.0, -1.0);\n }\n else {\n EyeDir = input.vertexVC.xyz;\n EyePos = vec3<f32>(0.0,0.0,0.0);\n var lengthED: f32 = length(EyeDir);\n EyeDir = normalize(EyeDir);\n // we adjust the EyePos to be closer if it is too far away\n // to prevent floating point precision noise\n if (lengthED > input.radiusVC*3.0) {\n EyePos = input.vertexVC.xyz - EyeDir*3.0*input.radiusVC;\n }\n }\n\n // translate to Sphere center\n EyePos = EyePos - input.centerVC;\n // scale to radius 1.0\n EyePos = EyePos * (1.0 / input.radiusVC);\n // find the intersection\n var b: f32 = 2.0*dot(EyePos,EyeDir);\n var c: f32 = dot(EyePos,EyePos) - 1.0;\n var d: f32 = b*b - 4.0*c;\n var normal: vec3<f32> = vec3<f32>(0.0,0.0,1.0);\n if (d < 0.0) { discard; }\n else {\n var t: f32 = (-b - invertedDepth*sqrt(d))*0.5;\n\n // compute the normal, for unit sphere this is just\n // the intersection point\n normal = invertedDepth*normalize(EyePos + t*EyeDir);\n // compute the intersection point in VC\n vertexVC = vec4<f32>(normal * input.radiusVC + input.centerVC, 1.0);\n }\n // compute the pixel's depth\n var pos: vec4<f32> = rendererUBO.VCPCMatrix * vertexVC;\n output.fragDepth = pos.z / pos.w;\n ";
var code = fDesc.getCode();
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Normal::Impl', [sphereFrag]).result;
fDesc.setCode(code);
};
publicAPI.replaceShaderPosition = function (hash, pipeline, vertexInput) {
var vDesc = pipeline.getShaderDescription('vertex');
vDesc.addBuiltinOutput('vec4<f32>', '[[builtin(position)]] Position');
var code = vDesc.getCode();
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Position::Impl', [' output.Position = rendererUBO.VCPCMatrix*vertexVC;']).result;
vDesc.setCode(code);
}; // compute a unique hash for a pipeline, this needs to be unique enough to
// capture any pipeline code changes (which includes shader changes)
// or vertex input changes/ bind groups/ etc
publicAPI.computePipelineHash = function (vertexInput) {
var pipelineHash = 'spm';
if (vertexInput.hasAttribute("colorVI")) {
pipelineHash += "c";
}
pipelineHash += model.renderEncoder.getPipelineHash();
return pipelineHash;
}; // was originally buildIBOs() but not using IBOs right now
publicAPI.buildPrimitives = function () {
var poly = model.currentInput;
var device = model.WebGPURenderWindow.getDevice();
model.renderable.mapScalars(poly, 1.0); // handle triangles
var i = PrimitiveTypes.Triangles;
var points = poly.getPoints();
var numPoints = points.getNumberOfPoints();
var pointArray = points.getData();
var primHelper = model.primitives[i]; // default to one instance and computed number of verts
primHelper.setNumberOfInstances(1);
primHelper.setNumberOfVertices(3 * numPoints);
var vertexInput = model.primitives[i].getVertexInput();
var buffRequest = {
hash: points.getMTime(),
source: points,
time: points.getMTime(),
usage: BufferUsage.RawVertex,
format: 'float32x3'
};
if (!device.getBufferManager().hasBuffer(buffRequest)) {
// xyz v1 v2 v3
var tmpVBO = new Float32Array(3 * numPoints * 3);
var pointIdx = 0;
var vboIdx = 0;
for (var id = 0; id < numPoints; ++id) {
pointIdx = id * 3;
tmpVBO[vboIdx++] = pointArray[pointIdx];
tmpVBO[vboIdx++] = pointArray[pointIdx + 1];
tmpVBO[vboIdx++] = pointArray[pointIdx + 2];
tmpVBO[vboIdx++] = pointArray[pointIdx];
tmpVBO[vboIdx++] = pointArray[pointIdx + 1];
tmpVBO[vboIdx++] = pointArray[pointIdx + 2];
tmpVBO[vboIdx++] = pointArray[pointIdx];
tmpVBO[vboIdx++] = pointArray[pointIdx + 1];
tmpVBO[vboIdx++] = pointArray[pointIdx + 2];
}
buffRequest.nativeArray = tmpVBO;
var buff = device.getBufferManager().getBuffer(buffRequest);
vertexInput.addBuffer(buff, ['vertexBC']);
} // compute offset VBO
var pointData = poly.getPointData();
var scales = null;
if (model.renderable.getScaleArray() != null && pointData.hasArray(model.renderable.getScaleArray())) {
scales = pointData.getArray(model.renderable.getScaleArray()).getData();
}
var defaultRadius = model.renderable.getRadius();
if (scales || defaultRadius !== model._lastRadius) {
buffRequest = {
hash: scales,
source: scales,
time: scales ? pointData.getArray(model.renderable.getScaleArray()).getMTime() : 0,
usage: BufferUsage.RawVertex,
format: 'float32x2'
};
if (!device.getBufferManager().hasBuffer(buffRequest)) {
var _tmpVBO = new Float32Array(3 * numPoints * 2);
var cos30 = Math.cos(radiansFromDegrees(30.0));
var _vboIdx = 0;
for (var _id = 0; _id < numPoints; ++_id) {
var radius = model.renderable.getRadius();
if (scales) {
radius = scales[_id];
}
_tmpVBO[_vboIdx++] = -2.0 * radius * cos30;
_tmpVBO[_vboIdx++] = -radius;
_tmpVBO[_vboIdx++] = 2.0 * radius * cos30;
_tmpVBO[_vboIdx++] = -radius;
_tmpVBO[_vboIdx++] = 0.0;
_tmpVBO[_vboIdx++] = 2.0 * radius;
}
buffRequest.nativeArray = _tmpVBO;
var _buff = device.getBufferManager().getBuffer(buffRequest);
vertexInput.addBuffer(_buff, ['offsetMC']);
}
model._lastRadius = defaultRadius;
}
model.renderable.mapScalars(poly, 1.0); // deal with colors but only if modified
var haveColors = false;
if (model.renderable.getScalarVisibility()) {
var c = model.renderable.getColorMapColors();
if (c) {
buffRequest = {
hash: c,
source: c,
time: c.getMTime(),
usage: BufferUsage.RawVertex,
format: 'unorm8x4'
};
if (!device.getBufferManager().hasBuffer(buffRequest)) {
var colorComponents = c.getNumberOfComponents();
if (colorComponents !== 4) {
vtkErrorMacro('this should be 4');
}
var _tmpVBO2 = new Uint8Array(3 * numPoints * 4);
var _vboIdx2 = 0;
var colorData = c.getData();
for (var _id2 = 0; _id2 < numPoints; ++_id2) {
var colorIdx = _id2 * colorComponents;
for (var v = 0; v < 3; v++) {
_tmpVBO2[_vboIdx2++] = colorData[colorIdx];
_tmpVBO2[_vboIdx2++] = colorData[colorIdx + 1];
_tmpVBO2[_vboIdx2++] = colorData[colorIdx + 2];
_tmpVBO2[_vboIdx2++] = colorData[colorIdx + 3];
}
}
buffRequest.nativeArray = _tmpVBO2;
var _buff2 = device.getBufferManager().getBuffer(buffRequest);
vertexInput.addBuffer(_buff2, ['colorVI']);
}
haveColors = true;
}
}
if (!haveColors) {
vertexInput.removeBufferIfPresent('colorVI');
}
primHelper.setPipelineHash(publicAPI.computePipelineHash(vertexInput));
primHelper.setWebGPURenderer(model.WebGPURenderer);
primHelper.setTopology('triangle-list');
primHelper.build(model.renderEncoder, device);
primHelper.registerToDraw();
};
} // ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
var DEFAULT_VALUES = {}; // ----------------------------------------------------------------------------
function extend(publicAPI, model) {
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance
vtkWebGPUPolyDataMapper.extend(publicAPI, model, initialValues);
model.primitives[PrimitiveTypes.Triangles].setVertexShaderTemplate(vtkWebGPUSphereMapperVS); // Object methods
vtkWebGPUSphereMapper(publicAPI, model);
var sr = model.primitives[PrimitiveTypes.Triangles].getShaderReplacements();
sr.set('replaceShaderPosition', publicAPI.replaceShaderPosition);
sr.set('replaceShaderNormal', publicAPI.replaceShaderNormal);
} // ----------------------------------------------------------------------------
var newInstance = newInstance$1(extend, 'vtkWebGPUSphereMapper'); // ----------------------------------------------------------------------------
var index = {
newInstance: newInstance,
extend: extend
}; // Register ourself to WebGPU backend if imported
registerOverride('vtkSphereMapper', newInstance);
export default index;
export { extend, newInstance };