{"version":3,"file":"GPUComputationRenderer.cjs","sources":["../../src/misc/GPUComputationRenderer.js"],"sourcesContent":["import {\n  Camera,\n  ClampToEdgeWrapping,\n  DataTexture,\n  FloatType,\n  Mesh,\n  NearestFilter,\n  NoToneMapping,\n  PlaneGeometry,\n  RGBAFormat,\n  Scene,\n  ShaderMaterial,\n  WebGLRenderTarget,\n} from 'three'\n\n/**\n * GPUComputationRenderer, based on SimulationRenderer by zz85\n *\n * The GPUComputationRenderer uses the concept of variables. These variables are RGBA float textures that hold 4 floats\n * for each compute element (texel)\n *\n * Each variable has a fragment shader that defines the computation made to obtain the variable in question.\n * You can use as many variables you need, and make dependencies so you can use textures of other variables in the shader\n * (the sampler uniforms are added automatically) Most of the variables will need themselves as dependency.\n *\n * The renderer has actually two render targets per variable, to make ping-pong. Textures from the current frame are used\n * as inputs to render the textures of the next frame.\n *\n * The render targets of the variables can be used as input textures for your visualization shaders.\n *\n * Variable names should be valid identifiers and should not collide with THREE GLSL used identifiers.\n * a common approach could be to use 'texture' prefixing the variable name; i.e texturePosition, textureVelocity...\n *\n * The size of the computation (sizeX * sizeY) is defined as 'resolution' automatically in the shader. For example:\n * #DEFINE resolution vec2( 1024.0, 1024.0 )\n *\n * -------------\n *\n * Basic use:\n *\n * // Initialization...\n *\n * // Create computation renderer\n * const gpuCompute = new GPUComputationRenderer( 1024, 1024, renderer );\n *\n * // Create initial state float textures\n * const pos0 = gpuCompute.createTexture();\n * const vel0 = gpuCompute.createTexture();\n * // and fill in here the texture data...\n *\n * // Add texture variables\n * const velVar = gpuCompute.addVariable( \"textureVelocity\", fragmentShaderVel, pos0 );\n * const posVar = gpuCompute.addVariable( \"texturePosition\", fragmentShaderPos, vel0 );\n *\n * // Add variable dependencies\n * gpuCompute.setVariableDependencies( velVar, [ velVar, posVar ] );\n * gpuCompute.setVariableDependencies( posVar, [ velVar, posVar ] );\n *\n * // Add custom uniforms\n * velVar.material.uniforms.time = { value: 0.0 };\n *\n * // Check for completeness\n * const error = gpuCompute.init();\n * if ( error !== null ) {\n *\t\tconsole.error( error );\n * }\n *\n *\n * // In each frame...\n *\n * // Compute!\n * gpuCompute.compute();\n *\n * // Update texture uniforms in your visualization materials with the gpu renderer output\n * myMaterial.uniforms.myTexture.value = gpuCompute.getCurrentRenderTarget( posVar ).texture;\n *\n * // Do your rendering\n * renderer.render( myScene, myCamera );\n *\n * -------------\n *\n * Also, you can use utility functions to create ShaderMaterial and perform computations (rendering between textures)\n * Note that the shaders can have multiple input textures.\n *\n * const myFilter1 = gpuCompute.createShaderMaterial( myFilterFragmentShader1, { theTexture: { value: null } } );\n * const myFilter2 = gpuCompute.createShaderMaterial( myFilterFragmentShader2, { theTexture: { value: null } } );\n *\n * const inputTexture = gpuCompute.createTexture();\n *\n * // Fill in here inputTexture...\n *\n * myFilter1.uniforms.theTexture.value = inputTexture;\n *\n * const myRenderTarget = gpuCompute.createRenderTarget();\n * myFilter2.uniforms.theTexture.value = myRenderTarget.texture;\n *\n * const outputRenderTarget = gpuCompute.createRenderTarget();\n *\n * // Now use the output texture where you want:\n * myMaterial.uniforms.map.value = outputRenderTarget.texture;\n *\n * // And compute each frame, before rendering to screen:\n * gpuCompute.doRenderTarget( myFilter1, myRenderTarget );\n * gpuCompute.doRenderTarget( myFilter2, outputRenderTarget );\n *\n *\n *\n * @param {int} sizeX Computation problem size is always 2d: sizeX * sizeY elements.\n * @param {int} sizeY Computation problem size is always 2d: sizeX * sizeY elements.\n * @param {WebGLRenderer} renderer The renderer\n */\n\nclass GPUComputationRenderer {\n  constructor(sizeX, sizeY, renderer) {\n    this.variables = []\n\n    this.currentTextureIndex = 0\n\n    let dataType = FloatType\n\n    const scene = new Scene()\n\n    const camera = new Camera()\n    camera.position.z = 1\n\n    const passThruUniforms = {\n      passThruTexture: { value: null },\n    }\n\n    const passThruShader = createShaderMaterial(getPassThroughFragmentShader(), passThruUniforms)\n\n    const mesh = new Mesh(new PlaneGeometry(2, 2), passThruShader)\n    scene.add(mesh)\n\n    this.setDataType = function (type) {\n      dataType = type\n      return this\n    }\n\n    this.addVariable = function (variableName, computeFragmentShader, initialValueTexture) {\n      const material = this.createShaderMaterial(computeFragmentShader)\n\n      const variable = {\n        name: variableName,\n        initialValueTexture: initialValueTexture,\n        material: material,\n        dependencies: null,\n        renderTargets: [],\n        wrapS: null,\n        wrapT: null,\n        minFilter: NearestFilter,\n        magFilter: NearestFilter,\n      }\n\n      this.variables.push(variable)\n\n      return variable\n    }\n\n    this.setVariableDependencies = function (variable, dependencies) {\n      variable.dependencies = dependencies\n    }\n\n    this.init = function () {\n      if (renderer.capabilities.isWebGL2 === false && renderer.extensions.has('OES_texture_float') === false) {\n        return 'No OES_texture_float support for float textures.'\n      }\n\n      if (renderer.capabilities.maxVertexTextures === 0) {\n        return 'No support for vertex shader textures.'\n      }\n\n      for (let i = 0; i < this.variables.length; i++) {\n        const variable = this.variables[i]\n\n        // Creates rendertargets and initialize them with input texture\n        variable.renderTargets[0] = this.createRenderTarget(\n          sizeX,\n          sizeY,\n          variable.wrapS,\n          variable.wrapT,\n          variable.minFilter,\n          variable.magFilter,\n        )\n        variable.renderTargets[1] = this.createRenderTarget(\n          sizeX,\n          sizeY,\n          variable.wrapS,\n          variable.wrapT,\n          variable.minFilter,\n          variable.magFilter,\n        )\n        this.renderTexture(variable.initialValueTexture, variable.renderTargets[0])\n        this.renderTexture(variable.initialValueTexture, variable.renderTargets[1])\n\n        // Adds dependencies uniforms to the ShaderMaterial\n        const material = variable.material\n        const uniforms = material.uniforms\n\n        if (variable.dependencies !== null) {\n          for (let d = 0; d < variable.dependencies.length; d++) {\n            const depVar = variable.dependencies[d]\n\n            if (depVar.name !== variable.name) {\n              // Checks if variable exists\n              let found = false\n\n              for (let j = 0; j < this.variables.length; j++) {\n                if (depVar.name === this.variables[j].name) {\n                  found = true\n                  break\n                }\n              }\n\n              if (!found) {\n                return 'Variable dependency not found. Variable=' + variable.name + ', dependency=' + depVar.name\n              }\n            }\n\n            uniforms[depVar.name] = { value: null }\n\n            material.fragmentShader = '\\nuniform sampler2D ' + depVar.name + ';\\n' + material.fragmentShader\n          }\n        }\n      }\n\n      this.currentTextureIndex = 0\n\n      return null\n    }\n\n    this.compute = function () {\n      const currentTextureIndex = this.currentTextureIndex\n      const nextTextureIndex = this.currentTextureIndex === 0 ? 1 : 0\n\n      for (let i = 0, il = this.variables.length; i < il; i++) {\n        const variable = this.variables[i]\n\n        // Sets texture dependencies uniforms\n        if (variable.dependencies !== null) {\n          const uniforms = variable.material.uniforms\n\n          for (let d = 0, dl = variable.dependencies.length; d < dl; d++) {\n            const depVar = variable.dependencies[d]\n\n            uniforms[depVar.name].value = depVar.renderTargets[currentTextureIndex].texture\n          }\n        }\n\n        // Performs the computation for this variable\n        this.doRenderTarget(variable.material, variable.renderTargets[nextTextureIndex])\n      }\n\n      this.currentTextureIndex = nextTextureIndex\n    }\n\n    this.getCurrentRenderTarget = function (variable) {\n      return variable.renderTargets[this.currentTextureIndex]\n    }\n\n    this.getAlternateRenderTarget = function (variable) {\n      return variable.renderTargets[this.currentTextureIndex === 0 ? 1 : 0]\n    }\n\n    this.dispose = function () {\n      mesh.geometry.dispose()\n      mesh.material.dispose()\n\n      const variables = this.variables\n\n      for (let i = 0; i < variables.length; i++) {\n        const variable = variables[i]\n\n        if (variable.initialValueTexture) variable.initialValueTexture.dispose()\n\n        const renderTargets = variable.renderTargets\n\n        for (let j = 0; j < renderTargets.length; j++) {\n          const renderTarget = renderTargets[j]\n          renderTarget.dispose()\n        }\n      }\n    }\n\n    function addResolutionDefine(materialShader) {\n      materialShader.defines.resolution = 'vec2( ' + sizeX.toFixed(1) + ', ' + sizeY.toFixed(1) + ' )'\n    }\n\n    this.addResolutionDefine = addResolutionDefine\n\n    // The following functions can be used to compute things manually\n\n    function createShaderMaterial(computeFragmentShader, uniforms) {\n      uniforms = uniforms || {}\n\n      const material = new ShaderMaterial({\n        uniforms: uniforms,\n        vertexShader: getPassThroughVertexShader(),\n        fragmentShader: computeFragmentShader,\n      })\n\n      addResolutionDefine(material)\n\n      return material\n    }\n\n    this.createShaderMaterial = createShaderMaterial\n\n    this.createRenderTarget = function (sizeXTexture, sizeYTexture, wrapS, wrapT, minFilter, magFilter) {\n      sizeXTexture = sizeXTexture || sizeX\n      sizeYTexture = sizeYTexture || sizeY\n\n      wrapS = wrapS || ClampToEdgeWrapping\n      wrapT = wrapT || ClampToEdgeWrapping\n\n      minFilter = minFilter || NearestFilter\n      magFilter = magFilter || NearestFilter\n\n      const renderTarget = new WebGLRenderTarget(sizeXTexture, sizeYTexture, {\n        wrapS: wrapS,\n        wrapT: wrapT,\n        minFilter: minFilter,\n        magFilter: magFilter,\n        format: RGBAFormat,\n        type: dataType,\n        depthBuffer: false,\n      })\n\n      return renderTarget\n    }\n\n    this.createTexture = function () {\n      const data = new Float32Array(sizeX * sizeY * 4)\n      const texture = new DataTexture(data, sizeX, sizeY, RGBAFormat, FloatType)\n      texture.needsUpdate = true\n      return texture\n    }\n\n    this.renderTexture = function (input, output) {\n      // Takes a texture, and render out in rendertarget\n      // input = Texture\n      // output = RenderTarget\n\n      passThruUniforms.passThruTexture.value = input\n\n      this.doRenderTarget(passThruShader, output)\n\n      passThruUniforms.passThruTexture.value = null\n    }\n\n    this.doRenderTarget = function (material, output) {\n      const currentRenderTarget = renderer.getRenderTarget()\n\n      const currentXrEnabled = renderer.xr.enabled\n      const currentShadowAutoUpdate = renderer.shadowMap.autoUpdate\n      const currentOutputColorSpace = renderer.outputColorSpace\n      const currentToneMapping = renderer.toneMapping\n\n      renderer.xr.enabled = false // Avoid camera modification\n      renderer.shadowMap.autoUpdate = false // Avoid re-computing shadows\n      if ('outputColorSpace' in renderer) renderer.outputColorSpace = 'srgb-linear'\n      else renderer.encoding = 3000 // LinearEncoding\n      renderer.toneMapping = NoToneMapping\n\n      mesh.material = material\n      renderer.setRenderTarget(output)\n      renderer.render(scene, camera)\n      mesh.material = passThruShader\n\n      renderer.xr.enabled = currentXrEnabled\n      renderer.shadowMap.autoUpdate = currentShadowAutoUpdate\n      renderer.outputColorSpace = currentOutputColorSpace\n      renderer.toneMapping = currentToneMapping\n\n      renderer.setRenderTarget(currentRenderTarget)\n    }\n\n    // Shaders\n\n    function getPassThroughVertexShader() {\n      return 'void main()\t{\\n' + '\\n' + '\tgl_Position = vec4( position, 1.0 );\\n' + '\\n' + '}\\n'\n    }\n\n    function getPassThroughFragmentShader() {\n      return (\n        'uniform sampler2D passThruTexture;\\n' +\n        '\\n' +\n        'void main() {\\n' +\n        '\\n' +\n        '\tvec2 uv = gl_FragCoord.xy / resolution.xy;\\n' +\n        '\\n' +\n        '\tgl_FragColor = texture2D( passThruTexture, uv );\\n' +\n        '\\n' +\n        '}\\n'\n      )\n    }\n  }\n}\n\nexport { GPUComputationRenderer }\n"],"names":["FloatType","Scene","Camera","Mesh","PlaneGeometry","NearestFilter","ShaderMaterial","ClampToEdgeWrapping","WebGLRenderTarget","RGBAFormat","DataTexture","NoToneMapping"],"mappings":"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"}