UNPKG

@thewtex/vtk.js-esm

Version:

Visualization Toolkit for the Web

406 lines (335 loc) 17.3 kB
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray'; import _slicedToArray from '@babel/runtime/helpers/slicedToArray'; import macro from '../../../macro.js'; import { v as vtkLineIntegralConvolution2D_LIC0 } from './glsl/vtkLineIntegralConvolution2D_LIC0.glsl.js'; import { v as vtkLineIntegralConvolution2D_LICI } from './glsl/vtkLineIntegralConvolution2D_LICI.glsl.js'; import { v as vtkLineIntegralConvolution2D_LICN } from './glsl/vtkLineIntegralConvolution2D_LICN.glsl.js'; import { v as vtkLineIntegralConvolution2D_CE } from './glsl/vtkLineIntegralConvolution2D_CE.glsl.js'; import { v as vtkLineIntegralConvolution2D_EE } from './glsl/vtkLineIntegralConvolution2D_EE.glsl.js'; import { v as vtkLineIntegralConvolution2D_AAH } from './glsl/vtkLineIntegralConvolution2D_AAH.glsl.js'; import { v as vtkLineIntegralConvolution2D_VT } from './glsl/vtkLineIntegralConvolution2D_VT.glsl.js'; import { v as vtkLineIntegralConvolution2D_AAV } from './glsl/vtkLineIntegralConvolution2D_AAV.glsl.js'; import { v as vtkLineIntegralConvolution2D_quadVS } from './glsl/vtkLineIntegralConvolution2D_quadVS.glsl.js'; import vtkShaderProgram from '../ShaderProgram.js'; import vtkOpenGLFramebuffer from '../Framebuffer.js'; import vtkLICPingPongBufferManager from './LineIntegralConvolution2D/pingpong.js'; import { ContrastEnhanceMode } from '../../Core/SurfaceLICInterface/Constants.js'; function getVectorLookupProgram() { var normalize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; // lookup the vector and normalize var getNormVecSrc = "\n vec2 getVector( vec2 vectc )\n\n {\n\n vec2 V = texture2D( texVectors, vectc ).xy;\n\n // normalize if |V| not 0\n\n float lenV = length( V );\n\n if ( lenV > 1.0e-8 )\n\n {\n\n return V/lenV;\n\n }\n\n else\n\n {\n\n return vec2( 0.0, 0.0 );\n\n }\n\n }\n\n "; // lookup the vector var getVecSrc = "\n vec2 getVector( vec2 vectc )\n\n {\n\n return texture2D( texVectors, vectc ).xy;\n\n }\n\n "; if (normalize) { return getNormVecSrc; } return getVecSrc; } function vtkLineIntegralConvolution2D(publicAPI, model) { model.classHierarchy.push('vtkLineIntegralConvolution2D'); publicAPI.buildAShader = function (fSource) { return model.openGLRenderWindow.getShaderCache().readyShaderProgramArray(vtkLineIntegralConvolution2D_quadVS, fSource, ''); }; publicAPI.dumpTextureValues = function (texture, _ref) { var _ref2 = _slicedToArray(_ref, 2), width = _ref2[0], height = _ref2[1]; var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : model.context; var openGLRenderWindow = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : model.openGLRenderWindow; var nComp = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 4; // To get texture values in es 2.0, we need to attach the texture to a fbo, // then use glReadPixels var fb = vtkOpenGLFramebuffer.newInstance(); var gl = context; var pixels = null; fb.setOpenGLRenderWindow(openGLRenderWindow); fb.saveCurrentBindingsAndBuffers(); fb.create(width, height); fb.populateFramebuffer(); fb.setColorBuffer(texture); pixels = new Float32Array(width * height * nComp); gl.readPixels(0, 0, width, height, nComp === 4 ? gl.RGBA : gl.RGB, gl.FLOAT, pixels); fb.restorePreviousBindingsAndBuffers(); return pixels; }; publicAPI.getTextureMinMax = function (texture, size) { var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : model.context; var openGLRenderWindow = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : model.openGLRenderWindow; var values = publicAPI.dumpTextureValues(texture, size, context, openGLRenderWindow, 4); var min = Number.MAX_VALUE; var max = Number.MIN_VALUE; for (var i = 0; i < values.length; i += 4) { // Make sure the current pixel is inside the rendered geometry (g === 0) if (values[i + 1] === 0.0) { var val = values[i]; if (val < min) { min = val; } if (val > max) { max = val; } } } return { min: min, max: max }; }; publicAPI.getComponentSelectionProgram = function (ids) { var compNames = 'xyzw'; return ".".concat(compNames[ids[0]]).concat(compNames[ids[1]]); }; publicAPI.buildShaders = function () { model.LIC0ShaderProgram = publicAPI.buildAShader(vtkLineIntegralConvolution2D_LIC0); var VTFSource = vtkShaderProgram.substitute(vtkLineIntegralConvolution2D_VT, '//VTK::LICComponentSelection::Impl', "vec2 V = texture2D(texVectors, tcoordVC.st)".concat(publicAPI.getComponentSelectionProgram(model.componentIds), ";")).result; model.VTProgram = publicAPI.buildAShader(VTFSource); var LICISource = vtkShaderProgram.substitute(vtkLineIntegralConvolution2D_LICI, '//VTK::LICVectorLookup::Impl', getVectorLookupProgram(model.normalizeVectors), true).result; model.LICIShaderProgram = publicAPI.buildAShader(LICISource); model.LICNShaderProgram = publicAPI.buildAShader(vtkLineIntegralConvolution2D_LICN); model.CEProgram = publicAPI.buildAShader(vtkLineIntegralConvolution2D_CE); model.EEProgram = publicAPI.buildAShader(vtkLineIntegralConvolution2D_EE); model.AAHProgram = publicAPI.buildAShader(vtkLineIntegralConvolution2D_AAH); model.AAVProgram = publicAPI.buildAShader(vtkLineIntegralConvolution2D_AAV); }; // factorized out frequent patterns function setLICUniforms(program, bufs) { program.setUniformi('texLIC', bufs.getLICTextureUnit()); program.setUniformi('texSeedPts', bufs.getSeedTextureUnit()); } function renderPingPong(bufs, size, program) { bufs.attachLICBuffers(); bufs.renderQuad(size, program); bufs.detachLICBuffers(); bufs.swap(); } publicAPI.executeLIC = function (size, vectorTexture, maskVectorTexture, noiseTexture, openGLRenderWindow, options) { model.openGLRenderWindow = openGLRenderWindow; model.context = openGLRenderWindow.getContext(); Object.assign(model, options); if (size[0] <= 0.0 || size[1] <= 0.0) { return null; } var tcScale = [1.0 / size[0], 1.0 / size[1]]; var stepSize = model.stepSize * Math.sqrt(tcScale[0] * tcScale[0] + tcScale[1] * tcScale[1]); if (stepSize <= 0) { stepSize = 1.0e-10; } var gl = model.context; var fb = model.framebuffer; if (!fb || size[0] !== fb.getSize()[0] || size[1] !== fb.getSize()[1]) { var _fb; fb = vtkOpenGLFramebuffer.newInstance(); fb.setOpenGLRenderWindow(model.openGLRenderWindow); fb.saveCurrentBindingsAndBuffers(); (_fb = fb).create.apply(_fb, _toConsumableArray(size)); fb.populateFramebuffer(); fb.restorePreviousBindingsAndBuffers(); model.framebuffer = fb; } fb.saveCurrentBindingsAndBuffers(); fb.bind(); gl.viewport.apply(gl, [0, 0].concat(_toConsumableArray(size))); gl.scissor.apply(gl, [0, 0].concat(_toConsumableArray(size))); if (model.shadersNeedBuild) { publicAPI.buildShaders(); model.shadersNeedBuild = false; } if (!model.bufs) { model.bufs = vtkLICPingPongBufferManager.newInstance({ openGLRenderWindow: openGLRenderWindow, doEEPass: model.enhancedLIC, doVTPass: model.transformVectors, vectorTexture: vectorTexture, maskVectorTexture: maskVectorTexture, noiseTexture: noiseTexture, framebuffer: fb, size: size }); } else { model.bufs.setVectorTexture(vectorTexture); model.bufs.setMaskVectorTexture(maskVectorTexture); model.bufs.setNoiseTexture(noiseTexture); } var noiseBoundsPt1 = [(noiseTexture.getWidth() + 1) / size[0], (noiseTexture.getHeight() + 1) / size[1]]; var dx = 1.0 / size[0]; var dy = 1.0 / size[1]; var shaderCache = model.openGLRenderWindow.getShaderCache(); if (model.transformVectors) { var VTShaderProgram = model.VTProgram; shaderCache.readyShaderProgram(VTShaderProgram); model.bufs.attachImageVectorBuffer(); VTShaderProgram.setUniform2f.apply(VTShaderProgram, ['uTexSize'].concat(_toConsumableArray(size))); VTShaderProgram.setUniformi('texVectors', model.bufs.getVectorTextureUnit()); gl.clearColor(0.0, 0.0, 0.0, 0.0); gl.clear(gl.COLOR_BUFFER_BIT); model.bufs.renderQuad(size, VTShaderProgram); model.bufs.detachImageVectorBuffer(); } // first pass // initialize convolution and seeds model.bufs.clearBuffers(model.enhancedLIC); model.bufs.activateVectorTextures(); model.bufs.activateNoiseTexture(0); var LIC0ShaderProgram = model.LIC0ShaderProgram; shaderCache.readyShaderProgram(LIC0ShaderProgram); LIC0ShaderProgram.setUniformi('uStepNo', 0); LIC0ShaderProgram.setUniformi('uPassNo', 0); LIC0ShaderProgram.setUniformf('uMaskThreshold', model.maskThreshold); LIC0ShaderProgram.setUniform2f.apply(LIC0ShaderProgram, ['uNoiseBoundsPt1'].concat(noiseBoundsPt1)); LIC0ShaderProgram.setUniformi('texMaskVectors', model.bufs.getMaskVectorTextureUnit()); LIC0ShaderProgram.setUniformi('texLIC', model.bufs.getLICTextureUnit()); LIC0ShaderProgram.setUniformi('texNoise', model.bufs.getNoiseTextureUnit(0)); renderPingPong(model.bufs, size, LIC0ShaderProgram); // backward lic var LICIShaderProgram = model.LICIShaderProgram; shaderCache.readyShaderProgram(LICIShaderProgram); LICIShaderProgram.setUniformi('uPassNo', 0); LICIShaderProgram.setUniformf('uStepSize', -stepSize); LICIShaderProgram.setUniform2f.apply(LICIShaderProgram, ['uNoiseBoundsPt1'].concat(noiseBoundsPt1)); LICIShaderProgram.setUniformi('texVectors', model.bufs.getImageVectorTextureUnit()); LICIShaderProgram.setUniformi('texNoise', model.bufs.getNoiseTextureUnit(0)); for (var stepIdx = 0; stepIdx < model.numberOfSteps; ++stepIdx) { setLICUniforms(LICIShaderProgram, model.bufs); renderPingPong(model.bufs, size, LICIShaderProgram); } // initialize seeds shaderCache.readyShaderProgram(LIC0ShaderProgram); LIC0ShaderProgram.setUniformi('uStepNo', 1); setLICUniforms(LIC0ShaderProgram, model.bufs); renderPingPong(model.bufs, size, LIC0ShaderProgram); // forward LIC shaderCache.readyShaderProgram(LICIShaderProgram); LICIShaderProgram.setUniformf('uStepSize', stepSize); for (var _stepIdx = 0; _stepIdx < model.numberOfSteps; ++_stepIdx) { setLICUniforms(LICIShaderProgram, model.bufs); renderPingPong(model.bufs, size, LICIShaderProgram); } model.bufs.deactivateNoiseTexture(0); model.bufs.deactivateVectorTextures(); // finalize LIC var LICNShaderProgram = model.LICNShaderProgram; shaderCache.readyShaderProgram(LICNShaderProgram); LICNShaderProgram.setUniformi('texLIC', model.bufs.getLICTextureUnit()); renderPingPong(model.bufs, size, LICNShaderProgram); // end of first-pass lic if (model.enhancedLIC) { if (model.enhanceContrast === ContrastEnhanceMode.LIC || model.enhanceContrast === ContrastEnhanceMode.BOTH) { publicAPI.contrastEnhance(false, size); } // EE stage model.bufs.attachEEBuffer(); var EEProgram = model.EEProgram; shaderCache.readyShaderProgram(EEProgram); EEProgram.setUniformi('texLIC', model.bufs.getLICTextureUnit()); EEProgram.setUniformf('uDx', dx); EEProgram.setUniformf('uDy', dy); model.bufs.renderQuad(size, EEProgram); model.bufs.detachEEBuffer(); // begin second pass LIC // clear buffers model.bufs.detachBuffers(); model.bufs.clearBuffers(false); model.bufs.activateVectorTextures(); model.bufs.activateNoiseTexture(1); // initialize convolution and seeds shaderCache.readyShaderProgram(LIC0ShaderProgram); LIC0ShaderProgram.setUniformi('uStepNo', 0); LIC0ShaderProgram.setUniformi('uPassNo', 1); setLICUniforms(LIC0ShaderProgram, model.bufs); LIC0ShaderProgram.setUniformi('texNoise', model.bufs.getNoiseTextureUnit(1)); renderPingPong(model.bufs, size, LIC0ShaderProgram); // backward LIC shaderCache.readyShaderProgram(LICIShaderProgram); LICIShaderProgram.setUniformi('uPassNo', 1); LICIShaderProgram.setUniformf('uStepSize', -stepSize); LICIShaderProgram.setUniformi('texNoise', model.bufs.getNoiseTextureUnit(1)); var nSteps = model.numberOfSteps / 2; for (var _stepIdx2 = 0; _stepIdx2 < nSteps; ++_stepIdx2) { setLICUniforms(LICIShaderProgram, model.bufs); renderPingPong(model.bufs, size, LICIShaderProgram); } // initialize seeds shaderCache.readyShaderProgram(LIC0ShaderProgram); LIC0ShaderProgram.setUniformi('uStepNo', 1); setLICUniforms(LIC0ShaderProgram, model.bufs); renderPingPong(model.bufs, size, LIC0ShaderProgram); // forward LIC shaderCache.readyShaderProgram(LICIShaderProgram); LICIShaderProgram.setUniformf('uStepSize', stepSize); for (var _stepIdx3 = 0; _stepIdx3 < nSteps; ++_stepIdx3) { setLICUniforms(LICIShaderProgram, model.bufs); renderPingPong(model.bufs, size, LICIShaderProgram); } model.bufs.deactivateNoiseTexture(1); model.bufs.deactivateVectorTextures(); // finalize LIC shaderCache.readyShaderProgram(LICNShaderProgram); LICNShaderProgram.setUniformi('texLIC', model.bufs.getLICTextureUnit()); LICNShaderProgram.setUniformi('texSeedPts', model.bufs.getSeedTextureUnit()); renderPingPong(model.bufs, size, LICNShaderProgram); } if (model.antiAlias) { var AAHShaderProgram = model.AAHProgram; shaderCache.readyShaderProgram(AAHShaderProgram); AAHShaderProgram.setUniformi('texLIC', model.bufs.getLICTextureUnit()); AAHShaderProgram.setUniformf('uDx', dx); var AAVShaderProgram = model.AAVProgram; shaderCache.readyShaderProgram(AAVShaderProgram); AAVShaderProgram.setUniformi('texLIC', model.bufs.getLICTextureUnit()); AAVShaderProgram.setUniformf('uDy', dy); for (var i = 0; i < model.antiAlias; ++i) { // Vertical pass shaderCache.readyShaderProgram(AAHShaderProgram); setLICUniforms(AAHShaderProgram, model.bufs); renderPingPong(model.bufs, size, AAHShaderProgram); // Horizontal pass shaderCache.readyShaderProgram(AAVShaderProgram); setLICUniforms(AAVShaderProgram, model.bufs); renderPingPong(model.bufs, size, AAVShaderProgram); } } if (model.enhanceContrast === ContrastEnhanceMode.LIC || model.enhanceContrast === ContrastEnhanceMode.BOTH) { publicAPI.contrastEnhance(true, size); } model.bufs.detachBuffers(); fb.restorePreviousBindingsAndBuffers(); return model.bufs.getLastLICBuffer(); }; publicAPI.contrastEnhance = function (isSecondStage, size) { var shaderCache = model.openGLRenderWindow.getShaderCache(); var _publicAPI$getTexture = publicAPI.getTextureMinMax(model.bufs.getLastLICBuffer(), size, model.context, model.openGLRenderWindow), min = _publicAPI$getTexture.min, max = _publicAPI$getTexture.max; if (max <= min || max > 1.0 || min < 0) { console.error('Invalid color range: ', min, max); min = 0.0; max = 1.0; } var diff = max - min; if (isSecondStage) { min += diff * model.lowLICContrastEnhancementFactor; max -= diff * model.highLICContrastEnhancementFactor; diff = max - min; } var CEProgram = model.CEProgram; shaderCache.readyShaderProgram(CEProgram); CEProgram.setUniformi('texLIC', model.bufs.getLICTextureUnit()); CEProgram.setUniformf('uMin', min); CEProgram.setUniformf('uMaxMinDiff', diff); renderPingPong(model.bufs, size, CEProgram); }; } var DEFAULT_VALUES = { shadersNeedBuild: true, stepSize: 1, numberOfSteps: 10, enhancedLIC: true, enhanceContrast: false, lowContrastEnhancementFactor: 0, highContrastEnhancementFactor: 0, antiAlias: 0, componentIds: [0, 1], normalizeVectors: true, maskThreshold: 0.0, transformVectors: true, bufs: null, isComposite: true }; function extend(publicAPI, model) { var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; Object.assign(model, DEFAULT_VALUES, initialValues); macro.obj(publicAPI, model); macro.setGet(publicAPI, model, ['context', 'openGLRenderWindow', 'nuberOfSteps', 'stepSize', 'normalizeVectors', 'maskThreshold', 'enhancedLIC', 'enhanceContrast', 'lowLICContrastEnhancementFactor', 'highLICContrastEnhancementFactor', 'antiAlias', 'componentIds', 'isComposite']); // Object methods vtkLineIntegralConvolution2D(publicAPI, model); } // ---------------------------------------------------------------------------- var newInstance = macro.newInstance(extend, 'vtkLineIntegralConvolution2D'); var vtkLineIntegralConvolution2D$1 = { newInstance: newInstance, extend: extend }; export default vtkLineIntegralConvolution2D$1; export { extend, newInstance };