UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

291 lines (227 loc) 11.9 kB
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray'; import macro from '../../macros.js'; import vtkViewNode from '../SceneGraph/ViewNode.js'; import vtkWebGPUBindGroup from './BindGroup.js'; import vtkWebGPUPipeline from './Pipeline.js'; import vtkWebGPUShaderCache from './ShaderCache.js'; import vtkWebGPUShaderDescription from './ShaderDescription.js'; import vtkWebGPUVertexInput from './VertexInput.js'; var vtkWebGPUSimpleMapperVS = "\n//VTK::Renderer::Dec\n\n//VTK::Color::Dec\n\n//VTK::Normal::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::Select::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::IOStructs::Dec\n\n@vertex\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : vertexOutput;\n\n // var vertex: vec4<f32> = vertexBC;\n\n //VTK::Color::Impl\n\n //VTK::Normal::Impl\n\n //VTK::TCoord::Impl\n\n //VTK::Select::Impl\n\n //VTK::Position::Impl\n\n return output;\n}\n"; var vtkWebGPUSimpleMapperFS = "\n//VTK::Renderer::Dec\n\n//VTK::Color::Dec\n\n//VTK::Normal::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::Select::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::IOStructs::Dec\n\n@fragment\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : fragmentOutput;\n\n //VTK::Color::Impl\n\n //VTK::Normal::Impl\n\n //VTK::Light::Impl\n\n //VTK::TCoord::Impl\n\n //VTK::Select::Impl\n\n // var computedColor:vec4<f32> = vec4<f32>(1.0,0.5,0.5,1.0);\n\n //VTK::RenderEncoder::Impl\n return output;\n}\n"; // ---------------------------------------------------------------------------- // vtkWebGPUSimpleMapper methods // ---------------------------------------------------------------------------- function vtkWebGPUSimpleMapper(publicAPI, model) { // Set our className model.classHierarchy.push('vtkWebGPUSimpleMapper'); publicAPI.generateShaderDescriptions = function (hash, pipeline, vertexInput) { // create the shader descriptions var vDesc = vtkWebGPUShaderDescription.newInstance({ type: 'vertex', hash: hash, code: model.vertexShaderTemplate }); var fDesc = vtkWebGPUShaderDescription.newInstance({ type: 'fragment', hash: hash, code: model.fragmentShaderTemplate }); // add them to the pipeline var sdrs = pipeline.getShaderDescriptions(); sdrs.push(vDesc); sdrs.push(fDesc); // look for replacements to invoke var scode = model.vertexShaderTemplate + model.fragmentShaderTemplate; // eslint-disable-next-line prefer-regex-literals var re = new RegExp('//VTK::[^:]*::', 'g'); var unique = scode.match(re).filter(function (v, i, a) { return a.indexOf(v) === i; }); var fnames = unique.map(function (v) { return "replaceShader".concat(v.substring(7, v.length - 2)); }); // now invoke shader replacement functions for (var i = 0; i < fnames.length; i++) { var fname = fnames[i]; if (fname !== 'replaceShaderIOStructs' && model.shaderReplacements.has(fname)) { model.shaderReplacements.get(fname)(hash, pipeline, vertexInput); } } // always replace the IOStructs last as other replacement funcs may // add inputs or outputs publicAPI.replaceShaderIOStructs(hash, pipeline, vertexInput); // console.log(vDesc.getCode()); // console.log(fDesc.getCode()); }; publicAPI.replaceShaderIOStructs = function (hash, pipeline, vertexInput) { var vDesc = pipeline.getShaderDescription('vertex'); vDesc.replaceShaderCode(null, vertexInput); var fDesc = pipeline.getShaderDescription('fragment'); fDesc.replaceShaderCode(vDesc); }; publicAPI.replaceShaderRenderEncoder = function (hash, pipeline, vertexInput) { model.renderEncoder.replaceShaderCode(pipeline); }; model.shaderReplacements.set('replaceShaderRenderEncoder', publicAPI.replaceShaderRenderEncoder); publicAPI.replaceShaderRenderer = function (hash, pipeline, vertexInput) { if (!model.WebGPURenderer) { return; } var ubocode = model.WebGPURenderer.getBindGroup().getShaderCode(pipeline); var vDesc = pipeline.getShaderDescription('vertex'); var code = vDesc.getCode(); code = vtkWebGPUShaderCache.substitute(code, '//VTK::Renderer::Dec', [ubocode]).result; vDesc.setCode(code); var fDesc = pipeline.getShaderDescription('fragment'); code = fDesc.getCode(); code = vtkWebGPUShaderCache.substitute(code, '//VTK::Renderer::Dec', [ubocode]).result; fDesc.setCode(code); }; model.shaderReplacements.set('replaceShaderRenderer', publicAPI.replaceShaderRenderer); publicAPI.replaceShaderMapper = function (hash, pipeline, vertexInput) { var ubocode = model.bindGroup.getShaderCode(pipeline); var vDesc = pipeline.getShaderDescription('vertex'); var code = vDesc.getCode(); code = vtkWebGPUShaderCache.substitute(code, '//VTK::Mapper::Dec', [ubocode]).result; vDesc.setCode(code); var fDesc = pipeline.getShaderDescription('fragment'); fDesc.addBuiltinInput('bool', '@builtin(front_facing) frontFacing'); code = fDesc.getCode(); code = vtkWebGPUShaderCache.substitute(code, '//VTK::Mapper::Dec', [ubocode]).result; fDesc.setCode(code); }; model.shaderReplacements.set('replaceShaderMapper', publicAPI.replaceShaderMapper); 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.SCPCMatrix*vertexBC;']).result; vDesc.setCode(code); }; model.shaderReplacements.set('replaceShaderPosition', publicAPI.replaceShaderPosition); publicAPI.replaceShaderTCoord = function (hash, pipeline, vertexInput) { var vDesc = pipeline.getShaderDescription('vertex'); vDesc.addOutput('vec2<f32>', 'tcoordVS'); }; model.shaderReplacements.set('replaceShaderTCoord', publicAPI.replaceShaderTCoord); publicAPI.addTextureView = function (view) { // is it already there? if (model.textureViews.includes(view)) { return; } model.textureViews.push(view); }; // do everything required for this mapper to be rerady to draw // but do not bind or do the actual draw commands as the pipeline // is not neccessarily bound yet publicAPI.prepareToDraw = function (renderEncoder) { model.renderEncoder = renderEncoder; // do anything needed to get our input data up to date publicAPI.updateInput(); // make sure buffers are created and up to date publicAPI.updateBuffers(); // update bindings and bind groups/layouts // does not acutally bind them, that is done in draw(...) publicAPI.updateBindings(); // update the pipeline, includes computing the hash, and if needed // creating the pipeline, shader code etc publicAPI.updatePipeline(); }; publicAPI.updateInput = function () {}; publicAPI.updateBuffers = function () {}; publicAPI.updateBindings = function () { // bindings can change without a pipeline change // as long as their layout remains the same. // That is why this is done even when the pipeline // hash doesn't change. model.bindGroup.setBindables(publicAPI.getBindables()); }; publicAPI.computePipelineHash = function () {}; publicAPI.registerDrawCallback = function (encoder) { encoder.registerDrawCallback(model.pipeline, publicAPI.draw); }; publicAPI.prepareAndDraw = function (encoder) { publicAPI.prepareToDraw(encoder); encoder.setPipeline(model.pipeline); publicAPI.draw(encoder); }; // do the rest of the calls required to draw this mapper // at this point the command encouder and pipeline are // created and bound publicAPI.draw = function (renderEncoder) { var pipeline = renderEncoder.getBoundPipeline(); // bind the mapper bind group renderEncoder.activateBindGroup(model.bindGroup); if (model.WebGPURenderer) { model.WebGPURenderer.bindUBO(renderEncoder); } // bind the vertex input pipeline.bindVertexInput(renderEncoder, model.vertexInput); var indexBuffer = model.vertexInput.getIndexBuffer(); if (indexBuffer) { renderEncoder.drawIndexed(indexBuffer.getIndexCount(), model.numberOfInstances, 0, 0, 0); } else { renderEncoder.draw(model.numberOfVertices, model.numberOfInstances, 0, 0); } }; publicAPI.getBindables = function () { var bindables = _toConsumableArray(model.additionalBindables); if (model.UBO) { bindables.push(model.UBO); } if (model.SSBO) { bindables.push(model.SSBO); } // add texture BindGroupLayouts for (var t = 0; t < model.textureViews.length; t++) { bindables.push(model.textureViews[t]); var samp = model.textureViews[t].getSampler(); if (samp) { bindables.push(samp); } } return bindables; }; publicAPI.updatePipeline = function () { publicAPI.computePipelineHash(); model.pipeline = model.device.getPipeline(model.pipelineHash); // build the pipeline if needed if (!model.pipeline) { model.pipeline = vtkWebGPUPipeline.newInstance(); model.pipeline.setDevice(model.device); if (model.WebGPURenderer) { model.pipeline.addBindGroupLayout(model.WebGPURenderer.getBindGroup()); } model.pipeline.addBindGroupLayout(model.bindGroup); publicAPI.generateShaderDescriptions(model.pipelineHash, model.pipeline, model.vertexInput); model.pipeline.setTopology(model.topology); model.pipeline.setRenderEncoder(model.renderEncoder); model.pipeline.setVertexState(model.vertexInput.getVertexInputInformation()); model.device.createPipeline(model.pipelineHash, model.pipeline); } }; } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- var DEFAULT_VALUES = { additionalBindables: undefined, bindGroup: null, device: null, fragmentShaderTemplate: null, numberOfInstances: 1, numberOfVertices: 0, pipelineHash: null, shaderReplacements: null, SSBO: null, textureViews: null, topology: 'triangle-list', UBO: null, vertexShaderTemplate: null, WebGPURenderer: null }; // ---------------------------------------------------------------------------- function extend(publicAPI, model) { var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance vtkViewNode.extend(publicAPI, model, initialValues); model.textureViews = []; model.vertexInput = vtkWebGPUVertexInput.newInstance(); model.bindGroup = vtkWebGPUBindGroup.newInstance({ label: 'mapperBG' }); model.additionalBindables = []; model.fragmentShaderTemplate = model.fragmentShaderTemplate || vtkWebGPUSimpleMapperFS; model.vertexShaderTemplate = model.vertexShaderTemplate || vtkWebGPUSimpleMapperVS; model.shaderReplacements = new Map(); // Build VTK API macro.get(publicAPI, model, ['pipeline', 'vertexInput']); macro.setGet(publicAPI, model, ['additionalBindables', 'device', 'fragmentShaderTemplate', 'interpolate', 'numberOfInstances', 'numberOfVertices', 'pipelineHash', 'shaderReplacements', 'SSBO', 'textureViews', 'topology', 'UBO', 'vertexShaderTemplate', 'WebGPURenderer']); // Object methods vtkWebGPUSimpleMapper(publicAPI, model); } // ---------------------------------------------------------------------------- var newInstance = macro.newInstance(extend, 'vtkWebGPUSimpleMapper'); // ---------------------------------------------------------------------------- var vtkWebGPUSimpleMapper$1 = { newInstance: newInstance, extend: extend }; export { vtkWebGPUSimpleMapper$1 as default, extend, newInstance };