import macro from 'vtk.js/Sources/macros'; import vtkOpenGLTexture from 'vtk.js/Sources/Rendering/OpenGL/Texture'; import vtkOpenGLFramebuffer from 'vtk.js/Sources/Rendering/OpenGL/Framebuffer'; import vtkRenderPass from 'vtk.js/Sources/Rendering/SceneGraph/RenderPass'; import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray'; import vtkHelper from 'vtk.js/Sources/Rendering/OpenGL/Helper'; import vtkProperty from 'vtk.js/Sources/Rendering/Core/Property'; import vtkShaderProgram from 'vtk.js/Sources/Rendering/OpenGL/ShaderProgram'; import vtkVertexArrayObject from 'vtk.js/Sources/Rendering/OpenGL/VertexArrayObject';
const { Representation } = vtkProperty; const { vtkErrorMacro } = macro;
function translucentShaderReplacement(shaders) { const substituteRes = vtkShaderProgram.substitute( shaders.Fragment, '//VTK::RenderPassFragmentShader::Impl', ` float weight = gl_FragData[0].a * pow(max(1.1 - gl_FragCoord.z, 0.0), 2.0); gl_FragData[0] = vec4(gl_FragData[0].rgb*weight, gl_FragData[0].a); gl_FragData[1].r = weight; `, false ); shaders.Fragment = substituteRes.result; }
const oitpFragTemplate = `//VTK::System::Dec
in vec2 tcoord;
uniform sampler2D translucentRTexture; uniform sampler2D translucentRGBATexture;
// the output of this shader //VTK::Output::Dec
void main() { vec4 t1Color = texture(translucentRGBATexture, tcoord); float t2Color = texture(translucentRTexture, tcoord).r; gl_FragData[0] = vec4(t1Color.rgb/max(t2Color,0.01), 1.0 - t1Color.a); } `;
function vtkOpenGLOrderIndependentTranslucentPass(publicAPI, model) { model.classHierarchy.push('vtkOpenGLOrderIndependentTranslucentPass');
publicAPI.createVertexBuffer = () => { const ptsArray = new Float32Array([ -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, ]);
const tcoordArray = new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]);
const cellArray = new Uint16Array([4, 0, 1, 3, 2]);
const points = vtkDataArray.newInstance({ numberOfComponents: 3, values: ptsArray, }); points.setName('points'); const tcoords = vtkDataArray.newInstance({ numberOfComponents: 2, values: tcoordArray, }); tcoords.setName('tcoords'); const cells = vtkDataArray.newInstance({ numberOfComponents: 1, values: cellArray, }); model.tris.getCABO().createVBO(cells, 'polys', Representation.SURFACE, { points, tcoords, cellOffset: 0, });
model.VBOBuildTime.modified(); };
publicAPI.createFramebuffer = (viewNode) => { const size = viewNode.getSize(); const gl = viewNode.getContext();
model.framebuffer = vtkOpenGLFramebuffer.newInstance(); model.framebuffer.setOpenGLRenderWindow(viewNode); model.framebuffer.create(...size); model.framebuffer.saveCurrentBindingsAndBuffers(); model.framebuffer.bind();
model.translucentRGBATexture = vtkOpenGLTexture.newInstance(); model.translucentRGBATexture.setInternalFormat(gl.RGBA16F); model.translucentRGBATexture.setFormat(gl.RGBA); model.translucentRGBATexture.setOpenGLDataType(gl.HALF_FLOAT); model.translucentRGBATexture.setOpenGLRenderWindow(viewNode); model.translucentRGBATexture.create2DFromRaw( size[0], size[1], 4, 'Float32Array', null );
model.translucentRTexture = vtkOpenGLTexture.newInstance(); model.translucentRTexture.setInternalFormat(gl.R16F); model.translucentRTexture.setFormat(gl.RED); model.translucentRTexture.setOpenGLDataType(gl.HALF_FLOAT); model.translucentRTexture.setOpenGLRenderWindow(viewNode); model.translucentRTexture.create2DFromRaw( size[0], size[1], 1, 'Float32Array', null );
model.translucentZTexture = vtkOpenGLTexture.newInstance(); model.translucentZTexture.setOpenGLRenderWindow(viewNode); model.translucentZTexture.createDepthFromRaw( size[0], size[1], 'Float32Array', null );
model.framebuffer.setColorBuffer(model.translucentRGBATexture, 0); model.framebuffer.setColorBuffer(model.translucentRTexture, 1); model.framebuffer.setDepthBuffer(model.translucentZTexture); };
publicAPI.createCopyShader = (viewNode) => { model.copyShader = viewNode .getShaderCache() .readyShaderProgramArray( [ '//VTK::System::Dec', 'attribute vec4 vertexDC;', 'attribute vec2 tcoordTC;', 'varying vec2 tcoord;', 'void main() { tcoord = tcoordTC; gl_Position = vertexDC; }', ].join('\n'), oitpFragTemplate, '' ); };
publicAPI.createVBO = (viewNode) => { const gl = viewNode.getContext(); model.tris.setOpenGLRenderWindow(viewNode); publicAPI.createVertexBuffer();
const program = model.copyShader;
model.tris.getCABO().bind(); if ( !model.copyVAO.addAttributeArray( program, model.tris.getCABO(), 'vertexDC', model.tris.getCABO().getVertexOffset(), model.tris.getCABO().getStride(), gl.FLOAT, 3, gl.FALSE ) ) { vtkErrorMacro('Error setting vertexDC in copy shader VAO.'); } if ( !model.copyVAO.addAttributeArray( program, model.tris.getCABO(), 'tcoordTC', model.tris.getCABO().getTCoordOffset(), model.tris.getCABO().getStride(), gl.FLOAT, 2, gl.FALSE ) ) { vtkErrorMacro('Error setting vertexDC in copy shader VAO.'); } };
publicAPI.traverse = (viewNode, renNode, forwardPass) => { if (model.deleted) { return; }
const size = viewNode.getSize(); const gl = viewNode.getContext();
model._supported = false; if ( renNode.getSelector() || !gl || !viewNode.getWebgl2() || (!gl.getExtension('EXT_color_buffer_half_float') && !gl.getExtension('EXT_color_buffer_float')) ) { publicAPI.setCurrentOperation('translucentPass'); renNode.traverse(publicAPI); return; }
model._supported = true;
if (model.framebuffer === null) { publicAPI.createFramebuffer(viewNode); } else { const fbSize = model.framebuffer.getSize(); if (fbSize === null || fbSize[0] !== size[0] || fbSize[1] !== size[1]) { model.framebuffer.releaseGraphicsResources(); model.translucentRGBATexture.releaseGraphicsResources(viewNode); model.translucentRTexture.releaseGraphicsResources(viewNode); model.translucentZTexture.releaseGraphicsResources(viewNode); publicAPI.createFramebuffer(viewNode); } else { model.framebuffer.saveCurrentBindingsAndBuffers(); model.framebuffer.bind(); } }
gl.drawBuffers([gl.COLOR_ATTACHMENT0]); gl.clearBufferfv(gl.COLOR, 0, [0.0, 0.0, 0.0, 0.0]); gl.clearBufferfv(gl.DEPTH, 0, [1.0]);
gl.colorMask(false, false, false, false);
if (forwardPass.getOpaqueActorCount() > 0) { forwardPass.setCurrentOperation('opaqueZBufferPass'); renNode.traverse(forwardPass); }
gl.colorMask(true, true, true, true); gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]);
gl.viewport(0, 0, size[0], size[1]); gl.scissor(0, 0, size[0], size[1]);
gl.clearBufferfv(gl.COLOR, 0, [0.0, 0.0, 0.0, 1.0]); gl.clearBufferfv(gl.COLOR, 1, [0.0, 0.0, 0.0, 0.0]);
gl.enable(gl.DEPTH_TEST); gl.enable(gl.BLEND);
gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ZERO, gl.ONE_MINUS_SRC_ALPHA);
publicAPI.setCurrentOperation('translucentPass'); renNode.traverse(publicAPI);
gl.drawBuffers([gl.NONE]); model.framebuffer.restorePreviousBindingsAndBuffers();
if (model.copyShader === null) { publicAPI.createCopyShader(viewNode); } else { viewNode.getShaderCache().readyShaderProgram(model.copyShader); }
if (!model.copyVAO) { model.copyVAO = vtkVertexArrayObject.newInstance(); model.copyVAO.setOpenGLRenderWindow(viewNode); } model.copyVAO.bind();
if (model.VBOBuildTime.getMTime() < publicAPI.getMTime()) { publicAPI.createVBO(viewNode); }
gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); gl.depthMask(false); gl.depthFunc(gl.ALWAYS);
gl.viewport(0, 0, size[0], size[1]); gl.scissor(0, 0, size[0], size[1]);
model.translucentRGBATexture.activate(); model.copyShader.setUniformi( 'translucentRGBATexture', model.translucentRGBATexture.getTextureUnit() ); model.translucentRTexture.activate(); model.copyShader.setUniformi( 'translucentRTexture', model.translucentRTexture.getTextureUnit() );
gl.drawArrays(gl.TRIANGLES, 0, model.tris.getCABO().getElementCount());
gl.depthMask(true); gl.depthFunc(gl.LEQUAL); model.translucentRGBATexture.deactivate(); model.translucentRTexture.deactivate();
const ts = renNode.getTiledSizeAndOrigin(); gl.scissor(ts.lowerLeftU, ts.lowerLeftV, ts.usize, ts.vsize); gl.viewport(ts.lowerLeftU, ts.lowerLeftV, ts.usize, ts.vsize); };
publicAPI.getShaderReplacement = () => { if (model._supported) { return translucentShaderReplacement; } return null; };
publicAPI.releaseGraphicsResources = (viewNode) => { if (model.framebuffer) { model.framebuffer.releaseGraphicsResources(viewNode); model.framebuffer = null; } if (model.translucentRGBATexture) { model.translucentRGBATexture.releaseGraphicsResources(viewNode); model.translucentRGBATexture = null; } if (model.translucentRTexture) { model.translucentRTexture.releaseGraphicsResources(viewNode); model.translucentRTexture = null; } if (model.translucentZTexture) { model.translucentZTexture.releaseGraphicsResources(viewNode); model.translucentZTexture = null; } if (model.copyVAO) { model.copyVAO.releaseGraphicsResources(viewNode); model.copyVAO = null; } if (model.copyShader) { model.copyShader.releaseGraphicsResources(viewNode); model.copyShader = null; } if (model.tris) { model.tris.releaseGraphicsResources(viewNode); model.tris = null; } publicAPI.modified(); }; }
const DEFAULT_VALUES = { framebuffer: null, copyShader: null, tris: null, };
export function extend(publicAPI, model, initialValues = {}) { Object.assign(model, DEFAULT_VALUES, initialValues);
vtkRenderPass.extend(publicAPI, model, initialValues);
model.VBOBuildTime = {}; macro.obj(model.VBOBuildTime, { mtime: 0 });
model.tris = vtkHelper.newInstance();
macro.get(publicAPI, model, ['framebuffer']);
vtkOpenGLOrderIndependentTranslucentPass(publicAPI, model); }
export const newInstance = macro.newInstance( extend, 'vtkOpenGLOrderIndependentTranslucentPass' );
export default { newInstance, extend };
|