diff --git a/build/three.cjs b/build/three.cjs index 59dccfea241256..f7d7094d4838c8 100644 --- a/build/three.cjs +++ b/build/three.cjs @@ -5,7 +5,7 @@ */ 'use strict'; -const REVISION = '168'; +const REVISION = '169'; const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; @@ -1594,6 +1594,38 @@ function probeAsync( gl, sync, interval ) { } +function toNormalizedProjectionMatrix( projectionMatrix ) { + + const m = projectionMatrix.elements; + + // Convert [-1, 1] to [0, 1] projection matrix + m[ 2 ] = 0.5 * m[ 2 ] + 0.5 * m[ 3 ]; + m[ 6 ] = 0.5 * m[ 6 ] + 0.5 * m[ 7 ]; + m[ 10 ] = 0.5 * m[ 10 ] + 0.5 * m[ 11 ]; + m[ 14 ] = 0.5 * m[ 14 ] + 0.5 * m[ 15 ]; + +} + +function toReversedProjectionMatrix( projectionMatrix ) { + + const m = projectionMatrix.elements; + const isPerspectiveMatrix = m[ 11 ] === - 1; + + // Reverse [0, 1] projection matrix + if ( isPerspectiveMatrix ) { + + m[ 10 ] = - m[ 10 ] - 1; + m[ 14 ] = - m[ 14 ]; + + } else { + + m[ 10 ] = - m[ 10 ]; + m[ 14 ] = - m[ 14 ] + 1; + + } + +} + /** * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping * or clipping. Based on W3C specifications for sRGB and Display P3, @@ -8189,6 +8221,10 @@ const _vap = /*@__PURE__*/ new Vector3(); const _vbp = /*@__PURE__*/ new Vector3(); const _vcp = /*@__PURE__*/ new Vector3(); +const _v40 = /*@__PURE__*/ new Vector4(); +const _v41 = /*@__PURE__*/ new Vector4(); +const _v42 = /*@__PURE__*/ new Vector4(); + class Triangle { constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { @@ -8283,6 +8319,25 @@ class Triangle { } + static getInterpolatedAttribute( attr, i1, i2, i3, barycoord, target ) { + + _v40.setScalar( 0 ); + _v41.setScalar( 0 ); + _v42.setScalar( 0 ); + + _v40.fromBufferAttribute( attr, i1 ); + _v41.fromBufferAttribute( attr, i2 ); + _v42.fromBufferAttribute( attr, i3 ); + + target.setScalar( 0 ); + target.addScaledVector( _v40, barycoord.x ); + target.addScaledVector( _v41, barycoord.y ); + target.addScaledVector( _v42, barycoord.z ); + + return target; + + } + static isFrontFacing( a, b, c, direction ) { _v0$2.subVectors( c, b ); @@ -9898,7 +9953,6 @@ class BufferAttribute { this.normalized = normalized; this.usage = StaticDrawUsage; - this._updateRange = { offset: 0, count: - 1 }; this.updateRanges = []; this.gpuType = FloatType; @@ -9914,13 +9968,6 @@ class BufferAttribute { } - get updateRange() { - - warnOnce( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 - return this._updateRange; - - } - setUsage( value ) { this.usage = value; @@ -11565,14 +11612,6 @@ const _vC$1 = /*@__PURE__*/ new Vector3(); const _tempA = /*@__PURE__*/ new Vector3(); const _morphA = /*@__PURE__*/ new Vector3(); -const _uvA$1 = /*@__PURE__*/ new Vector2(); -const _uvB$1 = /*@__PURE__*/ new Vector2(); -const _uvC$1 = /*@__PURE__*/ new Vector2(); - -const _normalA = /*@__PURE__*/ new Vector3(); -const _normalB = /*@__PURE__*/ new Vector3(); -const _normalC = /*@__PURE__*/ new Vector3(); - const _intersectionPoint = /*@__PURE__*/ new Vector3(); const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); @@ -11915,33 +11954,24 @@ function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, n if ( intersection ) { - if ( uv ) { + const barycoord = new Vector3(); + Triangle.getBarycoord( _intersectionPoint, _vA$1, _vB$1, _vC$1, barycoord ); - _uvA$1.fromBufferAttribute( uv, a ); - _uvB$1.fromBufferAttribute( uv, b ); - _uvC$1.fromBufferAttribute( uv, c ); + if ( uv ) { - intersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + intersection.uv = Triangle.getInterpolatedAttribute( uv, a, b, c, barycoord, new Vector2() ); } if ( uv1 ) { - _uvA$1.fromBufferAttribute( uv1, a ); - _uvB$1.fromBufferAttribute( uv1, b ); - _uvC$1.fromBufferAttribute( uv1, c ); - - intersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + intersection.uv1 = Triangle.getInterpolatedAttribute( uv1, a, b, c, barycoord, new Vector2() ); } if ( normal ) { - _normalA.fromBufferAttribute( normal, a ); - _normalB.fromBufferAttribute( normal, b ); - _normalC.fromBufferAttribute( normal, c ); - - intersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() ); + intersection.normal = Triangle.getInterpolatedAttribute( normal, a, b, c, barycoord, new Vector3() ); if ( intersection.normal.dot( ray.direction ) > 0 ) { @@ -11962,6 +11992,7 @@ function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, n Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal ); intersection.face = face; + intersection.barycoord = barycoord; } @@ -13605,40 +13636,71 @@ function WebGLAttributes( gl ) { function updateBuffer( buffer, attribute, bufferType ) { const array = attribute.array; - const updateRange = attribute._updateRange; // @deprecated, r159 const updateRanges = attribute.updateRanges; gl.bindBuffer( bufferType, buffer ); - if ( updateRange.count === - 1 && updateRanges.length === 0 ) { + if ( updateRanges.length === 0 ) { // Not using update ranges gl.bufferSubData( bufferType, 0, array ); - } + } else { - if ( updateRanges.length !== 0 ) { + // Before applying update ranges, we merge any adjacent / overlapping + // ranges to reduce load on `gl.bufferSubData`. Empirically, this has led + // to performance improvements for applications which make heavy use of + // update ranges. Likely due to GPU command overhead. + // + // Note that to reduce garbage collection between frames, we merge the + // update ranges in-place. This is safe because this method will clear the + // update ranges once updated. - for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { + updateRanges.sort( ( a, b ) => a.start - b.start ); + // To merge the update ranges in-place, we work from left to right in the + // existing updateRanges array, merging ranges. This may result in a final + // array which is smaller than the original. This index tracks the last + // index representing a merged range, any data after this index can be + // trimmed once the merge algorithm is completed. + let mergeIndex = 0; + + for ( let i = 1; i < updateRanges.length; i ++ ) { + + const previousRange = updateRanges[ mergeIndex ]; const range = updateRanges[ i ]; - gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, - array, range.start, range.count ); + // We add one here to merge adjacent ranges. This is safe because ranges + // operate over positive integers. + if ( range.start <= previousRange.start + previousRange.count + 1 ) { + + previousRange.count = Math.max( + previousRange.count, + range.start + range.count - previousRange.start + ); + + } else { + + ++ mergeIndex; + updateRanges[ mergeIndex ] = range; + + } } - attribute.clearUpdateRanges(); + // Trim the array to only contain the merged ranges. + updateRanges.length = mergeIndex + 1; - } + for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { - // @deprecated, r159 - if ( updateRange.count !== - 1 ) { + const range = updateRanges[ i ]; - gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, - array, updateRange.offset, updateRange.count ); + gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, + array, range.start, range.count ); + + } - updateRange.count = - 1; // reset range + attribute.clearUpdateRanges(); } @@ -14099,7 +14161,7 @@ const vertex$2 = "#include \n#include \n#include < const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}"; -const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"; +const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix[ 3 ];\n\tvec2 scale = vec2( length( modelMatrix[ 0 ].xyz ), length( modelMatrix[ 1 ].xyz ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"; const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; @@ -15865,6 +15927,14 @@ function WebGLCapabilities( gl, extensions, parameters, utils ) { } const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; + const reverseDepthBuffer = parameters.reverseDepthBuffer === true && extensions.has( 'EXT_clip_control' ); + + if ( reverseDepthBuffer === true ) { + + const ext = extensions.get( 'EXT_clip_control' ); + ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT ); + + } const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); @@ -15892,6 +15962,7 @@ function WebGLCapabilities( gl, extensions, parameters, utils ) { precision: precision, logarithmicDepthBuffer: logarithmicDepthBuffer, + reverseDepthBuffer: reverseDepthBuffer, maxTextures: maxTextures, maxVertexTextures: maxVertexTextures, @@ -19909,6 +19980,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) { parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + parameters.reverseDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '', 'uniform mat4 modelMatrix;', 'uniform mat4 modelViewMatrix;', @@ -20074,6 +20146,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) { parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + parameters.reverseDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '', 'uniform mat4 viewMatrix;', 'uniform vec3 cameraPosition;', @@ -20466,6 +20539,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities const programs = []; const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; + const reverseDepthBuffer = capabilities.reverseDepthBuffer; const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures; let precision = capabilities.precision; @@ -20757,6 +20831,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities sizeAttenuation: material.sizeAttenuation === true, logarithmicDepthBuffer: logarithmicDepthBuffer, + reverseDepthBuffer: reverseDepthBuffer, skinning: object.isSkinnedMesh === true, @@ -20976,38 +21051,40 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities _programLayers.enable( 2 ); if ( parameters.logarithmicDepthBuffer ) _programLayers.enable( 3 ); - if ( parameters.skinning ) + if ( parameters.reverseDepthBuffer ) _programLayers.enable( 4 ); - if ( parameters.morphTargets ) + if ( parameters.skinning ) _programLayers.enable( 5 ); - if ( parameters.morphNormals ) + if ( parameters.morphTargets ) _programLayers.enable( 6 ); - if ( parameters.morphColors ) + if ( parameters.morphNormals ) _programLayers.enable( 7 ); - if ( parameters.premultipliedAlpha ) + if ( parameters.morphColors ) _programLayers.enable( 8 ); - if ( parameters.shadowMapEnabled ) + if ( parameters.premultipliedAlpha ) _programLayers.enable( 9 ); - if ( parameters.doubleSided ) + if ( parameters.shadowMapEnabled ) _programLayers.enable( 10 ); - if ( parameters.flipSided ) + if ( parameters.doubleSided ) _programLayers.enable( 11 ); - if ( parameters.useDepthPacking ) + if ( parameters.flipSided ) _programLayers.enable( 12 ); - if ( parameters.dithering ) + if ( parameters.useDepthPacking ) _programLayers.enable( 13 ); - if ( parameters.transmission ) + if ( parameters.dithering ) _programLayers.enable( 14 ); - if ( parameters.sheen ) + if ( parameters.transmission ) _programLayers.enable( 15 ); - if ( parameters.opaque ) + if ( parameters.sheen ) _programLayers.enable( 16 ); - if ( parameters.pointsUvs ) + if ( parameters.opaque ) _programLayers.enable( 17 ); - if ( parameters.decodeVideoTexture ) + if ( parameters.pointsUvs ) _programLayers.enable( 18 ); - if ( parameters.alphaToCoverage ) + if ( parameters.decodeVideoTexture ) _programLayers.enable( 19 ); + if ( parameters.alphaToCoverage ) + _programLayers.enable( 20 ); array.push( _programLayers.mask ); @@ -22565,6 +22642,18 @@ function WebGLShadowMap( renderer, objects, capabilities ) { } +const reversedFuncs = { + [ NeverDepth ]: AlwaysDepth, + [ LessDepth ]: GreaterDepth, + [ EqualDepth ]: NotEqualDepth, + [ LessEqualDepth ]: GreaterEqualDepth, + + [ AlwaysDepth ]: NeverDepth, + [ GreaterDepth ]: LessDepth, + [ NotEqualDepth ]: EqualDepth, + [ GreaterEqualDepth ]: LessEqualDepth, +}; + function WebGLState( gl ) { function ColorBuffer() { @@ -22629,6 +22718,7 @@ function WebGLState( gl ) { function DepthBuffer() { let locked = false; + let reversed = false; let currentDepthMask = null; let currentDepthFunc = null; @@ -22636,6 +22726,12 @@ function WebGLState( gl ) { return { + setReversed: function ( value ) { + + reversed = value; + + }, + setTest: function ( depthTest ) { if ( depthTest ) { @@ -22663,6 +22759,8 @@ function WebGLState( gl ) { setFunc: function ( depthFunc ) { + if ( reversed ) depthFunc = reversedFuncs[ depthFunc ]; + if ( currentDepthFunc !== depthFunc ) { switch ( depthFunc ) { @@ -24204,6 +24302,28 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, } + if ( glFormat === _gl.RGB_INTEGER ) { + + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGB8UI; + if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGB16UI; + if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGB32UI; + if ( glType === _gl.BYTE ) internalFormat = _gl.RGB8I; + if ( glType === _gl.SHORT ) internalFormat = _gl.RGB16I; + if ( glType === _gl.INT ) internalFormat = _gl.RGB32I; + + } + + if ( glFormat === _gl.RGBA_INTEGER ) { + + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGBA8UI; + if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGBA16UI; + if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGBA32UI; + if ( glType === _gl.BYTE ) internalFormat = _gl.RGBA8I; + if ( glType === _gl.SHORT ) internalFormat = _gl.RGBA16I; + if ( glType === _gl.INT ) internalFormat = _gl.RGBA32I; + + } + if ( glFormat === _gl.RGB ) { if ( glType === _gl.UNSIGNED_INT_5_9_9_9_REV ) internalFormat = _gl.RGB9_E5; @@ -28797,6 +28917,7 @@ class WebGLRenderer { // camera matrices cache + const _currentProjectionMatrix = new Matrix4(); const _projScreenMatrix = new Matrix4(); const _vector3 = new Vector3(); @@ -28892,6 +29013,8 @@ class WebGLRenderer { state = new WebGLState( _gl ); + if ( capabilities.reverseDepthBuffer ) state.buffers.depth.setReversed( true ); + info = new WebGLInfo( _gl ); properties = new WebGLProperties(); textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); @@ -29191,7 +29314,13 @@ class WebGLRenderer { } - if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT; + if ( depth ) { + + bits |= _gl.DEPTH_BUFFER_BIT; + _gl.clearDepth( this.capabilities.reverseDepthBuffer ? 0 : 1 ); + + } + if ( stencil ) { bits |= _gl.STENCIL_BUFFER_BIT; @@ -29580,6 +29709,12 @@ class WebGLRenderer { scene.traverse( function ( object ) { + if ( ! ( object.isMesh || object.isPoints || object.isLine || object.isSprite ) ) { + + return; + + } + const material = object.material; if ( material ) { @@ -30566,7 +30701,21 @@ class WebGLRenderer { // common camera uniforms - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + if ( capabilities.reverseDepthBuffer ) { + + _currentProjectionMatrix.copy( camera.projectionMatrix ); + + toNormalizedProjectionMatrix( _currentProjectionMatrix ); + toReversedProjectionMatrix( _currentProjectionMatrix ); + + p_uniforms.setValue( _gl, 'projectionMatrix', _currentProjectionMatrix ); + + } else { + + p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + + } + p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); const uCamPos = p_uniforms.map.cameraPosition; @@ -31047,61 +31196,55 @@ class WebGLRenderer { if ( framebuffer ) { - state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - try { - - const texture = renderTarget.texture; - const textureFormat = texture.format; - const textureType = texture.type; - - if ( ! capabilities.textureFormatReadable( textureFormat ) ) { - - throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' ); + const texture = renderTarget.texture; + const textureFormat = texture.format; + const textureType = texture.type; - } + if ( ! capabilities.textureFormatReadable( textureFormat ) ) { - if ( ! capabilities.textureTypeReadable( textureType ) ) { + throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' ); - throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' ); + } - } + if ( ! capabilities.textureTypeReadable( textureType ) ) { - // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) - if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { + throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' ); - const glBuffer = _gl.createBuffer(); - _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer ); - _gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ ); - _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 ); - _gl.flush(); + } - // check if the commands have finished every 8 ms - const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 ); - await probeAsync( _gl, sync, 4 ); + // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) + if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { - try { + // set the active frame buffer to the one we want to read + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer ); - _gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer ); + const glBuffer = _gl.createBuffer(); + _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer ); + _gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ ); + _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 ); - } finally { + // reset the frame buffer to the currently set buffer before waiting + const currFramebuffer = _currentRenderTarget !== null ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; + state.bindFramebuffer( _gl.FRAMEBUFFER, currFramebuffer ); - _gl.deleteBuffer( glBuffer ); - _gl.deleteSync( sync ); + // check if the commands have finished every 8 ms + const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 ); - } + _gl.flush(); - return buffer; + await probeAsync( _gl, sync, 4 ); - } + // read the data and delete the buffer + _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer ); + _gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer ); + _gl.deleteBuffer( glBuffer ); + _gl.deleteSync( sync ); - } finally { + return buffer; - // restore framebuffer of current render target if necessary + } else { - const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; - state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.' ); } @@ -31587,7 +31730,6 @@ class InterleavedBuffer { this.count = array !== undefined ? array.length / stride : 0; this.usage = StaticDrawUsage; - this._updateRange = { offset: 0, count: - 1 }; this.updateRanges = []; this.version = 0; @@ -31604,13 +31746,6 @@ class InterleavedBuffer { } - get updateRange() { - - warnOnce( 'THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 - return this._updateRange; - - } - setUsage( value ) { this.usage = value; @@ -32375,6 +32510,27 @@ class LOD extends Object3D { } + removeLevel( distance ) { + + const levels = this.levels; + + for ( let i = 0; i < levels.length; i ++ ) { + + if ( levels[ i ].distance === distance ) { + + const removedElements = levels.splice( i, 1 ); + this.remove( removedElements[ 0 ].object ); + + return true; + + } + + } + + return false; + + } + getCurrentLevel() { return this._currentLevel; @@ -33494,6 +33650,9 @@ class BatchedMesh extends Mesh { // stores visible, active, and geometry id per object this._drawInfo = []; + // instance ids that have been set as inactive, and are available to be overwritten + this._availableInstanceIds = []; + // geometry information this._drawRanges = []; this._reservedRanges = []; @@ -33693,23 +33852,36 @@ class BatchedMesh extends Mesh { addInstance( geometryId ) { + const atCapacity = this._drawInfo.length >= this.maxInstanceCount; + // ensure we're not over geometry - if ( this._drawInfo.length >= this._maxInstanceCount ) { + if ( atCapacity && this._availableInstanceIds.length === 0 ) { throw new Error( 'BatchedMesh: Maximum item count reached.' ); } - this._drawInfo.push( { - + const instanceDrawInfo = { visible: true, active: true, geometryIndex: geometryId, + }; - } ); + let drawId = null; + + // Prioritize using previously freed instance ids + if ( this._availableInstanceIds.length > 0 ) { + + drawId = this._availableInstanceIds.pop(); + this._drawInfo[ drawId ] = instanceDrawInfo; + + } else { + + drawId = this._drawInfo.length; + this._drawInfo.push( instanceDrawInfo ); + + } - // initialize the matrix - const drawId = this._drawInfo.length - 1; const matricesTexture = this._matricesTexture; const matricesArray = matricesTexture.image.data; _identityMatrix.toArray( matricesArray, drawId * 16 ); @@ -33958,11 +34130,8 @@ class BatchedMesh extends Mesh { } */ - /* deleteInstance( instanceId ) { - // Note: User needs to call optimize() afterward to pack the data. - const drawInfo = this._drawInfo; if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { @@ -33971,12 +34140,12 @@ class BatchedMesh extends Mesh { } drawInfo[ instanceId ].active = false; + this._availableInstanceIds.push( instanceId ); this._visibilityChanged = true; return this; } - */ // get bounding box and compute it if it doesn't exist getBoundingBoxAt( geometryId, target ) { @@ -34181,6 +34350,59 @@ class BatchedMesh extends Mesh { } + setGeometryIdAt( instanceId, geometryId ) { + + // return early if the geometry is out of range or not active + const drawInfo = this._drawInfo; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return null; + + } + + // check if the provided geometryId is within the valid range + if ( geometryId < 0 || geometryId >= this._geometryCount ) { + + return null; + + } + + drawInfo[ instanceId ].geometryIndex = geometryId; + + return this; + + } + + getGeometryIdAt( instanceId ) { + + const drawInfo = this._drawInfo; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return - 1; + + } + + return drawInfo[ instanceId ].geometryIndex; + + } + + getGeometryRangeAt( geometryId, target = {} ) { + + if ( geometryId < 0 || geometryId >= this._geometryCount ) { + + return null; + + } + + const drawRange = this._drawRanges[ geometryId ]; + + target.start = drawRange.start; + target.count = drawRange.count; + + return target; + + } + raycast( raycaster, intersects ) { const drawInfo = this._drawInfo; @@ -34732,6 +34954,7 @@ function checkIntersection( object, raycaster, ray, thresholdSq, a, b ) { index: a, face: null, faceIndex: null, + barycoord: null, object: object }; @@ -34997,6 +35220,8 @@ function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, inte point: intersectPoint, index: index, face: null, + faceIndex: null, + barycoord: null, object: object } ); @@ -37499,12 +37724,19 @@ class CylinderGeometry extends BufferGeometry { // faces - indices.push( a, b, d ); - indices.push( b, c, d ); + if ( radiusTop > 0 ) { - // update group counter + indices.push( a, b, d ); + groupCount += 3; - groupCount += 6; + } + + if ( radiusBottom > 0 ) { + + indices.push( b, c, d ); + groupCount += 3; + + } } @@ -45814,7 +46046,7 @@ class MaterialLoader extends Loader { } - const material = MaterialLoader.createMaterialFromType( json.type ); + const material = this.createMaterialFromType( json.type ); if ( json.uuid !== undefined ) material.uuid = json.uuid; if ( json.name !== undefined ) material.name = json.name; @@ -46070,6 +46302,12 @@ class MaterialLoader extends Loader { } + createMaterialFromType( type ) { + + return MaterialLoader.createMaterialFromType( type ); + + } + static createMaterialFromType( type ) { const materialLib = { @@ -47900,7 +48138,7 @@ class Clock { function now() { - return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 + return performance.now(); } @@ -48192,7 +48430,7 @@ class Audio extends Object3D { } - stop() { + stop( delay = 0 ) { if ( this.hasPlaybackControl === false ) { @@ -48205,7 +48443,7 @@ class Audio extends Object3D { if ( this.source !== null ) { - this.source.stop(); + this.source.stop( this.context.currentTime + delay ); this.source.onended = null; } @@ -53847,7 +54085,7 @@ class ShapePath { class Controls extends EventDispatcher { - constructor( object, domElement ) { + constructor( object, domElement = null ) { super(); diff --git a/build/three.module.js b/build/three.module.js index 99b665f0966a5c..f0f4a90230d0fd 100644 --- a/build/three.module.js +++ b/build/three.module.js @@ -3,7 +3,7 @@ * Copyright 2010-2024 Three.js Authors * SPDX-License-Identifier: MIT */ -const REVISION = '168'; +const REVISION = '169'; const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; @@ -1592,6 +1592,38 @@ function probeAsync( gl, sync, interval ) { } +function toNormalizedProjectionMatrix( projectionMatrix ) { + + const m = projectionMatrix.elements; + + // Convert [-1, 1] to [0, 1] projection matrix + m[ 2 ] = 0.5 * m[ 2 ] + 0.5 * m[ 3 ]; + m[ 6 ] = 0.5 * m[ 6 ] + 0.5 * m[ 7 ]; + m[ 10 ] = 0.5 * m[ 10 ] + 0.5 * m[ 11 ]; + m[ 14 ] = 0.5 * m[ 14 ] + 0.5 * m[ 15 ]; + +} + +function toReversedProjectionMatrix( projectionMatrix ) { + + const m = projectionMatrix.elements; + const isPerspectiveMatrix = m[ 11 ] === - 1; + + // Reverse [0, 1] projection matrix + if ( isPerspectiveMatrix ) { + + m[ 10 ] = - m[ 10 ] - 1; + m[ 14 ] = - m[ 14 ]; + + } else { + + m[ 10 ] = - m[ 10 ]; + m[ 14 ] = - m[ 14 ] + 1; + + } + +} + /** * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping * or clipping. Based on W3C specifications for sRGB and Display P3, @@ -8187,6 +8219,10 @@ const _vap = /*@__PURE__*/ new Vector3(); const _vbp = /*@__PURE__*/ new Vector3(); const _vcp = /*@__PURE__*/ new Vector3(); +const _v40 = /*@__PURE__*/ new Vector4(); +const _v41 = /*@__PURE__*/ new Vector4(); +const _v42 = /*@__PURE__*/ new Vector4(); + class Triangle { constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { @@ -8281,6 +8317,25 @@ class Triangle { } + static getInterpolatedAttribute( attr, i1, i2, i3, barycoord, target ) { + + _v40.setScalar( 0 ); + _v41.setScalar( 0 ); + _v42.setScalar( 0 ); + + _v40.fromBufferAttribute( attr, i1 ); + _v41.fromBufferAttribute( attr, i2 ); + _v42.fromBufferAttribute( attr, i3 ); + + target.setScalar( 0 ); + target.addScaledVector( _v40, barycoord.x ); + target.addScaledVector( _v41, barycoord.y ); + target.addScaledVector( _v42, barycoord.z ); + + return target; + + } + static isFrontFacing( a, b, c, direction ) { _v0$2.subVectors( c, b ); @@ -9896,7 +9951,6 @@ class BufferAttribute { this.normalized = normalized; this.usage = StaticDrawUsage; - this._updateRange = { offset: 0, count: - 1 }; this.updateRanges = []; this.gpuType = FloatType; @@ -9912,13 +9966,6 @@ class BufferAttribute { } - get updateRange() { - - warnOnce( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 - return this._updateRange; - - } - setUsage( value ) { this.usage = value; @@ -11563,14 +11610,6 @@ const _vC$1 = /*@__PURE__*/ new Vector3(); const _tempA = /*@__PURE__*/ new Vector3(); const _morphA = /*@__PURE__*/ new Vector3(); -const _uvA$1 = /*@__PURE__*/ new Vector2(); -const _uvB$1 = /*@__PURE__*/ new Vector2(); -const _uvC$1 = /*@__PURE__*/ new Vector2(); - -const _normalA = /*@__PURE__*/ new Vector3(); -const _normalB = /*@__PURE__*/ new Vector3(); -const _normalC = /*@__PURE__*/ new Vector3(); - const _intersectionPoint = /*@__PURE__*/ new Vector3(); const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); @@ -11913,33 +11952,24 @@ function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, n if ( intersection ) { - if ( uv ) { + const barycoord = new Vector3(); + Triangle.getBarycoord( _intersectionPoint, _vA$1, _vB$1, _vC$1, barycoord ); - _uvA$1.fromBufferAttribute( uv, a ); - _uvB$1.fromBufferAttribute( uv, b ); - _uvC$1.fromBufferAttribute( uv, c ); + if ( uv ) { - intersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + intersection.uv = Triangle.getInterpolatedAttribute( uv, a, b, c, barycoord, new Vector2() ); } if ( uv1 ) { - _uvA$1.fromBufferAttribute( uv1, a ); - _uvB$1.fromBufferAttribute( uv1, b ); - _uvC$1.fromBufferAttribute( uv1, c ); - - intersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + intersection.uv1 = Triangle.getInterpolatedAttribute( uv1, a, b, c, barycoord, new Vector2() ); } if ( normal ) { - _normalA.fromBufferAttribute( normal, a ); - _normalB.fromBufferAttribute( normal, b ); - _normalC.fromBufferAttribute( normal, c ); - - intersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() ); + intersection.normal = Triangle.getInterpolatedAttribute( normal, a, b, c, barycoord, new Vector3() ); if ( intersection.normal.dot( ray.direction ) > 0 ) { @@ -11960,6 +11990,7 @@ function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, n Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal ); intersection.face = face; + intersection.barycoord = barycoord; } @@ -13603,40 +13634,71 @@ function WebGLAttributes( gl ) { function updateBuffer( buffer, attribute, bufferType ) { const array = attribute.array; - const updateRange = attribute._updateRange; // @deprecated, r159 const updateRanges = attribute.updateRanges; gl.bindBuffer( bufferType, buffer ); - if ( updateRange.count === - 1 && updateRanges.length === 0 ) { + if ( updateRanges.length === 0 ) { // Not using update ranges gl.bufferSubData( bufferType, 0, array ); - } + } else { - if ( updateRanges.length !== 0 ) { + // Before applying update ranges, we merge any adjacent / overlapping + // ranges to reduce load on `gl.bufferSubData`. Empirically, this has led + // to performance improvements for applications which make heavy use of + // update ranges. Likely due to GPU command overhead. + // + // Note that to reduce garbage collection between frames, we merge the + // update ranges in-place. This is safe because this method will clear the + // update ranges once updated. - for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { + updateRanges.sort( ( a, b ) => a.start - b.start ); + // To merge the update ranges in-place, we work from left to right in the + // existing updateRanges array, merging ranges. This may result in a final + // array which is smaller than the original. This index tracks the last + // index representing a merged range, any data after this index can be + // trimmed once the merge algorithm is completed. + let mergeIndex = 0; + + for ( let i = 1; i < updateRanges.length; i ++ ) { + + const previousRange = updateRanges[ mergeIndex ]; const range = updateRanges[ i ]; - gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, - array, range.start, range.count ); + // We add one here to merge adjacent ranges. This is safe because ranges + // operate over positive integers. + if ( range.start <= previousRange.start + previousRange.count + 1 ) { + + previousRange.count = Math.max( + previousRange.count, + range.start + range.count - previousRange.start + ); + + } else { + + ++ mergeIndex; + updateRanges[ mergeIndex ] = range; + + } } - attribute.clearUpdateRanges(); + // Trim the array to only contain the merged ranges. + updateRanges.length = mergeIndex + 1; - } + for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { - // @deprecated, r159 - if ( updateRange.count !== - 1 ) { + const range = updateRanges[ i ]; - gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, - array, updateRange.offset, updateRange.count ); + gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, + array, range.start, range.count ); + + } - updateRange.count = - 1; // reset range + attribute.clearUpdateRanges(); } @@ -14097,7 +14159,7 @@ const vertex$2 = "#include \n#include \n#include < const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}"; -const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"; +const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix[ 3 ];\n\tvec2 scale = vec2( length( modelMatrix[ 0 ].xyz ), length( modelMatrix[ 1 ].xyz ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"; const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; @@ -15863,6 +15925,14 @@ function WebGLCapabilities( gl, extensions, parameters, utils ) { } const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; + const reverseDepthBuffer = parameters.reverseDepthBuffer === true && extensions.has( 'EXT_clip_control' ); + + if ( reverseDepthBuffer === true ) { + + const ext = extensions.get( 'EXT_clip_control' ); + ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT ); + + } const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); @@ -15890,6 +15960,7 @@ function WebGLCapabilities( gl, extensions, parameters, utils ) { precision: precision, logarithmicDepthBuffer: logarithmicDepthBuffer, + reverseDepthBuffer: reverseDepthBuffer, maxTextures: maxTextures, maxVertexTextures: maxVertexTextures, @@ -19907,6 +19978,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) { parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + parameters.reverseDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '', 'uniform mat4 modelMatrix;', 'uniform mat4 modelViewMatrix;', @@ -20072,6 +20144,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) { parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + parameters.reverseDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '', 'uniform mat4 viewMatrix;', 'uniform vec3 cameraPosition;', @@ -20464,6 +20537,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities const programs = []; const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; + const reverseDepthBuffer = capabilities.reverseDepthBuffer; const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures; let precision = capabilities.precision; @@ -20755,6 +20829,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities sizeAttenuation: material.sizeAttenuation === true, logarithmicDepthBuffer: logarithmicDepthBuffer, + reverseDepthBuffer: reverseDepthBuffer, skinning: object.isSkinnedMesh === true, @@ -20974,38 +21049,40 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities _programLayers.enable( 2 ); if ( parameters.logarithmicDepthBuffer ) _programLayers.enable( 3 ); - if ( parameters.skinning ) + if ( parameters.reverseDepthBuffer ) _programLayers.enable( 4 ); - if ( parameters.morphTargets ) + if ( parameters.skinning ) _programLayers.enable( 5 ); - if ( parameters.morphNormals ) + if ( parameters.morphTargets ) _programLayers.enable( 6 ); - if ( parameters.morphColors ) + if ( parameters.morphNormals ) _programLayers.enable( 7 ); - if ( parameters.premultipliedAlpha ) + if ( parameters.morphColors ) _programLayers.enable( 8 ); - if ( parameters.shadowMapEnabled ) + if ( parameters.premultipliedAlpha ) _programLayers.enable( 9 ); - if ( parameters.doubleSided ) + if ( parameters.shadowMapEnabled ) _programLayers.enable( 10 ); - if ( parameters.flipSided ) + if ( parameters.doubleSided ) _programLayers.enable( 11 ); - if ( parameters.useDepthPacking ) + if ( parameters.flipSided ) _programLayers.enable( 12 ); - if ( parameters.dithering ) + if ( parameters.useDepthPacking ) _programLayers.enable( 13 ); - if ( parameters.transmission ) + if ( parameters.dithering ) _programLayers.enable( 14 ); - if ( parameters.sheen ) + if ( parameters.transmission ) _programLayers.enable( 15 ); - if ( parameters.opaque ) + if ( parameters.sheen ) _programLayers.enable( 16 ); - if ( parameters.pointsUvs ) + if ( parameters.opaque ) _programLayers.enable( 17 ); - if ( parameters.decodeVideoTexture ) + if ( parameters.pointsUvs ) _programLayers.enable( 18 ); - if ( parameters.alphaToCoverage ) + if ( parameters.decodeVideoTexture ) _programLayers.enable( 19 ); + if ( parameters.alphaToCoverage ) + _programLayers.enable( 20 ); array.push( _programLayers.mask ); @@ -22563,6 +22640,18 @@ function WebGLShadowMap( renderer, objects, capabilities ) { } +const reversedFuncs = { + [ NeverDepth ]: AlwaysDepth, + [ LessDepth ]: GreaterDepth, + [ EqualDepth ]: NotEqualDepth, + [ LessEqualDepth ]: GreaterEqualDepth, + + [ AlwaysDepth ]: NeverDepth, + [ GreaterDepth ]: LessDepth, + [ NotEqualDepth ]: EqualDepth, + [ GreaterEqualDepth ]: LessEqualDepth, +}; + function WebGLState( gl ) { function ColorBuffer() { @@ -22627,6 +22716,7 @@ function WebGLState( gl ) { function DepthBuffer() { let locked = false; + let reversed = false; let currentDepthMask = null; let currentDepthFunc = null; @@ -22634,6 +22724,12 @@ function WebGLState( gl ) { return { + setReversed: function ( value ) { + + reversed = value; + + }, + setTest: function ( depthTest ) { if ( depthTest ) { @@ -22661,6 +22757,8 @@ function WebGLState( gl ) { setFunc: function ( depthFunc ) { + if ( reversed ) depthFunc = reversedFuncs[ depthFunc ]; + if ( currentDepthFunc !== depthFunc ) { switch ( depthFunc ) { @@ -24202,6 +24300,28 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, } + if ( glFormat === _gl.RGB_INTEGER ) { + + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGB8UI; + if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGB16UI; + if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGB32UI; + if ( glType === _gl.BYTE ) internalFormat = _gl.RGB8I; + if ( glType === _gl.SHORT ) internalFormat = _gl.RGB16I; + if ( glType === _gl.INT ) internalFormat = _gl.RGB32I; + + } + + if ( glFormat === _gl.RGBA_INTEGER ) { + + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGBA8UI; + if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGBA16UI; + if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGBA32UI; + if ( glType === _gl.BYTE ) internalFormat = _gl.RGBA8I; + if ( glType === _gl.SHORT ) internalFormat = _gl.RGBA16I; + if ( glType === _gl.INT ) internalFormat = _gl.RGBA32I; + + } + if ( glFormat === _gl.RGB ) { if ( glType === _gl.UNSIGNED_INT_5_9_9_9_REV ) internalFormat = _gl.RGB9_E5; @@ -28795,6 +28915,7 @@ class WebGLRenderer { // camera matrices cache + const _currentProjectionMatrix = new Matrix4(); const _projScreenMatrix = new Matrix4(); const _vector3 = new Vector3(); @@ -28890,6 +29011,8 @@ class WebGLRenderer { state = new WebGLState( _gl ); + if ( capabilities.reverseDepthBuffer ) state.buffers.depth.setReversed( true ); + info = new WebGLInfo( _gl ); properties = new WebGLProperties(); textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); @@ -29189,7 +29312,13 @@ class WebGLRenderer { } - if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT; + if ( depth ) { + + bits |= _gl.DEPTH_BUFFER_BIT; + _gl.clearDepth( this.capabilities.reverseDepthBuffer ? 0 : 1 ); + + } + if ( stencil ) { bits |= _gl.STENCIL_BUFFER_BIT; @@ -29578,6 +29707,12 @@ class WebGLRenderer { scene.traverse( function ( object ) { + if ( ! ( object.isMesh || object.isPoints || object.isLine || object.isSprite ) ) { + + return; + + } + const material = object.material; if ( material ) { @@ -30564,7 +30699,21 @@ class WebGLRenderer { // common camera uniforms - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + if ( capabilities.reverseDepthBuffer ) { + + _currentProjectionMatrix.copy( camera.projectionMatrix ); + + toNormalizedProjectionMatrix( _currentProjectionMatrix ); + toReversedProjectionMatrix( _currentProjectionMatrix ); + + p_uniforms.setValue( _gl, 'projectionMatrix', _currentProjectionMatrix ); + + } else { + + p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + + } + p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); const uCamPos = p_uniforms.map.cameraPosition; @@ -31045,61 +31194,55 @@ class WebGLRenderer { if ( framebuffer ) { - state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - try { - - const texture = renderTarget.texture; - const textureFormat = texture.format; - const textureType = texture.type; - - if ( ! capabilities.textureFormatReadable( textureFormat ) ) { - - throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' ); + const texture = renderTarget.texture; + const textureFormat = texture.format; + const textureType = texture.type; - } + if ( ! capabilities.textureFormatReadable( textureFormat ) ) { - if ( ! capabilities.textureTypeReadable( textureType ) ) { + throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' ); - throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' ); + } - } + if ( ! capabilities.textureTypeReadable( textureType ) ) { - // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) - if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { + throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' ); - const glBuffer = _gl.createBuffer(); - _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer ); - _gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ ); - _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 ); - _gl.flush(); + } - // check if the commands have finished every 8 ms - const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 ); - await probeAsync( _gl, sync, 4 ); + // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) + if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { - try { + // set the active frame buffer to the one we want to read + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer ); - _gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer ); + const glBuffer = _gl.createBuffer(); + _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer ); + _gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ ); + _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 ); - } finally { + // reset the frame buffer to the currently set buffer before waiting + const currFramebuffer = _currentRenderTarget !== null ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; + state.bindFramebuffer( _gl.FRAMEBUFFER, currFramebuffer ); - _gl.deleteBuffer( glBuffer ); - _gl.deleteSync( sync ); + // check if the commands have finished every 8 ms + const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 ); - } + _gl.flush(); - return buffer; + await probeAsync( _gl, sync, 4 ); - } + // read the data and delete the buffer + _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer ); + _gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer ); + _gl.deleteBuffer( glBuffer ); + _gl.deleteSync( sync ); - } finally { + return buffer; - // restore framebuffer of current render target if necessary + } else { - const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; - state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.' ); } @@ -31585,7 +31728,6 @@ class InterleavedBuffer { this.count = array !== undefined ? array.length / stride : 0; this.usage = StaticDrawUsage; - this._updateRange = { offset: 0, count: - 1 }; this.updateRanges = []; this.version = 0; @@ -31602,13 +31744,6 @@ class InterleavedBuffer { } - get updateRange() { - - warnOnce( 'THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 - return this._updateRange; - - } - setUsage( value ) { this.usage = value; @@ -32373,6 +32508,27 @@ class LOD extends Object3D { } + removeLevel( distance ) { + + const levels = this.levels; + + for ( let i = 0; i < levels.length; i ++ ) { + + if ( levels[ i ].distance === distance ) { + + const removedElements = levels.splice( i, 1 ); + this.remove( removedElements[ 0 ].object ); + + return true; + + } + + } + + return false; + + } + getCurrentLevel() { return this._currentLevel; @@ -33492,6 +33648,9 @@ class BatchedMesh extends Mesh { // stores visible, active, and geometry id per object this._drawInfo = []; + // instance ids that have been set as inactive, and are available to be overwritten + this._availableInstanceIds = []; + // geometry information this._drawRanges = []; this._reservedRanges = []; @@ -33691,23 +33850,36 @@ class BatchedMesh extends Mesh { addInstance( geometryId ) { + const atCapacity = this._drawInfo.length >= this.maxInstanceCount; + // ensure we're not over geometry - if ( this._drawInfo.length >= this._maxInstanceCount ) { + if ( atCapacity && this._availableInstanceIds.length === 0 ) { throw new Error( 'BatchedMesh: Maximum item count reached.' ); } - this._drawInfo.push( { - + const instanceDrawInfo = { visible: true, active: true, geometryIndex: geometryId, + }; - } ); + let drawId = null; + + // Prioritize using previously freed instance ids + if ( this._availableInstanceIds.length > 0 ) { + + drawId = this._availableInstanceIds.pop(); + this._drawInfo[ drawId ] = instanceDrawInfo; + + } else { + + drawId = this._drawInfo.length; + this._drawInfo.push( instanceDrawInfo ); + + } - // initialize the matrix - const drawId = this._drawInfo.length - 1; const matricesTexture = this._matricesTexture; const matricesArray = matricesTexture.image.data; _identityMatrix.toArray( matricesArray, drawId * 16 ); @@ -33956,11 +34128,8 @@ class BatchedMesh extends Mesh { } */ - /* deleteInstance( instanceId ) { - // Note: User needs to call optimize() afterward to pack the data. - const drawInfo = this._drawInfo; if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { @@ -33969,12 +34138,12 @@ class BatchedMesh extends Mesh { } drawInfo[ instanceId ].active = false; + this._availableInstanceIds.push( instanceId ); this._visibilityChanged = true; return this; } - */ // get bounding box and compute it if it doesn't exist getBoundingBoxAt( geometryId, target ) { @@ -34179,6 +34348,59 @@ class BatchedMesh extends Mesh { } + setGeometryIdAt( instanceId, geometryId ) { + + // return early if the geometry is out of range or not active + const drawInfo = this._drawInfo; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return null; + + } + + // check if the provided geometryId is within the valid range + if ( geometryId < 0 || geometryId >= this._geometryCount ) { + + return null; + + } + + drawInfo[ instanceId ].geometryIndex = geometryId; + + return this; + + } + + getGeometryIdAt( instanceId ) { + + const drawInfo = this._drawInfo; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return - 1; + + } + + return drawInfo[ instanceId ].geometryIndex; + + } + + getGeometryRangeAt( geometryId, target = {} ) { + + if ( geometryId < 0 || geometryId >= this._geometryCount ) { + + return null; + + } + + const drawRange = this._drawRanges[ geometryId ]; + + target.start = drawRange.start; + target.count = drawRange.count; + + return target; + + } + raycast( raycaster, intersects ) { const drawInfo = this._drawInfo; @@ -34730,6 +34952,7 @@ function checkIntersection( object, raycaster, ray, thresholdSq, a, b ) { index: a, face: null, faceIndex: null, + barycoord: null, object: object }; @@ -34995,6 +35218,8 @@ function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, inte point: intersectPoint, index: index, face: null, + faceIndex: null, + barycoord: null, object: object } ); @@ -37497,12 +37722,19 @@ class CylinderGeometry extends BufferGeometry { // faces - indices.push( a, b, d ); - indices.push( b, c, d ); + if ( radiusTop > 0 ) { - // update group counter + indices.push( a, b, d ); + groupCount += 3; - groupCount += 6; + } + + if ( radiusBottom > 0 ) { + + indices.push( b, c, d ); + groupCount += 3; + + } } @@ -45812,7 +46044,7 @@ class MaterialLoader extends Loader { } - const material = MaterialLoader.createMaterialFromType( json.type ); + const material = this.createMaterialFromType( json.type ); if ( json.uuid !== undefined ) material.uuid = json.uuid; if ( json.name !== undefined ) material.name = json.name; @@ -46068,6 +46300,12 @@ class MaterialLoader extends Loader { } + createMaterialFromType( type ) { + + return MaterialLoader.createMaterialFromType( type ); + + } + static createMaterialFromType( type ) { const materialLib = { @@ -47898,7 +48136,7 @@ class Clock { function now() { - return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 + return performance.now(); } @@ -48190,7 +48428,7 @@ class Audio extends Object3D { } - stop() { + stop( delay = 0 ) { if ( this.hasPlaybackControl === false ) { @@ -48203,7 +48441,7 @@ class Audio extends Object3D { if ( this.source !== null ) { - this.source.stop(); + this.source.stop( this.context.currentTime + delay ); this.source.onended = null; } @@ -53845,7 +54083,7 @@ class ShapePath { class Controls extends EventDispatcher { - constructor( object, domElement ) { + constructor( object, domElement = null ) { super(); diff --git a/build/three.module.min.js b/build/three.module.min.js index 37ba7e294348c6..424ef1c8e5dd8c 100644 --- a/build/three.module.min.js +++ b/build/three.module.min.js @@ -3,4 +3,4 @@ * Copyright 2010-2024 Three.js Authors * SPDX-License-Identifier: MIT */ -const t="168",e={LEFT:0,MIDDLE:1,RIGHT:2,ROTATE:0,DOLLY:1,PAN:2},n={ROTATE:0,PAN:1,DOLLY_PAN:2,DOLLY_ROTATE:3},i=0,r=1,s=2,a=3,o=0,l=1,c=2,h=3,u=0,d=1,p=2,m=0,f=1,g=2,v=3,_=4,x=5,y=100,M=101,S=102,b=103,w=104,T=200,E=201,A=202,R=203,C=204,P=205,I=206,L=207,U=208,N=209,D=210,O=211,F=212,B=213,z=214,k=0,V=1,H=2,G=3,W=4,X=5,j=6,q=7,Y=0,Z=1,J=2,K=0,$=1,Q=2,tt=3,et=4,nt=5,it=6,rt=7,st="attached",at="detached",ot=300,lt=301,ct=302,ht=303,ut=304,dt=306,pt=1e3,mt=1001,ft=1002,gt=1003,vt=1004,_t=1004,xt=1005,yt=1005,Mt=1006,St=1007,bt=1007,wt=1008,Tt=1008,Et=1009,At=1010,Rt=1011,Ct=1012,Pt=1013,It=1014,Lt=1015,Ut=1016,Nt=1017,Dt=1018,Ot=1020,Ft=35902,Bt=1021,zt=1022,kt=1023,Vt=1024,Ht=1025,Gt=1026,Wt=1027,Xt=1028,jt=1029,qt=1030,Yt=1031,Zt=1032,Jt=1033,Kt=33776,$t=33777,Qt=33778,te=33779,ee=35840,ne=35841,ie=35842,re=35843,se=36196,ae=37492,oe=37496,le=37808,ce=37809,he=37810,ue=37811,de=37812,pe=37813,me=37814,fe=37815,ge=37816,ve=37817,_e=37818,xe=37819,ye=37820,Me=37821,Se=36492,be=36494,we=36495,Te=36283,Ee=36284,Ae=36285,Re=36286,Ce=2200,Pe=2201,Ie=2202,Le=2300,Ue=2301,Ne=2302,De=2400,Oe=2401,Fe=2402,Be=2500,ze=2501,ke=0,Ve=1,He=2,Ge=3200,We=3201,Xe=3202,je=3203,qe=0,Ye=1,Ze="",Je="srgb",Ke="srgb-linear",$e="display-p3",Qe="display-p3-linear",tn="linear",en="srgb",nn="rec709",rn="p3",sn=0,an=7680,on=7681,ln=7682,cn=7683,hn=34055,un=34056,dn=5386,pn=512,mn=513,fn=514,gn=515,vn=516,_n=517,xn=518,yn=519,Mn=512,Sn=513,bn=514,wn=515,Tn=516,En=517,An=518,Rn=519,Cn=35044,Pn=35048,In=35040,Ln=35045,Un=35049,Nn=35041,Dn=35046,On=35050,Fn=35042,Bn="100",zn="300 es",kn=2e3,Vn=2001;class Hn{addEventListener(t,e){void 0===this._listeners&&(this._listeners={});const n=this._listeners;void 0===n[t]&&(n[t]=[]),-1===n[t].indexOf(e)&&n[t].push(e)}hasEventListener(t,e){if(void 0===this._listeners)return!1;const n=this._listeners;return void 0!==n[t]&&-1!==n[t].indexOf(e)}removeEventListener(t,e){if(void 0===this._listeners)return;const n=this._listeners[t];if(void 0!==n){const t=n.indexOf(e);-1!==t&&n.splice(t,1)}}dispatchEvent(t){if(void 0===this._listeners)return;const e=this._listeners[t.type];if(void 0!==e){t.target=this;const n=e.slice(0);for(let e=0,i=n.length;e>8&255]+Gn[t>>16&255]+Gn[t>>24&255]+"-"+Gn[255&e]+Gn[e>>8&255]+"-"+Gn[e>>16&15|64]+Gn[e>>24&255]+"-"+Gn[63&n|128]+Gn[n>>8&255]+"-"+Gn[n>>16&255]+Gn[n>>24&255]+Gn[255&i]+Gn[i>>8&255]+Gn[i>>16&255]+Gn[i>>24&255]).toLowerCase()}function Yn(t,e,n){return Math.max(e,Math.min(n,t))}function Zn(t,e){return(t%e+e)%e}function Jn(t,e,n){return(1-n)*t+n*e}function Kn(t,e){switch(e.constructor){case Float32Array:return t;case Uint32Array:return t/4294967295;case Uint16Array:return t/65535;case Uint8Array:return t/255;case Int32Array:return Math.max(t/2147483647,-1);case Int16Array:return Math.max(t/32767,-1);case Int8Array:return Math.max(t/127,-1);default:throw new Error("Invalid component type.")}}function $n(t,e){switch(e.constructor){case Float32Array:return t;case Uint32Array:return Math.round(4294967295*t);case Uint16Array:return Math.round(65535*t);case Uint8Array:return Math.round(255*t);case Int32Array:return Math.round(2147483647*t);case Int16Array:return Math.round(32767*t);case Int8Array:return Math.round(127*t);default:throw new Error("Invalid component type.")}}const Qn={DEG2RAD:Xn,RAD2DEG:jn,generateUUID:qn,clamp:Yn,euclideanModulo:Zn,mapLinear:function(t,e,n,i,r){return i+(t-e)*(r-i)/(n-e)},inverseLerp:function(t,e,n){return t!==e?(n-t)/(e-t):0},lerp:Jn,damp:function(t,e,n,i){return Jn(t,e,1-Math.exp(-n*i))},pingpong:function(t,e=1){return e-Math.abs(Zn(t,2*e)-e)},smoothstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*(3-2*t)},smootherstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*t*(t*(6*t-15)+10)},randInt:function(t,e){return t+Math.floor(Math.random()*(e-t+1))},randFloat:function(t,e){return t+Math.random()*(e-t)},randFloatSpread:function(t){return t*(.5-Math.random())},seededRandom:function(t){void 0!==t&&(Wn=t);let e=Wn+=1831565813;return e=Math.imul(e^e>>>15,1|e),e^=e+Math.imul(e^e>>>7,61|e),((e^e>>>14)>>>0)/4294967296},degToRad:function(t){return t*Xn},radToDeg:function(t){return t*jn},isPowerOfTwo:function(t){return 0==(t&t-1)&&0!==t},ceilPowerOfTwo:function(t){return Math.pow(2,Math.ceil(Math.log(t)/Math.LN2))},floorPowerOfTwo:function(t){return Math.pow(2,Math.floor(Math.log(t)/Math.LN2))},setQuaternionFromProperEuler:function(t,e,n,i,r){const s=Math.cos,a=Math.sin,o=s(n/2),l=a(n/2),c=s((e+i)/2),h=a((e+i)/2),u=s((e-i)/2),d=a((e-i)/2),p=s((i-e)/2),m=a((i-e)/2);switch(r){case"XYX":t.set(o*h,l*u,l*d,o*c);break;case"YZY":t.set(l*d,o*h,l*u,o*c);break;case"ZXZ":t.set(l*u,l*d,o*h,o*c);break;case"XZX":t.set(o*h,l*m,l*p,o*c);break;case"YXY":t.set(l*p,o*h,l*m,o*c);break;case"ZYZ":t.set(l*m,l*p,o*h,o*c);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+r)}},normalize:$n,denormalize:Kn};class ti{constructor(t=0,e=0){ti.prototype.isVector2=!0,this.x=t,this.y=e}get width(){return this.x}set width(t){this.x=t}get height(){return this.y}set height(t){this.y=t}set(t,e){return this.x=t,this.y=e,this}setScalar(t){return this.x=t,this.y=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y)}copy(t){return this.x=t.x,this.y=t.y,this}add(t){return this.x+=t.x,this.y+=t.y,this}addScalar(t){return this.x+=t,this.y+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this}subScalar(t){return this.x-=t,this.y-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}multiplyScalar(t){return this.x*=t,this.y*=t,this}divide(t){return this.x/=t.x,this.y/=t.y,this}divideScalar(t){return this.multiplyScalar(1/t)}applyMatrix3(t){const e=this.x,n=this.y,i=t.elements;return this.x=i[0]*e+i[3]*n+i[6],this.y=i[1]*e+i[4]*n+i[7],this}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this}clamp(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this}clampScalar(t,e){return this.x=Math.max(t,Math.min(e,this.x)),this.y=Math.max(t,Math.min(e,this.y)),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(t,Math.min(e,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(t){return this.x*t.x+this.y*t.y}cross(t){return this.x*t.y-this.y*t.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(0===e)return Math.PI/2;const n=this.dot(t)/e;return Math.acos(Yn(n,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y;return e*e+n*n}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this}equals(t){return t.x===this.x&&t.y===this.y}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this}rotateAround(t,e){const n=Math.cos(e),i=Math.sin(e),r=this.x-t.x,s=this.y-t.y;return this.x=r*n-s*i+t.x,this.y=r*i+s*n+t.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class ei{constructor(t,e,n,i,r,s,a,o,l){ei.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],void 0!==t&&this.set(t,e,n,i,r,s,a,o,l)}set(t,e,n,i,r,s,a,o,l){const c=this.elements;return c[0]=t,c[1]=i,c[2]=a,c[3]=e,c[4]=r,c[5]=o,c[6]=n,c[7]=s,c[8]=l,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(t){const e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],this}extractBasis(t,e,n){return t.setFromMatrix3Column(this,0),e.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(t){const e=t.elements;return this.set(e[0],e[4],e[8],e[1],e[5],e[9],e[2],e[6],e[10]),this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const n=t.elements,i=e.elements,r=this.elements,s=n[0],a=n[3],o=n[6],l=n[1],c=n[4],h=n[7],u=n[2],d=n[5],p=n[8],m=i[0],f=i[3],g=i[6],v=i[1],_=i[4],x=i[7],y=i[2],M=i[5],S=i[8];return r[0]=s*m+a*v+o*y,r[3]=s*f+a*_+o*M,r[6]=s*g+a*x+o*S,r[1]=l*m+c*v+h*y,r[4]=l*f+c*_+h*M,r[7]=l*g+c*x+h*S,r[2]=u*m+d*v+p*y,r[5]=u*f+d*_+p*M,r[8]=u*g+d*x+p*S,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[3]*=t,e[6]*=t,e[1]*=t,e[4]*=t,e[7]*=t,e[2]*=t,e[5]*=t,e[8]*=t,this}determinant(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8];return e*s*c-e*a*l-n*r*c+n*a*o+i*r*l-i*s*o}invert(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8],h=c*s-a*l,u=a*o-c*r,d=l*r-s*o,p=e*h+n*u+i*d;if(0===p)return this.set(0,0,0,0,0,0,0,0,0);const m=1/p;return t[0]=h*m,t[1]=(i*l-c*n)*m,t[2]=(a*n-i*s)*m,t[3]=u*m,t[4]=(c*e-i*o)*m,t[5]=(i*r-a*e)*m,t[6]=d*m,t[7]=(n*o-l*e)*m,t[8]=(s*e-n*r)*m,this}transpose(){let t;const e=this.elements;return t=e[1],e[1]=e[3],e[3]=t,t=e[2],e[2]=e[6],e[6]=t,t=e[5],e[5]=e[7],e[7]=t,this}getNormalMatrix(t){return this.setFromMatrix4(t).invert().transpose()}transposeIntoArray(t){const e=this.elements;return t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8],this}setUvTransform(t,e,n,i,r,s,a){const o=Math.cos(r),l=Math.sin(r);return this.set(n*o,n*l,-n*(o*s+l*a)+s+t,-i*l,i*o,-i*(-l*s+o*a)+a+e,0,0,1),this}scale(t,e){return this.premultiply(ni.makeScale(t,e)),this}rotate(t){return this.premultiply(ni.makeRotation(-t)),this}translate(t,e){return this.premultiply(ni.makeTranslation(t,e)),this}makeTranslation(t,e){return t.isVector2?this.set(1,0,t.x,0,1,t.y,0,0,1):this.set(1,0,t,0,1,e,0,0,1),this}makeRotation(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,-n,0,n,e,0,0,0,1),this}makeScale(t,e){return this.set(t,0,0,0,e,0,0,0,1),this}equals(t){const e=this.elements,n=t.elements;for(let t=0;t<9;t++)if(e[t]!==n[t])return!1;return!0}fromArray(t,e=0){for(let n=0;n<9;n++)this.elements[n]=t[n+e];return this}toArray(t=[],e=0){const n=this.elements;return t[e]=n[0],t[e+1]=n[1],t[e+2]=n[2],t[e+3]=n[3],t[e+4]=n[4],t[e+5]=n[5],t[e+6]=n[6],t[e+7]=n[7],t[e+8]=n[8],t}clone(){return(new this.constructor).fromArray(this.elements)}}const ni=new ei;function ii(t){for(let e=t.length-1;e>=0;--e)if(t[e]>=65535)return!0;return!1}const ri={Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:Uint8ClampedArray,Int16Array:Int16Array,Uint16Array:Uint16Array,Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array};function si(t,e){return new ri[t](e)}function ai(t){return document.createElementNS("http://www.w3.org/1999/xhtml",t)}function oi(){const t=ai("canvas");return t.style.display="block",t}const li={};function ci(t){t in li||(li[t]=!0,console.warn(t))}const hi=(new ei).set(.8224621,.177538,0,.0331941,.9668058,0,.0170827,.0723974,.9105199),ui=(new ei).set(1.2249401,-.2249404,0,-.0420569,1.0420571,0,-.0196376,-.0786361,1.0982735),di={[Ke]:{transfer:tn,primaries:nn,luminanceCoefficients:[.2126,.7152,.0722],toReference:t=>t,fromReference:t=>t},[Je]:{transfer:en,primaries:nn,luminanceCoefficients:[.2126,.7152,.0722],toReference:t=>t.convertSRGBToLinear(),fromReference:t=>t.convertLinearToSRGB()},[Qe]:{transfer:tn,primaries:rn,luminanceCoefficients:[.2289,.6917,.0793],toReference:t=>t.applyMatrix3(ui),fromReference:t=>t.applyMatrix3(hi)},[$e]:{transfer:en,primaries:rn,luminanceCoefficients:[.2289,.6917,.0793],toReference:t=>t.convertSRGBToLinear().applyMatrix3(ui),fromReference:t=>t.applyMatrix3(hi).convertLinearToSRGB()}},pi=new Set([Ke,Qe]),mi={enabled:!0,_workingColorSpace:Ke,get workingColorSpace(){return this._workingColorSpace},set workingColorSpace(t){if(!pi.has(t))throw new Error(`Unsupported working color space, "${t}".`);this._workingColorSpace=t},convert:function(t,e,n){if(!1===this.enabled||e===n||!e||!n)return t;const i=di[e].toReference;return(0,di[n].fromReference)(i(t))},fromWorkingColorSpace:function(t,e){return this.convert(t,this._workingColorSpace,e)},toWorkingColorSpace:function(t,e){return this.convert(t,e,this._workingColorSpace)},getPrimaries:function(t){return di[t].primaries},getTransfer:function(t){return t===Ze?tn:di[t].transfer},getLuminanceCoefficients:function(t,e=this._workingColorSpace){return t.fromArray(di[e].luminanceCoefficients)}};function fi(t){return t<.04045?.0773993808*t:Math.pow(.9478672986*t+.0521327014,2.4)}function gi(t){return t<.0031308?12.92*t:1.055*Math.pow(t,.41666)-.055}let vi;class _i{static getDataURL(t){if(/^data:/i.test(t.src))return t.src;if("undefined"==typeof HTMLCanvasElement)return t.src;let e;if(t instanceof HTMLCanvasElement)e=t;else{void 0===vi&&(vi=ai("canvas")),vi.width=t.width,vi.height=t.height;const n=vi.getContext("2d");t instanceof ImageData?n.putImageData(t,0,0):n.drawImage(t,0,0,t.width,t.height),e=vi}return e.width>2048||e.height>2048?(console.warn("THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons",t),e.toDataURL("image/jpeg",.6)):e.toDataURL("image/png")}static sRGBToLinear(t){if("undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&t instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&t instanceof ImageBitmap){const e=ai("canvas");e.width=t.width,e.height=t.height;const n=e.getContext("2d");n.drawImage(t,0,0,t.width,t.height);const i=n.getImageData(0,0,t.width,t.height),r=i.data;for(let t=0;t0&&(n.userData=this.userData),e||(t.textures[this.uuid]=n),n}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(t){if(this.mapping!==ot)return t;if(t.applyMatrix3(this.matrix),t.x<0||t.x>1)switch(this.wrapS){case pt:t.x=t.x-Math.floor(t.x);break;case mt:t.x=t.x<0?0:1;break;case ft:1===Math.abs(Math.floor(t.x)%2)?t.x=Math.ceil(t.x)-t.x:t.x=t.x-Math.floor(t.x)}if(t.y<0||t.y>1)switch(this.wrapT){case pt:t.y=t.y-Math.floor(t.y);break;case mt:t.y=t.y<0?0:1;break;case ft:1===Math.abs(Math.floor(t.y)%2)?t.y=Math.ceil(t.y)-t.y:t.y=t.y-Math.floor(t.y)}return this.flipY&&(t.y=1-t.y),t}set needsUpdate(t){!0===t&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(t){!0===t&&this.pmremVersion++}}bi.DEFAULT_IMAGE=null,bi.DEFAULT_MAPPING=ot,bi.DEFAULT_ANISOTROPY=1;class wi{constructor(t=0,e=0,n=0,i=1){wi.prototype.isVector4=!0,this.x=t,this.y=e,this.z=n,this.w=i}get width(){return this.z}set width(t){this.z=t}get height(){return this.w}set height(t){this.w=t}set(t,e,n,i){return this.x=t,this.y=e,this.z=n,this.w=i,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this.w=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setW(t){return this.w=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;case 3:this.w=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this.w=void 0!==t.w?t.w:1,this}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this.w+=t.w,this}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this.w+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this.w=t.w+e.w,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this.w+=t.w*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this.w-=t.w,this}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this.w-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this.w=t.w-e.w,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this.w*=t.w,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this.w*=t,this}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=this.w,s=t.elements;return this.x=s[0]*e+s[4]*n+s[8]*i+s[12]*r,this.y=s[1]*e+s[5]*n+s[9]*i+s[13]*r,this.z=s[2]*e+s[6]*n+s[10]*i+s[14]*r,this.w=s[3]*e+s[7]*n+s[11]*i+s[15]*r,this}divideScalar(t){return this.multiplyScalar(1/t)}setAxisAngleFromQuaternion(t){this.w=2*Math.acos(t.w);const e=Math.sqrt(1-t.w*t.w);return e<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=t.x/e,this.y=t.y/e,this.z=t.z/e),this}setAxisAngleFromRotationMatrix(t){let e,n,i,r;const s=.01,a=.1,o=t.elements,l=o[0],c=o[4],h=o[8],u=o[1],d=o[5],p=o[9],m=o[2],f=o[6],g=o[10];if(Math.abs(c-u)o&&t>v?tv?o=0?1:-1,i=1-e*e;if(i>Number.EPSILON){const r=Math.sqrt(i),s=Math.atan2(r,e*n);t=Math.sin(t*s)/r,a=Math.sin(a*s)/r}const r=a*n;if(o=o*t+u*r,l=l*t+d*r,c=c*t+p*r,h=h*t+m*r,t===1-a){const t=1/Math.sqrt(o*o+l*l+c*c+h*h);o*=t,l*=t,c*=t,h*=t}}t[e]=o,t[e+1]=l,t[e+2]=c,t[e+3]=h}static multiplyQuaternionsFlat(t,e,n,i,r,s){const a=n[i],o=n[i+1],l=n[i+2],c=n[i+3],h=r[s],u=r[s+1],d=r[s+2],p=r[s+3];return t[e]=a*p+c*h+o*d-l*u,t[e+1]=o*p+c*u+l*h-a*d,t[e+2]=l*p+c*d+a*u-o*h,t[e+3]=c*p-a*h-o*u-l*d,t}get x(){return this._x}set x(t){this._x=t,this._onChangeCallback()}get y(){return this._y}set y(t){this._y=t,this._onChangeCallback()}get z(){return this._z}set z(t){this._z=t,this._onChangeCallback()}get w(){return this._w}set w(t){this._w=t,this._onChangeCallback()}set(t,e,n,i){return this._x=t,this._y=e,this._z=n,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(t){return this._x=t.x,this._y=t.y,this._z=t.z,this._w=t.w,this._onChangeCallback(),this}setFromEuler(t,e=!0){const n=t._x,i=t._y,r=t._z,s=t._order,a=Math.cos,o=Math.sin,l=a(n/2),c=a(i/2),h=a(r/2),u=o(n/2),d=o(i/2),p=o(r/2);switch(s){case"XYZ":this._x=u*c*h+l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h-u*d*p;break;case"YXZ":this._x=u*c*h+l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h+u*d*p;break;case"ZXY":this._x=u*c*h-l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h-u*d*p;break;case"ZYX":this._x=u*c*h-l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h+u*d*p;break;case"YZX":this._x=u*c*h+l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h-u*d*p;break;case"XZY":this._x=u*c*h-l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h+u*d*p;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+s)}return!0===e&&this._onChangeCallback(),this}setFromAxisAngle(t,e){const n=e/2,i=Math.sin(n);return this._x=t.x*i,this._y=t.y*i,this._z=t.z*i,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(t){const e=t.elements,n=e[0],i=e[4],r=e[8],s=e[1],a=e[5],o=e[9],l=e[2],c=e[6],h=e[10],u=n+a+h;if(u>0){const t=.5/Math.sqrt(u+1);this._w=.25/t,this._x=(c-o)*t,this._y=(r-l)*t,this._z=(s-i)*t}else if(n>a&&n>h){const t=2*Math.sqrt(1+n-a-h);this._w=(c-o)/t,this._x=.25*t,this._y=(i+s)/t,this._z=(r+l)/t}else if(a>h){const t=2*Math.sqrt(1+a-n-h);this._w=(r-l)/t,this._x=(i+s)/t,this._y=.25*t,this._z=(o+c)/t}else{const t=2*Math.sqrt(1+h-n-a);this._w=(s-i)/t,this._x=(r+l)/t,this._y=(o+c)/t,this._z=.25*t}return this._onChangeCallback(),this}setFromUnitVectors(t,e){let n=t.dot(e)+1;return nMath.abs(t.z)?(this._x=-t.y,this._y=t.x,this._z=0,this._w=n):(this._x=0,this._y=-t.z,this._z=t.y,this._w=n)):(this._x=t.y*e.z-t.z*e.y,this._y=t.z*e.x-t.x*e.z,this._z=t.x*e.y-t.y*e.x,this._w=n),this.normalize()}angleTo(t){return 2*Math.acos(Math.abs(Yn(this.dot(t),-1,1)))}rotateTowards(t,e){const n=this.angleTo(t);if(0===n)return this;const i=Math.min(1,e/n);return this.slerp(t,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(t){return this._x*t._x+this._y*t._y+this._z*t._z+this._w*t._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let t=this.length();return 0===t?(this._x=0,this._y=0,this._z=0,this._w=1):(t=1/t,this._x=this._x*t,this._y=this._y*t,this._z=this._z*t,this._w=this._w*t),this._onChangeCallback(),this}multiply(t){return this.multiplyQuaternions(this,t)}premultiply(t){return this.multiplyQuaternions(t,this)}multiplyQuaternions(t,e){const n=t._x,i=t._y,r=t._z,s=t._w,a=e._x,o=e._y,l=e._z,c=e._w;return this._x=n*c+s*a+i*l-r*o,this._y=i*c+s*o+r*a-n*l,this._z=r*c+s*l+n*o-i*a,this._w=s*c-n*a-i*o-r*l,this._onChangeCallback(),this}slerp(t,e){if(0===e)return this;if(1===e)return this.copy(t);const n=this._x,i=this._y,r=this._z,s=this._w;let a=s*t._w+n*t._x+i*t._y+r*t._z;if(a<0?(this._w=-t._w,this._x=-t._x,this._y=-t._y,this._z=-t._z,a=-a):this.copy(t),a>=1)return this._w=s,this._x=n,this._y=i,this._z=r,this;const o=1-a*a;if(o<=Number.EPSILON){const t=1-e;return this._w=t*s+e*this._w,this._x=t*n+e*this._x,this._y=t*i+e*this._y,this._z=t*r+e*this._z,this.normalize(),this}const l=Math.sqrt(o),c=Math.atan2(l,a),h=Math.sin((1-e)*c)/l,u=Math.sin(e*c)/l;return this._w=s*h+this._w*u,this._x=n*h+this._x*u,this._y=i*h+this._y*u,this._z=r*h+this._z*u,this._onChangeCallback(),this}slerpQuaternions(t,e,n){return this.copy(t).slerp(e,n)}random(){const t=2*Math.PI*Math.random(),e=2*Math.PI*Math.random(),n=Math.random(),i=Math.sqrt(1-n),r=Math.sqrt(n);return this.set(i*Math.sin(t),i*Math.cos(t),r*Math.sin(e),r*Math.cos(e))}equals(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._w===this._w}fromArray(t,e=0){return this._x=t[e],this._y=t[e+1],this._z=t[e+2],this._w=t[e+3],this._onChangeCallback(),this}toArray(t=[],e=0){return t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._w,t}fromBufferAttribute(t,e){return this._x=t.getX(e),this._y=t.getY(e),this._z=t.getZ(e),this._w=t.getW(e),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(t){return this._onChangeCallback=t,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}class Li{constructor(t=0,e=0,n=0){Li.prototype.isVector3=!0,this.x=t,this.y=e,this.z=n}set(t,e,n){return void 0===n&&(n=this.z),this.x=t,this.y=e,this.z=n,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this}multiplyVectors(t,e){return this.x=t.x*e.x,this.y=t.y*e.y,this.z=t.z*e.z,this}applyEuler(t){return this.applyQuaternion(Ni.setFromEuler(t))}applyAxisAngle(t,e){return this.applyQuaternion(Ni.setFromAxisAngle(t,e))}applyMatrix3(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[3]*n+r[6]*i,this.y=r[1]*e+r[4]*n+r[7]*i,this.z=r[2]*e+r[5]*n+r[8]*i,this}applyNormalMatrix(t){return this.applyMatrix3(t).normalize()}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=t.elements,s=1/(r[3]*e+r[7]*n+r[11]*i+r[15]);return this.x=(r[0]*e+r[4]*n+r[8]*i+r[12])*s,this.y=(r[1]*e+r[5]*n+r[9]*i+r[13])*s,this.z=(r[2]*e+r[6]*n+r[10]*i+r[14])*s,this}applyQuaternion(t){const e=this.x,n=this.y,i=this.z,r=t.x,s=t.y,a=t.z,o=t.w,l=2*(s*i-a*n),c=2*(a*e-r*i),h=2*(r*n-s*e);return this.x=e+o*l+s*h-a*c,this.y=n+o*c+a*l-r*h,this.z=i+o*h+r*c-s*l,this}project(t){return this.applyMatrix4(t.matrixWorldInverse).applyMatrix4(t.projectionMatrix)}unproject(t){return this.applyMatrix4(t.projectionMatrixInverse).applyMatrix4(t.matrixWorld)}transformDirection(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[4]*n+r[8]*i,this.y=r[1]*e+r[5]*n+r[9]*i,this.z=r[2]*e+r[6]*n+r[10]*i,this.normalize()}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this}divideScalar(t){return this.multiplyScalar(1/t)}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this.z=Math.min(this.z,t.z),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this.z=Math.max(this.z,t.z),this}clamp(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this.z=Math.max(t.z,Math.min(e.z,this.z)),this}clampScalar(t,e){return this.x=Math.max(t,Math.min(e,this.x)),this.y=Math.max(t,Math.min(e,this.y)),this.z=Math.max(t,Math.min(e,this.z)),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(t,Math.min(e,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(t){return this.x*t.x+this.y*t.y+this.z*t.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this.z+=(t.z-this.z)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this.z=t.z+(e.z-t.z)*n,this}cross(t){return this.crossVectors(this,t)}crossVectors(t,e){const n=t.x,i=t.y,r=t.z,s=e.x,a=e.y,o=e.z;return this.x=i*o-r*a,this.y=r*s-n*o,this.z=n*a-i*s,this}projectOnVector(t){const e=t.lengthSq();if(0===e)return this.set(0,0,0);const n=t.dot(this)/e;return this.copy(t).multiplyScalar(n)}projectOnPlane(t){return Ui.copy(this).projectOnVector(t),this.sub(Ui)}reflect(t){return this.sub(Ui.copy(t).multiplyScalar(2*this.dot(t)))}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(0===e)return Math.PI/2;const n=this.dot(t)/e;return Math.acos(Yn(n,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y,i=this.z-t.z;return e*e+n*n+i*i}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)+Math.abs(this.z-t.z)}setFromSpherical(t){return this.setFromSphericalCoords(t.radius,t.phi,t.theta)}setFromSphericalCoords(t,e,n){const i=Math.sin(e)*t;return this.x=i*Math.sin(n),this.y=Math.cos(e)*t,this.z=i*Math.cos(n),this}setFromCylindrical(t){return this.setFromCylindricalCoords(t.radius,t.theta,t.y)}setFromCylindricalCoords(t,e,n){return this.x=t*Math.sin(e),this.y=n,this.z=t*Math.cos(e),this}setFromMatrixPosition(t){const e=t.elements;return this.x=e[12],this.y=e[13],this.z=e[14],this}setFromMatrixScale(t){const e=this.setFromMatrixColumn(t,0).length(),n=this.setFromMatrixColumn(t,1).length(),i=this.setFromMatrixColumn(t,2).length();return this.x=e,this.y=n,this.z=i,this}setFromMatrixColumn(t,e){return this.fromArray(t.elements,4*e)}setFromMatrix3Column(t,e){return this.fromArray(t.elements,3*e)}setFromEuler(t){return this.x=t._x,this.y=t._y,this.z=t._z,this}setFromColor(t){return this.x=t.r,this.y=t.g,this.z=t.b,this}equals(t){return t.x===this.x&&t.y===this.y&&t.z===this.z}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this.z=t[e+2],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t[e+2]=this.z,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this.z=t.getZ(e),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const t=Math.random()*Math.PI*2,e=2*Math.random()-1,n=Math.sqrt(1-e*e);return this.x=n*Math.cos(t),this.y=e,this.z=n*Math.sin(t),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const Ui=new Li,Ni=new Ii;class Di{constructor(t=new Li(1/0,1/0,1/0),e=new Li(-1/0,-1/0,-1/0)){this.isBox3=!0,this.min=t,this.max=e}set(t,e){return this.min.copy(t),this.max.copy(e),this}setFromArray(t){this.makeEmpty();for(let e=0,n=t.length;e=this.min.x&&t.x<=this.max.x&&t.y>=this.min.y&&t.y<=this.max.y&&t.z>=this.min.z&&t.z<=this.max.z}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y&&this.min.z<=t.min.z&&t.max.z<=this.max.z}getParameter(t,e){return e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y),(t.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(t){return t.max.x>=this.min.x&&t.min.x<=this.max.x&&t.max.y>=this.min.y&&t.min.y<=this.max.y&&t.max.z>=this.min.z&&t.min.z<=this.max.z}intersectsSphere(t){return this.clampPoint(t.center,Fi),Fi.distanceToSquared(t.center)<=t.radius*t.radius}intersectsPlane(t){let e,n;return t.normal.x>0?(e=t.normal.x*this.min.x,n=t.normal.x*this.max.x):(e=t.normal.x*this.max.x,n=t.normal.x*this.min.x),t.normal.y>0?(e+=t.normal.y*this.min.y,n+=t.normal.y*this.max.y):(e+=t.normal.y*this.max.y,n+=t.normal.y*this.min.y),t.normal.z>0?(e+=t.normal.z*this.min.z,n+=t.normal.z*this.max.z):(e+=t.normal.z*this.max.z,n+=t.normal.z*this.min.z),e<=-t.constant&&n>=-t.constant}intersectsTriangle(t){if(this.isEmpty())return!1;this.getCenter(Xi),ji.subVectors(this.max,Xi),zi.subVectors(t.a,Xi),ki.subVectors(t.b,Xi),Vi.subVectors(t.c,Xi),Hi.subVectors(ki,zi),Gi.subVectors(Vi,ki),Wi.subVectors(zi,Vi);let e=[0,-Hi.z,Hi.y,0,-Gi.z,Gi.y,0,-Wi.z,Wi.y,Hi.z,0,-Hi.x,Gi.z,0,-Gi.x,Wi.z,0,-Wi.x,-Hi.y,Hi.x,0,-Gi.y,Gi.x,0,-Wi.y,Wi.x,0];return!!Zi(e,zi,ki,Vi,ji)&&(e=[1,0,0,0,1,0,0,0,1],!!Zi(e,zi,ki,Vi,ji)&&(qi.crossVectors(Hi,Gi),e=[qi.x,qi.y,qi.z],Zi(e,zi,ki,Vi,ji)))}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return this.clampPoint(t,Fi).distanceTo(t)}getBoundingSphere(t){return this.isEmpty()?t.makeEmpty():(this.getCenter(t.center),t.radius=.5*this.getSize(Fi).length()),t}intersect(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}applyMatrix4(t){return this.isEmpty()||(Oi[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(t),Oi[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(t),Oi[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(t),Oi[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(t),Oi[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(t),Oi[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(t),Oi[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(t),Oi[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(t),this.setFromPoints(Oi)),this}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}}const Oi=[new Li,new Li,new Li,new Li,new Li,new Li,new Li,new Li],Fi=new Li,Bi=new Di,zi=new Li,ki=new Li,Vi=new Li,Hi=new Li,Gi=new Li,Wi=new Li,Xi=new Li,ji=new Li,qi=new Li,Yi=new Li;function Zi(t,e,n,i,r){for(let s=0,a=t.length-3;s<=a;s+=3){Yi.fromArray(t,s);const a=r.x*Math.abs(Yi.x)+r.y*Math.abs(Yi.y)+r.z*Math.abs(Yi.z),o=e.dot(Yi),l=n.dot(Yi),c=i.dot(Yi);if(Math.max(-Math.max(o,l,c),Math.min(o,l,c))>a)return!1}return!0}const Ji=new Di,Ki=new Li,$i=new Li;class Qi{constructor(t=new Li,e=-1){this.isSphere=!0,this.center=t,this.radius=e}set(t,e){return this.center.copy(t),this.radius=e,this}setFromPoints(t,e){const n=this.center;void 0!==e?n.copy(e):Ji.setFromPoints(t).getCenter(n);let i=0;for(let e=0,r=t.length;ethis.radius*this.radius&&(e.sub(this.center).normalize(),e.multiplyScalar(this.radius).add(this.center)),e}getBoundingBox(t){return this.isEmpty()?(t.makeEmpty(),t):(t.set(this.center,this.center),t.expandByScalar(this.radius),t)}applyMatrix4(t){return this.center.applyMatrix4(t),this.radius=this.radius*t.getMaxScaleOnAxis(),this}translate(t){return this.center.add(t),this}expandByPoint(t){if(this.isEmpty())return this.center.copy(t),this.radius=0,this;Ki.subVectors(t,this.center);const e=Ki.lengthSq();if(e>this.radius*this.radius){const t=Math.sqrt(e),n=.5*(t-this.radius);this.center.addScaledVector(Ki,n/t),this.radius+=n}return this}union(t){return t.isEmpty()?this:this.isEmpty()?(this.copy(t),this):(!0===this.center.equals(t.center)?this.radius=Math.max(this.radius,t.radius):($i.subVectors(t.center,this.center).setLength(t.radius),this.expandByPoint(Ki.copy(t.center).add($i)),this.expandByPoint(Ki.copy(t.center).sub($i))),this)}equals(t){return t.center.equals(this.center)&&t.radius===this.radius}clone(){return(new this.constructor).copy(this)}}const tr=new Li,er=new Li,nr=new Li,ir=new Li,rr=new Li,sr=new Li,ar=new Li;class or{constructor(t=new Li,e=new Li(0,0,-1)){this.origin=t,this.direction=e}set(t,e){return this.origin.copy(t),this.direction.copy(e),this}copy(t){return this.origin.copy(t.origin),this.direction.copy(t.direction),this}at(t,e){return e.copy(this.origin).addScaledVector(this.direction,t)}lookAt(t){return this.direction.copy(t).sub(this.origin).normalize(),this}recast(t){return this.origin.copy(this.at(t,tr)),this}closestPointToPoint(t,e){e.subVectors(t,this.origin);const n=e.dot(this.direction);return n<0?e.copy(this.origin):e.copy(this.origin).addScaledVector(this.direction,n)}distanceToPoint(t){return Math.sqrt(this.distanceSqToPoint(t))}distanceSqToPoint(t){const e=tr.subVectors(t,this.origin).dot(this.direction);return e<0?this.origin.distanceToSquared(t):(tr.copy(this.origin).addScaledVector(this.direction,e),tr.distanceToSquared(t))}distanceSqToSegment(t,e,n,i){er.copy(t).add(e).multiplyScalar(.5),nr.copy(e).sub(t).normalize(),ir.copy(this.origin).sub(er);const r=.5*t.distanceTo(e),s=-this.direction.dot(nr),a=ir.dot(this.direction),o=-ir.dot(nr),l=ir.lengthSq(),c=Math.abs(1-s*s);let h,u,d,p;if(c>0)if(h=s*o-a,u=s*a-o,p=r*c,h>=0)if(u>=-p)if(u<=p){const t=1/c;h*=t,u*=t,d=h*(h+s*u+2*a)+u*(s*h+u+2*o)+l}else u=r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;else u=-r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;else u<=-p?(h=Math.max(0,-(-s*r+a)),u=h>0?-r:Math.min(Math.max(-r,-o),r),d=-h*h+u*(u+2*o)+l):u<=p?(h=0,u=Math.min(Math.max(-r,-o),r),d=u*(u+2*o)+l):(h=Math.max(0,-(s*r+a)),u=h>0?r:Math.min(Math.max(-r,-o),r),d=-h*h+u*(u+2*o)+l);else u=s>0?-r:r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;return n&&n.copy(this.origin).addScaledVector(this.direction,h),i&&i.copy(er).addScaledVector(nr,u),d}intersectSphere(t,e){tr.subVectors(t.center,this.origin);const n=tr.dot(this.direction),i=tr.dot(tr)-n*n,r=t.radius*t.radius;if(i>r)return null;const s=Math.sqrt(r-i),a=n-s,o=n+s;return o<0?null:a<0?this.at(o,e):this.at(a,e)}intersectsSphere(t){return this.distanceSqToPoint(t.center)<=t.radius*t.radius}distanceToPlane(t){const e=t.normal.dot(this.direction);if(0===e)return 0===t.distanceToPoint(this.origin)?0:null;const n=-(this.origin.dot(t.normal)+t.constant)/e;return n>=0?n:null}intersectPlane(t,e){const n=this.distanceToPlane(t);return null===n?null:this.at(n,e)}intersectsPlane(t){const e=t.distanceToPoint(this.origin);if(0===e)return!0;return t.normal.dot(this.direction)*e<0}intersectBox(t,e){let n,i,r,s,a,o;const l=1/this.direction.x,c=1/this.direction.y,h=1/this.direction.z,u=this.origin;return l>=0?(n=(t.min.x-u.x)*l,i=(t.max.x-u.x)*l):(n=(t.max.x-u.x)*l,i=(t.min.x-u.x)*l),c>=0?(r=(t.min.y-u.y)*c,s=(t.max.y-u.y)*c):(r=(t.max.y-u.y)*c,s=(t.min.y-u.y)*c),n>s||r>i?null:((r>n||isNaN(n))&&(n=r),(s=0?(a=(t.min.z-u.z)*h,o=(t.max.z-u.z)*h):(a=(t.max.z-u.z)*h,o=(t.min.z-u.z)*h),n>o||a>i?null:((a>n||n!=n)&&(n=a),(o=0?n:i,e)))}intersectsBox(t){return null!==this.intersectBox(t,tr)}intersectTriangle(t,e,n,i,r){rr.subVectors(e,t),sr.subVectors(n,t),ar.crossVectors(rr,sr);let s,a=this.direction.dot(ar);if(a>0){if(i)return null;s=1}else{if(!(a<0))return null;s=-1,a=-a}ir.subVectors(this.origin,t);const o=s*this.direction.dot(sr.crossVectors(ir,sr));if(o<0)return null;const l=s*this.direction.dot(rr.cross(ir));if(l<0)return null;if(o+l>a)return null;const c=-s*ir.dot(ar);return c<0?null:this.at(c/a,r)}applyMatrix4(t){return this.origin.applyMatrix4(t),this.direction.transformDirection(t),this}equals(t){return t.origin.equals(this.origin)&&t.direction.equals(this.direction)}clone(){return(new this.constructor).copy(this)}}class lr{constructor(t,e,n,i,r,s,a,o,l,c,h,u,d,p,m,f){lr.prototype.isMatrix4=!0,this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],void 0!==t&&this.set(t,e,n,i,r,s,a,o,l,c,h,u,d,p,m,f)}set(t,e,n,i,r,s,a,o,l,c,h,u,d,p,m,f){const g=this.elements;return g[0]=t,g[4]=e,g[8]=n,g[12]=i,g[1]=r,g[5]=s,g[9]=a,g[13]=o,g[2]=l,g[6]=c,g[10]=h,g[14]=u,g[3]=d,g[7]=p,g[11]=m,g[15]=f,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return(new lr).fromArray(this.elements)}copy(t){const e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],e[9]=n[9],e[10]=n[10],e[11]=n[11],e[12]=n[12],e[13]=n[13],e[14]=n[14],e[15]=n[15],this}copyPosition(t){const e=this.elements,n=t.elements;return e[12]=n[12],e[13]=n[13],e[14]=n[14],this}setFromMatrix3(t){const e=t.elements;return this.set(e[0],e[3],e[6],0,e[1],e[4],e[7],0,e[2],e[5],e[8],0,0,0,0,1),this}extractBasis(t,e,n){return t.setFromMatrixColumn(this,0),e.setFromMatrixColumn(this,1),n.setFromMatrixColumn(this,2),this}makeBasis(t,e,n){return this.set(t.x,e.x,n.x,0,t.y,e.y,n.y,0,t.z,e.z,n.z,0,0,0,0,1),this}extractRotation(t){const e=this.elements,n=t.elements,i=1/cr.setFromMatrixColumn(t,0).length(),r=1/cr.setFromMatrixColumn(t,1).length(),s=1/cr.setFromMatrixColumn(t,2).length();return e[0]=n[0]*i,e[1]=n[1]*i,e[2]=n[2]*i,e[3]=0,e[4]=n[4]*r,e[5]=n[5]*r,e[6]=n[6]*r,e[7]=0,e[8]=n[8]*s,e[9]=n[9]*s,e[10]=n[10]*s,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this}makeRotationFromEuler(t){const e=this.elements,n=t.x,i=t.y,r=t.z,s=Math.cos(n),a=Math.sin(n),o=Math.cos(i),l=Math.sin(i),c=Math.cos(r),h=Math.sin(r);if("XYZ"===t.order){const t=s*c,n=s*h,i=a*c,r=a*h;e[0]=o*c,e[4]=-o*h,e[8]=l,e[1]=n+i*l,e[5]=t-r*l,e[9]=-a*o,e[2]=r-t*l,e[6]=i+n*l,e[10]=s*o}else if("YXZ"===t.order){const t=o*c,n=o*h,i=l*c,r=l*h;e[0]=t+r*a,e[4]=i*a-n,e[8]=s*l,e[1]=s*h,e[5]=s*c,e[9]=-a,e[2]=n*a-i,e[6]=r+t*a,e[10]=s*o}else if("ZXY"===t.order){const t=o*c,n=o*h,i=l*c,r=l*h;e[0]=t-r*a,e[4]=-s*h,e[8]=i+n*a,e[1]=n+i*a,e[5]=s*c,e[9]=r-t*a,e[2]=-s*l,e[6]=a,e[10]=s*o}else if("ZYX"===t.order){const t=s*c,n=s*h,i=a*c,r=a*h;e[0]=o*c,e[4]=i*l-n,e[8]=t*l+r,e[1]=o*h,e[5]=r*l+t,e[9]=n*l-i,e[2]=-l,e[6]=a*o,e[10]=s*o}else if("YZX"===t.order){const t=s*o,n=s*l,i=a*o,r=a*l;e[0]=o*c,e[4]=r-t*h,e[8]=i*h+n,e[1]=h,e[5]=s*c,e[9]=-a*c,e[2]=-l*c,e[6]=n*h+i,e[10]=t-r*h}else if("XZY"===t.order){const t=s*o,n=s*l,i=a*o,r=a*l;e[0]=o*c,e[4]=-h,e[8]=l*c,e[1]=t*h+r,e[5]=s*c,e[9]=n*h-i,e[2]=i*h-n,e[6]=a*c,e[10]=r*h+t}return e[3]=0,e[7]=0,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this}makeRotationFromQuaternion(t){return this.compose(ur,t,dr)}lookAt(t,e,n){const i=this.elements;return fr.subVectors(t,e),0===fr.lengthSq()&&(fr.z=1),fr.normalize(),pr.crossVectors(n,fr),0===pr.lengthSq()&&(1===Math.abs(n.z)?fr.x+=1e-4:fr.z+=1e-4,fr.normalize(),pr.crossVectors(n,fr)),pr.normalize(),mr.crossVectors(fr,pr),i[0]=pr.x,i[4]=mr.x,i[8]=fr.x,i[1]=pr.y,i[5]=mr.y,i[9]=fr.y,i[2]=pr.z,i[6]=mr.z,i[10]=fr.z,this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const n=t.elements,i=e.elements,r=this.elements,s=n[0],a=n[4],o=n[8],l=n[12],c=n[1],h=n[5],u=n[9],d=n[13],p=n[2],m=n[6],f=n[10],g=n[14],v=n[3],_=n[7],x=n[11],y=n[15],M=i[0],S=i[4],b=i[8],w=i[12],T=i[1],E=i[5],A=i[9],R=i[13],C=i[2],P=i[6],I=i[10],L=i[14],U=i[3],N=i[7],D=i[11],O=i[15];return r[0]=s*M+a*T+o*C+l*U,r[4]=s*S+a*E+o*P+l*N,r[8]=s*b+a*A+o*I+l*D,r[12]=s*w+a*R+o*L+l*O,r[1]=c*M+h*T+u*C+d*U,r[5]=c*S+h*E+u*P+d*N,r[9]=c*b+h*A+u*I+d*D,r[13]=c*w+h*R+u*L+d*O,r[2]=p*M+m*T+f*C+g*U,r[6]=p*S+m*E+f*P+g*N,r[10]=p*b+m*A+f*I+g*D,r[14]=p*w+m*R+f*L+g*O,r[3]=v*M+_*T+x*C+y*U,r[7]=v*S+_*E+x*P+y*N,r[11]=v*b+_*A+x*I+y*D,r[15]=v*w+_*R+x*L+y*O,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[4]*=t,e[8]*=t,e[12]*=t,e[1]*=t,e[5]*=t,e[9]*=t,e[13]*=t,e[2]*=t,e[6]*=t,e[10]*=t,e[14]*=t,e[3]*=t,e[7]*=t,e[11]*=t,e[15]*=t,this}determinant(){const t=this.elements,e=t[0],n=t[4],i=t[8],r=t[12],s=t[1],a=t[5],o=t[9],l=t[13],c=t[2],h=t[6],u=t[10],d=t[14];return t[3]*(+r*o*h-i*l*h-r*a*u+n*l*u+i*a*d-n*o*d)+t[7]*(+e*o*d-e*l*u+r*s*u-i*s*d+i*l*c-r*o*c)+t[11]*(+e*l*h-e*a*d-r*s*h+n*s*d+r*a*c-n*l*c)+t[15]*(-i*a*c-e*o*h+e*a*u+i*s*h-n*s*u+n*o*c)}transpose(){const t=this.elements;let e;return e=t[1],t[1]=t[4],t[4]=e,e=t[2],t[2]=t[8],t[8]=e,e=t[6],t[6]=t[9],t[9]=e,e=t[3],t[3]=t[12],t[12]=e,e=t[7],t[7]=t[13],t[13]=e,e=t[11],t[11]=t[14],t[14]=e,this}setPosition(t,e,n){const i=this.elements;return t.isVector3?(i[12]=t.x,i[13]=t.y,i[14]=t.z):(i[12]=t,i[13]=e,i[14]=n),this}invert(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8],h=t[9],u=t[10],d=t[11],p=t[12],m=t[13],f=t[14],g=t[15],v=h*f*l-m*u*l+m*o*d-a*f*d-h*o*g+a*u*g,_=p*u*l-c*f*l-p*o*d+s*f*d+c*o*g-s*u*g,x=c*m*l-p*h*l+p*a*d-s*m*d-c*a*g+s*h*g,y=p*h*o-c*m*o-p*a*u+s*m*u+c*a*f-s*h*f,M=e*v+n*_+i*x+r*y;if(0===M)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const S=1/M;return t[0]=v*S,t[1]=(m*u*r-h*f*r-m*i*d+n*f*d+h*i*g-n*u*g)*S,t[2]=(a*f*r-m*o*r+m*i*l-n*f*l-a*i*g+n*o*g)*S,t[3]=(h*o*r-a*u*r-h*i*l+n*u*l+a*i*d-n*o*d)*S,t[4]=_*S,t[5]=(c*f*r-p*u*r+p*i*d-e*f*d-c*i*g+e*u*g)*S,t[6]=(p*o*r-s*f*r-p*i*l+e*f*l+s*i*g-e*o*g)*S,t[7]=(s*u*r-c*o*r+c*i*l-e*u*l-s*i*d+e*o*d)*S,t[8]=x*S,t[9]=(p*h*r-c*m*r-p*n*d+e*m*d+c*n*g-e*h*g)*S,t[10]=(s*m*r-p*a*r+p*n*l-e*m*l-s*n*g+e*a*g)*S,t[11]=(c*a*r-s*h*r-c*n*l+e*h*l+s*n*d-e*a*d)*S,t[12]=y*S,t[13]=(c*m*i-p*h*i+p*n*u-e*m*u-c*n*f+e*h*f)*S,t[14]=(p*a*i-s*m*i-p*n*o+e*m*o+s*n*f-e*a*f)*S,t[15]=(s*h*i-c*a*i+c*n*o-e*h*o-s*n*u+e*a*u)*S,this}scale(t){const e=this.elements,n=t.x,i=t.y,r=t.z;return e[0]*=n,e[4]*=i,e[8]*=r,e[1]*=n,e[5]*=i,e[9]*=r,e[2]*=n,e[6]*=i,e[10]*=r,e[3]*=n,e[7]*=i,e[11]*=r,this}getMaxScaleOnAxis(){const t=this.elements,e=t[0]*t[0]+t[1]*t[1]+t[2]*t[2],n=t[4]*t[4]+t[5]*t[5]+t[6]*t[6],i=t[8]*t[8]+t[9]*t[9]+t[10]*t[10];return Math.sqrt(Math.max(e,n,i))}makeTranslation(t,e,n){return t.isVector3?this.set(1,0,0,t.x,0,1,0,t.y,0,0,1,t.z,0,0,0,1):this.set(1,0,0,t,0,1,0,e,0,0,1,n,0,0,0,1),this}makeRotationX(t){const e=Math.cos(t),n=Math.sin(t);return this.set(1,0,0,0,0,e,-n,0,0,n,e,0,0,0,0,1),this}makeRotationY(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,0,n,0,0,1,0,0,-n,0,e,0,0,0,0,1),this}makeRotationZ(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,-n,0,0,n,e,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(t,e){const n=Math.cos(e),i=Math.sin(e),r=1-n,s=t.x,a=t.y,o=t.z,l=r*s,c=r*a;return this.set(l*s+n,l*a-i*o,l*o+i*a,0,l*a+i*o,c*a+n,c*o-i*s,0,l*o-i*a,c*o+i*s,r*o*o+n,0,0,0,0,1),this}makeScale(t,e,n){return this.set(t,0,0,0,0,e,0,0,0,0,n,0,0,0,0,1),this}makeShear(t,e,n,i,r,s){return this.set(1,n,r,0,t,1,s,0,e,i,1,0,0,0,0,1),this}compose(t,e,n){const i=this.elements,r=e._x,s=e._y,a=e._z,o=e._w,l=r+r,c=s+s,h=a+a,u=r*l,d=r*c,p=r*h,m=s*c,f=s*h,g=a*h,v=o*l,_=o*c,x=o*h,y=n.x,M=n.y,S=n.z;return i[0]=(1-(m+g))*y,i[1]=(d+x)*y,i[2]=(p-_)*y,i[3]=0,i[4]=(d-x)*M,i[5]=(1-(u+g))*M,i[6]=(f+v)*M,i[7]=0,i[8]=(p+_)*S,i[9]=(f-v)*S,i[10]=(1-(u+m))*S,i[11]=0,i[12]=t.x,i[13]=t.y,i[14]=t.z,i[15]=1,this}decompose(t,e,n){const i=this.elements;let r=cr.set(i[0],i[1],i[2]).length();const s=cr.set(i[4],i[5],i[6]).length(),a=cr.set(i[8],i[9],i[10]).length();this.determinant()<0&&(r=-r),t.x=i[12],t.y=i[13],t.z=i[14],hr.copy(this);const o=1/r,l=1/s,c=1/a;return hr.elements[0]*=o,hr.elements[1]*=o,hr.elements[2]*=o,hr.elements[4]*=l,hr.elements[5]*=l,hr.elements[6]*=l,hr.elements[8]*=c,hr.elements[9]*=c,hr.elements[10]*=c,e.setFromRotationMatrix(hr),n.x=r,n.y=s,n.z=a,this}makePerspective(t,e,n,i,r,s,a=2e3){const o=this.elements,l=2*r/(e-t),c=2*r/(n-i),h=(e+t)/(e-t),u=(n+i)/(n-i);let d,p;if(a===kn)d=-(s+r)/(s-r),p=-2*s*r/(s-r);else{if(a!==Vn)throw new Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: "+a);d=-s/(s-r),p=-s*r/(s-r)}return o[0]=l,o[4]=0,o[8]=h,o[12]=0,o[1]=0,o[5]=c,o[9]=u,o[13]=0,o[2]=0,o[6]=0,o[10]=d,o[14]=p,o[3]=0,o[7]=0,o[11]=-1,o[15]=0,this}makeOrthographic(t,e,n,i,r,s,a=2e3){const o=this.elements,l=1/(e-t),c=1/(n-i),h=1/(s-r),u=(e+t)*l,d=(n+i)*c;let p,m;if(a===kn)p=(s+r)*h,m=-2*h;else{if(a!==Vn)throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+a);p=r*h,m=-1*h}return o[0]=2*l,o[4]=0,o[8]=0,o[12]=-u,o[1]=0,o[5]=2*c,o[9]=0,o[13]=-d,o[2]=0,o[6]=0,o[10]=m,o[14]=-p,o[3]=0,o[7]=0,o[11]=0,o[15]=1,this}equals(t){const e=this.elements,n=t.elements;for(let t=0;t<16;t++)if(e[t]!==n[t])return!1;return!0}fromArray(t,e=0){for(let n=0;n<16;n++)this.elements[n]=t[n+e];return this}toArray(t=[],e=0){const n=this.elements;return t[e]=n[0],t[e+1]=n[1],t[e+2]=n[2],t[e+3]=n[3],t[e+4]=n[4],t[e+5]=n[5],t[e+6]=n[6],t[e+7]=n[7],t[e+8]=n[8],t[e+9]=n[9],t[e+10]=n[10],t[e+11]=n[11],t[e+12]=n[12],t[e+13]=n[13],t[e+14]=n[14],t[e+15]=n[15],t}}const cr=new Li,hr=new lr,ur=new Li(0,0,0),dr=new Li(1,1,1),pr=new Li,mr=new Li,fr=new Li,gr=new lr,vr=new Ii;class _r{constructor(t=0,e=0,n=0,i=_r.DEFAULT_ORDER){this.isEuler=!0,this._x=t,this._y=e,this._z=n,this._order=i}get x(){return this._x}set x(t){this._x=t,this._onChangeCallback()}get y(){return this._y}set y(t){this._y=t,this._onChangeCallback()}get z(){return this._z}set z(t){this._z=t,this._onChangeCallback()}get order(){return this._order}set order(t){this._order=t,this._onChangeCallback()}set(t,e,n,i=this._order){return this._x=t,this._y=e,this._z=n,this._order=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(t){return this._x=t._x,this._y=t._y,this._z=t._z,this._order=t._order,this._onChangeCallback(),this}setFromRotationMatrix(t,e=this._order,n=!0){const i=t.elements,r=i[0],s=i[4],a=i[8],o=i[1],l=i[5],c=i[9],h=i[2],u=i[6],d=i[10];switch(e){case"XYZ":this._y=Math.asin(Yn(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(-c,d),this._z=Math.atan2(-s,r)):(this._x=Math.atan2(u,l),this._z=0);break;case"YXZ":this._x=Math.asin(-Yn(c,-1,1)),Math.abs(c)<.9999999?(this._y=Math.atan2(a,d),this._z=Math.atan2(o,l)):(this._y=Math.atan2(-h,r),this._z=0);break;case"ZXY":this._x=Math.asin(Yn(u,-1,1)),Math.abs(u)<.9999999?(this._y=Math.atan2(-h,d),this._z=Math.atan2(-s,l)):(this._y=0,this._z=Math.atan2(o,r));break;case"ZYX":this._y=Math.asin(-Yn(h,-1,1)),Math.abs(h)<.9999999?(this._x=Math.atan2(u,d),this._z=Math.atan2(o,r)):(this._x=0,this._z=Math.atan2(-s,l));break;case"YZX":this._z=Math.asin(Yn(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-c,l),this._y=Math.atan2(-h,r)):(this._x=0,this._y=Math.atan2(a,d));break;case"XZY":this._z=Math.asin(-Yn(s,-1,1)),Math.abs(s)<.9999999?(this._x=Math.atan2(u,l),this._y=Math.atan2(a,r)):(this._x=Math.atan2(-c,d),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+e)}return this._order=e,!0===n&&this._onChangeCallback(),this}setFromQuaternion(t,e,n){return gr.makeRotationFromQuaternion(t),this.setFromRotationMatrix(gr,e,n)}setFromVector3(t,e=this._order){return this.set(t.x,t.y,t.z,e)}reorder(t){return vr.setFromEuler(this),this.setFromQuaternion(vr,t)}equals(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._order===this._order}fromArray(t){return this._x=t[0],this._y=t[1],this._z=t[2],void 0!==t[3]&&(this._order=t[3]),this._onChangeCallback(),this}toArray(t=[],e=0){return t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._order,t}_onChange(t){return this._onChangeCallback=t,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._order}}_r.DEFAULT_ORDER="XYZ";class xr{constructor(){this.mask=1}set(t){this.mask=(1<>>0}enable(t){this.mask|=1<1){for(let t=0;t1){for(let t=0;t0&&(i.userData=this.userData),i.layers=this.layers.mask,i.matrix=this.matrix.toArray(),i.up=this.up.toArray(),!1===this.matrixAutoUpdate&&(i.matrixAutoUpdate=!1),this.isInstancedMesh&&(i.type="InstancedMesh",i.count=this.count,i.instanceMatrix=this.instanceMatrix.toJSON(),null!==this.instanceColor&&(i.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(i.type="BatchedMesh",i.perObjectFrustumCulled=this.perObjectFrustumCulled,i.sortObjects=this.sortObjects,i.drawRanges=this._drawRanges,i.reservedRanges=this._reservedRanges,i.visibility=this._visibility,i.active=this._active,i.bounds=this._bounds.map((t=>({boxInitialized:t.boxInitialized,boxMin:t.box.min.toArray(),boxMax:t.box.max.toArray(),sphereInitialized:t.sphereInitialized,sphereRadius:t.sphere.radius,sphereCenter:t.sphere.center.toArray()}))),i.maxInstanceCount=this._maxInstanceCount,i.maxVertexCount=this._maxVertexCount,i.maxIndexCount=this._maxIndexCount,i.geometryInitialized=this._geometryInitialized,i.geometryCount=this._geometryCount,i.matricesTexture=this._matricesTexture.toJSON(t),null!==this._colorsTexture&&(i.colorsTexture=this._colorsTexture.toJSON(t)),null!==this.boundingSphere&&(i.boundingSphere={center:i.boundingSphere.center.toArray(),radius:i.boundingSphere.radius}),null!==this.boundingBox&&(i.boundingBox={min:i.boundingBox.min.toArray(),max:i.boundingBox.max.toArray()})),this.isScene)this.background&&(this.background.isColor?i.background=this.background.toJSON():this.background.isTexture&&(i.background=this.background.toJSON(t).uuid)),this.environment&&this.environment.isTexture&&!0!==this.environment.isRenderTargetTexture&&(i.environment=this.environment.toJSON(t).uuid);else if(this.isMesh||this.isLine||this.isPoints){i.geometry=r(t.geometries,this.geometry);const e=this.geometry.parameters;if(void 0!==e&&void 0!==e.shapes){const n=e.shapes;if(Array.isArray(n))for(let e=0,i=n.length;e0){i.children=[];for(let e=0;e0){i.animations=[];for(let e=0;e0&&(n.geometries=e),i.length>0&&(n.materials=i),r.length>0&&(n.textures=r),a.length>0&&(n.images=a),o.length>0&&(n.shapes=o),l.length>0&&(n.skeletons=l),c.length>0&&(n.animations=c),h.length>0&&(n.nodes=h)}return n.object=i,n;function s(t){const e=[];for(const n in t){const i=t[n];delete i.metadata,e.push(i)}return e}}clone(t){return(new this.constructor).copy(this,t)}copy(t,e=!0){if(this.name=t.name,this.up.copy(t.up),this.position.copy(t.position),this.rotation.order=t.rotation.order,this.quaternion.copy(t.quaternion),this.scale.copy(t.scale),this.matrix.copy(t.matrix),this.matrixWorld.copy(t.matrixWorld),this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrixWorldAutoUpdate=t.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=t.matrixWorldNeedsUpdate,this.layers.mask=t.layers.mask,this.visible=t.visible,this.castShadow=t.castShadow,this.receiveShadow=t.receiveShadow,this.frustumCulled=t.frustumCulled,this.renderOrder=t.renderOrder,this.animations=t.animations.slice(),this.userData=JSON.parse(JSON.stringify(t.userData)),!0===e)for(let e=0;e0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(t,e,n,i,r){Or.subVectors(i,e),Fr.subVectors(n,e),Br.subVectors(t,e);const s=Or.dot(Or),a=Or.dot(Fr),o=Or.dot(Br),l=Fr.dot(Fr),c=Fr.dot(Br),h=s*l-a*a;if(0===h)return r.set(0,0,0),null;const u=1/h,d=(l*o-a*c)*u,p=(s*c-a*o)*u;return r.set(1-d-p,p,d)}static containsPoint(t,e,n,i){return null!==this.getBarycoord(t,e,n,i,zr)&&(zr.x>=0&&zr.y>=0&&zr.x+zr.y<=1)}static getInterpolation(t,e,n,i,r,s,a,o){return null===this.getBarycoord(t,e,n,i,zr)?(o.x=0,o.y=0,"z"in o&&(o.z=0),"w"in o&&(o.w=0),null):(o.setScalar(0),o.addScaledVector(r,zr.x),o.addScaledVector(s,zr.y),o.addScaledVector(a,zr.z),o)}static isFrontFacing(t,e,n,i){return Or.subVectors(n,e),Fr.subVectors(t,e),Or.cross(Fr).dot(i)<0}set(t,e,n){return this.a.copy(t),this.b.copy(e),this.c.copy(n),this}setFromPointsAndIndices(t,e,n,i){return this.a.copy(t[e]),this.b.copy(t[n]),this.c.copy(t[i]),this}setFromAttributeAndIndices(t,e,n,i){return this.a.fromBufferAttribute(t,e),this.b.fromBufferAttribute(t,n),this.c.fromBufferAttribute(t,i),this}clone(){return(new this.constructor).copy(this)}copy(t){return this.a.copy(t.a),this.b.copy(t.b),this.c.copy(t.c),this}getArea(){return Or.subVectors(this.c,this.b),Fr.subVectors(this.a,this.b),.5*Or.cross(Fr).length()}getMidpoint(t){return t.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(t){return jr.getNormal(this.a,this.b,this.c,t)}getPlane(t){return t.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(t,e){return jr.getBarycoord(t,this.a,this.b,this.c,e)}getInterpolation(t,e,n,i,r){return jr.getInterpolation(t,this.a,this.b,this.c,e,n,i,r)}containsPoint(t){return jr.containsPoint(t,this.a,this.b,this.c)}isFrontFacing(t){return jr.isFrontFacing(this.a,this.b,this.c,t)}intersectsBox(t){return t.intersectsTriangle(this)}closestPointToPoint(t,e){const n=this.a,i=this.b,r=this.c;let s,a;kr.subVectors(i,n),Vr.subVectors(r,n),Gr.subVectors(t,n);const o=kr.dot(Gr),l=Vr.dot(Gr);if(o<=0&&l<=0)return e.copy(n);Wr.subVectors(t,i);const c=kr.dot(Wr),h=Vr.dot(Wr);if(c>=0&&h<=c)return e.copy(i);const u=o*h-c*l;if(u<=0&&o>=0&&c<=0)return s=o/(o-c),e.copy(n).addScaledVector(kr,s);Xr.subVectors(t,r);const d=kr.dot(Xr),p=Vr.dot(Xr);if(p>=0&&d<=p)return e.copy(r);const m=d*l-o*p;if(m<=0&&l>=0&&p<=0)return a=l/(l-p),e.copy(n).addScaledVector(Vr,a);const f=c*p-d*h;if(f<=0&&h-c>=0&&d-p>=0)return Hr.subVectors(r,i),a=(h-c)/(h-c+(d-p)),e.copy(i).addScaledVector(Hr,a);const g=1/(f+m+u);return s=m*g,a=u*g,e.copy(n).addScaledVector(kr,s).addScaledVector(Vr,a)}equals(t){return t.a.equals(this.a)&&t.b.equals(this.b)&&t.c.equals(this.c)}}const qr={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},Yr={h:0,s:0,l:0},Zr={h:0,s:0,l:0};function Jr(t,e,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?t+6*(e-t)*n:n<.5?e:n<2/3?t+6*(e-t)*(2/3-n):t}class Kr{constructor(t,e,n){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(t,e,n)}set(t,e,n){if(void 0===e&&void 0===n){const e=t;e&&e.isColor?this.copy(e):"number"==typeof e?this.setHex(e):"string"==typeof e&&this.setStyle(e)}else this.setRGB(t,e,n);return this}setScalar(t){return this.r=t,this.g=t,this.b=t,this}setHex(t,e=Je){return t=Math.floor(t),this.r=(t>>16&255)/255,this.g=(t>>8&255)/255,this.b=(255&t)/255,mi.toWorkingColorSpace(this,e),this}setRGB(t,e,n,i=mi.workingColorSpace){return this.r=t,this.g=e,this.b=n,mi.toWorkingColorSpace(this,i),this}setHSL(t,e,n,i=mi.workingColorSpace){if(t=Zn(t,1),e=Yn(e,0,1),n=Yn(n,0,1),0===e)this.r=this.g=this.b=n;else{const i=n<=.5?n*(1+e):n+e-n*e,r=2*n-i;this.r=Jr(r,i,t+1/3),this.g=Jr(r,i,t),this.b=Jr(r,i,t-1/3)}return mi.toWorkingColorSpace(this,i),this}setStyle(t,e=Je){function n(e){void 0!==e&&parseFloat(e)<1&&console.warn("THREE.Color: Alpha component of "+t+" will be ignored.")}let i;if(i=/^(\w+)\(([^\)]*)\)/.exec(t)){let r;const s=i[1],a=i[2];switch(s){case"rgb":case"rgba":if(r=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setRGB(Math.min(255,parseInt(r[1],10))/255,Math.min(255,parseInt(r[2],10))/255,Math.min(255,parseInt(r[3],10))/255,e);if(r=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setRGB(Math.min(100,parseInt(r[1],10))/100,Math.min(100,parseInt(r[2],10))/100,Math.min(100,parseInt(r[3],10))/100,e);break;case"hsl":case"hsla":if(r=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setHSL(parseFloat(r[1])/360,parseFloat(r[2])/100,parseFloat(r[3])/100,e);break;default:console.warn("THREE.Color: Unknown color model "+t)}}else if(i=/^\#([A-Fa-f\d]+)$/.exec(t)){const n=i[1],r=n.length;if(3===r)return this.setRGB(parseInt(n.charAt(0),16)/15,parseInt(n.charAt(1),16)/15,parseInt(n.charAt(2),16)/15,e);if(6===r)return this.setHex(parseInt(n,16),e);console.warn("THREE.Color: Invalid hex color "+t)}else if(t&&t.length>0)return this.setColorName(t,e);return this}setColorName(t,e=Je){const n=qr[t.toLowerCase()];return void 0!==n?this.setHex(n,e):console.warn("THREE.Color: Unknown color "+t),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(t){return this.r=t.r,this.g=t.g,this.b=t.b,this}copySRGBToLinear(t){return this.r=fi(t.r),this.g=fi(t.g),this.b=fi(t.b),this}copyLinearToSRGB(t){return this.r=gi(t.r),this.g=gi(t.g),this.b=gi(t.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(t=Je){return mi.fromWorkingColorSpace($r.copy(this),t),65536*Math.round(Yn(255*$r.r,0,255))+256*Math.round(Yn(255*$r.g,0,255))+Math.round(Yn(255*$r.b,0,255))}getHexString(t=Je){return("000000"+this.getHex(t).toString(16)).slice(-6)}getHSL(t,e=mi.workingColorSpace){mi.fromWorkingColorSpace($r.copy(this),e);const n=$r.r,i=$r.g,r=$r.b,s=Math.max(n,i,r),a=Math.min(n,i,r);let o,l;const c=(a+s)/2;if(a===s)o=0,l=0;else{const t=s-a;switch(l=c<=.5?t/(s+a):t/(2-s-a),s){case n:o=(i-r)/t+(i0!=t>0&&this.version++,this._alphaTest=t}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(t){if(void 0!==t)for(const e in t){const n=t[e];if(void 0===n){console.warn(`THREE.Material: parameter '${e}' has value of undefined.`);continue}const i=this[e];void 0!==i?i&&i.isColor?i.set(n):i&&i.isVector3&&n&&n.isVector3?i.copy(n):this[e]=n:console.warn(`THREE.Material: '${e}' is not a property of THREE.${this.type}.`)}}toJSON(t){const e=void 0===t||"string"==typeof t;e&&(t={textures:{},images:{}});const n={metadata:{version:4.6,type:"Material",generator:"Material.toJSON"}};function i(t){const e=[];for(const n in t){const i=t[n];delete i.metadata,e.push(i)}return e}if(n.uuid=this.uuid,n.type=this.type,""!==this.name&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),void 0!==this.roughness&&(n.roughness=this.roughness),void 0!==this.metalness&&(n.metalness=this.metalness),void 0!==this.sheen&&(n.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(n.sheenColor=this.sheenColor.getHex()),void 0!==this.sheenRoughness&&(n.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),void 0!==this.emissiveIntensity&&1!==this.emissiveIntensity&&(n.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),void 0!==this.specularIntensity&&(n.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(n.specularColor=this.specularColor.getHex()),void 0!==this.shininess&&(n.shininess=this.shininess),void 0!==this.clearcoat&&(n.clearcoat=this.clearcoat),void 0!==this.clearcoatRoughness&&(n.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(n.clearcoatMap=this.clearcoatMap.toJSON(t).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(t).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(t).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),void 0!==this.dispersion&&(n.dispersion=this.dispersion),void 0!==this.iridescence&&(n.iridescence=this.iridescence),void 0!==this.iridescenceIOR&&(n.iridescenceIOR=this.iridescenceIOR),void 0!==this.iridescenceThicknessRange&&(n.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(n.iridescenceMap=this.iridescenceMap.toJSON(t).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(n.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(t).uuid),void 0!==this.anisotropy&&(n.anisotropy=this.anisotropy),void 0!==this.anisotropyRotation&&(n.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(n.anisotropyMap=this.anisotropyMap.toJSON(t).uuid),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(t).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(t).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(t).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(t).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(t).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(t).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(t).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(t).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(t).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(t).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(t).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(t).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(n.specularIntensityMap=this.specularIntensityMap.toJSON(t).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(n.specularColorMap=this.specularColorMap.toJSON(t).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(t).uuid,void 0!==this.combine&&(n.combine=this.combine)),void 0!==this.envMapRotation&&(n.envMapRotation=this.envMapRotation.toArray()),void 0!==this.envMapIntensity&&(n.envMapIntensity=this.envMapIntensity),void 0!==this.reflectivity&&(n.reflectivity=this.reflectivity),void 0!==this.refractionRatio&&(n.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(t).uuid),void 0!==this.transmission&&(n.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(n.transmissionMap=this.transmissionMap.toJSON(t).uuid),void 0!==this.thickness&&(n.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(n.thicknessMap=this.thicknessMap.toJSON(t).uuid),void 0!==this.attenuationDistance&&this.attenuationDistance!==1/0&&(n.attenuationDistance=this.attenuationDistance),void 0!==this.attenuationColor&&(n.attenuationColor=this.attenuationColor.getHex()),void 0!==this.size&&(n.size=this.size),null!==this.shadowSide&&(n.shadowSide=this.shadowSide),void 0!==this.sizeAttenuation&&(n.sizeAttenuation=this.sizeAttenuation),1!==this.blending&&(n.blending=this.blending),this.side!==u&&(n.side=this.side),!0===this.vertexColors&&(n.vertexColors=!0),this.opacity<1&&(n.opacity=this.opacity),!0===this.transparent&&(n.transparent=!0),this.blendSrc!==C&&(n.blendSrc=this.blendSrc),this.blendDst!==P&&(n.blendDst=this.blendDst),this.blendEquation!==y&&(n.blendEquation=this.blendEquation),null!==this.blendSrcAlpha&&(n.blendSrcAlpha=this.blendSrcAlpha),null!==this.blendDstAlpha&&(n.blendDstAlpha=this.blendDstAlpha),null!==this.blendEquationAlpha&&(n.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(n.blendColor=this.blendColor.getHex()),0!==this.blendAlpha&&(n.blendAlpha=this.blendAlpha),3!==this.depthFunc&&(n.depthFunc=this.depthFunc),!1===this.depthTest&&(n.depthTest=this.depthTest),!1===this.depthWrite&&(n.depthWrite=this.depthWrite),!1===this.colorWrite&&(n.colorWrite=this.colorWrite),255!==this.stencilWriteMask&&(n.stencilWriteMask=this.stencilWriteMask),519!==this.stencilFunc&&(n.stencilFunc=this.stencilFunc),0!==this.stencilRef&&(n.stencilRef=this.stencilRef),255!==this.stencilFuncMask&&(n.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==an&&(n.stencilFail=this.stencilFail),this.stencilZFail!==an&&(n.stencilZFail=this.stencilZFail),this.stencilZPass!==an&&(n.stencilZPass=this.stencilZPass),!0===this.stencilWrite&&(n.stencilWrite=this.stencilWrite),void 0!==this.rotation&&0!==this.rotation&&(n.rotation=this.rotation),!0===this.polygonOffset&&(n.polygonOffset=!0),0!==this.polygonOffsetFactor&&(n.polygonOffsetFactor=this.polygonOffsetFactor),0!==this.polygonOffsetUnits&&(n.polygonOffsetUnits=this.polygonOffsetUnits),void 0!==this.linewidth&&1!==this.linewidth&&(n.linewidth=this.linewidth),void 0!==this.dashSize&&(n.dashSize=this.dashSize),void 0!==this.gapSize&&(n.gapSize=this.gapSize),void 0!==this.scale&&(n.scale=this.scale),!0===this.dithering&&(n.dithering=!0),this.alphaTest>0&&(n.alphaTest=this.alphaTest),!0===this.alphaHash&&(n.alphaHash=!0),!0===this.alphaToCoverage&&(n.alphaToCoverage=!0),!0===this.premultipliedAlpha&&(n.premultipliedAlpha=!0),!0===this.forceSinglePass&&(n.forceSinglePass=!0),!0===this.wireframe&&(n.wireframe=!0),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),"round"!==this.wireframeLinecap&&(n.wireframeLinecap=this.wireframeLinecap),"round"!==this.wireframeLinejoin&&(n.wireframeLinejoin=this.wireframeLinejoin),!0===this.flatShading&&(n.flatShading=!0),!1===this.visible&&(n.visible=!1),!1===this.toneMapped&&(n.toneMapped=!1),!1===this.fog&&(n.fog=!1),Object.keys(this.userData).length>0&&(n.userData=this.userData),e){const e=i(t.textures),r=i(t.images);e.length>0&&(n.textures=e),r.length>0&&(n.images=r)}return n}clone(){return(new this.constructor).copy(this)}copy(t){this.name=t.name,this.blending=t.blending,this.side=t.side,this.vertexColors=t.vertexColors,this.opacity=t.opacity,this.transparent=t.transparent,this.blendSrc=t.blendSrc,this.blendDst=t.blendDst,this.blendEquation=t.blendEquation,this.blendSrcAlpha=t.blendSrcAlpha,this.blendDstAlpha=t.blendDstAlpha,this.blendEquationAlpha=t.blendEquationAlpha,this.blendColor.copy(t.blendColor),this.blendAlpha=t.blendAlpha,this.depthFunc=t.depthFunc,this.depthTest=t.depthTest,this.depthWrite=t.depthWrite,this.stencilWriteMask=t.stencilWriteMask,this.stencilFunc=t.stencilFunc,this.stencilRef=t.stencilRef,this.stencilFuncMask=t.stencilFuncMask,this.stencilFail=t.stencilFail,this.stencilZFail=t.stencilZFail,this.stencilZPass=t.stencilZPass,this.stencilWrite=t.stencilWrite;const e=t.clippingPlanes;let n=null;if(null!==e){const t=e.length;n=new Array(t);for(let i=0;i!==t;++i)n[i]=e[i].clone()}return this.clippingPlanes=n,this.clipIntersection=t.clipIntersection,this.clipShadows=t.clipShadows,this.shadowSide=t.shadowSide,this.colorWrite=t.colorWrite,this.precision=t.precision,this.polygonOffset=t.polygonOffset,this.polygonOffsetFactor=t.polygonOffsetFactor,this.polygonOffsetUnits=t.polygonOffsetUnits,this.dithering=t.dithering,this.alphaTest=t.alphaTest,this.alphaHash=t.alphaHash,this.alphaToCoverage=t.alphaToCoverage,this.premultipliedAlpha=t.premultipliedAlpha,this.forceSinglePass=t.forceSinglePass,this.visible=t.visible,this.toneMapped=t.toneMapped,this.userData=JSON.parse(JSON.stringify(t.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(t){!0===t&&this.version++}onBuild(){console.warn("Material: onBuild() has been removed.")}}class es extends ts{constructor(t){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new Kr(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new _r,this.combine=Y,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.fog=t.fog,this}}const ns=is();function is(){const t=new ArrayBuffer(4),e=new Float32Array(t),n=new Uint32Array(t),i=new Uint32Array(512),r=new Uint32Array(512);for(let t=0;t<256;++t){const e=t-127;e<-27?(i[t]=0,i[256|t]=32768,r[t]=24,r[256|t]=24):e<-14?(i[t]=1024>>-e-14,i[256|t]=1024>>-e-14|32768,r[t]=-e-1,r[256|t]=-e-1):e<=15?(i[t]=e+15<<10,i[256|t]=e+15<<10|32768,r[t]=13,r[256|t]=13):e<128?(i[t]=31744,i[256|t]=64512,r[t]=24,r[256|t]=24):(i[t]=31744,i[256|t]=64512,r[t]=13,r[256|t]=13)}const s=new Uint32Array(2048),a=new Uint32Array(64),o=new Uint32Array(64);for(let t=1;t<1024;++t){let e=t<<13,n=0;for(;0==(8388608&e);)e<<=1,n-=8388608;e&=-8388609,n+=947912704,s[t]=e|n}for(let t=1024;t<2048;++t)s[t]=939524096+(t-1024<<13);for(let t=1;t<31;++t)a[t]=t<<23;a[31]=1199570944,a[32]=2147483648;for(let t=33;t<63;++t)a[t]=2147483648+(t-32<<23);a[63]=3347054592;for(let t=1;t<64;++t)32!==t&&(o[t]=1024);return{floatView:e,uint32View:n,baseTable:i,shiftTable:r,mantissaTable:s,exponentTable:a,offsetTable:o}}function rs(t){Math.abs(t)>65504&&console.warn("THREE.DataUtils.toHalfFloat(): Value out of range."),t=Yn(t,-65504,65504),ns.floatView[0]=t;const e=ns.uint32View[0],n=e>>23&511;return ns.baseTable[n]+((8388607&e)>>ns.shiftTable[n])}function ss(t){const e=t>>10;return ns.uint32View[0]=ns.mantissaTable[ns.offsetTable[e]+(1023&t)]+ns.exponentTable[e],ns.floatView[0]}const as={toHalfFloat:rs,fromHalfFloat:ss},os=new Li,ls=new ti;class cs{constructor(t,e,n=!1){if(Array.isArray(t))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,this.name="",this.array=t,this.itemSize=e,this.count=void 0!==t?t.length/e:0,this.normalized=n,this.usage=Cn,this._updateRange={offset:0,count:-1},this.updateRanges=[],this.gpuType=Lt,this.version=0}onUploadCallback(){}set needsUpdate(t){!0===t&&this.version++}get updateRange(){return ci("THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead."),this._updateRange}setUsage(t){return this.usage=t,this}addUpdateRange(t,e){this.updateRanges.push({start:t,count:e})}clearUpdateRanges(){this.updateRanges.length=0}copy(t){return this.name=t.name,this.array=new t.array.constructor(t.array),this.itemSize=t.itemSize,this.count=t.count,this.normalized=t.normalized,this.usage=t.usage,this.gpuType=t.gpuType,this}copyAt(t,e,n){t*=this.itemSize,n*=e.itemSize;for(let i=0,r=this.itemSize;i0&&(t.userData=this.userData),void 0!==this.parameters){const e=this.parameters;for(const n in e)void 0!==e[n]&&(t[n]=e[n]);return t}t.data={attributes:{}};const e=this.index;null!==e&&(t.data.index={type:e.array.constructor.name,array:Array.prototype.slice.call(e.array)});const n=this.attributes;for(const e in n){const i=n[e];t.data.attributes[e]=i.toJSON(t.data)}const i={};let r=!1;for(const e in this.morphAttributes){const n=this.morphAttributes[e],s=[];for(let e=0,i=n.length;e0&&(i[e]=s,r=!0)}r&&(t.data.morphAttributes=i,t.data.morphTargetsRelative=this.morphTargetsRelative);const s=this.groups;s.length>0&&(t.data.groups=JSON.parse(JSON.stringify(s)));const a=this.boundingSphere;return null!==a&&(t.data.boundingSphere={center:a.center.toArray(),radius:a.radius}),t}clone(){return(new this.constructor).copy(this)}copy(t){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const e={};this.name=t.name;const n=t.index;null!==n&&this.setIndex(n.clone(e));const i=t.attributes;for(const t in i){const n=i[t];this.setAttribute(t,n.clone(e))}const r=t.morphAttributes;for(const t in r){const n=[],i=r[t];for(let t=0,r=i.length;t0){const n=t[e[0]];if(void 0!==n){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=n.length;t(t.far-t.near)**2)return}As.copy(r).invert(),Rs.copy(t.ray).applyMatrix4(As),null!==n.boundingBox&&!1===Rs.intersectsBox(n.boundingBox)||this._computeIntersections(t,e,Rs)}}_computeIntersections(t,e,n){let i;const r=this.geometry,s=this.material,a=r.index,o=r.attributes.position,l=r.attributes.uv,c=r.attributes.uv1,h=r.attributes.normal,u=r.groups,d=r.drawRange;if(null!==a)if(Array.isArray(s))for(let r=0,o=u.length;rn.far?null:{distance:c,point:Gs.clone(),object:t}}(t,e,n,i,Is,Ls,Us,Hs);if(h){r&&(Os.fromBufferAttribute(r,o),Fs.fromBufferAttribute(r,l),Bs.fromBufferAttribute(r,c),h.uv=jr.getInterpolation(Hs,Is,Ls,Us,Os,Fs,Bs,new ti)),s&&(Os.fromBufferAttribute(s,o),Fs.fromBufferAttribute(s,l),Bs.fromBufferAttribute(s,c),h.uv1=jr.getInterpolation(Hs,Is,Ls,Us,Os,Fs,Bs,new ti)),a&&(zs.fromBufferAttribute(a,o),ks.fromBufferAttribute(a,l),Vs.fromBufferAttribute(a,c),h.normal=jr.getInterpolation(Hs,Is,Ls,Us,zs,ks,Vs,new Li),h.normal.dot(i.direction)>0&&h.normal.multiplyScalar(-1));const t={a:o,b:l,c:c,normal:new Li,materialIndex:0};jr.getNormal(Is,Ls,Us,t.normal),h.face=t}return h}class js extends Es{constructor(t=1,e=1,n=1,i=1,r=1,s=1){super(),this.type="BoxGeometry",this.parameters={width:t,height:e,depth:n,widthSegments:i,heightSegments:r,depthSegments:s};const a=this;i=Math.floor(i),r=Math.floor(r),s=Math.floor(s);const o=[],l=[],c=[],h=[];let u=0,d=0;function p(t,e,n,i,r,s,p,m,f,g,v){const _=s/f,x=p/g,y=s/2,M=p/2,S=m/2,b=f+1,w=g+1;let T=0,E=0;const A=new Li;for(let s=0;s0?1:-1,c.push(A.x,A.y,A.z),h.push(o/f),h.push(1-s/g),T+=1}}for(let t=0;t0&&(e.defines=this.defines),e.vertexShader=this.vertexShader,e.fragmentShader=this.fragmentShader,e.lights=this.lights,e.clipping=this.clipping;const n={};for(const t in this.extensions)!0===this.extensions[t]&&(n[t]=!0);return Object.keys(n).length>0&&(e.extensions=n),e}}class $s extends Dr{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new lr,this.projectionMatrix=new lr,this.projectionMatrixInverse=new lr,this.coordinateSystem=kn}copy(t,e){return super.copy(t,e),this.matrixWorldInverse.copy(t.matrixWorldInverse),this.projectionMatrix.copy(t.projectionMatrix),this.projectionMatrixInverse.copy(t.projectionMatrixInverse),this.coordinateSystem=t.coordinateSystem,this}getWorldDirection(t){return super.getWorldDirection(t).negate()}updateMatrixWorld(t){super.updateMatrixWorld(t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(t,e){super.updateWorldMatrix(t,e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return(new this.constructor).copy(this)}}const Qs=new Li,ta=new ti,ea=new ti;class na extends $s{constructor(t=50,e=1,n=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=t,this.zoom=1,this.near=n,this.far=i,this.focus=10,this.aspect=e,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(t,e){return super.copy(t,e),this.fov=t.fov,this.zoom=t.zoom,this.near=t.near,this.far=t.far,this.focus=t.focus,this.aspect=t.aspect,this.view=null===t.view?null:Object.assign({},t.view),this.filmGauge=t.filmGauge,this.filmOffset=t.filmOffset,this}setFocalLength(t){const e=.5*this.getFilmHeight()/t;this.fov=2*jn*Math.atan(e),this.updateProjectionMatrix()}getFocalLength(){const t=Math.tan(.5*Xn*this.fov);return.5*this.getFilmHeight()/t}getEffectiveFOV(){return 2*jn*Math.atan(Math.tan(.5*Xn*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(t,e,n){Qs.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),e.set(Qs.x,Qs.y).multiplyScalar(-t/Qs.z),Qs.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),n.set(Qs.x,Qs.y).multiplyScalar(-t/Qs.z)}getViewSize(t,e){return this.getViewBounds(t,ta,ea),e.subVectors(ea,ta)}setViewOffset(t,e,n,i,r,s){this.aspect=t/e,null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=t,this.view.fullHeight=e,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=s,this.updateProjectionMatrix()}clearViewOffset(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const t=this.near;let e=t*Math.tan(.5*Xn*this.fov)/this.zoom,n=2*e,i=this.aspect*n,r=-.5*i;const s=this.view;if(null!==this.view&&this.view.enabled){const t=s.fullWidth,a=s.fullHeight;r+=s.offsetX*i/t,e-=s.offsetY*n/a,i*=s.width/t,n*=s.height/a}const a=this.filmOffset;0!==a&&(r+=t*a/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,e,e-n,t,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(t){const e=super.toJSON(t);return e.object.fov=this.fov,e.object.zoom=this.zoom,e.object.near=this.near,e.object.far=this.far,e.object.focus=this.focus,e.object.aspect=this.aspect,null!==this.view&&(e.object.view=Object.assign({},this.view)),e.object.filmGauge=this.filmGauge,e.object.filmOffset=this.filmOffset,e}}const ia=-90;class ra extends Dr{constructor(t,e,n){super(),this.type="CubeCamera",this.renderTarget=n,this.coordinateSystem=null,this.activeMipmapLevel=0;const i=new na(ia,1,t,e);i.layers=this.layers,this.add(i);const r=new na(ia,1,t,e);r.layers=this.layers,this.add(r);const s=new na(ia,1,t,e);s.layers=this.layers,this.add(s);const a=new na(ia,1,t,e);a.layers=this.layers,this.add(a);const o=new na(ia,1,t,e);o.layers=this.layers,this.add(o);const l=new na(ia,1,t,e);l.layers=this.layers,this.add(l)}updateCoordinateSystem(){const t=this.coordinateSystem,e=this.children.concat(),[n,i,r,s,a,o]=e;for(const t of e)this.remove(t);if(t===kn)n.up.set(0,1,0),n.lookAt(1,0,0),i.up.set(0,1,0),i.lookAt(-1,0,0),r.up.set(0,0,-1),r.lookAt(0,1,0),s.up.set(0,0,1),s.lookAt(0,-1,0),a.up.set(0,1,0),a.lookAt(0,0,1),o.up.set(0,1,0),o.lookAt(0,0,-1);else{if(t!==Vn)throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+t);n.up.set(0,-1,0),n.lookAt(-1,0,0),i.up.set(0,-1,0),i.lookAt(1,0,0),r.up.set(0,0,1),r.lookAt(0,1,0),s.up.set(0,0,-1),s.lookAt(0,-1,0),a.up.set(0,-1,0),a.lookAt(0,0,1),o.up.set(0,-1,0),o.lookAt(0,0,-1)}for(const t of e)this.add(t),t.updateMatrixWorld()}update(t,e){null===this.parent&&this.updateMatrixWorld();const{renderTarget:n,activeMipmapLevel:i}=this;this.coordinateSystem!==t.coordinateSystem&&(this.coordinateSystem=t.coordinateSystem,this.updateCoordinateSystem());const[r,s,a,o,l,c]=this.children,h=t.getRenderTarget(),u=t.getActiveCubeFace(),d=t.getActiveMipmapLevel(),p=t.xr.enabled;t.xr.enabled=!1;const m=n.texture.generateMipmaps;n.texture.generateMipmaps=!1,t.setRenderTarget(n,0,i),t.render(e,r),t.setRenderTarget(n,1,i),t.render(e,s),t.setRenderTarget(n,2,i),t.render(e,a),t.setRenderTarget(n,3,i),t.render(e,o),t.setRenderTarget(n,4,i),t.render(e,l),n.texture.generateMipmaps=m,t.setRenderTarget(n,5,i),t.render(e,c),t.setRenderTarget(h,u,d),t.xr.enabled=p,n.texture.needsPMREMUpdate=!0}}class sa extends bi{constructor(t,e,n,i,r,s,a,o,l,c){super(t=void 0!==t?t:[],e=void 0!==e?e:lt,n,i,r,s,a,o,l,c),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(t){this.image=t}}class aa extends Ei{constructor(t=1,e={}){super(t,t,e),this.isWebGLCubeRenderTarget=!0;const n={width:t,height:t,depth:1},i=[n,n,n,n,n,n];this.texture=new sa(i,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.format,e.type,e.anisotropy,e.colorSpace),this.texture.isRenderTargetTexture=!0,this.texture.generateMipmaps=void 0!==e.generateMipmaps&&e.generateMipmaps,this.texture.minFilter=void 0!==e.minFilter?e.minFilter:Mt}fromEquirectangularTexture(t,e){this.texture.type=e.type,this.texture.colorSpace=e.colorSpace,this.texture.generateMipmaps=e.generateMipmaps,this.texture.minFilter=e.minFilter,this.texture.magFilter=e.magFilter;const n={uniforms:{tEquirect:{value:null}},vertexShader:"\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\tvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\n\t\t\t\t\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvWorldDirection = transformDirection( position, modelMatrix );\n\n\t\t\t\t\t#include \n\t\t\t\t\t#include \n\n\t\t\t\t}\n\t\t\t",fragmentShader:"\n\n\t\t\t\tuniform sampler2D tEquirect;\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\t#include \n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvec3 direction = normalize( vWorldDirection );\n\n\t\t\t\t\tvec2 sampleUV = equirectUv( direction );\n\n\t\t\t\t\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\n\t\t\t\t}\n\t\t\t"},i=new js(5,5,5),r=new Ks({name:"CubemapFromEquirect",uniforms:qs(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:d,blending:0});r.uniforms.tEquirect.value=e;const s=new Ws(i,r),a=e.minFilter;e.minFilter===wt&&(e.minFilter=Mt);return new ra(1,10,this).update(t,s),e.minFilter=a,s.geometry.dispose(),s.material.dispose(),this}clear(t,e,n,i){const r=t.getRenderTarget();for(let r=0;r<6;r++)t.setRenderTarget(this,r),t.clear(e,n,i);t.setRenderTarget(r)}}const oa=new Li,la=new Li,ca=new ei;class ha{constructor(t=new Li(1,0,0),e=0){this.isPlane=!0,this.normal=t,this.constant=e}set(t,e){return this.normal.copy(t),this.constant=e,this}setComponents(t,e,n,i){return this.normal.set(t,e,n),this.constant=i,this}setFromNormalAndCoplanarPoint(t,e){return this.normal.copy(t),this.constant=-e.dot(this.normal),this}setFromCoplanarPoints(t,e,n){const i=oa.subVectors(n,e).cross(la.subVectors(t,e)).normalize();return this.setFromNormalAndCoplanarPoint(i,t),this}copy(t){return this.normal.copy(t.normal),this.constant=t.constant,this}normalize(){const t=1/this.normal.length();return this.normal.multiplyScalar(t),this.constant*=t,this}negate(){return this.constant*=-1,this.normal.negate(),this}distanceToPoint(t){return this.normal.dot(t)+this.constant}distanceToSphere(t){return this.distanceToPoint(t.center)-t.radius}projectPoint(t,e){return e.copy(t).addScaledVector(this.normal,-this.distanceToPoint(t))}intersectLine(t,e){const n=t.delta(oa),i=this.normal.dot(n);if(0===i)return 0===this.distanceToPoint(t.start)?e.copy(t.start):null;const r=-(t.start.dot(this.normal)+this.constant)/i;return r<0||r>1?null:e.copy(t.start).addScaledVector(n,r)}intersectsLine(t){const e=this.distanceToPoint(t.start),n=this.distanceToPoint(t.end);return e<0&&n>0||n<0&&e>0}intersectsBox(t){return t.intersectsPlane(this)}intersectsSphere(t){return t.intersectsPlane(this)}coplanarPoint(t){return t.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(t,e){const n=e||ca.getNormalMatrix(t),i=this.coplanarPoint(oa).applyMatrix4(t),r=this.normal.applyMatrix3(n).normalize();return this.constant=-i.dot(r),this}translate(t){return this.constant-=t.dot(this.normal),this}equals(t){return t.normal.equals(this.normal)&&t.constant===this.constant}clone(){return(new this.constructor).copy(this)}}const ua=new Qi,da=new Li;class pa{constructor(t=new ha,e=new ha,n=new ha,i=new ha,r=new ha,s=new ha){this.planes=[t,e,n,i,r,s]}set(t,e,n,i,r,s){const a=this.planes;return a[0].copy(t),a[1].copy(e),a[2].copy(n),a[3].copy(i),a[4].copy(r),a[5].copy(s),this}copy(t){const e=this.planes;for(let n=0;n<6;n++)e[n].copy(t.planes[n]);return this}setFromProjectionMatrix(t,e=2e3){const n=this.planes,i=t.elements,r=i[0],s=i[1],a=i[2],o=i[3],l=i[4],c=i[5],h=i[6],u=i[7],d=i[8],p=i[9],m=i[10],f=i[11],g=i[12],v=i[13],_=i[14],x=i[15];if(n[0].setComponents(o-r,u-l,f-d,x-g).normalize(),n[1].setComponents(o+r,u+l,f+d,x+g).normalize(),n[2].setComponents(o+s,u+c,f+p,x+v).normalize(),n[3].setComponents(o-s,u-c,f-p,x-v).normalize(),n[4].setComponents(o-a,u-h,f-m,x-_).normalize(),e===kn)n[5].setComponents(o+a,u+h,f+m,x+_).normalize();else{if(e!==Vn)throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+e);n[5].setComponents(a,h,m,_).normalize()}return this}intersectsObject(t){if(void 0!==t.boundingSphere)null===t.boundingSphere&&t.computeBoundingSphere(),ua.copy(t.boundingSphere).applyMatrix4(t.matrixWorld);else{const e=t.geometry;null===e.boundingSphere&&e.computeBoundingSphere(),ua.copy(e.boundingSphere).applyMatrix4(t.matrixWorld)}return this.intersectsSphere(ua)}intersectsSprite(t){return ua.center.set(0,0,0),ua.radius=.7071067811865476,ua.applyMatrix4(t.matrixWorld),this.intersectsSphere(ua)}intersectsSphere(t){const e=this.planes,n=t.center,i=-t.radius;for(let t=0;t<6;t++){if(e[t].distanceToPoint(n)0?t.max.x:t.min.x,da.y=i.normal.y>0?t.max.y:t.min.y,da.z=i.normal.z>0?t.max.z:t.min.z,i.distanceToPoint(da)<0)return!1}return!0}containsPoint(t){const e=this.planes;for(let n=0;n<6;n++)if(e[n].distanceToPoint(t)<0)return!1;return!0}clone(){return(new this.constructor).copy(this)}}function ma(){let t=null,e=!1,n=null,i=null;function r(e,s){n(e,s),i=t.requestAnimationFrame(r)}return{start:function(){!0!==e&&null!==n&&(i=t.requestAnimationFrame(r),e=!0)},stop:function(){t.cancelAnimationFrame(i),e=!1},setAnimationLoop:function(t){n=t},setContext:function(e){t=e}}}function fa(t){const e=new WeakMap;return{get:function(t){return t.isInterleavedBufferAttribute&&(t=t.data),e.get(t)},remove:function(n){n.isInterleavedBufferAttribute&&(n=n.data);const i=e.get(n);i&&(t.deleteBuffer(i.buffer),e.delete(n))},update:function(n,i){if(n.isInterleavedBufferAttribute&&(n=n.data),n.isGLBufferAttribute){const t=e.get(n);return void((!t||t.version 0\n\tvec4 plane;\n\t#ifdef ALPHA_TO_COVERAGE\n\t\tfloat distanceToPlane, distanceGradient;\n\t\tfloat clipOpacity = 1.0;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\tclipOpacity *= smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\tif ( clipOpacity == 0.0 ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tfloat unionClipOpacity = 1.0;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\t\tunionClipOpacity *= 1.0 - smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tclipOpacity *= 1.0 - unionClipOpacity;\n\t\t#endif\n\t\tdiffuseColor.a *= clipOpacity;\n\t\tif ( diffuseColor.a == 0.0 ) discard;\n\t#else\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tbool clipped = true;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tif ( clipped ) discard;\n\t\t#endif\n\t#endif\n#endif",clipping_planes_pars_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif",color_fragment:"#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif",color_pars_fragment:"#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif",color_pars_vertex:"#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )\n\tvarying vec3 vColor;\n#endif",color_vertex:"#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif\n#ifdef USE_BATCHING_COLOR\n\tvec3 batchingColor = getBatchingColor( getIndirectIndex( gl_DrawID ) );\n\tvColor.xyz *= batchingColor.xyz;\n#endif",common:"#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\n#ifdef USE_ALPHAHASH\n\tvarying vec3 vPosition;\n#endif\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}\nvec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n} // validated",cube_uv_reflection_fragment:"#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\thighp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif",defaultnormal_vertex:"vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );\n\ttransformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );\n\ttransformedNormal = bm * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = bm * transformedTangent;\n\t#endif\n#endif\n#ifdef USE_INSTANCING\n\tmat3 im = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) );\n\ttransformedNormal = im * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = im * transformedTangent;\n\t#endif\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\ttransformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif",displacementmap_pars_vertex:"#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif",displacementmap_vertex:"#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif",emissivemap_fragment:"#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif",emissivemap_pars_fragment:"#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif",colorspace_fragment:"gl_FragColor = linearToOutputTexel( gl_FragColor );",colorspace_pars_fragment:"\nconst mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3(\n\tvec3( 0.8224621, 0.177538, 0.0 ),\n\tvec3( 0.0331941, 0.9668058, 0.0 ),\n\tvec3( 0.0170827, 0.0723974, 0.9105199 )\n);\nconst mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.2249401, - 0.2249404, 0.0 ),\n\tvec3( - 0.0420569, 1.0420571, 0.0 ),\n\tvec3( - 0.0196376, - 0.0786361, 1.0982735 )\n);\nvec4 LinearSRGBToLinearDisplayP3( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a );\n}\nvec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a );\n}\nvec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferOETF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}",envmap_fragment:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, envMapRotation * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif",envmap_common_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform mat3 envMapRotation;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif",envmap_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif",envmap_pars_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif",envmap_physical_pars_fragment:"#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, envMapRotation * worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, envMapRotation * reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\treturn getIBLRadiance( viewDir, bentNormal, roughness );\n\t\t\t#else\n\t\t\t\treturn vec3( 0.0 );\n\t\t\t#endif\n\t\t}\n\t#endif\n#endif",envmap_vertex:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif",fog_vertex:"#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif",fog_pars_vertex:"#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif",fog_fragment:"#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, vFogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif",fog_pars_fragment:"#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif",gradientmap_pars_fragment:"#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn vec3( texture2D( gradientMap, coord ).r );\n\t#else\n\t\tvec2 fw = fwidth( coord ) * 0.5;\n\t\treturn mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) );\n\t#endif\n}",lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif",lights_lambert_fragment:"LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;",lights_lambert_pars_fragment:"varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert",lights_pars_begin:"uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif ( cutoffDistance > 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif",lights_toon_fragment:"ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;",lights_toon_pars_fragment:"varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon",lights_phong_fragment:"BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;",lights_phong_pars_fragment:"varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong",lights_physical_fragment:"PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_DISPERSION\n\tmaterial.dispersion = dispersion;\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\t#ifdef USE_ANISOTROPYMAP\n\t\tmat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x );\n\t\tvec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb;\n\t\tvec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b;\n\t#else\n\t\tvec2 anisotropyV = anisotropyVector;\n\t#endif\n\tmaterial.anisotropy = length( anisotropyV );\n\tif( material.anisotropy == 0.0 ) {\n\t\tanisotropyV = vec2( 1.0, 0.0 );\n\t} else {\n\t\tanisotropyV /= material.anisotropy;\n\t\tmaterial.anisotropy = saturate( material.anisotropy );\n\t}\n\tmaterial.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) );\n\tmaterial.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y;\n\tmaterial.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y;\n#endif",lights_physical_pars_fragment:"struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\tfloat dispersion;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\tfloat v = 0.5 / ( gv + gl );\n\t\treturn saturate(v);\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColor;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}",lights_fragment_begin:"\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowIntensity, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometryPosition, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowIntensity, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowIntensity, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif",lights_fragment_maps:"#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tradiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tradiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif",lights_fragment_end:"#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif",logdepthbuf_fragment:"#if defined( USE_LOGDEPTHBUF )\n\tgl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif",logdepthbuf_pars_fragment:"#if defined( USE_LOGDEPTHBUF )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif",logdepthbuf_pars_vertex:"#ifdef USE_LOGDEPTHBUF\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif",logdepthbuf_vertex:"#ifdef USE_LOGDEPTHBUF\n\tvFragDepth = 1.0 + gl_Position.w;\n\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n#endif",map_fragment:"#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif",map_pars_fragment:"#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif",map_particle_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t#if defined( USE_POINTS_UV )\n\t\tvec2 uv = vUv;\n\t#else\n\t\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif",map_particle_pars_fragment:"#if defined( USE_POINTS_UV )\n\tvarying vec2 vUv;\n#else\n\t#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t\tuniform mat3 uvTransform;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif",metalnessmap_fragment:"float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif",metalnessmap_pars_fragment:"#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif",morphinstance_vertex:"#ifdef USE_INSTANCING_MORPH\n\tfloat morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\tfloat morphTargetBaseInfluence = texelFetch( morphTexture, ivec2( 0, gl_InstanceID ), 0 ).r;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\tmorphTargetInfluences[i] = texelFetch( morphTexture, ivec2( i + 1, gl_InstanceID ), 0 ).r;\n\t}\n#endif",morphcolor_vertex:"#if defined( USE_MORPHCOLORS )\n\tvColor *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t#if defined( USE_COLOR_ALPHA )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ];\n\t\t#elif defined( USE_COLOR )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ];\n\t\t#endif\n\t}\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\n\t}\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n\t#ifndef USE_INSTANCING_MORPH\n\t\tuniform float morphTargetBaseInfluence;\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\t#endif\n\tuniform sampler2DArray morphTargetsTexture;\n\tuniform ivec2 morphTargetsTextureSize;\n\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\n\t\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\n\t\tint y = texelIndex / morphTargetsTextureSize.x;\n\t\tint x = texelIndex - y * morphTargetsTextureSize.x;\n\t\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\n\t\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\n\t}\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t}\n#endif",normal_fragment_begin:"float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal *= faceDirection;\n\t#endif\n#endif\n#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY )\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn = getTangentFrame( - vViewPosition, normal,\n\t\t#if defined( USE_NORMALMAP )\n\t\t\tvNormalMapUv\n\t\t#elif defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tvClearcoatNormalMapUv\n\t\t#else\n\t\t\tvUv\n\t\t#endif\n\t\t);\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn[0] *= faceDirection;\n\t\ttbn[1] *= faceDirection;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;",normal_fragment_maps:"#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif",normal_pars_fragment:"#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif",normal_pars_vertex:"#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif",normal_vertex:"#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif",normalmap_pars_fragment:"#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef USE_NORMALMAP_OBJECTSPACE\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) )\n\tmat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( uv.st );\n\t\tvec2 st1 = dFdy( uv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det );\n\t\treturn mat3( T * scale, B * scale, N );\n\t}\n#endif",clearcoat_normal_fragment_begin:"#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif",clearcoat_normal_fragment_maps:"#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\tclearcoatNormal = normalize( tbn2 * clearcoatMapN );\n#endif",clearcoat_pars_fragment:"#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif",iridescence_pars_fragment:"#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif",opaque_fragment:"#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );",packing:"vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;const float ShiftRight8 = 1. / 256.;\nconst float Inv255 = 1. / 255.;\nconst vec4 PackFactors = vec4( 1.0, 256.0, 256.0 * 256.0, 256.0 * 256.0 * 256.0 );\nconst vec2 UnpackFactors2 = vec2( UnpackDownscale, 1.0 / PackFactors.g );\nconst vec3 UnpackFactors3 = vec3( UnpackDownscale / PackFactors.rg, 1.0 / PackFactors.b );\nconst vec4 UnpackFactors4 = vec4( UnpackDownscale / PackFactors.rgb, 1.0 / PackFactors.a );\nvec4 packDepthToRGBA( const in float v ) {\n\tif( v <= 0.0 )\n\t\treturn vec4( 0., 0., 0., 0. );\n\tif( v >= 1.0 )\n\t\treturn vec4( 1., 1., 1., 1. );\n\tfloat vuf;\n\tfloat af = modf( v * PackFactors.a, vuf );\n\tfloat bf = modf( vuf * ShiftRight8, vuf );\n\tfloat gf = modf( vuf * ShiftRight8, vuf );\n\treturn vec4( vuf * Inv255, gf * PackUpscale, bf * PackUpscale, af );\n}\nvec3 packDepthToRGB( const in float v ) {\n\tif( v <= 0.0 )\n\t\treturn vec3( 0., 0., 0. );\n\tif( v >= 1.0 )\n\t\treturn vec3( 1., 1., 1. );\n\tfloat vuf;\n\tfloat bf = modf( v * PackFactors.b, vuf );\n\tfloat gf = modf( vuf * ShiftRight8, vuf );\n\treturn vec3( vuf * Inv255, gf * PackUpscale, bf );\n}\nvec2 packDepthToRG( const in float v ) {\n\tif( v <= 0.0 )\n\t\treturn vec2( 0., 0. );\n\tif( v >= 1.0 )\n\t\treturn vec2( 1., 1. );\n\tfloat vuf;\n\tfloat gf = modf( v * 256., vuf );\n\treturn vec2( vuf * Inv255, gf );\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors4 );\n}\nfloat unpackRGBToDepth( const in vec3 v ) {\n\treturn dot( v, UnpackFactors3 );\n}\nfloat unpackRGToDepth( const in vec2 v ) {\n\treturn v.r * UnpackFactors2.r + v.g * UnpackFactors2.g;\n}\nvec4 pack2HalfToRGBA( const in vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( const in vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn depth * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * depth - far );\n}",premultiplied_alpha_fragment:"#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif",project_vertex:"vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_BATCHING\n\tmvPosition = batchingMatrix * mvPosition;\n#endif\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;",dithering_fragment:"#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif",dithering_pars_fragment:"#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif",roughnessmap_fragment:"float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif",roughnessmap_pars_fragment:"#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif",shadowmap_pars_fragment:"#if NUM_SPOT_LIGHT_COORDS > 0\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n\tuniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn mix( 1.0, shadow, shadowIntensity );\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tfloat shadow = 1.0;\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\t\n\t\tfloat lightToPositionLength = length( lightToPosition );\n\t\tif ( lightToPositionLength - shadowCameraFar <= 0.0 && lightToPositionLength - shadowCameraNear >= 0.0 ) {\n\t\t\tfloat dp = ( lightToPositionLength - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\t\tdp += shadowBias;\n\t\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\t\tshadow = (\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t\t) * ( 1.0 / 9.0 );\n\t\t\t#else\n\t\t\t\tshadow = texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t\t#endif\n\t\t}\n\t\treturn mix( 1.0, shadow, shadowIntensity );\n\t}\n#endif",shadowmap_pars_vertex:"#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif",shadowmap_vertex:"#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif",shadowmask_pars_fragment:"float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowIntensity, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowIntensity, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowIntensity, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}",skinbase_vertex:"#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tint size = textureSize( boneTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif",skinning_vertex:"#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif",skinnormal_vertex:"#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif",specularmap_fragment:"float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vSpecularMapUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif",specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif",tonemapping_fragment:"#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif",tonemapping_pars_fragment:"#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn saturate( toneMappingExposure * color );\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 CineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nconst mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.6605, - 0.1246, - 0.0182 ),\n\tvec3( - 0.5876, 1.1329, - 0.1006 ),\n\tvec3( - 0.0728, - 0.0083, 1.1187 )\n);\nconst mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(\n\tvec3( 0.6274, 0.0691, 0.0164 ),\n\tvec3( 0.3293, 0.9195, 0.0880 ),\n\tvec3( 0.0433, 0.0113, 0.8956 )\n);\nvec3 agxDefaultContrastApprox( vec3 x ) {\n\tvec3 x2 = x * x;\n\tvec3 x4 = x2 * x2;\n\treturn + 15.5 * x4 * x2\n\t\t- 40.14 * x4 * x\n\t\t+ 31.96 * x4\n\t\t- 6.868 * x2 * x\n\t\t+ 0.4298 * x2\n\t\t+ 0.1191 * x\n\t\t- 0.00232;\n}\nvec3 AgXToneMapping( vec3 color ) {\n\tconst mat3 AgXInsetMatrix = mat3(\n\t\tvec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),\n\t\tvec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),\n\t\tvec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 )\n\t);\n\tconst mat3 AgXOutsetMatrix = mat3(\n\t\tvec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ),\n\t\tvec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ),\n\t\tvec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 )\n\t);\n\tconst float AgxMinEv = - 12.47393;\tconst float AgxMaxEv = 4.026069;\n\tcolor *= toneMappingExposure;\n\tcolor = LINEAR_SRGB_TO_LINEAR_REC2020 * color;\n\tcolor = AgXInsetMatrix * color;\n\tcolor = max( color, 1e-10 );\tcolor = log2( color );\n\tcolor = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv );\n\tcolor = clamp( color, 0.0, 1.0 );\n\tcolor = agxDefaultContrastApprox( color );\n\tcolor = AgXOutsetMatrix * color;\n\tcolor = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) );\n\tcolor = LINEAR_REC2020_TO_LINEAR_SRGB * color;\n\tcolor = clamp( color, 0.0, 1.0 );\n\treturn color;\n}\nvec3 NeutralToneMapping( vec3 color ) {\n\tconst float StartCompression = 0.8 - 0.04;\n\tconst float Desaturation = 0.15;\n\tcolor *= toneMappingExposure;\n\tfloat x = min( color.r, min( color.g, color.b ) );\n\tfloat offset = x < 0.08 ? x - 6.25 * x * x : 0.04;\n\tcolor -= offset;\n\tfloat peak = max( color.r, max( color.g, color.b ) );\n\tif ( peak < StartCompression ) return color;\n\tfloat d = 1. - StartCompression;\n\tfloat newPeak = 1. - d * d / ( peak + d - StartCompression );\n\tcolor *= newPeak / peak;\n\tfloat g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. );\n\treturn mix( color, vec3( newPeak ), g );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }",transmission_fragment:"#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmitted = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.dispersion, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission );\n#endif",transmission_pars_fragment:"#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tfloat w0( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 );\n\t}\n\tfloat w1( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 );\n\t}\n\tfloat w2( float a ){\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 );\n\t}\n\tfloat w3( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * a );\n\t}\n\tfloat g0( float a ) {\n\t\treturn w0( a ) + w1( a );\n\t}\n\tfloat g1( float a ) {\n\t\treturn w2( a ) + w3( a );\n\t}\n\tfloat h0( float a ) {\n\t\treturn - 1.0 + w1( a ) / ( w0( a ) + w1( a ) );\n\t}\n\tfloat h1( float a ) {\n\t\treturn 1.0 + w3( a ) / ( w2( a ) + w3( a ) );\n\t}\n\tvec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) {\n\t\tuv = uv * texelSize.zw + 0.5;\n\t\tvec2 iuv = floor( uv );\n\t\tvec2 fuv = fract( uv );\n\t\tfloat g0x = g0( fuv.x );\n\t\tfloat g1x = g1( fuv.x );\n\t\tfloat h0x = h0( fuv.x );\n\t\tfloat h1x = h1( fuv.x );\n\t\tfloat h0y = h0( fuv.y );\n\t\tfloat h1y = h1( fuv.y );\n\t\tvec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\treturn g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) +\n\t\t\tg1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) );\n\t}\n\tvec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) {\n\t\tvec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) );\n\t\tvec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) );\n\t\tvec2 fLodSizeInv = 1.0 / fLodSize;\n\t\tvec2 cLodSizeInv = 1.0 / cLodSize;\n\t\tvec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) );\n\t\tvec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) );\n\t\treturn mix( fSample, cSample, fract( lod ) );\n\t}\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\treturn textureBicubic( transmissionSamplerMap, fragCoord.xy, lod );\n\t}\n\tvec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn vec3( 1.0 );\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float dispersion, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec4 transmittedLight;\n\t\tvec3 transmittance;\n\t\t#ifdef USE_DISPERSION\n\t\t\tfloat halfSpread = ( ior - 1.0 ) * 0.025 * dispersion;\n\t\t\tvec3 iors = vec3( ior - halfSpread, ior, ior + halfSpread );\n\t\t\tfor ( int i = 0; i < 3; i ++ ) {\n\t\t\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, iors[ i ], modelMatrix );\n\t\t\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\t\n\t\t\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\t\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\t\t\trefractionCoords += 1.0;\n\t\t\t\trefractionCoords /= 2.0;\n\t\t\n\t\t\t\tvec4 transmissionSample = getTransmissionSample( refractionCoords, roughness, iors[ i ] );\n\t\t\t\ttransmittedLight[ i ] = transmissionSample[ i ];\n\t\t\t\ttransmittedLight.a += transmissionSample.a;\n\t\t\t\ttransmittance[ i ] = diffuseColor[ i ] * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance )[ i ];\n\t\t\t}\n\t\t\ttransmittedLight.a /= 3.0;\n\t\t\n\t\t#else\n\t\t\n\t\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\t\trefractionCoords += 1.0;\n\t\t\trefractionCoords /= 2.0;\n\t\t\ttransmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\t\ttransmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\t\n\t\t#endif\n\t\tvec3 attenuatedColor = transmittance * transmittedLight.rgb;\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\tfloat transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0;\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor );\n\t}\n#endif",uv_pars_fragment:"#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif",uv_pars_vertex:"#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tuniform mat3 mapTransform;\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform mat3 alphaMapTransform;\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tuniform mat3 lightMapTransform;\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tuniform mat3 aoMapTransform;\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tuniform mat3 bumpMapTransform;\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tuniform mat3 normalMapTransform;\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tuniform mat3 displacementMapTransform;\n\tvarying vec2 vDisplacementMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tuniform mat3 emissiveMapTransform;\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tuniform mat3 metalnessMapTransform;\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tuniform mat3 roughnessMapTransform;\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tuniform mat3 anisotropyMapTransform;\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tuniform mat3 clearcoatMapTransform;\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform mat3 clearcoatNormalMapTransform;\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform mat3 clearcoatRoughnessMapTransform;\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tuniform mat3 sheenColorMapTransform;\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tuniform mat3 sheenRoughnessMapTransform;\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tuniform mat3 iridescenceMapTransform;\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform mat3 iridescenceThicknessMapTransform;\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tuniform mat3 specularMapTransform;\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tuniform mat3 specularColorMapTransform;\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tuniform mat3 specularIntensityMapTransform;\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif",uv_vertex:"#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvUv = vec3( uv, 1 ).xy;\n#endif\n#ifdef USE_MAP\n\tvMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ALPHAMAP\n\tvAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_LIGHTMAP\n\tvLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_AOMAP\n\tvAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_BUMPMAP\n\tvBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_NORMALMAP\n\tvNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tvDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_METALNESSMAP\n\tvMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULARMAP\n\tvSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tvTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_THICKNESSMAP\n\tvThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy;\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_BATCHING\n\t\tworldPosition = batchingMatrix * worldPosition;\n\t#endif\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif",background_vert:"varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}",background_frag:"uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}",backgroundCube_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}",backgroundCube_frag:"#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nuniform mat3 backgroundRotation;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, backgroundRotation * vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, backgroundRotation * vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}",cube_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}",cube_frag:"uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}",depth_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}",depth_frag:"#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#elif DEPTH_PACKING == 3202\n\t\tgl_FragColor = vec4( packDepthToRGB( fragCoordZ ), 1.0 );\n\t#elif DEPTH_PACKING == 3203\n\t\tgl_FragColor = vec4( packDepthToRG( fragCoordZ ), 0.0, 1.0 );\n\t#endif\n}",distanceRGBA_vert:"#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}",distanceRGBA_frag:"#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}",equirect_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}",equirect_frag:"uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include \n\t#include \n}",linedashed_vert:"uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",linedashed_frag:"uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshbasic_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshbasic_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_vert:"#define LAMBERT\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_frag:"#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshmatcap_vert:"#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}",meshmatcap_frag:"#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshnormal_vert:"#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}",meshnormal_frag:"#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( 0.0, 0.0, 0.0, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), diffuseColor.a );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}",meshphong_vert:"#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphong_frag:"#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphysical_vert:"#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}",meshphysical_frag:"#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define USE_SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef USE_SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULAR_COLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_DISPERSION\n\tuniform float dispersion;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\tuniform vec2 anisotropyVector;\n\t#ifdef USE_ANISOTROPYMAP\n\t\tuniform sampler2D anisotropyMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshtoon_vert:"#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}",meshtoon_frag:"#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",points_vert:"uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef USE_POINTS_UV\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\nvoid main() {\n\t#ifdef USE_POINTS_UV\n\t\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}",points_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",shadow_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",shadow_frag:"uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}",sprite_vert:"uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}",sprite_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"},_a={common:{diffuse:{value:new Kr(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new ei},alphaMap:{value:null},alphaMapTransform:{value:new ei},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new ei}},envmap:{envMap:{value:null},envMapRotation:{value:new ei},flipEnvMap:{value:-1},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new ei}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new ei}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new ei},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new ei},normalScale:{value:new ti(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new ei},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new ei}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new ei}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new ei}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new Kr(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotLightMap:{value:[]},spotShadowMap:{value:[]},spotLightMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null}},points:{diffuse:{value:new Kr(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new ei},alphaTest:{value:0},uvTransform:{value:new ei}},sprite:{diffuse:{value:new Kr(16777215)},opacity:{value:1},center:{value:new ti(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new ei},alphaMap:{value:null},alphaMapTransform:{value:new ei},alphaTest:{value:0}}},xa={basic:{uniforms:Ys([_a.common,_a.specularmap,_a.envmap,_a.aomap,_a.lightmap,_a.fog]),vertexShader:va.meshbasic_vert,fragmentShader:va.meshbasic_frag},lambert:{uniforms:Ys([_a.common,_a.specularmap,_a.envmap,_a.aomap,_a.lightmap,_a.emissivemap,_a.bumpmap,_a.normalmap,_a.displacementmap,_a.fog,_a.lights,{emissive:{value:new Kr(0)}}]),vertexShader:va.meshlambert_vert,fragmentShader:va.meshlambert_frag},phong:{uniforms:Ys([_a.common,_a.specularmap,_a.envmap,_a.aomap,_a.lightmap,_a.emissivemap,_a.bumpmap,_a.normalmap,_a.displacementmap,_a.fog,_a.lights,{emissive:{value:new Kr(0)},specular:{value:new Kr(1118481)},shininess:{value:30}}]),vertexShader:va.meshphong_vert,fragmentShader:va.meshphong_frag},standard:{uniforms:Ys([_a.common,_a.envmap,_a.aomap,_a.lightmap,_a.emissivemap,_a.bumpmap,_a.normalmap,_a.displacementmap,_a.roughnessmap,_a.metalnessmap,_a.fog,_a.lights,{emissive:{value:new Kr(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:va.meshphysical_vert,fragmentShader:va.meshphysical_frag},toon:{uniforms:Ys([_a.common,_a.aomap,_a.lightmap,_a.emissivemap,_a.bumpmap,_a.normalmap,_a.displacementmap,_a.gradientmap,_a.fog,_a.lights,{emissive:{value:new Kr(0)}}]),vertexShader:va.meshtoon_vert,fragmentShader:va.meshtoon_frag},matcap:{uniforms:Ys([_a.common,_a.bumpmap,_a.normalmap,_a.displacementmap,_a.fog,{matcap:{value:null}}]),vertexShader:va.meshmatcap_vert,fragmentShader:va.meshmatcap_frag},points:{uniforms:Ys([_a.points,_a.fog]),vertexShader:va.points_vert,fragmentShader:va.points_frag},dashed:{uniforms:Ys([_a.common,_a.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:va.linedashed_vert,fragmentShader:va.linedashed_frag},depth:{uniforms:Ys([_a.common,_a.displacementmap]),vertexShader:va.depth_vert,fragmentShader:va.depth_frag},normal:{uniforms:Ys([_a.common,_a.bumpmap,_a.normalmap,_a.displacementmap,{opacity:{value:1}}]),vertexShader:va.meshnormal_vert,fragmentShader:va.meshnormal_frag},sprite:{uniforms:Ys([_a.sprite,_a.fog]),vertexShader:va.sprite_vert,fragmentShader:va.sprite_frag},background:{uniforms:{uvTransform:{value:new ei},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:va.background_vert,fragmentShader:va.background_frag},backgroundCube:{uniforms:{envMap:{value:null},flipEnvMap:{value:-1},backgroundBlurriness:{value:0},backgroundIntensity:{value:1},backgroundRotation:{value:new ei}},vertexShader:va.backgroundCube_vert,fragmentShader:va.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:va.cube_vert,fragmentShader:va.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:va.equirect_vert,fragmentShader:va.equirect_frag},distanceRGBA:{uniforms:Ys([_a.common,_a.displacementmap,{referencePosition:{value:new Li},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:va.distanceRGBA_vert,fragmentShader:va.distanceRGBA_frag},shadow:{uniforms:Ys([_a.lights,_a.fog,{color:{value:new Kr(0)},opacity:{value:1}}]),vertexShader:va.shadow_vert,fragmentShader:va.shadow_frag}};xa.physical={uniforms:Ys([xa.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new ei},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new ei},clearcoatNormalScale:{value:new ti(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new ei},dispersion:{value:0},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new ei},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new ei},sheen:{value:0},sheenColor:{value:new Kr(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new ei},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new ei},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new ei},transmissionSamplerSize:{value:new ti},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new ei},attenuationDistance:{value:0},attenuationColor:{value:new Kr(0)},specularColor:{value:new Kr(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new ei},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new ei},anisotropyVector:{value:new ti},anisotropyMap:{value:null},anisotropyMapTransform:{value:new ei}}]),vertexShader:va.meshphysical_vert,fragmentShader:va.meshphysical_frag};const ya={r:0,b:0,g:0},Ma=new _r,Sa=new lr;function ba(t,e,n,i,r,s,a){const o=new Kr(0);let l,c,h=!0===s?0:1,p=null,m=0,f=null;function g(t){let i=!0===t.isScene?t.background:null;if(i&&i.isTexture){i=(t.backgroundBlurriness>0?n:e).get(i)}return i}function v(e,n){e.getRGB(ya,Zs(t)),i.buffers.color.setClear(ya.r,ya.g,ya.b,n,a)}return{getClearColor:function(){return o},setClearColor:function(t,e=1){o.set(t),h=e,v(o,h)},getClearAlpha:function(){return h},setClearAlpha:function(t){h=t,v(o,h)},render:function(e){let n=!1;const r=g(e);null===r?v(o,h):r&&r.isColor&&(v(r,1),n=!0);const s=t.xr.getEnvironmentBlendMode();"additive"===s?i.buffers.color.setClear(0,0,0,1,a):"alpha-blend"===s&&i.buffers.color.setClear(0,0,0,0,a),(t.autoClear||n)&&(i.buffers.depth.setTest(!0),i.buffers.depth.setMask(!0),i.buffers.color.setMask(!0),t.clear(t.autoClearColor,t.autoClearDepth,t.autoClearStencil))},addToRenderList:function(e,n){const i=g(n);i&&(i.isCubeTexture||i.mapping===dt)?(void 0===c&&(c=new Ws(new js(1,1,1),new Ks({name:"BackgroundCubeMaterial",uniforms:qs(xa.backgroundCube.uniforms),vertexShader:xa.backgroundCube.vertexShader,fragmentShader:xa.backgroundCube.fragmentShader,side:d,depthTest:!1,depthWrite:!1,fog:!1})),c.geometry.deleteAttribute("normal"),c.geometry.deleteAttribute("uv"),c.onBeforeRender=function(t,e,n){this.matrixWorld.copyPosition(n.matrixWorld)},Object.defineProperty(c.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),r.update(c)),Ma.copy(n.backgroundRotation),Ma.x*=-1,Ma.y*=-1,Ma.z*=-1,i.isCubeTexture&&!1===i.isRenderTargetTexture&&(Ma.y*=-1,Ma.z*=-1),c.material.uniforms.envMap.value=i,c.material.uniforms.flipEnvMap.value=i.isCubeTexture&&!1===i.isRenderTargetTexture?-1:1,c.material.uniforms.backgroundBlurriness.value=n.backgroundBlurriness,c.material.uniforms.backgroundIntensity.value=n.backgroundIntensity,c.material.uniforms.backgroundRotation.value.setFromMatrix4(Sa.makeRotationFromEuler(Ma)),c.material.toneMapped=mi.getTransfer(i.colorSpace)!==en,p===i&&m===i.version&&f===t.toneMapping||(c.material.needsUpdate=!0,p=i,m=i.version,f=t.toneMapping),c.layers.enableAll(),e.unshift(c,c.geometry,c.material,0,0,null)):i&&i.isTexture&&(void 0===l&&(l=new Ws(new ga(2,2),new Ks({name:"BackgroundMaterial",uniforms:qs(xa.background.uniforms),vertexShader:xa.background.vertexShader,fragmentShader:xa.background.fragmentShader,side:u,depthTest:!1,depthWrite:!1,fog:!1})),l.geometry.deleteAttribute("normal"),Object.defineProperty(l.material,"map",{get:function(){return this.uniforms.t2D.value}}),r.update(l)),l.material.uniforms.t2D.value=i,l.material.uniforms.backgroundIntensity.value=n.backgroundIntensity,l.material.toneMapped=mi.getTransfer(i.colorSpace)!==en,!0===i.matrixAutoUpdate&&i.updateMatrix(),l.material.uniforms.uvTransform.value.copy(i.matrix),p===i&&m===i.version&&f===t.toneMapping||(l.material.needsUpdate=!0,p=i,m=i.version,f=t.toneMapping),l.layers.enableAll(),e.unshift(l,l.geometry,l.material,0,0,null))}}}function wa(t,e){const n=t.getParameter(t.MAX_VERTEX_ATTRIBS),i={},r=c(null);let s=r,a=!1;function o(e){return t.bindVertexArray(e)}function l(e){return t.deleteVertexArray(e)}function c(t){const e=[],i=[],r=[];for(let t=0;t=0){const n=r[e];let i=a[e];if(void 0===i&&("instanceMatrix"===e&&t.instanceMatrix&&(i=t.instanceMatrix),"instanceColor"===e&&t.instanceColor&&(i=t.instanceColor)),void 0===n)return!0;if(n.attribute!==i)return!0;if(i&&n.data!==i.data)return!0;o++}}return s.attributesNum!==o||s.index!==i}(n,f,l,g),v&&function(t,e,n,i){const r={},a=e.attributes;let o=0;const l=n.getAttributes();for(const e in l){if(l[e].location>=0){let n=a[e];void 0===n&&("instanceMatrix"===e&&t.instanceMatrix&&(n=t.instanceMatrix),"instanceColor"===e&&t.instanceColor&&(n=t.instanceColor));const i={};i.attribute=n,n&&n.data&&(i.data=n.data),r[e]=i,o++}}s.attributes=r,s.attributesNum=o,s.index=i}(n,f,l,g),null!==g&&e.update(g,t.ELEMENT_ARRAY_BUFFER),(v||a)&&(a=!1,function(n,i,r,s){h();const a=s.attributes,o=r.getAttributes(),l=i.defaultAttributeValues;for(const i in o){const r=o[i];if(r.location>=0){let o=a[i];if(void 0===o&&("instanceMatrix"===i&&n.instanceMatrix&&(o=n.instanceMatrix),"instanceColor"===i&&n.instanceColor&&(o=n.instanceColor)),void 0!==o){const i=o.normalized,a=o.itemSize,l=e.get(o);if(void 0===l)continue;const c=l.buffer,h=l.type,p=l.bytesPerElement,f=h===t.INT||h===t.UNSIGNED_INT||o.gpuType===Pt;if(o.isInterleavedBufferAttribute){const e=o.data,l=e.stride,g=o.offset;if(e.isInstancedInterleavedBuffer){for(let t=0;t0&&t.getShaderPrecisionFormat(t.FRAGMENT_SHADER,t.HIGH_FLOAT).precision>0)return"highp";e="mediump"}return"mediump"===e&&t.getShaderPrecisionFormat(t.VERTEX_SHADER,t.MEDIUM_FLOAT).precision>0&&t.getShaderPrecisionFormat(t.FRAGMENT_SHADER,t.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}let a=void 0!==n.precision?n.precision:"highp";const o=s(a);o!==a&&(console.warn("THREE.WebGLRenderer:",a,"not supported, using",o,"instead."),a=o);const l=!0===n.logarithmicDepthBuffer,c=t.getParameter(t.MAX_TEXTURE_IMAGE_UNITS),h=t.getParameter(t.MAX_VERTEX_TEXTURE_IMAGE_UNITS);return{isWebGL2:!0,getMaxAnisotropy:function(){if(void 0!==r)return r;if(!0===e.has("EXT_texture_filter_anisotropic")){const n=e.get("EXT_texture_filter_anisotropic");r=t.getParameter(n.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else r=0;return r},getMaxPrecision:s,textureFormatReadable:function(e){return e===kt||i.convert(e)===t.getParameter(t.IMPLEMENTATION_COLOR_READ_FORMAT)},textureTypeReadable:function(n){const r=n===Ut&&(e.has("EXT_color_buffer_half_float")||e.has("EXT_color_buffer_float"));return!(n!==Et&&i.convert(n)!==t.getParameter(t.IMPLEMENTATION_COLOR_READ_TYPE)&&n!==Lt&&!r)},precision:a,logarithmicDepthBuffer:l,maxTextures:c,maxVertexTextures:h,maxTextureSize:t.getParameter(t.MAX_TEXTURE_SIZE),maxCubemapSize:t.getParameter(t.MAX_CUBE_MAP_TEXTURE_SIZE),maxAttributes:t.getParameter(t.MAX_VERTEX_ATTRIBS),maxVertexUniforms:t.getParameter(t.MAX_VERTEX_UNIFORM_VECTORS),maxVaryings:t.getParameter(t.MAX_VARYING_VECTORS),maxFragmentUniforms:t.getParameter(t.MAX_FRAGMENT_UNIFORM_VECTORS),vertexTextures:h>0,maxSamples:t.getParameter(t.MAX_SAMPLES)}}function Aa(t){const e=this;let n=null,i=0,r=!1,s=!1;const a=new ha,o=new ei,l={value:null,needsUpdate:!1};function c(t,n,i,r){const s=null!==t?t.length:0;let c=null;if(0!==s){if(c=l.value,!0!==r||null===c){const e=i+4*s,r=n.matrixWorldInverse;o.getNormalMatrix(r),(null===c||c.length0);e.numPlanes=i,e.numIntersection=0}();else{const t=s?0:i,e=4*t;let r=m.clippingState||null;l.value=r,r=c(u,o,e,h);for(let t=0;t!==e;++t)r[t]=n[t];m.clippingState=r,this.numIntersection=d?this.numPlanes:0,this.numPlanes+=t}}}function Ra(t){let e=new WeakMap;function n(t,e){return e===ht?t.mapping=lt:e===ut&&(t.mapping=ct),t}function i(t){const n=t.target;n.removeEventListener("dispose",i);const r=e.get(n);void 0!==r&&(e.delete(n),r.dispose())}return{get:function(r){if(r&&r.isTexture){const s=r.mapping;if(s===ht||s===ut){if(e.has(r)){return n(e.get(r).texture,r.mapping)}{const s=r.image;if(s&&s.height>0){const a=new aa(s.height);return a.fromEquirectangularTexture(t,r),e.set(r,a),r.addEventListener("dispose",i),n(a.texture,r.mapping)}return null}}}return r},dispose:function(){e=new WeakMap}}}class Ca extends $s{constructor(t=-1,e=1,n=1,i=-1,r=.1,s=2e3){super(),this.isOrthographicCamera=!0,this.type="OrthographicCamera",this.zoom=1,this.view=null,this.left=t,this.right=e,this.top=n,this.bottom=i,this.near=r,this.far=s,this.updateProjectionMatrix()}copy(t,e){return super.copy(t,e),this.left=t.left,this.right=t.right,this.top=t.top,this.bottom=t.bottom,this.near=t.near,this.far=t.far,this.zoom=t.zoom,this.view=null===t.view?null:Object.assign({},t.view),this}setViewOffset(t,e,n,i,r,s){null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=t,this.view.fullHeight=e,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=s,this.updateProjectionMatrix()}clearViewOffset(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const t=(this.right-this.left)/(2*this.zoom),e=(this.top-this.bottom)/(2*this.zoom),n=(this.right+this.left)/2,i=(this.top+this.bottom)/2;let r=n-t,s=n+t,a=i+e,o=i-e;if(null!==this.view&&this.view.enabled){const t=(this.right-this.left)/this.view.fullWidth/this.zoom,e=(this.top-this.bottom)/this.view.fullHeight/this.zoom;r+=t*this.view.offsetX,s=r+t*this.view.width,a-=e*this.view.offsetY,o=a-e*this.view.height}this.projectionMatrix.makeOrthographic(r,s,a,o,this.near,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(t){const e=super.toJSON(t);return e.object.zoom=this.zoom,e.object.left=this.left,e.object.right=this.right,e.object.top=this.top,e.object.bottom=this.bottom,e.object.near=this.near,e.object.far=this.far,null!==this.view&&(e.object.view=Object.assign({},this.view)),e}}const Pa=[.125,.215,.35,.446,.526,.582],Ia=20,La=new Ca,Ua=new Kr;let Na=null,Da=0,Oa=0,Fa=!1;const Ba=(1+Math.sqrt(5))/2,za=1/Ba,ka=[new Li(-Ba,za,0),new Li(Ba,za,0),new Li(-za,0,Ba),new Li(za,0,Ba),new Li(0,Ba,-za),new Li(0,Ba,za),new Li(-1,1,-1),new Li(1,1,-1),new Li(-1,1,1),new Li(1,1,1)];class Va{constructor(t){this._renderer=t,this._pingPongRenderTarget=null,this._lodMax=0,this._cubeSize=0,this._lodPlanes=[],this._sizeLods=[],this._sigmas=[],this._blurMaterial=null,this._cubemapMaterial=null,this._equirectMaterial=null,this._compileMaterial(this._blurMaterial)}fromScene(t,e=0,n=.1,i=100){Na=this._renderer.getRenderTarget(),Da=this._renderer.getActiveCubeFace(),Oa=this._renderer.getActiveMipmapLevel(),Fa=this._renderer.xr.enabled,this._renderer.xr.enabled=!1,this._setSize(256);const r=this._allocateTargets();return r.depthBuffer=!0,this._sceneToCubeUV(t,n,i,r),e>0&&this._blur(r,0,0,e),this._applyPMREM(r),this._cleanup(r),r}fromEquirectangular(t,e=null){return this._fromTexture(t,e)}fromCubemap(t,e=null){return this._fromTexture(t,e)}compileCubemapShader(){null===this._cubemapMaterial&&(this._cubemapMaterial=Xa(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){null===this._equirectMaterial&&(this._equirectMaterial=Wa(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),null!==this._cubemapMaterial&&this._cubemapMaterial.dispose(),null!==this._equirectMaterial&&this._equirectMaterial.dispose()}_setSize(t){this._lodMax=Math.floor(Math.log2(t)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){null!==this._blurMaterial&&this._blurMaterial.dispose(),null!==this._pingPongRenderTarget&&this._pingPongRenderTarget.dispose();for(let t=0;tt-4?o=Pa[a-t+4-1]:0===a&&(o=0),i.push(o);const l=1/(s-2),c=-l,h=1+l,u=[c,c,h,c,h,h,c,c,h,h,c,h],d=6,p=6,m=3,f=2,g=1,v=new Float32Array(m*p*d),_=new Float32Array(f*p*d),x=new Float32Array(g*p*d);for(let t=0;t2?0:-1,i=[e,n,0,e+2/3,n,0,e+2/3,n+1,0,e,n,0,e+2/3,n+1,0,e,n+1,0];v.set(i,m*p*t),_.set(u,f*p*t);const r=[t,t,t,t,t,t];x.set(r,g*p*t)}const y=new Es;y.setAttribute("position",new cs(v,m)),y.setAttribute("uv",new cs(_,f)),y.setAttribute("faceIndex",new cs(x,g)),e.push(y),r>4&&r--}return{lodPlanes:e,sizeLods:n,sigmas:i}}(i)),this._blurMaterial=function(t,e,n){const i=new Float32Array(Ia),r=new Li(0,1,0),s=new Ks({name:"SphericalGaussianBlur",defines:{n:Ia,CUBEUV_TEXEL_WIDTH:1/e,CUBEUV_TEXEL_HEIGHT:1/n,CUBEUV_MAX_MIP:`${t}.0`},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:i},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:r}},vertexShader:ja(),fragmentShader:"\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform sampler2D envMap;\n\t\t\tuniform int samples;\n\t\t\tuniform float weights[ n ];\n\t\t\tuniform bool latitudinal;\n\t\t\tuniform float dTheta;\n\t\t\tuniform float mipInt;\n\t\t\tuniform vec3 poleAxis;\n\n\t\t\t#define ENVMAP_TYPE_CUBE_UV\n\t\t\t#include \n\n\t\t\tvec3 getSample( float theta, vec3 axis ) {\n\n\t\t\t\tfloat cosTheta = cos( theta );\n\t\t\t\t// Rodrigues' axis-angle rotation\n\t\t\t\tvec3 sampleDirection = vOutputDirection * cosTheta\n\t\t\t\t\t+ cross( axis, vOutputDirection ) * sin( theta )\n\t\t\t\t\t+ axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );\n\n\t\t\t\treturn bilinearCubeUV( envMap, sampleDirection, mipInt );\n\n\t\t\t}\n\n\t\t\tvoid main() {\n\n\t\t\t\tvec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );\n\n\t\t\t\tif ( all( equal( axis, vec3( 0.0 ) ) ) ) {\n\n\t\t\t\t\taxis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );\n\n\t\t\t\t}\n\n\t\t\t\taxis = normalize( axis );\n\n\t\t\t\tgl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t\t\t\tgl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );\n\n\t\t\t\tfor ( int i = 1; i < n; i++ ) {\n\n\t\t\t\t\tif ( i >= samples ) {\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfloat theta = dTheta * float( i );\n\t\t\t\t\tgl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );\n\t\t\t\t\tgl_FragColor.rgb += weights[ i ] * getSample( theta, axis );\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t",blending:0,depthTest:!1,depthWrite:!1});return s}(i,t,e)}return i}_compileMaterial(t){const e=new Ws(this._lodPlanes[0],t);this._renderer.compile(e,La)}_sceneToCubeUV(t,e,n,i){const r=new na(90,1,e,n),s=[1,-1,1,1,1,1],a=[1,1,1,-1,-1,-1],o=this._renderer,l=o.autoClear,c=o.toneMapping;o.getClearColor(Ua),o.toneMapping=K,o.autoClear=!1;const h=new es({name:"PMREM.Background",side:d,depthWrite:!1,depthTest:!1}),u=new Ws(new js,h);let p=!1;const m=t.background;m?m.isColor&&(h.color.copy(m),t.background=null,p=!0):(h.color.copy(Ua),p=!0);for(let e=0;e<6;e++){const n=e%3;0===n?(r.up.set(0,s[e],0),r.lookAt(a[e],0,0)):1===n?(r.up.set(0,0,s[e]),r.lookAt(0,a[e],0)):(r.up.set(0,s[e],0),r.lookAt(0,0,a[e]));const l=this._cubeSize;Ga(i,n*l,e>2?l:0,l,l),o.setRenderTarget(i),p&&o.render(u,r),o.render(t,r)}u.geometry.dispose(),u.material.dispose(),o.toneMapping=c,o.autoClear=l,t.background=m}_textureToCubeUV(t,e){const n=this._renderer,i=t.mapping===lt||t.mapping===ct;i?(null===this._cubemapMaterial&&(this._cubemapMaterial=Xa()),this._cubemapMaterial.uniforms.flipEnvMap.value=!1===t.isRenderTargetTexture?-1:1):null===this._equirectMaterial&&(this._equirectMaterial=Wa());const r=i?this._cubemapMaterial:this._equirectMaterial,s=new Ws(this._lodPlanes[0],r);r.uniforms.envMap.value=t;const a=this._cubeSize;Ga(e,0,0,3*a,2*a),n.setRenderTarget(e),n.render(s,La)}_applyPMREM(t){const e=this._renderer,n=e.autoClear;e.autoClear=!1;const i=this._lodPlanes.length;for(let e=1;eIa&&console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${m} samples when the maximum is set to 20`);const f=[];let g=0;for(let t=0;tv-4?i-v+4:0),4*(this._cubeSize-_),3*_,2*_),o.setRenderTarget(e),o.render(c,La)}}function Ha(t,e,n){const i=new Ei(t,e,n);return i.texture.mapping=dt,i.texture.name="PMREM.cubeUv",i.scissorTest=!0,i}function Ga(t,e,n,i,r){t.viewport.set(e,n,i,r),t.scissor.set(e,n,i,r)}function Wa(){return new Ks({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:ja(),fragmentShader:"\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform sampler2D envMap;\n\n\t\t\t#include \n\n\t\t\tvoid main() {\n\n\t\t\t\tvec3 outputDirection = normalize( vOutputDirection );\n\t\t\t\tvec2 uv = equirectUv( outputDirection );\n\n\t\t\t\tgl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 );\n\n\t\t\t}\n\t\t",blending:0,depthTest:!1,depthWrite:!1})}function Xa(){return new Ks({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:ja(),fragmentShader:"\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tuniform float flipEnvMap;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform samplerCube envMap;\n\n\t\t\tvoid main() {\n\n\t\t\t\tgl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) );\n\n\t\t\t}\n\t\t",blending:0,depthTest:!1,depthWrite:!1})}function ja(){return"\n\n\t\tprecision mediump float;\n\t\tprecision mediump int;\n\n\t\tattribute float faceIndex;\n\n\t\tvarying vec3 vOutputDirection;\n\n\t\t// RH coordinate system; PMREM face-indexing convention\n\t\tvec3 getDirection( vec2 uv, float face ) {\n\n\t\t\tuv = 2.0 * uv - 1.0;\n\n\t\t\tvec3 direction = vec3( uv, 1.0 );\n\n\t\t\tif ( face == 0.0 ) {\n\n\t\t\t\tdirection = direction.zyx; // ( 1, v, u ) pos x\n\n\t\t\t} else if ( face == 1.0 ) {\n\n\t\t\t\tdirection = direction.xzy;\n\t\t\t\tdirection.xz *= -1.0; // ( -u, 1, -v ) pos y\n\n\t\t\t} else if ( face == 2.0 ) {\n\n\t\t\t\tdirection.x *= -1.0; // ( -u, v, 1 ) pos z\n\n\t\t\t} else if ( face == 3.0 ) {\n\n\t\t\t\tdirection = direction.zyx;\n\t\t\t\tdirection.xz *= -1.0; // ( -1, v, -u ) neg x\n\n\t\t\t} else if ( face == 4.0 ) {\n\n\t\t\t\tdirection = direction.xzy;\n\t\t\t\tdirection.xy *= -1.0; // ( -u, -1, v ) neg y\n\n\t\t\t} else if ( face == 5.0 ) {\n\n\t\t\t\tdirection.z *= -1.0; // ( u, v, -1 ) neg z\n\n\t\t\t}\n\n\t\t\treturn direction;\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tvOutputDirection = getDirection( uv, faceIndex );\n\t\t\tgl_Position = vec4( position, 1.0 );\n\n\t\t}\n\t"}function qa(t){let e=new WeakMap,n=null;function i(t){const n=t.target;n.removeEventListener("dispose",i);const r=e.get(n);void 0!==r&&(e.delete(n),r.dispose())}return{get:function(r){if(r&&r.isTexture){const s=r.mapping,a=s===ht||s===ut,o=s===lt||s===ct;if(a||o){let s=e.get(r);const l=void 0!==s?s.texture.pmremVersion:0;if(r.isRenderTargetTexture&&r.pmremVersion!==l)return null===n&&(n=new Va(t)),s=a?n.fromEquirectangular(r,s):n.fromCubemap(r,s),s.texture.pmremVersion=r.pmremVersion,e.set(r,s),s.texture;if(void 0!==s)return s.texture;{const l=r.image;return a&&l&&l.height>0||o&&l&&function(t){let e=0;const n=6;for(let i=0;ie.maxTextureSize&&(y=Math.ceil(x/e.maxTextureSize),x=e.maxTextureSize);const M=new Float32Array(x*y*4*h),S=new Ai(M,x,y,h);S.type=Lt,S.needsUpdate=!0;const b=4*_;for(let T=0;T0)return t;const r=e*n;let s=ao[r];if(void 0===s&&(s=new Float32Array(r),ao[r]=s),0!==e){i.toArray(s,0);for(let i=1,r=0;i!==e;++i)r+=n,t[i].toArray(s,r)}return s}function po(t,e){if(t.length!==e.length)return!1;for(let n=0,i=t.length;n":" "} ${r}: ${n[t]}`)}return i.join("\n")}(t.getShaderSource(e),i)}return r}function ul(t,e){const n=function(t){const e=mi.getPrimaries(mi.workingColorSpace),n=mi.getPrimaries(t);let i;switch(e===n?i="":e===rn&&n===nn?i="LinearDisplayP3ToLinearSRGB":e===nn&&n===rn&&(i="LinearSRGBToLinearDisplayP3"),t){case Ke:case Qe:return[i,"LinearTransferOETF"];case Je:case $e:return[i,"sRGBTransferOETF"];default:return console.warn("THREE.WebGLProgram: Unsupported color space:",t),[i,"LinearTransferOETF"]}}(e);return`vec4 ${t}( vec4 value ) { return ${n[0]}( ${n[1]}( value ) ); }`}function dl(t,e){let n;switch(e){case $:n="Linear";break;case Q:n="Reinhard";break;case tt:n="Cineon";break;case et:n="ACESFilmic";break;case it:n="AgX";break;case rt:n="Neutral";break;case nt:n="Custom";break;default:console.warn("THREE.WebGLProgram: Unsupported toneMapping:",e),n="Linear"}return"vec3 "+t+"( vec3 color ) { return "+n+"ToneMapping( color ); }"}const pl=new Li;function ml(){mi.getLuminanceCoefficients(pl);return["float luminance( const in vec3 rgb ) {",`\tconst vec3 weights = vec3( ${pl.x.toFixed(4)}, ${pl.y.toFixed(4)}, ${pl.z.toFixed(4)} );`,"\treturn dot( weights, rgb );","}"].join("\n")}function fl(t){return""!==t}function gl(t,e){const n=e.numSpotLightShadows+e.numSpotLightMaps-e.numSpotLightShadowsWithMaps;return t.replace(/NUM_DIR_LIGHTS/g,e.numDirLights).replace(/NUM_SPOT_LIGHTS/g,e.numSpotLights).replace(/NUM_SPOT_LIGHT_MAPS/g,e.numSpotLightMaps).replace(/NUM_SPOT_LIGHT_COORDS/g,n).replace(/NUM_RECT_AREA_LIGHTS/g,e.numRectAreaLights).replace(/NUM_POINT_LIGHTS/g,e.numPointLights).replace(/NUM_HEMI_LIGHTS/g,e.numHemiLights).replace(/NUM_DIR_LIGHT_SHADOWS/g,e.numDirLightShadows).replace(/NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g,e.numSpotLightShadowsWithMaps).replace(/NUM_SPOT_LIGHT_SHADOWS/g,e.numSpotLightShadows).replace(/NUM_POINT_LIGHT_SHADOWS/g,e.numPointLightShadows)}function vl(t,e){return t.replace(/NUM_CLIPPING_PLANES/g,e.numClippingPlanes).replace(/UNION_CLIPPING_PLANES/g,e.numClippingPlanes-e.numClipIntersection)}const _l=/^[ \t]*#include +<([\w\d./]+)>/gm;function xl(t){return t.replace(_l,Ml)}const yl=new Map;function Ml(t,e){let n=va[e];if(void 0===n){const t=yl.get(e);if(void 0===t)throw new Error("Can not resolve #include <"+e+">");n=va[t],console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',e,t)}return xl(n)}const Sl=/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;function bl(t){return t.replace(Sl,wl)}function wl(t,e,n,i){let r="";for(let t=parseInt(e);t0&&(x+="\n"),y=["#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,v].filter(fl).join("\n"),y.length>0&&(y+="\n")):(x=[Tl(n),"#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,v,n.extensionClipCullDistance?"#define USE_CLIP_DISTANCE":"",n.batching?"#define USE_BATCHING":"",n.batchingColor?"#define USE_BATCHING_COLOR":"",n.instancing?"#define USE_INSTANCING":"",n.instancingColor?"#define USE_INSTANCING_COLOR":"",n.instancingMorph?"#define USE_INSTANCING_MORPH":"",n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.map?"#define USE_MAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+p:"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",n.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",n.displacementMap?"#define USE_DISPLACEMENTMAP":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.anisotropy?"#define USE_ANISOTROPY":"",n.anisotropyMap?"#define USE_ANISOTROPYMAP":"",n.clearcoatMap?"#define USE_CLEARCOATMAP":"",n.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",n.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",n.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.alphaHash?"#define USE_ALPHAHASH":"",n.transmission?"#define USE_TRANSMISSION":"",n.transmissionMap?"#define USE_TRANSMISSIONMAP":"",n.thicknessMap?"#define USE_THICKNESSMAP":"",n.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",n.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",n.mapUv?"#define MAP_UV "+n.mapUv:"",n.alphaMapUv?"#define ALPHAMAP_UV "+n.alphaMapUv:"",n.lightMapUv?"#define LIGHTMAP_UV "+n.lightMapUv:"",n.aoMapUv?"#define AOMAP_UV "+n.aoMapUv:"",n.emissiveMapUv?"#define EMISSIVEMAP_UV "+n.emissiveMapUv:"",n.bumpMapUv?"#define BUMPMAP_UV "+n.bumpMapUv:"",n.normalMapUv?"#define NORMALMAP_UV "+n.normalMapUv:"",n.displacementMapUv?"#define DISPLACEMENTMAP_UV "+n.displacementMapUv:"",n.metalnessMapUv?"#define METALNESSMAP_UV "+n.metalnessMapUv:"",n.roughnessMapUv?"#define ROUGHNESSMAP_UV "+n.roughnessMapUv:"",n.anisotropyMapUv?"#define ANISOTROPYMAP_UV "+n.anisotropyMapUv:"",n.clearcoatMapUv?"#define CLEARCOATMAP_UV "+n.clearcoatMapUv:"",n.clearcoatNormalMapUv?"#define CLEARCOAT_NORMALMAP_UV "+n.clearcoatNormalMapUv:"",n.clearcoatRoughnessMapUv?"#define CLEARCOAT_ROUGHNESSMAP_UV "+n.clearcoatRoughnessMapUv:"",n.iridescenceMapUv?"#define IRIDESCENCEMAP_UV "+n.iridescenceMapUv:"",n.iridescenceThicknessMapUv?"#define IRIDESCENCE_THICKNESSMAP_UV "+n.iridescenceThicknessMapUv:"",n.sheenColorMapUv?"#define SHEEN_COLORMAP_UV "+n.sheenColorMapUv:"",n.sheenRoughnessMapUv?"#define SHEEN_ROUGHNESSMAP_UV "+n.sheenRoughnessMapUv:"",n.specularMapUv?"#define SPECULARMAP_UV "+n.specularMapUv:"",n.specularColorMapUv?"#define SPECULAR_COLORMAP_UV "+n.specularColorMapUv:"",n.specularIntensityMapUv?"#define SPECULAR_INTENSITYMAP_UV "+n.specularIntensityMapUv:"",n.transmissionMapUv?"#define TRANSMISSIONMAP_UV "+n.transmissionMapUv:"",n.thicknessMapUv?"#define THICKNESSMAP_UV "+n.thicknessMapUv:"",n.vertexTangents&&!1===n.flatShading?"#define USE_TANGENT":"",n.vertexColors?"#define USE_COLOR":"",n.vertexAlphas?"#define USE_COLOR_ALPHA":"",n.vertexUv1s?"#define USE_UV1":"",n.vertexUv2s?"#define USE_UV2":"",n.vertexUv3s?"#define USE_UV3":"",n.pointsUvs?"#define USE_POINTS_UV":"",n.flatShading?"#define FLAT_SHADED":"",n.skinning?"#define USE_SKINNING":"",n.morphTargets?"#define USE_MORPHTARGETS":"",n.morphNormals&&!1===n.flatShading?"#define USE_MORPHNORMALS":"",n.morphColors?"#define USE_MORPHCOLORS":"",n.morphTargetsCount>0?"#define MORPHTARGETS_TEXTURE_STRIDE "+n.morphTextureStride:"",n.morphTargetsCount>0?"#define MORPHTARGETS_COUNT "+n.morphTargetsCount:"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+u:"",n.sizeAttenuation?"#define USE_SIZEATTENUATION":"",n.numLightProbes>0?"#define USE_LIGHT_PROBES":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING","\tattribute mat4 instanceMatrix;","#endif","#ifdef USE_INSTANCING_COLOR","\tattribute vec3 instanceColor;","#endif","#ifdef USE_INSTANCING_MORPH","\tuniform sampler2D morphTexture;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_UV1","\tattribute vec2 uv1;","#endif","#ifdef USE_UV2","\tattribute vec2 uv2;","#endif","#ifdef USE_UV3","\tattribute vec2 uv3;","#endif","#ifdef USE_TANGENT","\tattribute vec4 tangent;","#endif","#if defined( USE_COLOR_ALPHA )","\tattribute vec4 color;","#elif defined( USE_COLOR )","\tattribute vec3 color;","#endif","#ifdef USE_SKINNING","\tattribute vec4 skinIndex;","\tattribute vec4 skinWeight;","#endif","\n"].filter(fl).join("\n"),y=[Tl(n),"#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,v,n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.alphaToCoverage?"#define ALPHA_TO_COVERAGE":"",n.map?"#define USE_MAP":"",n.matcap?"#define USE_MATCAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+d:"",n.envMap?"#define "+p:"",n.envMap?"#define "+m:"",f?"#define CUBEUV_TEXEL_WIDTH "+f.texelWidth:"",f?"#define CUBEUV_TEXEL_HEIGHT "+f.texelHeight:"",f?"#define CUBEUV_MAX_MIP "+f.maxMip+".0":"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",n.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.anisotropy?"#define USE_ANISOTROPY":"",n.anisotropyMap?"#define USE_ANISOTROPYMAP":"",n.clearcoat?"#define USE_CLEARCOAT":"",n.clearcoatMap?"#define USE_CLEARCOATMAP":"",n.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.dispersion?"#define USE_DISPERSION":"",n.iridescence?"#define USE_IRIDESCENCE":"",n.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",n.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",n.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.alphaTest?"#define USE_ALPHATEST":"",n.alphaHash?"#define USE_ALPHAHASH":"",n.sheen?"#define USE_SHEEN":"",n.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",n.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",n.transmission?"#define USE_TRANSMISSION":"",n.transmissionMap?"#define USE_TRANSMISSIONMAP":"",n.thicknessMap?"#define USE_THICKNESSMAP":"",n.vertexTangents&&!1===n.flatShading?"#define USE_TANGENT":"",n.vertexColors||n.instancingColor||n.batchingColor?"#define USE_COLOR":"",n.vertexAlphas?"#define USE_COLOR_ALPHA":"",n.vertexUv1s?"#define USE_UV1":"",n.vertexUv2s?"#define USE_UV2":"",n.vertexUv3s?"#define USE_UV3":"",n.pointsUvs?"#define USE_POINTS_UV":"",n.gradientMap?"#define USE_GRADIENTMAP":"",n.flatShading?"#define FLAT_SHADED":"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+u:"",n.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",n.numLightProbes>0?"#define USE_LIGHT_PROBES":"",n.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",n.toneMapping!==K?"#define TONE_MAPPING":"",n.toneMapping!==K?va.tonemapping_pars_fragment:"",n.toneMapping!==K?dl("toneMapping",n.toneMapping):"",n.dithering?"#define DITHERING":"",n.opaque?"#define OPAQUE":"",va.colorspace_pars_fragment,ul("linearToOutputTexel",n.outputColorSpace),ml(),n.useDepthPacking?"#define DEPTH_PACKING "+n.depthPacking:"","\n"].filter(fl).join("\n")),a=xl(a),a=gl(a,n),a=vl(a,n),o=xl(o),o=gl(o,n),o=vl(o,n),a=bl(a),o=bl(o),!0!==n.isRawShaderMaterial&&(M="#version 300 es\n",x=[g,"#define attribute in","#define varying out","#define texture2D texture"].join("\n")+"\n"+x,y=["#define varying in",n.glslVersion===zn?"":"layout(location = 0) out highp vec4 pc_fragColor;",n.glslVersion===zn?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join("\n")+"\n"+y);const S=M+x+a,b=M+y+o,w=ol(r,r.VERTEX_SHADER,S),T=ol(r,r.FRAGMENT_SHADER,b);function E(e){if(t.debug.checkShaderErrors){const n=r.getProgramInfoLog(_).trim(),i=r.getShaderInfoLog(w).trim(),s=r.getShaderInfoLog(T).trim();let a=!0,o=!0;if(!1===r.getProgramParameter(_,r.LINK_STATUS))if(a=!1,"function"==typeof t.debug.onShaderError)t.debug.onShaderError(r,_,w,T);else{const t=hl(r,w,"vertex"),i=hl(r,T,"fragment");console.error("THREE.WebGLProgram: Shader Error "+r.getError()+" - VALIDATE_STATUS "+r.getProgramParameter(_,r.VALIDATE_STATUS)+"\n\nMaterial Name: "+e.name+"\nMaterial Type: "+e.type+"\n\nProgram Info Log: "+n+"\n"+t+"\n"+i)}else""!==n?console.warn("THREE.WebGLProgram: Program Info Log:",n):""!==i&&""!==s||(o=!1);o&&(e.diagnostics={runnable:a,programLog:n,vertexShader:{log:i,prefix:x},fragmentShader:{log:s,prefix:y}})}r.deleteShader(w),r.deleteShader(T),A=new al(r,_),R=function(t,e){const n={},i=t.getProgramParameter(e,t.ACTIVE_ATTRIBUTES);for(let r=0;r0,q=s.clearcoat>0,Y=s.dispersion>0,Z=s.iridescence>0,J=s.sheen>0,$=s.transmission>0,Q=j&&!!s.anisotropyMap,tt=q&&!!s.clearcoatMap,et=q&&!!s.clearcoatNormalMap,nt=q&&!!s.clearcoatRoughnessMap,it=Z&&!!s.iridescenceMap,rt=Z&&!!s.iridescenceThicknessMap,st=J&&!!s.sheenColorMap,at=J&&!!s.sheenRoughnessMap,ot=!!s.specularMap,lt=!!s.specularColorMap,ct=!!s.specularIntensityMap,ht=$&&!!s.transmissionMap,ut=$&&!!s.thicknessMap,pt=!!s.gradientMap,mt=!!s.alphaMap,ft=s.alphaTest>0,gt=!!s.alphaHash,vt=!!s.extensions;let _t=K;s.toneMapped&&(null!==L&&!0!==L.isXRRenderTarget||(_t=t.toneMapping));const xt={shaderID:w,shaderType:s.type,shaderName:s.name,vertexShader:A,fragmentShader:R,defines:s.defines,customVertexShaderID:C,customFragmentShaderID:P,isRawShaderMaterial:!0===s.isRawShaderMaterial,glslVersion:s.glslVersion,precision:m,batching:N,batchingColor:N&&null!==_._colorsTexture,instancing:U,instancingColor:U&&null!==_.instanceColor,instancingMorph:U&&null!==_.morphTexture,supportsVertexTextures:p,outputColorSpace:null===L?t.outputColorSpace:!0===L.isXRRenderTarget?L.texture.colorSpace:Ke,alphaToCoverage:!!s.alphaToCoverage,map:D,matcap:O,envMap:F,envMapMode:F&&S.mapping,envMapCubeUVHeight:b,aoMap:B,lightMap:z,bumpMap:k,normalMap:V,displacementMap:p&&H,emissiveMap:G,normalMapObjectSpace:V&&1===s.normalMapType,normalMapTangentSpace:V&&0===s.normalMapType,metalnessMap:W,roughnessMap:X,anisotropy:j,anisotropyMap:Q,clearcoat:q,clearcoatMap:tt,clearcoatNormalMap:et,clearcoatRoughnessMap:nt,dispersion:Y,iridescence:Z,iridescenceMap:it,iridescenceThicknessMap:rt,sheen:J,sheenColorMap:st,sheenRoughnessMap:at,specularMap:ot,specularColorMap:lt,specularIntensityMap:ct,transmission:$,transmissionMap:ht,thicknessMap:ut,gradientMap:pt,opaque:!1===s.transparent&&1===s.blending&&!1===s.alphaToCoverage,alphaMap:mt,alphaTest:ft,alphaHash:gt,combine:s.combine,mapUv:D&&g(s.map.channel),aoMapUv:B&&g(s.aoMap.channel),lightMapUv:z&&g(s.lightMap.channel),bumpMapUv:k&&g(s.bumpMap.channel),normalMapUv:V&&g(s.normalMap.channel),displacementMapUv:H&&g(s.displacementMap.channel),emissiveMapUv:G&&g(s.emissiveMap.channel),metalnessMapUv:W&&g(s.metalnessMap.channel),roughnessMapUv:X&&g(s.roughnessMap.channel),anisotropyMapUv:Q&&g(s.anisotropyMap.channel),clearcoatMapUv:tt&&g(s.clearcoatMap.channel),clearcoatNormalMapUv:et&&g(s.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:nt&&g(s.clearcoatRoughnessMap.channel),iridescenceMapUv:it&&g(s.iridescenceMap.channel),iridescenceThicknessMapUv:rt&&g(s.iridescenceThicknessMap.channel),sheenColorMapUv:st&&g(s.sheenColorMap.channel),sheenRoughnessMapUv:at&&g(s.sheenRoughnessMap.channel),specularMapUv:ot&&g(s.specularMap.channel),specularColorMapUv:lt&&g(s.specularColorMap.channel),specularIntensityMapUv:ct&&g(s.specularIntensityMap.channel),transmissionMapUv:ht&&g(s.transmissionMap.channel),thicknessMapUv:ut&&g(s.thicknessMap.channel),alphaMapUv:mt&&g(s.alphaMap.channel),vertexTangents:!!y.attributes.tangent&&(V||j),vertexColors:s.vertexColors,vertexAlphas:!0===s.vertexColors&&!!y.attributes.color&&4===y.attributes.color.itemSize,pointsUvs:!0===_.isPoints&&!!y.attributes.uv&&(D||mt),fog:!!x,useFog:!0===s.fog,fogExp2:!!x&&x.isFogExp2,flatShading:!0===s.flatShading,sizeAttenuation:!0===s.sizeAttenuation,logarithmicDepthBuffer:u,skinning:!0===_.isSkinnedMesh,morphTargets:void 0!==y.morphAttributes.position,morphNormals:void 0!==y.morphAttributes.normal,morphColors:void 0!==y.morphAttributes.color,morphTargetsCount:E,morphTextureStride:I,numDirLights:o.directional.length,numPointLights:o.point.length,numSpotLights:o.spot.length,numSpotLightMaps:o.spotLightMap.length,numRectAreaLights:o.rectArea.length,numHemiLights:o.hemi.length,numDirLightShadows:o.directionalShadowMap.length,numPointLightShadows:o.pointShadowMap.length,numSpotLightShadows:o.spotShadowMap.length,numSpotLightShadowsWithMaps:o.numSpotLightShadowsWithMaps,numLightProbes:o.numLightProbes,numClippingPlanes:a.numPlanes,numClipIntersection:a.numIntersection,dithering:s.dithering,shadowMapEnabled:t.shadowMap.enabled&&h.length>0,shadowMapType:t.shadowMap.type,toneMapping:_t,decodeVideoTexture:D&&!0===s.map.isVideoTexture&&mi.getTransfer(s.map.colorSpace)===en,premultipliedAlpha:s.premultipliedAlpha,doubleSided:2===s.side,flipSided:s.side===d,useDepthPacking:s.depthPacking>=0,depthPacking:s.depthPacking||0,index0AttributeName:s.index0AttributeName,extensionClipCullDistance:vt&&!0===s.extensions.clipCullDistance&&i.has("WEBGL_clip_cull_distance"),extensionMultiDraw:(vt&&!0===s.extensions.multiDraw||N)&&i.has("WEBGL_multi_draw"),rendererExtensionParallelShaderCompile:i.has("KHR_parallel_shader_compile"),customProgramCacheKey:s.customProgramCacheKey()};return xt.vertexUv1s=c.has(1),xt.vertexUv2s=c.has(2),xt.vertexUv3s=c.has(3),c.clear(),xt},getProgramCacheKey:function(e){const n=[];if(e.shaderID?n.push(e.shaderID):(n.push(e.customVertexShaderID),n.push(e.customFragmentShaderID)),void 0!==e.defines)for(const t in e.defines)n.push(t),n.push(e.defines[t]);return!1===e.isRawShaderMaterial&&(!function(t,e){t.push(e.precision),t.push(e.outputColorSpace),t.push(e.envMapMode),t.push(e.envMapCubeUVHeight),t.push(e.mapUv),t.push(e.alphaMapUv),t.push(e.lightMapUv),t.push(e.aoMapUv),t.push(e.bumpMapUv),t.push(e.normalMapUv),t.push(e.displacementMapUv),t.push(e.emissiveMapUv),t.push(e.metalnessMapUv),t.push(e.roughnessMapUv),t.push(e.anisotropyMapUv),t.push(e.clearcoatMapUv),t.push(e.clearcoatNormalMapUv),t.push(e.clearcoatRoughnessMapUv),t.push(e.iridescenceMapUv),t.push(e.iridescenceThicknessMapUv),t.push(e.sheenColorMapUv),t.push(e.sheenRoughnessMapUv),t.push(e.specularMapUv),t.push(e.specularColorMapUv),t.push(e.specularIntensityMapUv),t.push(e.transmissionMapUv),t.push(e.thicknessMapUv),t.push(e.combine),t.push(e.fogExp2),t.push(e.sizeAttenuation),t.push(e.morphTargetsCount),t.push(e.morphAttributeCount),t.push(e.numDirLights),t.push(e.numPointLights),t.push(e.numSpotLights),t.push(e.numSpotLightMaps),t.push(e.numHemiLights),t.push(e.numRectAreaLights),t.push(e.numDirLightShadows),t.push(e.numPointLightShadows),t.push(e.numSpotLightShadows),t.push(e.numSpotLightShadowsWithMaps),t.push(e.numLightProbes),t.push(e.shadowMapType),t.push(e.toneMapping),t.push(e.numClippingPlanes),t.push(e.numClipIntersection),t.push(e.depthPacking)}(n,e),function(t,e){o.disableAll(),e.supportsVertexTextures&&o.enable(0);e.instancing&&o.enable(1);e.instancingColor&&o.enable(2);e.instancingMorph&&o.enable(3);e.matcap&&o.enable(4);e.envMap&&o.enable(5);e.normalMapObjectSpace&&o.enable(6);e.normalMapTangentSpace&&o.enable(7);e.clearcoat&&o.enable(8);e.iridescence&&o.enable(9);e.alphaTest&&o.enable(10);e.vertexColors&&o.enable(11);e.vertexAlphas&&o.enable(12);e.vertexUv1s&&o.enable(13);e.vertexUv2s&&o.enable(14);e.vertexUv3s&&o.enable(15);e.vertexTangents&&o.enable(16);e.anisotropy&&o.enable(17);e.alphaHash&&o.enable(18);e.batching&&o.enable(19);e.dispersion&&o.enable(20);e.batchingColor&&o.enable(21);t.push(o.mask),o.disableAll(),e.fog&&o.enable(0);e.useFog&&o.enable(1);e.flatShading&&o.enable(2);e.logarithmicDepthBuffer&&o.enable(3);e.skinning&&o.enable(4);e.morphTargets&&o.enable(5);e.morphNormals&&o.enable(6);e.morphColors&&o.enable(7);e.premultipliedAlpha&&o.enable(8);e.shadowMapEnabled&&o.enable(9);e.doubleSided&&o.enable(10);e.flipSided&&o.enable(11);e.useDepthPacking&&o.enable(12);e.dithering&&o.enable(13);e.transmission&&o.enable(14);e.sheen&&o.enable(15);e.opaque&&o.enable(16);e.pointsUvs&&o.enable(17);e.decodeVideoTexture&&o.enable(18);e.alphaToCoverage&&o.enable(19);t.push(o.mask)}(n,e),n.push(t.outputColorSpace)),n.push(e.customProgramCacheKey),n.join()},getUniforms:function(t){const e=f[t.type];let n;if(e){const t=xa[e];n=Js.clone(t.uniforms)}else n=t.uniforms;return n},acquireProgram:function(e,n){let i;for(let t=0,e=h.length;t0?i.push(h):!0===a.transparent?r.push(h):n.push(h)},unshift:function(t,e,a,o,l,c){const h=s(t,e,a,o,l,c);a.transmission>0?i.unshift(h):!0===a.transparent?r.unshift(h):n.unshift(h)},finish:function(){for(let n=e,i=t.length;n1&&n.sort(t||Ll),i.length>1&&i.sort(e||Ul),r.length>1&&r.sort(e||Ul)}}}function Dl(){let t=new WeakMap;return{get:function(e,n){const i=t.get(e);let r;return void 0===i?(r=new Nl,t.set(e,[r])):n>=i.length?(r=new Nl,i.push(r)):r=i[n],r},dispose:function(){t=new WeakMap}}}function Ol(){const t={};return{get:function(e){if(void 0!==t[e.id])return t[e.id];let n;switch(e.type){case"DirectionalLight":n={direction:new Li,color:new Kr};break;case"SpotLight":n={position:new Li,direction:new Li,color:new Kr,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":n={position:new Li,color:new Kr,distance:0,decay:0};break;case"HemisphereLight":n={direction:new Li,skyColor:new Kr,groundColor:new Kr};break;case"RectAreaLight":n={color:new Kr,position:new Li,halfWidth:new Li,halfHeight:new Li}}return t[e.id]=n,n}}}let Fl=0;function Bl(t,e){return(e.castShadow?2:0)-(t.castShadow?2:0)+(e.map?1:0)-(t.map?1:0)}function zl(t){const e=new Ol,n=function(){const t={};return{get:function(e){if(void 0!==t[e.id])return t[e.id];let n;switch(e.type){case"DirectionalLight":case"SpotLight":n={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new ti};break;case"PointLight":n={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new ti,shadowCameraNear:1,shadowCameraFar:1e3}}return t[e.id]=n,n}}}(),i={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1,numSpotMaps:-1,numLightProbes:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotLightMap:[],spotShadow:[],spotShadowMap:[],spotLightMatrix:[],rectArea:[],rectAreaLTC1:null,rectAreaLTC2:null,point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[],numSpotLightShadowsWithMaps:0,numLightProbes:0};for(let t=0;t<9;t++)i.probe.push(new Li);const r=new Li,s=new lr,a=new lr;return{setup:function(r){let s=0,a=0,o=0;for(let t=0;t<9;t++)i.probe[t].set(0,0,0);let l=0,c=0,h=0,u=0,d=0,p=0,m=0,f=0,g=0,v=0,_=0;r.sort(Bl);for(let t=0,x=r.length;t0&&(!0===t.has("OES_texture_float_linear")?(i.rectAreaLTC1=_a.LTC_FLOAT_1,i.rectAreaLTC2=_a.LTC_FLOAT_2):(i.rectAreaLTC1=_a.LTC_HALF_1,i.rectAreaLTC2=_a.LTC_HALF_2)),i.ambient[0]=s,i.ambient[1]=a,i.ambient[2]=o;const x=i.hash;x.directionalLength===l&&x.pointLength===c&&x.spotLength===h&&x.rectAreaLength===u&&x.hemiLength===d&&x.numDirectionalShadows===p&&x.numPointShadows===m&&x.numSpotShadows===f&&x.numSpotMaps===g&&x.numLightProbes===_||(i.directional.length=l,i.spot.length=h,i.rectArea.length=u,i.point.length=c,i.hemi.length=d,i.directionalShadow.length=p,i.directionalShadowMap.length=p,i.pointShadow.length=m,i.pointShadowMap.length=m,i.spotShadow.length=f,i.spotShadowMap.length=f,i.directionalShadowMatrix.length=p,i.pointShadowMatrix.length=m,i.spotLightMatrix.length=f+g-v,i.spotLightMap.length=g,i.numSpotLightShadowsWithMaps=v,i.numLightProbes=_,x.directionalLength=l,x.pointLength=c,x.spotLength=h,x.rectAreaLength=u,x.hemiLength=d,x.numDirectionalShadows=p,x.numPointShadows=m,x.numSpotShadows=f,x.numSpotMaps=g,x.numLightProbes=_,i.version=Fl++)},setupView:function(t,e){let n=0,o=0,l=0,c=0,h=0;const u=e.matrixWorldInverse;for(let e=0,d=t.length;e=r.length?(s=new kl(t),r.push(s)):s=r[i],s},dispose:function(){e=new WeakMap}}}class Hl extends ts{constructor(t){super(),this.isMeshDepthMaterial=!0,this.type="MeshDepthMaterial",this.depthPacking=3200,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.setValues(t)}copy(t){return super.copy(t),this.depthPacking=t.depthPacking,this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this}}class Gl extends ts{constructor(t){super(),this.isMeshDistanceMaterial=!0,this.type="MeshDistanceMaterial",this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.setValues(t)}copy(t){return super.copy(t),this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this}}function Wl(t,e,n){let i=new pa;const r=new ti,s=new ti,a=new wi,o=new Hl({depthPacking:3201}),c=new Gl,p={},m=n.maxTextureSize,f={[u]:d,[d]:u,2:2},g=new Ks({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new ti},radius:{value:4}},vertexShader:"void main() {\n\tgl_Position = vec4( position, 1.0 );\n}",fragmentShader:"uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include \nvoid main() {\n\tconst float samples = float( VSM_SAMPLES );\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"}),v=g.clone();v.defines.HORIZONTAL_PASS=1;const _=new Es;_.setAttribute("position",new cs(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const x=new Ws(_,g),y=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=l;let M=this.type;function S(n,i){const s=e.update(x);g.defines.VSM_SAMPLES!==n.blurSamples&&(g.defines.VSM_SAMPLES=n.blurSamples,v.defines.VSM_SAMPLES=n.blurSamples,g.needsUpdate=!0,v.needsUpdate=!0),null===n.mapPass&&(n.mapPass=new Ei(r.x,r.y)),g.uniforms.shadow_pass.value=n.map.texture,g.uniforms.resolution.value=n.mapSize,g.uniforms.radius.value=n.radius,t.setRenderTarget(n.mapPass),t.clear(),t.renderBufferDirect(i,null,s,g,x,null),v.uniforms.shadow_pass.value=n.mapPass.texture,v.uniforms.resolution.value=n.mapSize,v.uniforms.radius.value=n.radius,t.setRenderTarget(n.map),t.clear(),t.renderBufferDirect(i,null,s,v,x,null)}function b(e,n,i,r){let s=null;const a=!0===i.isPointLight?e.customDistanceMaterial:e.customDepthMaterial;if(void 0!==a)s=a;else if(s=!0===i.isPointLight?c:o,t.localClippingEnabled&&!0===n.clipShadows&&Array.isArray(n.clippingPlanes)&&0!==n.clippingPlanes.length||n.displacementMap&&0!==n.displacementScale||n.alphaMap&&n.alphaTest>0||n.map&&n.alphaTest>0){const t=s.uuid,e=n.uuid;let i=p[t];void 0===i&&(i={},p[t]=i);let r=i[e];void 0===r&&(r=s.clone(),i[e]=r,n.addEventListener("dispose",T)),s=r}if(s.visible=n.visible,s.wireframe=n.wireframe,s.side=r===h?null!==n.shadowSide?n.shadowSide:n.side:null!==n.shadowSide?n.shadowSide:f[n.side],s.alphaMap=n.alphaMap,s.alphaTest=n.alphaTest,s.map=n.map,s.clipShadows=n.clipShadows,s.clippingPlanes=n.clippingPlanes,s.clipIntersection=n.clipIntersection,s.displacementMap=n.displacementMap,s.displacementScale=n.displacementScale,s.displacementBias=n.displacementBias,s.wireframeLinewidth=n.wireframeLinewidth,s.linewidth=n.linewidth,!0===i.isPointLight&&!0===s.isMeshDistanceMaterial){t.properties.get(s).light=i}return s}function w(n,r,s,a,o){if(!1===n.visible)return;if(n.layers.test(r.layers)&&(n.isMesh||n.isLine||n.isPoints)&&(n.castShadow||n.receiveShadow&&o===h)&&(!n.frustumCulled||i.intersectsObject(n))){n.modelViewMatrix.multiplyMatrices(s.matrixWorldInverse,n.matrixWorld);const i=e.update(n),l=n.material;if(Array.isArray(l)){const e=i.groups;for(let c=0,h=e.length;cm||r.y>m)&&(r.x>m&&(s.x=Math.floor(m/g.x),r.x=s.x*g.x,u.mapSize.x=s.x),r.y>m&&(s.y=Math.floor(m/g.y),r.y=s.y*g.y,u.mapSize.y=s.y)),null===u.map||!0===p||!0===f){const t=this.type!==h?{minFilter:gt,magFilter:gt}:{};null!==u.map&&u.map.dispose(),u.map=new Ei(r.x,r.y,t),u.map.texture.name=c.name+".shadowMap",u.camera.updateProjectionMatrix()}t.setRenderTarget(u.map),t.clear();const v=u.getViewportCount();for(let t=0;t=1):-1!==N.indexOf("OpenGL ES")&&(U=parseFloat(/^OpenGL ES (\d)/.exec(N)[1]),L=U>=2);let D=null,O={};const F=t.getParameter(t.SCISSOR_BOX),B=t.getParameter(t.VIEWPORT),z=(new wi).fromArray(F),k=(new wi).fromArray(B);function V(e,n,i,r){const s=new Uint8Array(4),a=t.createTexture();t.bindTexture(e,a),t.texParameteri(e,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(e,t.TEXTURE_MAG_FILTER,t.NEAREST);for(let a=0;ae?(t.repeat.x=1,t.repeat.y=n/e,t.offset.x=0,t.offset.y=(1-t.repeat.y)/2):(t.repeat.x=e/n,t.repeat.y=1,t.offset.x=(1-t.repeat.x)/2,t.offset.y=0),t},cover:function(t,e){const n=t.image&&t.image.width?t.image.width/t.image.height:1;return n>e?(t.repeat.x=e/n,t.repeat.y=1,t.offset.x=(1-t.repeat.x)/2,t.offset.y=0):(t.repeat.x=1,t.repeat.y=n/e,t.offset.x=0,t.offset.y=(1-t.repeat.y)/2),t},fill:function(t){return t.repeat.x=1,t.repeat.y=1,t.offset.x=0,t.offset.y=0,t},getByteLength:jl};function Yl(t,e,n,i,r,s,a){const o=e.has("WEBGL_multisampled_render_to_texture")?e.get("WEBGL_multisampled_render_to_texture"):null,l="undefined"!=typeof navigator&&/OculusBrowser/g.test(navigator.userAgent),c=new ti,h=new WeakMap;let u;const d=new WeakMap;let p=!1;try{p="undefined"!=typeof OffscreenCanvas&&null!==new OffscreenCanvas(1,1).getContext("2d")}catch(t){}function m(t,e){return p?new OffscreenCanvas(t,e):ai("canvas")}function f(t,e,n){let i=1;const r=k(t);if((r.width>n||r.height>n)&&(i=n/Math.max(r.width,r.height)),i<1){if("undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&t instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&t instanceof ImageBitmap||"undefined"!=typeof VideoFrame&&t instanceof VideoFrame){const n=Math.floor(i*r.width),s=Math.floor(i*r.height);void 0===u&&(u=m(n,s));const a=e?m(n,s):u;a.width=n,a.height=s;return a.getContext("2d").drawImage(t,0,0,n,s),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+r.width+"x"+r.height+") to ("+n+"x"+s+")."),a}return"data"in t&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+r.width+"x"+r.height+")."),t}return t}function g(t){return t.generateMipmaps&&t.minFilter!==gt&&t.minFilter!==Mt}function v(e){t.generateMipmap(e)}function _(n,i,r,s,a=!1){if(null!==n){if(void 0!==t[n])return t[n];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+n+"'")}let o=i;if(i===t.RED&&(r===t.FLOAT&&(o=t.R32F),r===t.HALF_FLOAT&&(o=t.R16F),r===t.UNSIGNED_BYTE&&(o=t.R8)),i===t.RED_INTEGER&&(r===t.UNSIGNED_BYTE&&(o=t.R8UI),r===t.UNSIGNED_SHORT&&(o=t.R16UI),r===t.UNSIGNED_INT&&(o=t.R32UI),r===t.BYTE&&(o=t.R8I),r===t.SHORT&&(o=t.R16I),r===t.INT&&(o=t.R32I)),i===t.RG&&(r===t.FLOAT&&(o=t.RG32F),r===t.HALF_FLOAT&&(o=t.RG16F),r===t.UNSIGNED_BYTE&&(o=t.RG8)),i===t.RG_INTEGER&&(r===t.UNSIGNED_BYTE&&(o=t.RG8UI),r===t.UNSIGNED_SHORT&&(o=t.RG16UI),r===t.UNSIGNED_INT&&(o=t.RG32UI),r===t.BYTE&&(o=t.RG8I),r===t.SHORT&&(o=t.RG16I),r===t.INT&&(o=t.RG32I)),i===t.RGB&&r===t.UNSIGNED_INT_5_9_9_9_REV&&(o=t.RGB9_E5),i===t.RGBA){const e=a?tn:mi.getTransfer(s);r===t.FLOAT&&(o=t.RGBA32F),r===t.HALF_FLOAT&&(o=t.RGBA16F),r===t.UNSIGNED_BYTE&&(o=e===en?t.SRGB8_ALPHA8:t.RGBA8),r===t.UNSIGNED_SHORT_4_4_4_4&&(o=t.RGBA4),r===t.UNSIGNED_SHORT_5_5_5_1&&(o=t.RGB5_A1)}return o!==t.R16F&&o!==t.R32F&&o!==t.RG16F&&o!==t.RG32F&&o!==t.RGBA16F&&o!==t.RGBA32F||e.get("EXT_color_buffer_float"),o}function x(e,n){let i;return e?null===n||n===It||n===Ot?i=t.DEPTH24_STENCIL8:n===Lt?i=t.DEPTH32F_STENCIL8:n===Ct&&(i=t.DEPTH24_STENCIL8,console.warn("DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.")):null===n||n===It||n===Ot?i=t.DEPTH_COMPONENT24:n===Lt?i=t.DEPTH_COMPONENT32F:n===Ct&&(i=t.DEPTH_COMPONENT16),i}function y(t,e){return!0===g(t)||t.isFramebufferTexture&&t.minFilter!==gt&&t.minFilter!==Mt?Math.log2(Math.max(e.width,e.height))+1:void 0!==t.mipmaps&&t.mipmaps.length>0?t.mipmaps.length:t.isCompressedTexture&&Array.isArray(t.image)?e.mipmaps.length:1}function M(t){const e=t.target;e.removeEventListener("dispose",M),function(t){const e=i.get(t);if(void 0===e.__webglInit)return;const n=t.source,r=d.get(n);if(r){const i=r[e.__cacheKey];i.usedTimes--,0===i.usedTimes&&b(t),0===Object.keys(r).length&&d.delete(n)}i.remove(t)}(e),e.isVideoTexture&&h.delete(e)}function S(e){const n=e.target;n.removeEventListener("dispose",S),function(e){const n=i.get(e);e.depthTexture&&e.depthTexture.dispose();if(e.isWebGLCubeRenderTarget)for(let e=0;e<6;e++){if(Array.isArray(n.__webglFramebuffer[e]))for(let i=0;i0&&s.__version!==e.version){const t=e.image;if(null===t)console.warn("THREE.WebGLRenderer: Texture marked for update but no image data found.");else{if(!1!==t.complete)return void I(s,e,r);console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete")}}n.bindTexture(t.TEXTURE_2D,s.__webglTexture,t.TEXTURE0+r)}const E={[pt]:t.REPEAT,[mt]:t.CLAMP_TO_EDGE,[ft]:t.MIRRORED_REPEAT},A={[gt]:t.NEAREST,[vt]:t.NEAREST_MIPMAP_NEAREST,[xt]:t.NEAREST_MIPMAP_LINEAR,[Mt]:t.LINEAR,[St]:t.LINEAR_MIPMAP_NEAREST,[wt]:t.LINEAR_MIPMAP_LINEAR},R={512:t.NEVER,519:t.ALWAYS,513:t.LESS,[wn]:t.LEQUAL,514:t.EQUAL,518:t.GEQUAL,516:t.GREATER,517:t.NOTEQUAL};function C(n,s){if(s.type!==Lt||!1!==e.has("OES_texture_float_linear")||s.magFilter!==Mt&&s.magFilter!==St&&s.magFilter!==xt&&s.magFilter!==wt&&s.minFilter!==Mt&&s.minFilter!==St&&s.minFilter!==xt&&s.minFilter!==wt||console.warn("THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device."),t.texParameteri(n,t.TEXTURE_WRAP_S,E[s.wrapS]),t.texParameteri(n,t.TEXTURE_WRAP_T,E[s.wrapT]),n!==t.TEXTURE_3D&&n!==t.TEXTURE_2D_ARRAY||t.texParameteri(n,t.TEXTURE_WRAP_R,E[s.wrapR]),t.texParameteri(n,t.TEXTURE_MAG_FILTER,A[s.magFilter]),t.texParameteri(n,t.TEXTURE_MIN_FILTER,A[s.minFilter]),s.compareFunction&&(t.texParameteri(n,t.TEXTURE_COMPARE_MODE,t.COMPARE_REF_TO_TEXTURE),t.texParameteri(n,t.TEXTURE_COMPARE_FUNC,R[s.compareFunction])),!0===e.has("EXT_texture_filter_anisotropic")){if(s.magFilter===gt)return;if(s.minFilter!==xt&&s.minFilter!==wt)return;if(s.type===Lt&&!1===e.has("OES_texture_float_linear"))return;if(s.anisotropy>1||i.get(s).__currentAnisotropy){const a=e.get("EXT_texture_filter_anisotropic");t.texParameterf(n,a.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(s.anisotropy,r.getMaxAnisotropy())),i.get(s).__currentAnisotropy=s.anisotropy}}}function P(e,n){let i=!1;void 0===e.__webglInit&&(e.__webglInit=!0,n.addEventListener("dispose",M));const r=n.source;let s=d.get(r);void 0===s&&(s={},d.set(r,s));const o=function(t){const e=[];return e.push(t.wrapS),e.push(t.wrapT),e.push(t.wrapR||0),e.push(t.magFilter),e.push(t.minFilter),e.push(t.anisotropy),e.push(t.internalFormat),e.push(t.format),e.push(t.type),e.push(t.generateMipmaps),e.push(t.premultiplyAlpha),e.push(t.flipY),e.push(t.unpackAlignment),e.push(t.colorSpace),e.join()}(n);if(o!==e.__cacheKey){void 0===s[o]&&(s[o]={texture:t.createTexture(),usedTimes:0},a.memory.textures++,i=!0),s[o].usedTimes++;const r=s[e.__cacheKey];void 0!==r&&(s[e.__cacheKey].usedTimes--,0===r.usedTimes&&b(n)),e.__cacheKey=o,e.__webglTexture=s[o].texture}return i}function I(e,a,o){let l=t.TEXTURE_2D;(a.isDataArrayTexture||a.isCompressedArrayTexture)&&(l=t.TEXTURE_2D_ARRAY),a.isData3DTexture&&(l=t.TEXTURE_3D);const c=P(e,a),h=a.source;n.bindTexture(l,e.__webglTexture,t.TEXTURE0+o);const u=i.get(h);if(h.version!==u.__version||!0===c){n.activeTexture(t.TEXTURE0+o);const e=mi.getPrimaries(mi.workingColorSpace),i=a.colorSpace===Ze?null:mi.getPrimaries(a.colorSpace),d=a.colorSpace===Ze||e===i?t.NONE:t.BROWSER_DEFAULT_WEBGL;t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,a.flipY),t.pixelStorei(t.UNPACK_PREMULTIPLY_ALPHA_WEBGL,a.premultiplyAlpha),t.pixelStorei(t.UNPACK_ALIGNMENT,a.unpackAlignment),t.pixelStorei(t.UNPACK_COLORSPACE_CONVERSION_WEBGL,d);let p=f(a.image,!1,r.maxTextureSize);p=z(a,p);const m=s.convert(a.format,a.colorSpace),M=s.convert(a.type);let S,b=_(a.internalFormat,m,M,a.colorSpace,a.isVideoTexture);C(l,a);const w=a.mipmaps,T=!0!==a.isVideoTexture,E=void 0===u.__version||!0===c,A=h.dataReady,R=y(a,p);if(a.isDepthTexture)b=x(a.format===Wt,a.type),E&&(T?n.texStorage2D(t.TEXTURE_2D,1,b,p.width,p.height):n.texImage2D(t.TEXTURE_2D,0,b,p.width,p.height,0,m,M,null));else if(a.isDataTexture)if(w.length>0){T&&E&&n.texStorage2D(t.TEXTURE_2D,R,b,w[0].width,w[0].height);for(let e=0,i=w.length;e0){const i=jl(S.width,S.height,a.format,a.type);for(const r of a.layerUpdates){const s=S.data.subarray(r*i/S.data.BYTES_PER_ELEMENT,(r+1)*i/S.data.BYTES_PER_ELEMENT);n.compressedTexSubImage3D(t.TEXTURE_2D_ARRAY,e,0,0,r,S.width,S.height,1,m,s,0,0)}a.clearLayerUpdates()}else n.compressedTexSubImage3D(t.TEXTURE_2D_ARRAY,e,0,0,0,S.width,S.height,p.depth,m,S.data,0,0)}else n.compressedTexImage3D(t.TEXTURE_2D_ARRAY,e,b,S.width,S.height,p.depth,0,S.data,0,0);else console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()");else T?A&&n.texSubImage3D(t.TEXTURE_2D_ARRAY,e,0,0,0,S.width,S.height,p.depth,m,M,S.data):n.texImage3D(t.TEXTURE_2D_ARRAY,e,b,S.width,S.height,p.depth,0,m,M,S.data)}else{T&&E&&n.texStorage2D(t.TEXTURE_2D,R,b,w[0].width,w[0].height);for(let e=0,i=w.length;e0){const e=jl(p.width,p.height,a.format,a.type);for(const i of a.layerUpdates){const r=p.data.subarray(i*e/p.data.BYTES_PER_ELEMENT,(i+1)*e/p.data.BYTES_PER_ELEMENT);n.texSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,i,p.width,p.height,1,m,M,r)}a.clearLayerUpdates()}else n.texSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,0,p.width,p.height,p.depth,m,M,p.data)}else n.texImage3D(t.TEXTURE_2D_ARRAY,0,b,p.width,p.height,p.depth,0,m,M,p.data);else if(a.isData3DTexture)T?(E&&n.texStorage3D(t.TEXTURE_3D,R,b,p.width,p.height,p.depth),A&&n.texSubImage3D(t.TEXTURE_3D,0,0,0,0,p.width,p.height,p.depth,m,M,p.data)):n.texImage3D(t.TEXTURE_3D,0,b,p.width,p.height,p.depth,0,m,M,p.data);else if(a.isFramebufferTexture){if(E)if(T)n.texStorage2D(t.TEXTURE_2D,R,b,p.width,p.height);else{let e=p.width,i=p.height;for(let r=0;r>=1,i>>=1}}else if(w.length>0){if(T&&E){const e=k(w[0]);n.texStorage2D(t.TEXTURE_2D,R,b,e.width,e.height)}for(let e=0,i=w.length;e>h),i=Math.max(1,r.height>>h);c===t.TEXTURE_3D||c===t.TEXTURE_2D_ARRAY?n.texImage3D(c,h,p,e,i,r.depth,0,u,d,null):n.texImage2D(c,h,p,e,i,0,u,d,null)}n.bindFramebuffer(t.FRAMEBUFFER,e),B(r)?o.framebufferTexture2DMultisampleEXT(t.FRAMEBUFFER,l,c,i.get(a).__webglTexture,0,F(r)):(c===t.TEXTURE_2D||c>=t.TEXTURE_CUBE_MAP_POSITIVE_X&&c<=t.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&t.framebufferTexture2D(t.FRAMEBUFFER,l,c,i.get(a).__webglTexture,h),n.bindFramebuffer(t.FRAMEBUFFER,null)}function U(e,n,i){if(t.bindRenderbuffer(t.RENDERBUFFER,e),n.depthBuffer){const r=n.depthTexture,s=r&&r.isDepthTexture?r.type:null,a=x(n.stencilBuffer,s),l=n.stencilBuffer?t.DEPTH_STENCIL_ATTACHMENT:t.DEPTH_ATTACHMENT,c=F(n);B(n)?o.renderbufferStorageMultisampleEXT(t.RENDERBUFFER,c,a,n.width,n.height):i?t.renderbufferStorageMultisample(t.RENDERBUFFER,c,a,n.width,n.height):t.renderbufferStorage(t.RENDERBUFFER,a,n.width,n.height),t.framebufferRenderbuffer(t.FRAMEBUFFER,l,t.RENDERBUFFER,e)}else{const e=n.textures;for(let r=0;r{delete r.__boundDepthTexture,delete r.__depthDisposeCallback,t.removeEventListener("dispose",e)};t.addEventListener("dispose",e),r.__depthDisposeCallback=e}r.__boundDepthTexture=t}if(e.depthTexture&&!r.__autoAllocateDepthBuffer){if(s)throw new Error("target.depthTexture not supported in Cube render targets");!function(e,r){if(r&&r.isWebGLCubeRenderTarget)throw new Error("Depth Texture with cube render targets is not supported");if(n.bindFramebuffer(t.FRAMEBUFFER,e),!r.depthTexture||!r.depthTexture.isDepthTexture)throw new Error("renderTarget.depthTexture must be an instance of THREE.DepthTexture");i.get(r.depthTexture).__webglTexture&&r.depthTexture.image.width===r.width&&r.depthTexture.image.height===r.height||(r.depthTexture.image.width=r.width,r.depthTexture.image.height=r.height,r.depthTexture.needsUpdate=!0),T(r.depthTexture,0);const s=i.get(r.depthTexture).__webglTexture,a=F(r);if(r.depthTexture.format===Gt)B(r)?o.framebufferTexture2DMultisampleEXT(t.FRAMEBUFFER,t.DEPTH_ATTACHMENT,t.TEXTURE_2D,s,0,a):t.framebufferTexture2D(t.FRAMEBUFFER,t.DEPTH_ATTACHMENT,t.TEXTURE_2D,s,0);else{if(r.depthTexture.format!==Wt)throw new Error("Unknown depthTexture format");B(r)?o.framebufferTexture2DMultisampleEXT(t.FRAMEBUFFER,t.DEPTH_STENCIL_ATTACHMENT,t.TEXTURE_2D,s,0,a):t.framebufferTexture2D(t.FRAMEBUFFER,t.DEPTH_STENCIL_ATTACHMENT,t.TEXTURE_2D,s,0)}}(r.__webglFramebuffer,e)}else if(s){r.__webglDepthbuffer=[];for(let i=0;i<6;i++)if(n.bindFramebuffer(t.FRAMEBUFFER,r.__webglFramebuffer[i]),void 0===r.__webglDepthbuffer[i])r.__webglDepthbuffer[i]=t.createRenderbuffer(),U(r.__webglDepthbuffer[i],e,!1);else{const n=e.stencilBuffer?t.DEPTH_STENCIL_ATTACHMENT:t.DEPTH_ATTACHMENT,s=r.__webglDepthbuffer[i];t.bindRenderbuffer(t.RENDERBUFFER,s),t.framebufferRenderbuffer(t.FRAMEBUFFER,n,t.RENDERBUFFER,s)}}else if(n.bindFramebuffer(t.FRAMEBUFFER,r.__webglFramebuffer),void 0===r.__webglDepthbuffer)r.__webglDepthbuffer=t.createRenderbuffer(),U(r.__webglDepthbuffer,e,!1);else{const n=e.stencilBuffer?t.DEPTH_STENCIL_ATTACHMENT:t.DEPTH_ATTACHMENT,i=r.__webglDepthbuffer;t.bindRenderbuffer(t.RENDERBUFFER,i),t.framebufferRenderbuffer(t.FRAMEBUFFER,n,t.RENDERBUFFER,i)}n.bindFramebuffer(t.FRAMEBUFFER,null)}const D=[],O=[];function F(t){return Math.min(r.maxSamples,t.samples)}function B(t){const n=i.get(t);return t.samples>0&&!0===e.has("WEBGL_multisampled_render_to_texture")&&!1!==n.__useRenderToTexture}function z(t,e){const n=t.colorSpace,i=t.format,r=t.type;return!0===t.isCompressedTexture||!0===t.isVideoTexture||n!==Ke&&n!==Ze&&(mi.getTransfer(n)===en?i===kt&&r===Et||console.warn("THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):console.error("THREE.WebGLTextures: Unsupported texture color space:",n)),e}function k(t){return"undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement?(c.width=t.naturalWidth||t.width,c.height=t.naturalHeight||t.height):"undefined"!=typeof VideoFrame&&t instanceof VideoFrame?(c.width=t.displayWidth,c.height=t.displayHeight):(c.width=t.width,c.height=t.height),c}this.allocateTextureUnit=function(){const t=w;return t>=r.maxTextures&&console.warn("THREE.WebGLTextures: Trying to use "+t+" texture units while this GPU supports only "+r.maxTextures),w+=1,t},this.resetTextureUnits=function(){w=0},this.setTexture2D=T,this.setTexture2DArray=function(e,r){const s=i.get(e);e.version>0&&s.__version!==e.version?I(s,e,r):n.bindTexture(t.TEXTURE_2D_ARRAY,s.__webglTexture,t.TEXTURE0+r)},this.setTexture3D=function(e,r){const s=i.get(e);e.version>0&&s.__version!==e.version?I(s,e,r):n.bindTexture(t.TEXTURE_3D,s.__webglTexture,t.TEXTURE0+r)},this.setTextureCube=function(e,a){const o=i.get(e);e.version>0&&o.__version!==e.version?function(e,a,o){if(6!==a.image.length)return;const l=P(e,a),c=a.source;n.bindTexture(t.TEXTURE_CUBE_MAP,e.__webglTexture,t.TEXTURE0+o);const h=i.get(c);if(c.version!==h.__version||!0===l){n.activeTexture(t.TEXTURE0+o);const e=mi.getPrimaries(mi.workingColorSpace),i=a.colorSpace===Ze?null:mi.getPrimaries(a.colorSpace),u=a.colorSpace===Ze||e===i?t.NONE:t.BROWSER_DEFAULT_WEBGL;t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,a.flipY),t.pixelStorei(t.UNPACK_PREMULTIPLY_ALPHA_WEBGL,a.premultiplyAlpha),t.pixelStorei(t.UNPACK_ALIGNMENT,a.unpackAlignment),t.pixelStorei(t.UNPACK_COLORSPACE_CONVERSION_WEBGL,u);const d=a.isCompressedTexture||a.image[0].isCompressedTexture,p=a.image[0]&&a.image[0].isDataTexture,m=[];for(let t=0;t<6;t++)m[t]=d||p?p?a.image[t].image:a.image[t]:f(a.image[t],!0,r.maxCubemapSize),m[t]=z(a,m[t]);const x=m[0],M=s.convert(a.format,a.colorSpace),S=s.convert(a.type),b=_(a.internalFormat,M,S,a.colorSpace),w=!0!==a.isVideoTexture,T=void 0===h.__version||!0===l,E=c.dataReady;let A,R=y(a,x);if(C(t.TEXTURE_CUBE_MAP,a),d){w&&T&&n.texStorage2D(t.TEXTURE_CUBE_MAP,R,b,x.width,x.height);for(let e=0;e<6;e++){A=m[e].mipmaps;for(let i=0;i0&&R++;const e=k(m[0]);n.texStorage2D(t.TEXTURE_CUBE_MAP,R,b,e.width,e.height)}for(let e=0;e<6;e++)if(p){w?E&&n.texSubImage2D(t.TEXTURE_CUBE_MAP_POSITIVE_X+e,0,0,0,m[e].width,m[e].height,M,S,m[e].data):n.texImage2D(t.TEXTURE_CUBE_MAP_POSITIVE_X+e,0,b,m[e].width,m[e].height,0,M,S,m[e].data);for(let i=0;i1;if(u||(void 0===l.__webglTexture&&(l.__webglTexture=t.createTexture()),l.__version=r.version,a.memory.textures++),h){o.__webglFramebuffer=[];for(let e=0;e<6;e++)if(r.mipmaps&&r.mipmaps.length>0){o.__webglFramebuffer[e]=[];for(let n=0;n0){o.__webglFramebuffer=[];for(let e=0;e0&&!1===B(e)){o.__webglMultisampledFramebuffer=t.createFramebuffer(),o.__webglColorRenderbuffer=[],n.bindFramebuffer(t.FRAMEBUFFER,o.__webglMultisampledFramebuffer);for(let n=0;n0)for(let i=0;i0)for(let n=0;n0)if(!1===B(e)){const r=e.textures,s=e.width,a=e.height;let o=t.COLOR_BUFFER_BIT;const c=e.stencilBuffer?t.DEPTH_STENCIL_ATTACHMENT:t.DEPTH_ATTACHMENT,h=i.get(e),u=r.length>1;if(u)for(let e=0;eo+c?(l.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:t.handedness,target:this})):!l.inputState.pinching&&a<=o-c&&(l.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:t.handedness,target:this}))}else null!==o&&t.gripSpace&&(r=e.getPose(t.gripSpace,n),null!==r&&(o.matrix.fromArray(r.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),o.matrixWorldNeedsUpdate=!0,r.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(r.linearVelocity)):o.hasLinearVelocity=!1,r.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(r.angularVelocity)):o.hasAngularVelocity=!1));null!==a&&(i=e.getPose(t.targetRaySpace,n),null===i&&null!==r&&(i=r),null!==i&&(a.matrix.fromArray(i.transform.matrix),a.matrix.decompose(a.position,a.rotation,a.scale),a.matrixWorldNeedsUpdate=!0,i.linearVelocity?(a.hasLinearVelocity=!0,a.linearVelocity.copy(i.linearVelocity)):a.hasLinearVelocity=!1,i.angularVelocity?(a.hasAngularVelocity=!0,a.angularVelocity.copy(i.angularVelocity)):a.hasAngularVelocity=!1,this.dispatchEvent($l)))}return null!==a&&(a.visible=null!==i),null!==o&&(o.visible=null!==r),null!==l&&(l.visible=null!==s),this}_getHandJoint(t,e){if(void 0===t.joints[e.jointName]){const n=new Kl;n.matrixAutoUpdate=!1,n.visible=!1,t.joints[e.jointName]=n,t.add(n)}return t.joints[e.jointName]}}class tc{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(t,e,n){if(null===this.texture){const i=new bi;t.properties.get(i).__webglTexture=e.texture,e.depthNear==n.depthNear&&e.depthFar==n.depthFar||(this.depthNear=e.depthNear,this.depthFar=e.depthFar),this.texture=i}}getMesh(t){if(null!==this.texture&&null===this.mesh){const e=t.cameras[0].viewport,n=new Ks({vertexShader:"\nvoid main() {\n\n\tgl_Position = vec4( position, 1.0 );\n\n}",fragmentShader:"\nuniform sampler2DArray depthColor;\nuniform float depthWidth;\nuniform float depthHeight;\n\nvoid main() {\n\n\tvec2 coord = vec2( gl_FragCoord.x / depthWidth, gl_FragCoord.y / depthHeight );\n\n\tif ( coord.x >= 1.0 ) {\n\n\t\tgl_FragDepth = texture( depthColor, vec3( coord.x - 1.0, coord.y, 1 ) ).r;\n\n\t} else {\n\n\t\tgl_FragDepth = texture( depthColor, vec3( coord.x, coord.y, 0 ) ).r;\n\n\t}\n\n}",uniforms:{depthColor:{value:this.texture},depthWidth:{value:e.z},depthHeight:{value:e.w}}});this.mesh=new Ws(new ga(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}}class ec extends Hn{constructor(t,e){super();const n=this;let i=null,r=1,s=null,a="local-floor",o=1,l=null,c=null,h=null,u=null,d=null,p=null;const m=new tc,f=e.getContextAttributes();let g=null,v=null;const _=[],x=[],y=new ti;let M=null;const S=new na;S.layers.enable(1),S.viewport=new wi;const b=new na;b.layers.enable(2),b.viewport=new wi;const w=[S,b],T=new Jl;T.layers.enable(1),T.layers.enable(2);let E=null,A=null;function R(t){const e=x.indexOf(t.inputSource);if(-1===e)return;const n=_[e];void 0!==n&&(n.update(t.inputSource,t.frame,l||s),n.dispatchEvent({type:t.type,data:t.inputSource}))}function C(){i.removeEventListener("select",R),i.removeEventListener("selectstart",R),i.removeEventListener("selectend",R),i.removeEventListener("squeeze",R),i.removeEventListener("squeezestart",R),i.removeEventListener("squeezeend",R),i.removeEventListener("end",C),i.removeEventListener("inputsourceschange",P);for(let t=0;t<_.length;t++){const e=x[t];null!==e&&(x[t]=null,_[t].disconnect(e))}E=null,A=null,m.reset(),t.setRenderTarget(g),d=null,u=null,h=null,i=null,v=null,D.stop(),n.isPresenting=!1,t.setPixelRatio(M),t.setSize(y.width,y.height,!1),n.dispatchEvent({type:"sessionend"})}function P(t){for(let e=0;e=0&&(x[i]=null,_[i].disconnect(n))}for(let e=0;e=x.length){x.push(n),i=t;break}if(null===x[t]){x[t]=n,i=t;break}}if(-1===i)break}const r=_[i];r&&r.connect(n)}}this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(t){let e=_[t];return void 0===e&&(e=new Ql,_[t]=e),e.getTargetRaySpace()},this.getControllerGrip=function(t){let e=_[t];return void 0===e&&(e=new Ql,_[t]=e),e.getGripSpace()},this.getHand=function(t){let e=_[t];return void 0===e&&(e=new Ql,_[t]=e),e.getHandSpace()},this.setFramebufferScaleFactor=function(t){r=t,!0===n.isPresenting&&console.warn("THREE.WebXRManager: Cannot change framebuffer scale while presenting.")},this.setReferenceSpaceType=function(t){a=t,!0===n.isPresenting&&console.warn("THREE.WebXRManager: Cannot change reference space type while presenting.")},this.getReferenceSpace=function(){return l||s},this.setReferenceSpace=function(t){l=t},this.getBaseLayer=function(){return null!==u?u:d},this.getBinding=function(){return h},this.getFrame=function(){return p},this.getSession=function(){return i},this.setSession=async function(c){if(i=c,null!==i){if(g=t.getRenderTarget(),i.addEventListener("select",R),i.addEventListener("selectstart",R),i.addEventListener("selectend",R),i.addEventListener("squeeze",R),i.addEventListener("squeezestart",R),i.addEventListener("squeezeend",R),i.addEventListener("end",C),i.addEventListener("inputsourceschange",P),!0!==f.xrCompatible&&await e.makeXRCompatible(),M=t.getPixelRatio(),t.getSize(y),void 0===i.renderState.layers){const n={antialias:f.antialias,alpha:!0,depth:f.depth,stencil:f.stencil,framebufferScaleFactor:r};d=new XRWebGLLayer(i,e,n),i.updateRenderState({baseLayer:d}),t.setPixelRatio(1),t.setSize(d.framebufferWidth,d.framebufferHeight,!1),v=new Ei(d.framebufferWidth,d.framebufferHeight,{format:kt,type:Et,colorSpace:t.outputColorSpace,stencilBuffer:f.stencil})}else{let n=null,s=null,a=null;f.depth&&(a=f.stencil?e.DEPTH24_STENCIL8:e.DEPTH_COMPONENT24,n=f.stencil?Wt:Gt,s=f.stencil?Ot:It);const o={colorFormat:e.RGBA8,depthFormat:a,scaleFactor:r};h=new XRWebGLBinding(i,e),u=h.createProjectionLayer(o),i.updateRenderState({layers:[u]}),t.setPixelRatio(1),t.setSize(u.textureWidth,u.textureHeight,!1),v=new Ei(u.textureWidth,u.textureHeight,{format:kt,type:Et,depthTexture:new to(u.textureWidth,u.textureHeight,s,void 0,void 0,void 0,void 0,void 0,void 0,n),stencilBuffer:f.stencil,colorSpace:t.outputColorSpace,samples:f.antialias?4:0,resolveDepthBuffer:!1===u.ignoreDepthValues})}v.isXRRenderTarget=!0,this.setFoveation(o),l=null,s=await i.requestReferenceSpace(a),D.setContext(i),D.start(),n.isPresenting=!0,n.dispatchEvent({type:"sessionstart"})}},this.getEnvironmentBlendMode=function(){if(null!==i)return i.environmentBlendMode},this.getDepthTexture=function(){return m.getDepthTexture()};const I=new Li,L=new Li;function U(t,e){null===e?t.matrixWorld.copy(t.matrix):t.matrixWorld.multiplyMatrices(e.matrixWorld,t.matrix),t.matrixWorldInverse.copy(t.matrixWorld).invert()}this.updateCamera=function(t){if(null===i)return;let e=t.near,n=t.far;null!==m.texture&&(m.depthNear>0&&(e=m.depthNear),m.depthFar>0&&(n=m.depthFar)),T.near=b.near=S.near=e,T.far=b.far=S.far=n,E===T.near&&A===T.far||(i.updateRenderState({depthNear:T.near,depthFar:T.far}),E=T.near,A=T.far);const r=t.parent,s=T.cameras;U(T,r);for(let t=0;t0&&(t.alphaTest.value=i.alphaTest);const r=e.get(i),s=r.envMap,a=r.envMapRotation;s&&(t.envMap.value=s,nc.copy(a),nc.x*=-1,nc.y*=-1,nc.z*=-1,s.isCubeTexture&&!1===s.isRenderTargetTexture&&(nc.y*=-1,nc.z*=-1),t.envMapRotation.value.setFromMatrix4(ic.makeRotationFromEuler(nc)),t.flipEnvMap.value=s.isCubeTexture&&!1===s.isRenderTargetTexture?-1:1,t.reflectivity.value=i.reflectivity,t.ior.value=i.ior,t.refractionRatio.value=i.refractionRatio),i.lightMap&&(t.lightMap.value=i.lightMap,t.lightMapIntensity.value=i.lightMapIntensity,n(i.lightMap,t.lightMapTransform)),i.aoMap&&(t.aoMap.value=i.aoMap,t.aoMapIntensity.value=i.aoMapIntensity,n(i.aoMap,t.aoMapTransform))}return{refreshFogUniforms:function(e,n){n.color.getRGB(e.fogColor.value,Zs(t)),n.isFog?(e.fogNear.value=n.near,e.fogFar.value=n.far):n.isFogExp2&&(e.fogDensity.value=n.density)},refreshMaterialUniforms:function(t,r,s,a,o){r.isMeshBasicMaterial||r.isMeshLambertMaterial?i(t,r):r.isMeshToonMaterial?(i(t,r),function(t,e){e.gradientMap&&(t.gradientMap.value=e.gradientMap)}(t,r)):r.isMeshPhongMaterial?(i(t,r),function(t,e){t.specular.value.copy(e.specular),t.shininess.value=Math.max(e.shininess,1e-4)}(t,r)):r.isMeshStandardMaterial?(i(t,r),function(t,e){t.metalness.value=e.metalness,e.metalnessMap&&(t.metalnessMap.value=e.metalnessMap,n(e.metalnessMap,t.metalnessMapTransform));t.roughness.value=e.roughness,e.roughnessMap&&(t.roughnessMap.value=e.roughnessMap,n(e.roughnessMap,t.roughnessMapTransform));e.envMap&&(t.envMapIntensity.value=e.envMapIntensity)}(t,r),r.isMeshPhysicalMaterial&&function(t,e,i){t.ior.value=e.ior,e.sheen>0&&(t.sheenColor.value.copy(e.sheenColor).multiplyScalar(e.sheen),t.sheenRoughness.value=e.sheenRoughness,e.sheenColorMap&&(t.sheenColorMap.value=e.sheenColorMap,n(e.sheenColorMap,t.sheenColorMapTransform)),e.sheenRoughnessMap&&(t.sheenRoughnessMap.value=e.sheenRoughnessMap,n(e.sheenRoughnessMap,t.sheenRoughnessMapTransform)));e.clearcoat>0&&(t.clearcoat.value=e.clearcoat,t.clearcoatRoughness.value=e.clearcoatRoughness,e.clearcoatMap&&(t.clearcoatMap.value=e.clearcoatMap,n(e.clearcoatMap,t.clearcoatMapTransform)),e.clearcoatRoughnessMap&&(t.clearcoatRoughnessMap.value=e.clearcoatRoughnessMap,n(e.clearcoatRoughnessMap,t.clearcoatRoughnessMapTransform)),e.clearcoatNormalMap&&(t.clearcoatNormalMap.value=e.clearcoatNormalMap,n(e.clearcoatNormalMap,t.clearcoatNormalMapTransform),t.clearcoatNormalScale.value.copy(e.clearcoatNormalScale),e.side===d&&t.clearcoatNormalScale.value.negate()));e.dispersion>0&&(t.dispersion.value=e.dispersion);e.iridescence>0&&(t.iridescence.value=e.iridescence,t.iridescenceIOR.value=e.iridescenceIOR,t.iridescenceThicknessMinimum.value=e.iridescenceThicknessRange[0],t.iridescenceThicknessMaximum.value=e.iridescenceThicknessRange[1],e.iridescenceMap&&(t.iridescenceMap.value=e.iridescenceMap,n(e.iridescenceMap,t.iridescenceMapTransform)),e.iridescenceThicknessMap&&(t.iridescenceThicknessMap.value=e.iridescenceThicknessMap,n(e.iridescenceThicknessMap,t.iridescenceThicknessMapTransform)));e.transmission>0&&(t.transmission.value=e.transmission,t.transmissionSamplerMap.value=i.texture,t.transmissionSamplerSize.value.set(i.width,i.height),e.transmissionMap&&(t.transmissionMap.value=e.transmissionMap,n(e.transmissionMap,t.transmissionMapTransform)),t.thickness.value=e.thickness,e.thicknessMap&&(t.thicknessMap.value=e.thicknessMap,n(e.thicknessMap,t.thicknessMapTransform)),t.attenuationDistance.value=e.attenuationDistance,t.attenuationColor.value.copy(e.attenuationColor));e.anisotropy>0&&(t.anisotropyVector.value.set(e.anisotropy*Math.cos(e.anisotropyRotation),e.anisotropy*Math.sin(e.anisotropyRotation)),e.anisotropyMap&&(t.anisotropyMap.value=e.anisotropyMap,n(e.anisotropyMap,t.anisotropyMapTransform)));t.specularIntensity.value=e.specularIntensity,t.specularColor.value.copy(e.specularColor),e.specularColorMap&&(t.specularColorMap.value=e.specularColorMap,n(e.specularColorMap,t.specularColorMapTransform));e.specularIntensityMap&&(t.specularIntensityMap.value=e.specularIntensityMap,n(e.specularIntensityMap,t.specularIntensityMapTransform))}(t,r,o)):r.isMeshMatcapMaterial?(i(t,r),function(t,e){e.matcap&&(t.matcap.value=e.matcap)}(t,r)):r.isMeshDepthMaterial?i(t,r):r.isMeshDistanceMaterial?(i(t,r),function(t,n){const i=e.get(n).light;t.referencePosition.value.setFromMatrixPosition(i.matrixWorld),t.nearDistance.value=i.shadow.camera.near,t.farDistance.value=i.shadow.camera.far}(t,r)):r.isMeshNormalMaterial?i(t,r):r.isLineBasicMaterial?(function(t,e){t.diffuse.value.copy(e.color),t.opacity.value=e.opacity,e.map&&(t.map.value=e.map,n(e.map,t.mapTransform))}(t,r),r.isLineDashedMaterial&&function(t,e){t.dashSize.value=e.dashSize,t.totalSize.value=e.dashSize+e.gapSize,t.scale.value=e.scale}(t,r)):r.isPointsMaterial?function(t,e,i,r){t.diffuse.value.copy(e.color),t.opacity.value=e.opacity,t.size.value=e.size*i,t.scale.value=.5*r,e.map&&(t.map.value=e.map,n(e.map,t.uvTransform));e.alphaMap&&(t.alphaMap.value=e.alphaMap,n(e.alphaMap,t.alphaMapTransform));e.alphaTest>0&&(t.alphaTest.value=e.alphaTest)}(t,r,s,a):r.isSpriteMaterial?function(t,e){t.diffuse.value.copy(e.color),t.opacity.value=e.opacity,t.rotation.value=e.rotation,e.map&&(t.map.value=e.map,n(e.map,t.mapTransform));e.alphaMap&&(t.alphaMap.value=e.alphaMap,n(e.alphaMap,t.alphaMapTransform));e.alphaTest>0&&(t.alphaTest.value=e.alphaTest)}(t,r):r.isShadowMaterial?(t.color.value.copy(r.color),t.opacity.value=r.opacity):r.isShaderMaterial&&(r.uniformsNeedUpdate=!1)}}}function sc(t,e,n,i){let r={},s={},a=[];const o=t.getParameter(t.MAX_UNIFORM_BUFFER_BINDINGS);function l(t,e,n,i){const r=t.value,s=e+"_"+n;if(void 0===i[s])return i[s]="number"==typeof r||"boolean"==typeof r?r:r.clone(),!0;{const t=i[s];if("number"==typeof r||"boolean"==typeof r){if(t!==r)return i[s]=r,!0}else if(!1===t.equals(r))return t.copy(r),!0}return!1}function c(t){const e={boundary:0,storage:0};return"number"==typeof t||"boolean"==typeof t?(e.boundary=4,e.storage=4):t.isVector2?(e.boundary=8,e.storage=8):t.isVector3||t.isColor?(e.boundary=16,e.storage=12):t.isVector4?(e.boundary=16,e.storage=16):t.isMatrix3?(e.boundary=48,e.storage=48):t.isMatrix4?(e.boundary=64,e.storage=64):t.isTexture?console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group."):console.warn("THREE.WebGLRenderer: Unsupported uniform value type.",t),e}function h(e){const n=e.target;n.removeEventListener("dispose",h);const i=a.indexOf(n.__bindingPointIndex);a.splice(i,1),t.deleteBuffer(r[n.id]),delete r[n.id],delete s[n.id]}return{bind:function(t,e){const n=e.program;i.uniformBlockBinding(t,n)},update:function(n,u){let d=r[n.id];void 0===d&&(!function(t){const e=t.uniforms;let n=0;const i=16;for(let t=0,r=e.length;t0&&(n+=i-r);t.__size=n,t.__cache={}}(n),d=function(e){const n=function(){for(let t=0;t0),u=!!n.morphAttributes.position,d=!!n.morphAttributes.normal,p=!!n.morphAttributes.color;let m=K;i.toneMapped&&(null!==T&&!0!==T.isXRRenderTarget||(m=M.toneMapping));const f=n.morphAttributes.position||n.morphAttributes.normal||n.morphAttributes.color,g=void 0!==f?f.length:0,v=et.get(i),x=_.state.lights;if(!0===H&&(!0===G||t!==A)){const e=t===A&&i.id===E;dt.setState(i,t,e)}let y=!1;i.version===v.__version?v.needsLights&&v.lightsStateVersion!==x.state.version||v.outputColorSpace!==o||r.isBatchedMesh&&!1===v.batching?y=!0:r.isBatchedMesh||!0!==v.batching?r.isBatchedMesh&&!0===v.batchingColor&&null===r.colorTexture||r.isBatchedMesh&&!1===v.batchingColor&&null!==r.colorTexture||r.isInstancedMesh&&!1===v.instancing?y=!0:r.isInstancedMesh||!0!==v.instancing?r.isSkinnedMesh&&!1===v.skinning?y=!0:r.isSkinnedMesh||!0!==v.skinning?r.isInstancedMesh&&!0===v.instancingColor&&null===r.instanceColor||r.isInstancedMesh&&!1===v.instancingColor&&null!==r.instanceColor||r.isInstancedMesh&&!0===v.instancingMorph&&null===r.morphTexture||r.isInstancedMesh&&!1===v.instancingMorph&&null!==r.morphTexture||v.envMap!==l||!0===i.fog&&v.fog!==s?y=!0:void 0===v.numClippingPlanes||v.numClippingPlanes===dt.numPlanes&&v.numIntersection===dt.numIntersection?(v.vertexAlphas!==c||v.vertexTangents!==h||v.morphTargets!==u||v.morphNormals!==d||v.morphColors!==p||v.toneMapping!==m||v.morphTargetsCount!==g)&&(y=!0):y=!0:y=!0:y=!0:y=!0:(y=!0,v.__version=i.version);let S=v.currentProgram;!0===y&&(S=Zt(i,e,r));let b=!1,w=!1,R=!1;const C=S.getUniforms(),P=v.uniforms;Q.useProgram(S.program)&&(b=!0,w=!0,R=!0);i.id!==E&&(E=i.id,w=!0);if(b||A!==t){C.setValue(Mt,"projectionMatrix",t.projectionMatrix),C.setValue(Mt,"viewMatrix",t.matrixWorldInverse);const e=C.map.cameraPosition;void 0!==e&&e.setValue(Mt,X.setFromMatrixPosition(t.matrixWorld)),$.logarithmicDepthBuffer&&C.setValue(Mt,"logDepthBufFC",2/(Math.log(t.far+1)/Math.LN2)),(i.isMeshPhongMaterial||i.isMeshToonMaterial||i.isMeshLambertMaterial||i.isMeshBasicMaterial||i.isMeshStandardMaterial||i.isShaderMaterial)&&C.setValue(Mt,"isOrthographic",!0===t.isOrthographicCamera),A!==t&&(A=t,w=!0,R=!0)}if(r.isSkinnedMesh){C.setOptional(Mt,r,"bindMatrix"),C.setOptional(Mt,r,"bindMatrixInverse");const t=r.skeleton;t&&(null===t.boneTexture&&t.computeBoneTexture(),C.setValue(Mt,"boneTexture",t.boneTexture,nt))}r.isBatchedMesh&&(C.setOptional(Mt,r,"batchingTexture"),C.setValue(Mt,"batchingTexture",r._matricesTexture,nt),C.setOptional(Mt,r,"batchingIdTexture"),C.setValue(Mt,"batchingIdTexture",r._indirectTexture,nt),C.setOptional(Mt,r,"batchingColorTexture"),null!==r._colorsTexture&&C.setValue(Mt,"batchingColorTexture",r._colorsTexture,nt));const I=n.morphAttributes;void 0===I.position&&void 0===I.normal&&void 0===I.color||ft.update(r,n,S);(w||v.receiveShadow!==r.receiveShadow)&&(v.receiveShadow=r.receiveShadow,C.setValue(Mt,"receiveShadow",r.receiveShadow));i.isMeshGouraudMaterial&&null!==i.envMap&&(P.envMap.value=l,P.flipEnvMap.value=l.isCubeTexture&&!1===l.isRenderTargetTexture?-1:1);i.isMeshStandardMaterial&&null===i.envMap&&null!==e.environment&&(P.envMapIntensity.value=e.environmentIntensity);w&&(C.setValue(Mt,"toneMappingExposure",M.toneMappingExposure),v.needsLights&&(U=R,(L=P).ambientLightColor.needsUpdate=U,L.lightProbe.needsUpdate=U,L.directionalLights.needsUpdate=U,L.directionalLightShadows.needsUpdate=U,L.pointLights.needsUpdate=U,L.pointLightShadows.needsUpdate=U,L.spotLights.needsUpdate=U,L.spotLightShadows.needsUpdate=U,L.rectAreaLights.needsUpdate=U,L.hemisphereLights.needsUpdate=U),s&&!0===i.fog&&ct.refreshFogUniforms(P,s),ct.refreshMaterialUniforms(P,i,D,N,_.state.transmissionRenderTarget[t.id]),al.upload(Mt,Kt(v),P,nt));var L,U;i.isShaderMaterial&&!0===i.uniformsNeedUpdate&&(al.upload(Mt,Kt(v),P,nt),i.uniformsNeedUpdate=!1);i.isSpriteMaterial&&C.setValue(Mt,"center",r.center);if(C.setValue(Mt,"modelViewMatrix",r.modelViewMatrix),C.setValue(Mt,"normalMatrix",r.normalMatrix),C.setValue(Mt,"modelMatrix",r.matrixWorld),i.isShaderMaterial||i.isRawShaderMaterial){const t=i.uniformsGroups;for(let e=0,n=t.length;e{function n(){i.forEach((function(t){et.get(t).currentProgram.isReady()&&i.delete(t)})),0!==i.size?setTimeout(n,10):e(t)}null!==J.get("KHR_parallel_shader_compile")?n():setTimeout(n,10)}))};let Bt=null;function zt(){Vt.stop()}function kt(){Vt.start()}const Vt=new ma;function Ht(t,e,n,i){if(!1===t.visible)return;if(t.layers.test(e.layers))if(t.isGroup)n=t.renderOrder;else if(t.isLOD)!0===t.autoUpdate&&t.update(e);else if(t.isLight)_.pushLight(t),t.castShadow&&_.pushShadow(t);else if(t.isSprite){if(!t.frustumCulled||V.intersectsSprite(t)){i&&j.setFromMatrixPosition(t.matrixWorld).applyMatrix4(W);const e=ot.update(t),r=t.material;r.visible&&v.push(t,e,r,n,j.z,null)}}else if((t.isMesh||t.isLine||t.isPoints)&&(!t.frustumCulled||V.intersectsObject(t))){const e=ot.update(t),r=t.material;if(i&&(void 0!==t.boundingSphere?(null===t.boundingSphere&&t.computeBoundingSphere(),j.copy(t.boundingSphere.center)):(null===e.boundingSphere&&e.computeBoundingSphere(),j.copy(e.boundingSphere.center)),j.applyMatrix4(t.matrixWorld).applyMatrix4(W)),Array.isArray(r)){const i=e.groups;for(let s=0,a=i.length;s0&&Xt(r,e,n),s.length>0&&Xt(s,e,n),a.length>0&&Xt(a,e,n),Q.buffers.depth.setTest(!0),Q.buffers.depth.setMask(!0),Q.buffers.color.setMask(!0),Q.setPolygonOffset(!1)}function Wt(t,e,n,i){if(null!==(!0===n.isScene?n.overrideMaterial:null))return;void 0===_.state.transmissionRenderTarget[i.id]&&(_.state.transmissionRenderTarget[i.id]=new Ei(1,1,{generateMipmaps:!0,type:J.has("EXT_color_buffer_half_float")||J.has("EXT_color_buffer_float")?Ut:Et,minFilter:wt,samples:4,stencilBuffer:s,resolveDepthBuffer:!1,resolveStencilBuffer:!1,colorSpace:mi.workingColorSpace}));const r=_.state.transmissionRenderTarget[i.id],a=i.viewport||R;r.setSize(a.z,a.w);const o=M.getRenderTarget();M.setRenderTarget(r),M.getClearColor(I),L=M.getClearAlpha(),L<1&&M.setClearColor(16777215,.5),M.clear(),Y&&mt.render(n);const l=M.toneMapping;M.toneMapping=K;const c=i.viewport;if(void 0!==i.viewport&&(i.viewport=void 0),_.setupLightsView(i),!0===H&&dt.setGlobalState(M.clippingPlanes,i),Xt(t,n,i),nt.updateMultisampleRenderTarget(r),nt.updateRenderTargetMipmap(r),!1===J.has("WEBGL_multisampled_render_to_texture")){let t=!1;for(let r=0,s=e.length;r0)for(let e=0,s=n.length;e0&&Wt(i,r,t,e),Y&&mt.render(t),Gt(v,t,e);null!==T&&(nt.updateMultisampleRenderTarget(T),nt.updateRenderTargetMipmap(T)),!0===t.isScene&&t.onAfterRender(M,t,e),xt.resetDefaultState(),E=-1,A=null,y.pop(),y.length>0?(_=y[y.length-1],!0===H&&dt.setGlobalState(M.clippingPlanes,_.state.camera)):_=null,x.pop(),v=x.length>0?x[x.length-1]:null},this.getActiveCubeFace=function(){return b},this.getActiveMipmapLevel=function(){return w},this.getRenderTarget=function(){return T},this.setRenderTargetTextures=function(t,e,n){et.get(t.texture).__webglTexture=e,et.get(t.depthTexture).__webglTexture=n;const i=et.get(t);i.__hasExternalTextures=!0,i.__autoAllocateDepthBuffer=void 0===n,i.__autoAllocateDepthBuffer||!0===J.has("WEBGL_multisampled_render_to_texture")&&(console.warn("THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided"),i.__useRenderToTexture=!1)},this.setRenderTargetFramebuffer=function(t,e){const n=et.get(t);n.__webglFramebuffer=e,n.__useDefaultFramebuffer=void 0===e},this.setRenderTarget=function(t,e=0,n=0){T=t,b=e,w=n;let i=!0,r=null,s=!1,a=!1;if(t){const o=et.get(t);if(void 0!==o.__useDefaultFramebuffer)Q.bindFramebuffer(Mt.FRAMEBUFFER,null),i=!1;else if(void 0===o.__webglFramebuffer)nt.setupRenderTarget(t);else if(o.__hasExternalTextures)nt.rebindTextures(t,et.get(t.texture).__webglTexture,et.get(t.depthTexture).__webglTexture);else if(t.depthBuffer){const e=t.depthTexture;if(o.__boundDepthTexture!==e){if(null!==e&&et.has(e)&&(t.width!==e.image.width||t.height!==e.image.height))throw new Error("WebGLRenderTarget: Attached DepthTexture is initialized to the incorrect size.");nt.setupDepthRenderbuffer(t)}}const l=t.texture;(l.isData3DTexture||l.isDataArrayTexture||l.isCompressedArrayTexture)&&(a=!0);const c=et.get(t).__webglFramebuffer;t.isWebGLCubeRenderTarget?(r=Array.isArray(c[e])?c[e][n]:c[e],s=!0):r=t.samples>0&&!1===nt.useMultisampledRTT(t)?et.get(t).__webglMultisampledFramebuffer:Array.isArray(c)?c[n]:c,R.copy(t.viewport),C.copy(t.scissor),P=t.scissorTest}else R.copy(B).multiplyScalar(D).floor(),C.copy(z).multiplyScalar(D).floor(),P=k;if(Q.bindFramebuffer(Mt.FRAMEBUFFER,r)&&i&&Q.drawBuffers(t,r),Q.viewport(R),Q.scissor(C),Q.setScissorTest(P),s){const i=et.get(t.texture);Mt.framebufferTexture2D(Mt.FRAMEBUFFER,Mt.COLOR_ATTACHMENT0,Mt.TEXTURE_CUBE_MAP_POSITIVE_X+e,i.__webglTexture,n)}else if(a){const i=et.get(t.texture),r=e||0;Mt.framebufferTextureLayer(Mt.FRAMEBUFFER,Mt.COLOR_ATTACHMENT0,i.__webglTexture,n||0,r)}E=-1},this.readRenderTargetPixels=function(t,e,n,i,r,s,a){if(!t||!t.isWebGLRenderTarget)return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let o=et.get(t).__webglFramebuffer;if(t.isWebGLCubeRenderTarget&&void 0!==a&&(o=o[a]),o){Q.bindFramebuffer(Mt.FRAMEBUFFER,o);try{const a=t.texture,o=a.format,l=a.type;if(!$.textureFormatReadable(o))return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");if(!$.textureTypeReadable(l))return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");e>=0&&e<=t.width-i&&n>=0&&n<=t.height-r&&Mt.readPixels(e,n,i,r,_t.convert(o),_t.convert(l),s)}finally{const t=null!==T?et.get(T).__webglFramebuffer:null;Q.bindFramebuffer(Mt.FRAMEBUFFER,t)}}},this.readRenderTargetPixelsAsync=async function(t,e,n,i,r,s,a){if(!t||!t.isWebGLRenderTarget)throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let o=et.get(t).__webglFramebuffer;if(t.isWebGLCubeRenderTarget&&void 0!==a&&(o=o[a]),o){Q.bindFramebuffer(Mt.FRAMEBUFFER,o);try{const a=t.texture,o=a.format,l=a.type;if(!$.textureFormatReadable(o))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(!$.textureTypeReadable(l))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");if(e>=0&&e<=t.width-i&&n>=0&&n<=t.height-r){const t=Mt.createBuffer();Mt.bindBuffer(Mt.PIXEL_PACK_BUFFER,t),Mt.bufferData(Mt.PIXEL_PACK_BUFFER,s.byteLength,Mt.STREAM_READ),Mt.readPixels(e,n,i,r,_t.convert(o),_t.convert(l),0),Mt.flush();const a=Mt.fenceSync(Mt.SYNC_GPU_COMMANDS_COMPLETE,0);await function(t,e,n){return new Promise((function(i,r){setTimeout((function s(){switch(t.clientWaitSync(e,t.SYNC_FLUSH_COMMANDS_BIT,0)){case t.WAIT_FAILED:r();break;case t.TIMEOUT_EXPIRED:setTimeout(s,n);break;default:i()}}),n)}))}(Mt,a,4);try{Mt.bindBuffer(Mt.PIXEL_PACK_BUFFER,t),Mt.getBufferSubData(Mt.PIXEL_PACK_BUFFER,0,s)}finally{Mt.deleteBuffer(t),Mt.deleteSync(a)}return s}}finally{const t=null!==T?et.get(T).__webglFramebuffer:null;Q.bindFramebuffer(Mt.FRAMEBUFFER,t)}}},this.copyFramebufferToTexture=function(t,e=null,n=0){!0!==t.isTexture&&(ci("WebGLRenderer: copyFramebufferToTexture function signature has changed."),e=arguments[0]||null,t=arguments[1]);const i=Math.pow(2,-n),r=Math.floor(t.image.width*i),s=Math.floor(t.image.height*i),a=null!==e?e.x:0,o=null!==e?e.y:0;nt.setTexture2D(t,0),Mt.copyTexSubImage2D(Mt.TEXTURE_2D,n,0,0,a,o,r,s),Q.unbindTexture()},this.copyTextureToTexture=function(t,e,n=null,i=null,r=0){let s,a,o,l,c,h;!0!==t.isTexture&&(ci("WebGLRenderer: copyTextureToTexture function signature has changed."),i=arguments[0]||null,t=arguments[1],e=arguments[2],r=arguments[3]||0,n=null),null!==n?(s=n.max.x-n.min.x,a=n.max.y-n.min.y,o=n.min.x,l=n.min.y):(s=t.image.width,a=t.image.height,o=0,l=0),null!==i?(c=i.x,h=i.y):(c=0,h=0);const u=_t.convert(e.format),d=_t.convert(e.type);nt.setTexture2D(e,0),Mt.pixelStorei(Mt.UNPACK_FLIP_Y_WEBGL,e.flipY),Mt.pixelStorei(Mt.UNPACK_PREMULTIPLY_ALPHA_WEBGL,e.premultiplyAlpha),Mt.pixelStorei(Mt.UNPACK_ALIGNMENT,e.unpackAlignment);const p=Mt.getParameter(Mt.UNPACK_ROW_LENGTH),m=Mt.getParameter(Mt.UNPACK_IMAGE_HEIGHT),f=Mt.getParameter(Mt.UNPACK_SKIP_PIXELS),g=Mt.getParameter(Mt.UNPACK_SKIP_ROWS),v=Mt.getParameter(Mt.UNPACK_SKIP_IMAGES),_=t.isCompressedTexture?t.mipmaps[r]:t.image;Mt.pixelStorei(Mt.UNPACK_ROW_LENGTH,_.width),Mt.pixelStorei(Mt.UNPACK_IMAGE_HEIGHT,_.height),Mt.pixelStorei(Mt.UNPACK_SKIP_PIXELS,o),Mt.pixelStorei(Mt.UNPACK_SKIP_ROWS,l),t.isDataTexture?Mt.texSubImage2D(Mt.TEXTURE_2D,r,c,h,s,a,u,d,_.data):t.isCompressedTexture?Mt.compressedTexSubImage2D(Mt.TEXTURE_2D,r,c,h,_.width,_.height,u,_.data):Mt.texSubImage2D(Mt.TEXTURE_2D,r,c,h,s,a,u,d,_),Mt.pixelStorei(Mt.UNPACK_ROW_LENGTH,p),Mt.pixelStorei(Mt.UNPACK_IMAGE_HEIGHT,m),Mt.pixelStorei(Mt.UNPACK_SKIP_PIXELS,f),Mt.pixelStorei(Mt.UNPACK_SKIP_ROWS,g),Mt.pixelStorei(Mt.UNPACK_SKIP_IMAGES,v),0===r&&e.generateMipmaps&&Mt.generateMipmap(Mt.TEXTURE_2D),Q.unbindTexture()},this.copyTextureToTexture3D=function(t,e,n=null,i=null,r=0){let s,a,o,l,c,h,u,d,p;!0!==t.isTexture&&(ci("WebGLRenderer: copyTextureToTexture3D function signature has changed."),n=arguments[0]||null,i=arguments[1]||null,t=arguments[2],e=arguments[3],r=arguments[4]||0);const m=t.isCompressedTexture?t.mipmaps[r]:t.image;null!==n?(s=n.max.x-n.min.x,a=n.max.y-n.min.y,o=n.max.z-n.min.z,l=n.min.x,c=n.min.y,h=n.min.z):(s=m.width,a=m.height,o=m.depth,l=0,c=0,h=0),null!==i?(u=i.x,d=i.y,p=i.z):(u=0,d=0,p=0);const f=_t.convert(e.format),g=_t.convert(e.type);let v;if(e.isData3DTexture)nt.setTexture3D(e,0),v=Mt.TEXTURE_3D;else{if(!e.isDataArrayTexture&&!e.isCompressedArrayTexture)return void console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.");nt.setTexture2DArray(e,0),v=Mt.TEXTURE_2D_ARRAY}Mt.pixelStorei(Mt.UNPACK_FLIP_Y_WEBGL,e.flipY),Mt.pixelStorei(Mt.UNPACK_PREMULTIPLY_ALPHA_WEBGL,e.premultiplyAlpha),Mt.pixelStorei(Mt.UNPACK_ALIGNMENT,e.unpackAlignment);const _=Mt.getParameter(Mt.UNPACK_ROW_LENGTH),x=Mt.getParameter(Mt.UNPACK_IMAGE_HEIGHT),y=Mt.getParameter(Mt.UNPACK_SKIP_PIXELS),M=Mt.getParameter(Mt.UNPACK_SKIP_ROWS),S=Mt.getParameter(Mt.UNPACK_SKIP_IMAGES);Mt.pixelStorei(Mt.UNPACK_ROW_LENGTH,m.width),Mt.pixelStorei(Mt.UNPACK_IMAGE_HEIGHT,m.height),Mt.pixelStorei(Mt.UNPACK_SKIP_PIXELS,l),Mt.pixelStorei(Mt.UNPACK_SKIP_ROWS,c),Mt.pixelStorei(Mt.UNPACK_SKIP_IMAGES,h),t.isDataTexture||t.isData3DTexture?Mt.texSubImage3D(v,r,u,d,p,s,a,o,f,g,m.data):e.isCompressedArrayTexture?Mt.compressedTexSubImage3D(v,r,u,d,p,s,a,o,f,m.data):Mt.texSubImage3D(v,r,u,d,p,s,a,o,f,g,m),Mt.pixelStorei(Mt.UNPACK_ROW_LENGTH,_),Mt.pixelStorei(Mt.UNPACK_IMAGE_HEIGHT,x),Mt.pixelStorei(Mt.UNPACK_SKIP_PIXELS,y),Mt.pixelStorei(Mt.UNPACK_SKIP_ROWS,M),Mt.pixelStorei(Mt.UNPACK_SKIP_IMAGES,S),0===r&&e.generateMipmaps&&Mt.generateMipmap(v),Q.unbindTexture()},this.initRenderTarget=function(t){void 0===et.get(t).__webglFramebuffer&&nt.setupRenderTarget(t)},this.initTexture=function(t){t.isCubeTexture?nt.setTextureCube(t,0):t.isData3DTexture?nt.setTexture3D(t,0):t.isDataArrayTexture||t.isCompressedArrayTexture?nt.setTexture2DArray(t,0):nt.setTexture2D(t,0),Q.unbindTexture()},this.resetState=function(){b=0,w=0,T=null,Q.reset(),xt.reset()},"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}get coordinateSystem(){return kn}get outputColorSpace(){return this._outputColorSpace}set outputColorSpace(t){this._outputColorSpace=t;const e=this.getContext();e.drawingBufferColorSpace=t===$e?"display-p3":"srgb",e.unpackColorSpace=mi.workingColorSpace===Qe?"display-p3":"srgb"}}class oc{constructor(t,e=25e-5){this.isFogExp2=!0,this.name="",this.color=new Kr(t),this.density=e}clone(){return new oc(this.color,this.density)}toJSON(){return{type:"FogExp2",name:this.name,color:this.color.getHex(),density:this.density}}}class lc{constructor(t,e=1,n=1e3){this.isFog=!0,this.name="",this.color=new Kr(t),this.near=e,this.far=n}clone(){return new lc(this.color,this.near,this.far)}toJSON(){return{type:"Fog",name:this.name,color:this.color.getHex(),near:this.near,far:this.far}}}class cc extends Dr{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.backgroundRotation=new _r,this.environmentIntensity=1,this.environmentRotation=new _r,this.overrideMaterial=null,"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(t,e){return super.copy(t,e),null!==t.background&&(this.background=t.background.clone()),null!==t.environment&&(this.environment=t.environment.clone()),null!==t.fog&&(this.fog=t.fog.clone()),this.backgroundBlurriness=t.backgroundBlurriness,this.backgroundIntensity=t.backgroundIntensity,this.backgroundRotation.copy(t.backgroundRotation),this.environmentIntensity=t.environmentIntensity,this.environmentRotation.copy(t.environmentRotation),null!==t.overrideMaterial&&(this.overrideMaterial=t.overrideMaterial.clone()),this.matrixAutoUpdate=t.matrixAutoUpdate,this}toJSON(t){const e=super.toJSON(t);return null!==this.fog&&(e.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(e.object.backgroundBlurriness=this.backgroundBlurriness),1!==this.backgroundIntensity&&(e.object.backgroundIntensity=this.backgroundIntensity),e.object.backgroundRotation=this.backgroundRotation.toArray(),1!==this.environmentIntensity&&(e.object.environmentIntensity=this.environmentIntensity),e.object.environmentRotation=this.environmentRotation.toArray(),e}}class hc{constructor(t,e){this.isInterleavedBuffer=!0,this.array=t,this.stride=e,this.count=void 0!==t?t.length/e:0,this.usage=Cn,this._updateRange={offset:0,count:-1},this.updateRanges=[],this.version=0,this.uuid=qn()}onUploadCallback(){}set needsUpdate(t){!0===t&&this.version++}get updateRange(){return ci("THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead."),this._updateRange}setUsage(t){return this.usage=t,this}addUpdateRange(t,e){this.updateRanges.push({start:t,count:e})}clearUpdateRanges(){this.updateRanges.length=0}copy(t){return this.array=new t.array.constructor(t.array),this.count=t.count,this.stride=t.stride,this.usage=t.usage,this}copyAt(t,e,n){t*=this.stride,n*=e.stride;for(let i=0,r=this.stride;it.far||e.push({distance:o,point:fc.clone(),uv:jr.getInterpolation(fc,Mc,Sc,bc,wc,Tc,Ec,new ti),face:null,object:this})}copy(t,e){return super.copy(t,e),void 0!==t.center&&this.center.copy(t.center),this.material=t.material,this}}function Rc(t,e,n,i,r,s){_c.subVectors(t,n).addScalar(.5).multiply(i),void 0!==r?(xc.x=s*_c.x-r*_c.y,xc.y=r*_c.x+s*_c.y):xc.copy(_c),t.copy(e),t.x+=xc.x,t.y+=xc.y,t.applyMatrix4(yc)}const Cc=new Li,Pc=new Li;class Ic extends Dr{constructor(){super(),this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]},isLOD:{value:!0}}),this.autoUpdate=!0}copy(t){super.copy(t,!1);const e=t.levels;for(let t=0,n=e.length;t0){let n,i;for(n=1,i=e.length;n0){Cc.setFromMatrixPosition(this.matrixWorld);const n=t.ray.origin.distanceTo(Cc);this.getObjectForDistance(n).raycast(t,e)}}update(t){const e=this.levels;if(e.length>1){Cc.setFromMatrixPosition(t.matrixWorld),Pc.setFromMatrixPosition(this.matrixWorld);const n=Cc.distanceTo(Pc)/t.zoom;let i,r;for(e[0].object.visible=!0,i=1,r=e.length;i=t))break;e[i-1].object.visible=!1,e[i].object.visible=!0}for(this._currentLevel=i-1;i=i.length&&i.push({start:-1,count:-1,z:-1,index:-1});const s=i[this.index];r.push(s),this.index++,s.start=t.start,s.count=t.count,s.z=e,s.index=n}reset(){this.list.length=0,this.index=0}}const sh=new lr,ah=new lr,oh=new lr,lh=new Kr(1,1,1),ch=new lr,hh=new pa,uh=new Di,dh=new Qi,ph=new Li,mh=new Li,fh=new Li,gh=new rh,vh=new Ws,_h=[];function xh(t,e,n=0){const i=e.itemSize;if(t.isInterleavedBufferAttribute||t.array.constructor!==e.array.constructor){const r=t.count;for(let s=0;s65535?new Uint32Array(i):new Uint16Array(i);e.setIndex(new cs(t,1))}this._geometryInitialized=!0}}_validateGeometry(t){const e=this.geometry;if(Boolean(t.getIndex())!==Boolean(e.getIndex()))throw new Error('BatchedMesh: All geometries must consistently have "index".');for(const n in e.attributes){if(!t.hasAttribute(n))throw new Error(`BatchedMesh: Added geometry missing "${n}". All geometries must have consistent attributes.`);const i=t.getAttribute(n),r=e.getAttribute(n);if(i.itemSize!==r.itemSize||i.normalized!==r.normalized)throw new Error("BatchedMesh: All attributes must have a consistent itemSize and normalized value.")}}setCustomSort(t){return this.customSort=t,this}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new Di);const t=this.boundingBox,e=this._drawInfo;t.makeEmpty();for(let n=0,i=e.length;n=this._maxInstanceCount)throw new Error("BatchedMesh: Maximum item count reached.");this._drawInfo.push({visible:!0,active:!0,geometryIndex:t});const e=this._drawInfo.length-1,n=this._matricesTexture,i=n.image.data;oh.toArray(i,16*e),n.needsUpdate=!0;const r=this._colorsTexture;return r&&(lh.toArray(r.image.data,4*e),r.needsUpdate=!0),e}addGeometry(t,e=-1,n=-1){if(this._initializeGeometry(t),this._validateGeometry(t),this._drawInfo.length>=this._maxInstanceCount)throw new Error("BatchedMesh: Maximum item count reached.");const i={vertexStart:-1,vertexCount:-1,indexStart:-1,indexCount:-1};let r=null;const s=this._reservedRanges,a=this._drawRanges,o=this._bounds;0!==this._geometryCount&&(r=s[s.length-1]),i.vertexCount=-1===e?t.getAttribute("position").count:e,i.vertexStart=null===r?0:r.vertexStart+r.vertexCount;const l=t.getIndex(),c=null!==l;if(c&&(i.indexCount=-1===n?l.count:n,i.indexStart=null===r?0:r.indexStart+r.indexCount),-1!==i.indexStart&&i.indexStart+i.indexCount>this._maxIndexCount||i.vertexStart+i.vertexCount>this._maxVertexCount)throw new Error("BatchedMesh: Reserved space request exceeds the maximum buffer size.");const h=this._geometryCount;return this._geometryCount++,s.push(i),a.push({start:c?i.indexStart:i.vertexStart,count:-1}),o.push({boxInitialized:!1,box:new Di,sphereInitialized:!1,sphere:new Qi}),this.setGeometryAt(h,t),h}setGeometryAt(t,e){if(t>=this._geometryCount)throw new Error("BatchedMesh: Maximum geometry count reached.");this._validateGeometry(e);const n=this.geometry,i=null!==n.getIndex(),r=n.getIndex(),s=e.getIndex(),a=this._reservedRanges[t];if(i&&s.count>a.indexCount||e.attributes.position.count>a.vertexCount)throw new Error("BatchedMesh: Reserved space not large enough for provided geometry.");const o=a.vertexStart,l=a.vertexCount;for(const t in n.attributes){const i=e.getAttribute(t),r=n.getAttribute(t);xh(i,r,o);const s=i.itemSize;for(let t=i.count,e=l;t=this._geometryCount)return null;const n=this._bounds[t],i=n.box,r=this.geometry;if(!1===n.boxInitialized){i.makeEmpty();const e=r.index,s=r.attributes.position,a=this._drawRanges[t];for(let t=a.start,n=a.start+a.count;t=this._geometryCount)return null;const n=this._bounds[t],i=n.sphere,r=this.geometry;if(!1===n.sphereInitialized){i.makeEmpty(),this.getBoundingBoxAt(t,uh),uh.getCenter(i.center);const e=r.index,s=r.attributes.position,a=this._drawRanges[t];let o=0;for(let t=a.start,n=a.start+a.count;t=n.length||!1===n[t].active||(e.toArray(r,16*t),i.needsUpdate=!0),this}getMatrixAt(t,e){const n=this._drawInfo,i=this._matricesTexture.image.data;return t>=n.length||!1===n[t].active?null:e.fromArray(i,16*t)}setColorAt(t,e){null===this._colorsTexture&&this._initColorsTexture();const n=this._colorsTexture,i=this._colorsTexture.image.data,r=this._drawInfo;return t>=r.length||!1===r[t].active||(e.toArray(i,4*t),n.needsUpdate=!0),this}getColorAt(t,e){const n=this._colorsTexture.image.data,i=this._drawInfo;return t>=i.length||!1===i[t].active?null:e.fromArray(n,4*t)}setVisibleAt(t,e){const n=this._drawInfo;return t>=n.length||!1===n[t].active||n[t].visible===e||(n[t].visible=e,this._visibilityChanged=!0),this}getVisibleAt(t){const e=this._drawInfo;return!(t>=e.length||!1===e[t].active)&&e[t].visible}raycast(t,e){const n=this._drawInfo,i=this._drawRanges,r=this.matrixWorld,s=this.geometry;vh.material=this.material,vh.geometry.index=s.index,vh.geometry.attributes=s.attributes,null===vh.geometry.boundingBox&&(vh.geometry.boundingBox=new Di),null===vh.geometry.boundingSphere&&(vh.geometry.boundingSphere=new Qi);for(let s=0,a=n.length;s({...t}))),this._reservedRanges=t._reservedRanges.map((t=>({...t}))),this._drawInfo=t._drawInfo.map((t=>({...t}))),this._bounds=t._bounds.map((t=>({boxInitialized:t.boxInitialized,box:t.box.clone(),sphereInitialized:t.sphereInitialized,sphere:t.sphere.clone()}))),this._maxInstanceCount=t._maxInstanceCount,this._maxVertexCount=t._maxVertexCount,this._maxIndexCount=t._maxIndexCount,this._geometryInitialized=t._geometryInitialized,this._geometryCount=t._geometryCount,this._multiDrawCounts=t._multiDrawCounts.slice(),this._multiDrawStarts=t._multiDrawStarts.slice(),this._matricesTexture=t._matricesTexture.clone(),this._matricesTexture.image.data=this._matricesTexture.image.data.slice(),null!==this._colorsTexture&&(this._colorsTexture=t._colorsTexture.clone(),this._colorsTexture.image.data=this._colorsTexture.image.data.slice()),this}dispose(){return this.geometry.dispose(),this._matricesTexture.dispose(),this._matricesTexture=null,this._indirectTexture.dispose(),this._indirectTexture=null,null!==this._colorsTexture&&(this._colorsTexture.dispose(),this._colorsTexture=null),this}onBeforeRender(t,e,n,i,r){if(!this._visibilityChanged&&!this.perObjectFrustumCulled&&!this.sortObjects)return;const s=i.getIndex(),a=null===s?1:s.array.BYTES_PER_ELEMENT,o=this._drawInfo,l=this._multiDrawStarts,c=this._multiDrawCounts,h=this._drawRanges,u=this.perObjectFrustumCulled,d=this._indirectTexture,p=d.image.data;u&&(ch.multiplyMatrices(n.projectionMatrix,n.matrixWorldInverse).multiply(this.matrixWorld),hh.setFromProjectionMatrix(ch,t.coordinateSystem));let m=0;if(this.sortObjects){ah.copy(this.matrixWorld).invert(),ph.setFromMatrixPosition(n.matrixWorld).applyMatrix4(ah),mh.set(0,0,-1).transformDirection(n.matrixWorld).transformDirection(ah);for(let t=0,e=o.length;t0){const n=t[e[0]];if(void 0!==n){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=n.length;ti)return;Ah.applyMatrix4(t.matrixWorld);const o=e.ray.origin.distanceTo(Ah);return oe.far?void 0:{distance:o,point:Rh.clone().applyMatrix4(t.matrixWorld),index:r,face:null,faceIndex:null,object:t}}const Ih=new Li,Lh=new Li;class Uh extends Ch{constructor(t,e){super(t,e),this.isLineSegments=!0,this.type="LineSegments"}computeLineDistances(){const t=this.geometry;if(null===t.index){const e=t.attributes.position,n=[];for(let t=0,i=e.count;t0){const n=t[e[0]];if(void 0!==n){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=n.length;tr.far)return;s.push({distance:l,distanceToRay:Math.sqrt(o),point:n,index:e,face:null,object:a})}}class Hh extends bi{constructor(t,e,n,i,r,s,a,o,l){super(t,e,n,i,r,s,a,o,l),this.isVideoTexture=!0,this.minFilter=void 0!==s?s:Mt,this.magFilter=void 0!==r?r:Mt,this.generateMipmaps=!1;const c=this;"requestVideoFrameCallback"in t&&t.requestVideoFrameCallback((function e(){c.needsUpdate=!0,t.requestVideoFrameCallback(e)}))}clone(){return new this.constructor(this.image).copy(this)}update(){const t=this.image;!1==="requestVideoFrameCallback"in t&&t.readyState>=t.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}}class Gh extends bi{constructor(t,e){super({width:t,height:e}),this.isFramebufferTexture=!0,this.magFilter=gt,this.minFilter=gt,this.generateMipmaps=!1,this.needsUpdate=!0}}class Wh extends bi{constructor(t,e,n,i,r,s,a,o,l,c,h,u){super(null,s,a,o,l,c,i,r,h,u),this.isCompressedTexture=!0,this.image={width:e,height:n},this.mipmaps=t,this.flipY=!1,this.generateMipmaps=!1}}class Xh extends Wh{constructor(t,e,n,i,r,s){super(t,e,n,r,s),this.isCompressedArrayTexture=!0,this.image.depth=i,this.wrapR=mt,this.layerUpdates=new Set}addLayerUpdate(t){this.layerUpdates.add(t)}clearLayerUpdates(){this.layerUpdates.clear()}}class jh extends Wh{constructor(t,e,n){super(void 0,t[0].width,t[0].height,e,n,lt),this.isCompressedCubeTexture=!0,this.isCubeTexture=!0,this.image=t}}class qh extends bi{constructor(t,e,n,i,r,s,a,o,l){super(t,e,n,i,r,s,a,o,l),this.isCanvasTexture=!0,this.needsUpdate=!0}}class Yh{constructor(){this.type="Curve",this.arcLengthDivisions=200}getPoint(){return console.warn("THREE.Curve: .getPoint() not implemented."),null}getPointAt(t,e){const n=this.getUtoTmapping(t);return this.getPoint(n,e)}getPoints(t=5){const e=[];for(let n=0;n<=t;n++)e.push(this.getPoint(n/t));return e}getSpacedPoints(t=5){const e=[];for(let n=0;n<=t;n++)e.push(this.getPointAt(n/t));return e}getLength(){const t=this.getLengths();return t[t.length-1]}getLengths(t=this.arcLengthDivisions){if(this.cacheArcLengths&&this.cacheArcLengths.length===t+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;const e=[];let n,i=this.getPoint(0),r=0;e.push(0);for(let s=1;s<=t;s++)n=this.getPoint(s/t),r+=n.distanceTo(i),e.push(r),i=n;return this.cacheArcLengths=e,e}updateArcLengths(){this.needsUpdate=!0,this.getLengths()}getUtoTmapping(t,e){const n=this.getLengths();let i=0;const r=n.length;let s;s=e||t*n[r-1];let a,o=0,l=r-1;for(;o<=l;)if(i=Math.floor(o+(l-o)/2),a=n[i]-s,a<0)o=i+1;else{if(!(a>0)){l=i;break}l=i-1}if(i=l,n[i]===s)return i/(r-1);const c=n[i];return(i+(s-c)/(n[i+1]-c))/(r-1)}getTangent(t,e){const n=1e-4;let i=t-n,r=t+n;i<0&&(i=0),r>1&&(r=1);const s=this.getPoint(i),a=this.getPoint(r),o=e||(s.isVector2?new ti:new Li);return o.copy(a).sub(s).normalize(),o}getTangentAt(t,e){const n=this.getUtoTmapping(t);return this.getTangent(n,e)}computeFrenetFrames(t,e){const n=new Li,i=[],r=[],s=[],a=new Li,o=new lr;for(let e=0;e<=t;e++){const n=e/t;i[e]=this.getTangentAt(n,new Li)}r[0]=new Li,s[0]=new Li;let l=Number.MAX_VALUE;const c=Math.abs(i[0].x),h=Math.abs(i[0].y),u=Math.abs(i[0].z);c<=l&&(l=c,n.set(1,0,0)),h<=l&&(l=h,n.set(0,1,0)),u<=l&&n.set(0,0,1),a.crossVectors(i[0],n).normalize(),r[0].crossVectors(i[0],a),s[0].crossVectors(i[0],r[0]);for(let e=1;e<=t;e++){if(r[e]=r[e-1].clone(),s[e]=s[e-1].clone(),a.crossVectors(i[e-1],i[e]),a.length()>Number.EPSILON){a.normalize();const t=Math.acos(Yn(i[e-1].dot(i[e]),-1,1));r[e].applyMatrix4(o.makeRotationAxis(a,t))}s[e].crossVectors(i[e],r[e])}if(!0===e){let e=Math.acos(Yn(r[0].dot(r[t]),-1,1));e/=t,i[0].dot(a.crossVectors(r[0],r[t]))>0&&(e=-e);for(let n=1;n<=t;n++)r[n].applyMatrix4(o.makeRotationAxis(i[n],e*n)),s[n].crossVectors(i[n],r[n])}return{tangents:i,normals:r,binormals:s}}clone(){return(new this.constructor).copy(this)}copy(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}toJSON(){const t={metadata:{version:4.6,type:"Curve",generator:"Curve.toJSON"}};return t.arcLengthDivisions=this.arcLengthDivisions,t.type=this.type,t}fromJSON(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}}class Zh extends Yh{constructor(t=0,e=0,n=1,i=1,r=0,s=2*Math.PI,a=!1,o=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=t,this.aY=e,this.xRadius=n,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=s,this.aClockwise=a,this.aRotation=o}getPoint(t,e=new ti){const n=e,i=2*Math.PI;let r=this.aEndAngle-this.aStartAngle;const s=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(l)/r)+1)*r:0===c&&l===r-1&&(l=r-2,c=1),this.closed||l>0?a=i[(l-1)%r]:($h.subVectors(i[0],i[1]).add(i[0]),a=$h);const h=i[l%r],u=i[(l+1)%r];if(this.closed||l+2i.length-2?i.length-1:s+1],h=i[s>i.length-3?i.length-1:s+2];return n.set(iu(a,o.x,l.x,c.x,h.x),iu(a,o.y,l.y,c.y,h.y)),n}copy(t){super.copy(t),this.points=[];for(let e=0,n=t.points.length;e=n){const t=i[r]-n,s=this.curves[r],a=s.getLength(),o=0===a?0:1-t/a;return s.getPointAt(o,e)}r++}return null}getLength(){const t=this.getCurveLengths();return t[t.length-1]}updateArcLengths(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()}getCurveLengths(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;const t=[];let e=0;for(let n=0,i=this.curves.length;n1&&!e[e.length-1].equals(e[0])&&e.push(e[0]),e}copy(t){super.copy(t),this.curves=[];for(let e=0,n=t.curves.length;e0){const t=l.getPoint(0);t.equals(this.currentPoint)||this.lineTo(t.x,t.y)}this.curves.push(l);const c=l.getPoint(1);return this.currentPoint.copy(c),this}copy(t){return super.copy(t),this.currentPoint.copy(t.currentPoint),this}toJSON(){const t=super.toJSON();return t.currentPoint=this.currentPoint.toArray(),t}fromJSON(t){return super.fromJSON(t),this.currentPoint.fromArray(t.currentPoint),this}}class gu extends Es{constructor(t=[new ti(0,-.5),new ti(.5,0),new ti(0,.5)],e=12,n=0,i=2*Math.PI){super(),this.type="LatheGeometry",this.parameters={points:t,segments:e,phiStart:n,phiLength:i},e=Math.floor(e),i=Yn(i,0,2*Math.PI);const r=[],s=[],a=[],o=[],l=[],c=1/e,h=new Li,u=new ti,d=new Li,p=new Li,m=new Li;let f=0,g=0;for(let e=0;e<=t.length-1;e++)switch(e){case 0:f=t[e+1].x-t[e].x,g=t[e+1].y-t[e].y,d.x=1*g,d.y=-f,d.z=0*g,m.copy(d),d.normalize(),o.push(d.x,d.y,d.z);break;case t.length-1:o.push(m.x,m.y,m.z);break;default:f=t[e+1].x-t[e].x,g=t[e+1].y-t[e].y,d.x=1*g,d.y=-f,d.z=0*g,p.copy(d),d.x+=m.x,d.y+=m.y,d.z+=m.z,d.normalize(),o.push(d.x,d.y,d.z),m.copy(p)}for(let r=0;r<=e;r++){const d=n+r*c*i,p=Math.sin(d),m=Math.cos(d);for(let n=0;n<=t.length-1;n++){h.x=t[n].x*p,h.y=t[n].y,h.z=t[n].x*m,s.push(h.x,h.y,h.z),u.x=r/e,u.y=n/(t.length-1),a.push(u.x,u.y);const i=o[3*n+0]*p,c=o[3*n+1],d=o[3*n+0]*m;l.push(i,c,d)}}for(let n=0;n0&&v(!0),e>0&&v(!1)),this.setIndex(c),this.setAttribute("position",new _s(h,3)),this.setAttribute("normal",new _s(u,3)),this.setAttribute("uv",new _s(d,2))}copy(t){return super.copy(t),this.parameters=Object.assign({},t.parameters),this}static fromJSON(t){return new xu(t.radiusTop,t.radiusBottom,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class yu extends xu{constructor(t=1,e=1,n=32,i=1,r=!1,s=0,a=2*Math.PI){super(0,t,e,n,i,r,s,a),this.type="ConeGeometry",this.parameters={radius:t,height:e,radialSegments:n,heightSegments:i,openEnded:r,thetaStart:s,thetaLength:a}}static fromJSON(t){return new yu(t.radius,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class Mu extends Es{constructor(t=[],e=[],n=1,i=0){super(),this.type="PolyhedronGeometry",this.parameters={vertices:t,indices:e,radius:n,detail:i};const r=[],s=[];function a(t,e,n,i){const r=i+1,s=[];for(let i=0;i<=r;i++){s[i]=[];const a=t.clone().lerp(n,i/r),o=e.clone().lerp(n,i/r),l=r-i;for(let t=0;t<=l;t++)s[i][t]=0===t&&i===r?a:a.clone().lerp(o,t/l)}for(let t=0;t.9&&a<.1&&(e<.2&&(s[t+0]+=1),n<.2&&(s[t+2]+=1),i<.2&&(s[t+4]+=1))}}()}(),this.setAttribute("position",new _s(r,3)),this.setAttribute("normal",new _s(r.slice(),3)),this.setAttribute("uv",new _s(s,2)),0===i?this.computeVertexNormals():this.normalizeNormals()}copy(t){return super.copy(t),this.parameters=Object.assign({},t.parameters),this}static fromJSON(t){return new Mu(t.vertices,t.indices,t.radius,t.details)}}class Su extends Mu{constructor(t=1,e=0){const n=(1+Math.sqrt(5))/2,i=1/n;super([-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-i,-n,0,-i,n,0,i,-n,0,i,n,-i,-n,0,-i,n,0,i,-n,0,i,n,0,-n,0,-i,n,0,-i,-n,0,i,n,0,i],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],t,e),this.type="DodecahedronGeometry",this.parameters={radius:t,detail:e}}static fromJSON(t){return new Su(t.radius,t.detail)}}const bu=new Li,wu=new Li,Tu=new Li,Eu=new jr;class Au extends Es{constructor(t=null,e=1){if(super(),this.type="EdgesGeometry",this.parameters={geometry:t,thresholdAngle:e},null!==t){const n=4,i=Math.pow(10,n),r=Math.cos(Xn*e),s=t.getIndex(),a=t.getAttribute("position"),o=s?s.count:a.count,l=[0,0,0],c=["a","b","c"],h=new Array(3),u={},d=[];for(let t=0;t80*n){o=c=t[0],l=h=t[1];for(let e=n;ec&&(c=u),d>h&&(h=d);p=Math.max(c-o,h-l),p=0!==p?32767/p:0}return Lu(s,a,n,o,l,p,0),a};function Pu(t,e,n,i,r){let s,a;if(r===function(t,e,n,i){let r=0;for(let s=e,a=n-i;s0)for(s=e;s=e;s-=i)a=Ku(s,t[s],t[s+1],a);return a&&Xu(a,a.next)&&($u(a),a=a.next),a}function Iu(t,e){if(!t)return t;e||(e=t);let n,i=t;do{if(n=!1,i.steiner||!Xu(i,i.next)&&0!==Wu(i.prev,i,i.next))i=i.next;else{if($u(i),i=e=i.prev,i===i.next)break;n=!0}}while(n||i!==e);return e}function Lu(t,e,n,i,r,s,a){if(!t)return;!a&&s&&function(t,e,n,i){let r=t;do{0===r.z&&(r.z=ku(r.x,r.y,e,n,i)),r.prevZ=r.prev,r.nextZ=r.next,r=r.next}while(r!==t);r.prevZ.nextZ=null,r.prevZ=null,function(t){let e,n,i,r,s,a,o,l,c=1;do{for(n=t,t=null,s=null,a=0;n;){for(a++,i=n,o=0,e=0;e0||l>0&&i;)0!==o&&(0===l||!i||n.z<=i.z)?(r=n,n=n.nextZ,o--):(r=i,i=i.nextZ,l--),s?s.nextZ=r:t=r,r.prevZ=s,s=r;n=i}s.nextZ=null,c*=2}while(a>1)}(r)}(t,i,r,s);let o,l,c=t;for(;t.prev!==t.next;)if(o=t.prev,l=t.next,s?Nu(t,i,r,s):Uu(t))e.push(o.i/n|0),e.push(t.i/n|0),e.push(l.i/n|0),$u(t),t=l.next,c=l.next;else if((t=l)===c){a?1===a?Lu(t=Du(Iu(t),e,n),e,n,i,r,s,2):2===a&&Ou(t,e,n,i,r,s):Lu(Iu(t),e,n,i,r,s,1);break}}function Uu(t){const e=t.prev,n=t,i=t.next;if(Wu(e,n,i)>=0)return!1;const r=e.x,s=n.x,a=i.x,o=e.y,l=n.y,c=i.y,h=rs?r>a?r:a:s>a?s:a,p=o>l?o>c?o:c:l>c?l:c;let m=i.next;for(;m!==e;){if(m.x>=h&&m.x<=d&&m.y>=u&&m.y<=p&&Hu(r,o,s,l,a,c,m.x,m.y)&&Wu(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function Nu(t,e,n,i){const r=t.prev,s=t,a=t.next;if(Wu(r,s,a)>=0)return!1;const o=r.x,l=s.x,c=a.x,h=r.y,u=s.y,d=a.y,p=ol?o>c?o:c:l>c?l:c,g=h>u?h>d?h:d:u>d?u:d,v=ku(p,m,e,n,i),_=ku(f,g,e,n,i);let x=t.prevZ,y=t.nextZ;for(;x&&x.z>=v&&y&&y.z<=_;){if(x.x>=p&&x.x<=f&&x.y>=m&&x.y<=g&&x!==r&&x!==a&&Hu(o,h,l,u,c,d,x.x,x.y)&&Wu(x.prev,x,x.next)>=0)return!1;if(x=x.prevZ,y.x>=p&&y.x<=f&&y.y>=m&&y.y<=g&&y!==r&&y!==a&&Hu(o,h,l,u,c,d,y.x,y.y)&&Wu(y.prev,y,y.next)>=0)return!1;y=y.nextZ}for(;x&&x.z>=v;){if(x.x>=p&&x.x<=f&&x.y>=m&&x.y<=g&&x!==r&&x!==a&&Hu(o,h,l,u,c,d,x.x,x.y)&&Wu(x.prev,x,x.next)>=0)return!1;x=x.prevZ}for(;y&&y.z<=_;){if(y.x>=p&&y.x<=f&&y.y>=m&&y.y<=g&&y!==r&&y!==a&&Hu(o,h,l,u,c,d,y.x,y.y)&&Wu(y.prev,y,y.next)>=0)return!1;y=y.nextZ}return!0}function Du(t,e,n){let i=t;do{const r=i.prev,s=i.next.next;!Xu(r,s)&&ju(r,i,i.next,s)&&Zu(r,s)&&Zu(s,r)&&(e.push(r.i/n|0),e.push(i.i/n|0),e.push(s.i/n|0),$u(i),$u(i.next),i=t=s),i=i.next}while(i!==t);return Iu(i)}function Ou(t,e,n,i,r,s){let a=t;do{let t=a.next.next;for(;t!==a.prev;){if(a.i!==t.i&&Gu(a,t)){let o=Ju(a,t);return a=Iu(a,a.next),o=Iu(o,o.next),Lu(a,e,n,i,r,s,0),void Lu(o,e,n,i,r,s,0)}t=t.next}a=a.next}while(a!==t)}function Fu(t,e){return t.x-e.x}function Bu(t,e){const n=function(t,e){let n,i=e,r=-1/0;const s=t.x,a=t.y;do{if(a<=i.y&&a>=i.next.y&&i.next.y!==i.y){const t=i.x+(a-i.y)*(i.next.x-i.x)/(i.next.y-i.y);if(t<=s&&t>r&&(r=t,n=i.x=i.x&&i.x>=l&&s!==i.x&&Hu(an.x||i.x===n.x&&zu(n,i)))&&(n=i,u=h)),i=i.next}while(i!==o);return n}(t,e);if(!n)return e;const i=Ju(n,t);return Iu(i,i.next),Iu(n,n.next)}function zu(t,e){return Wu(t.prev,t,e.prev)<0&&Wu(e.next,t,t.next)<0}function ku(t,e,n,i,r){return(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=(t-n)*r|0)|t<<8))|t<<4))|t<<2))|t<<1))|(e=1431655765&((e=858993459&((e=252645135&((e=16711935&((e=(e-i)*r|0)|e<<8))|e<<4))|e<<2))|e<<1))<<1}function Vu(t){let e=t,n=t;do{(e.x=(t-a)*(s-o)&&(t-a)*(i-o)>=(n-a)*(e-o)&&(n-a)*(s-o)>=(r-a)*(i-o)}function Gu(t,e){return t.next.i!==e.i&&t.prev.i!==e.i&&!function(t,e){let n=t;do{if(n.i!==t.i&&n.next.i!==t.i&&n.i!==e.i&&n.next.i!==e.i&&ju(n,n.next,t,e))return!0;n=n.next}while(n!==t);return!1}(t,e)&&(Zu(t,e)&&Zu(e,t)&&function(t,e){let n=t,i=!1;const r=(t.x+e.x)/2,s=(t.y+e.y)/2;do{n.y>s!=n.next.y>s&&n.next.y!==n.y&&r<(n.next.x-n.x)*(s-n.y)/(n.next.y-n.y)+n.x&&(i=!i),n=n.next}while(n!==t);return i}(t,e)&&(Wu(t.prev,t,e.prev)||Wu(t,e.prev,e))||Xu(t,e)&&Wu(t.prev,t,t.next)>0&&Wu(e.prev,e,e.next)>0)}function Wu(t,e,n){return(e.y-t.y)*(n.x-e.x)-(e.x-t.x)*(n.y-e.y)}function Xu(t,e){return t.x===e.x&&t.y===e.y}function ju(t,e,n,i){const r=Yu(Wu(t,e,n)),s=Yu(Wu(t,e,i)),a=Yu(Wu(n,i,t)),o=Yu(Wu(n,i,e));return r!==s&&a!==o||(!(0!==r||!qu(t,n,e))||(!(0!==s||!qu(t,i,e))||(!(0!==a||!qu(n,t,i))||!(0!==o||!qu(n,e,i)))))}function qu(t,e,n){return e.x<=Math.max(t.x,n.x)&&e.x>=Math.min(t.x,n.x)&&e.y<=Math.max(t.y,n.y)&&e.y>=Math.min(t.y,n.y)}function Yu(t){return t>0?1:t<0?-1:0}function Zu(t,e){return Wu(t.prev,t,t.next)<0?Wu(t,e,t.next)>=0&&Wu(t,t.prev,e)>=0:Wu(t,e,t.prev)<0||Wu(t,t.next,e)<0}function Ju(t,e){const n=new Qu(t.i,t.x,t.y),i=new Qu(e.i,e.x,e.y),r=t.next,s=e.prev;return t.next=e,e.prev=t,n.next=r,r.prev=n,i.next=n,n.prev=i,s.next=i,i.prev=s,i}function Ku(t,e,n,i){const r=new Qu(t,e,n);return i?(r.next=i.next,r.prev=i,i.next.prev=r,i.next=r):(r.prev=r,r.next=r),r}function $u(t){t.next.prev=t.prev,t.prev.next=t.next,t.prevZ&&(t.prevZ.nextZ=t.nextZ),t.nextZ&&(t.nextZ.prevZ=t.prevZ)}function Qu(t,e,n){this.i=t,this.x=e,this.y=n,this.prev=null,this.next=null,this.z=0,this.prevZ=null,this.nextZ=null,this.steiner=!1}class td{static area(t){const e=t.length;let n=0;for(let i=e-1,r=0;r2&&t[e-1].equals(t[0])&&t.pop()}function nd(t,e){for(let n=0;nNumber.EPSILON){const u=Math.sqrt(h),d=Math.sqrt(l*l+c*c),p=e.x-o/u,m=e.y+a/u,f=((n.x-c/d-p)*c-(n.y+l/d-m)*l)/(a*c-o*l);i=p+a*f-t.x,r=m+o*f-t.y;const g=i*i+r*r;if(g<=2)return new ti(i,r);s=Math.sqrt(g/2)}else{let t=!1;a>Number.EPSILON?l>Number.EPSILON&&(t=!0):a<-Number.EPSILON?l<-Number.EPSILON&&(t=!0):Math.sign(o)===Math.sign(c)&&(t=!0),t?(i=-o,r=a,s=Math.sqrt(h)):(i=a,r=o,s=Math.sqrt(h/2))}return new ti(i/s,r/s)}const I=[];for(let t=0,e=E.length,n=e-1,i=t+1;t=0;t--){const e=t/p,n=h*Math.cos(e*Math.PI/2),i=u*Math.sin(e*Math.PI/2)+d;for(let t=0,e=E.length;t=0;){const i=n;let r=n-1;r<0&&(r=t.length-1);for(let t=0,n=o+2*p;t0)&&d.push(e,r,l),(t!==n-1||o0!=t>0&&this.version++,this._anisotropy=t}get clearcoat(){return this._clearcoat}set clearcoat(t){this._clearcoat>0!=t>0&&this.version++,this._clearcoat=t}get iridescence(){return this._iridescence}set iridescence(t){this._iridescence>0!=t>0&&this.version++,this._iridescence=t}get dispersion(){return this._dispersion}set dispersion(t){this._dispersion>0!=t>0&&this.version++,this._dispersion=t}get sheen(){return this._sheen}set sheen(t){this._sheen>0!=t>0&&this.version++,this._sheen=t}get transmission(){return this._transmission}set transmission(t){this._transmission>0!=t>0&&this.version++,this._transmission=t}copy(t){return super.copy(t),this.defines={STANDARD:"",PHYSICAL:""},this.anisotropy=t.anisotropy,this.anisotropyRotation=t.anisotropyRotation,this.anisotropyMap=t.anisotropyMap,this.clearcoat=t.clearcoat,this.clearcoatMap=t.clearcoatMap,this.clearcoatRoughness=t.clearcoatRoughness,this.clearcoatRoughnessMap=t.clearcoatRoughnessMap,this.clearcoatNormalMap=t.clearcoatNormalMap,this.clearcoatNormalScale.copy(t.clearcoatNormalScale),this.dispersion=t.dispersion,this.ior=t.ior,this.iridescence=t.iridescence,this.iridescenceMap=t.iridescenceMap,this.iridescenceIOR=t.iridescenceIOR,this.iridescenceThicknessRange=[...t.iridescenceThicknessRange],this.iridescenceThicknessMap=t.iridescenceThicknessMap,this.sheen=t.sheen,this.sheenColor.copy(t.sheenColor),this.sheenColorMap=t.sheenColorMap,this.sheenRoughness=t.sheenRoughness,this.sheenRoughnessMap=t.sheenRoughnessMap,this.transmission=t.transmission,this.transmissionMap=t.transmissionMap,this.thickness=t.thickness,this.thicknessMap=t.thicknessMap,this.attenuationDistance=t.attenuationDistance,this.attenuationColor.copy(t.attenuationColor),this.specularIntensity=t.specularIntensity,this.specularIntensityMap=t.specularIntensityMap,this.specularColor.copy(t.specularColor),this.specularColorMap=t.specularColorMap,this}}class Md extends ts{constructor(t){super(),this.isMeshPhongMaterial=!0,this.type="MeshPhongMaterial",this.color=new Kr(16777215),this.specular=new Kr(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Kr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new ti(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new _r,this.combine=Y,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.specular.copy(t.specular),this.shininess=t.shininess,this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.flatShading=t.flatShading,this.fog=t.fog,this}}class Sd extends ts{constructor(t){super(),this.isMeshToonMaterial=!0,this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new Kr(16777215),this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Kr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new ti(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.gradientMap=t.gradientMap,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.alphaMap=t.alphaMap,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.fog=t.fog,this}}class bd extends ts{constructor(t){super(),this.isMeshNormalMaterial=!0,this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new ti(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.flatShading=!1,this.setValues(t)}copy(t){return super.copy(t),this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.flatShading=t.flatShading,this}}class wd extends ts{constructor(t){super(),this.isMeshLambertMaterial=!0,this.type="MeshLambertMaterial",this.color=new Kr(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Kr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new ti(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new _r,this.combine=Y,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.flatShading=t.flatShading,this.fog=t.fog,this}}class Td extends ts{constructor(t){super(),this.isMeshMatcapMaterial=!0,this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new Kr(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new ti(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.defines={MATCAP:""},this.color.copy(t.color),this.matcap=t.matcap,this.map=t.map,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.alphaMap=t.alphaMap,this.flatShading=t.flatShading,this.fog=t.fog,this}}class Ed extends Mh{constructor(t){super(),this.isLineDashedMaterial=!0,this.type="LineDashedMaterial",this.scale=1,this.dashSize=3,this.gapSize=1,this.setValues(t)}copy(t){return super.copy(t),this.scale=t.scale,this.dashSize=t.dashSize,this.gapSize=t.gapSize,this}}function Ad(t,e,n){return!t||!n&&t.constructor===e?t:"number"==typeof e.BYTES_PER_ELEMENT?new e(t):Array.prototype.slice.call(t)}function Rd(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}function Cd(t){const e=t.length,n=new Array(e);for(let t=0;t!==e;++t)n[t]=t;return n.sort((function(e,n){return t[e]-t[n]})),n}function Pd(t,e,n){const i=t.length,r=new t.constructor(i);for(let s=0,a=0;a!==i;++s){const i=n[s]*e;for(let n=0;n!==e;++n)r[a++]=t[i+n]}return r}function Id(t,e,n,i){let r=1,s=t[0];for(;void 0!==s&&void 0===s[i];)s=t[r++];if(void 0===s)return;let a=s[i];if(void 0!==a)if(Array.isArray(a))do{a=s[i],void 0!==a&&(e.push(s.time),n.push.apply(n,a)),s=t[r++]}while(void 0!==s);else if(void 0!==a.toArray)do{a=s[i],void 0!==a&&(e.push(s.time),a.toArray(n,n.length)),s=t[r++]}while(void 0!==s);else do{a=s[i],void 0!==a&&(e.push(s.time),n.push(a)),s=t[r++]}while(void 0!==s)}const Ld={convertArray:Ad,isTypedArray:Rd,getKeyframeOrder:Cd,sortedArray:Pd,flattenJSON:Id,subclip:function(t,e,n,i,r=30){const s=t.clone();s.name=e;const a=[];for(let t=0;t=i)){l.push(e.times[t]);for(let n=0;ns.tracks[t].times[0]&&(o=s.tracks[t].times[0]);for(let t=0;t=i.times[u]){const t=u*l+o,e=t+l-o;d=i.values.slice(t,e)}else{const t=i.createInterpolant(),e=o,n=l-o;t.evaluate(s),d=t.resultBuffer.slice(e,n)}if("quaternion"===r){(new Ii).fromArray(d).normalize().conjugate().toArray(d)}const p=a.times.length;for(let t=0;t=r)break t;{const a=e[1];t=r)break e}s=n,n=0}}for(;n>>1;te;)--s;if(++s,0!==r||s!==i){r>=s&&(s=Math.max(s,1),r=s-1);const t=this.getValueSize();this.times=n.slice(r,s),this.values=this.values.slice(r*t,s*t)}return this}validate(){let t=!0;const e=this.getValueSize();e-Math.floor(e)!=0&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),t=!1);const n=this.times,i=this.values,r=n.length;0===r&&(console.error("THREE.KeyframeTrack: Track is empty.",this),t=!1);let s=null;for(let e=0;e!==r;e++){const i=n[e];if("number"==typeof i&&isNaN(i)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,e,i),t=!1;break}if(null!==s&&s>i){console.error("THREE.KeyframeTrack: Out of order keys.",this,e,i,s),t=!1;break}s=i}if(void 0!==i&&Rd(i))for(let e=0,n=i.length;e!==n;++e){const n=i[e];if(isNaN(n)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,e,n),t=!1;break}}return t}optimize(){const t=this.times.slice(),e=this.values.slice(),n=this.getValueSize(),i=this.getInterpolation()===Ne,r=t.length-1;let s=1;for(let a=1;a0){t[s]=t[r];for(let t=r*n,i=s*n,a=0;a!==n;++a)e[i+a]=e[t+a];++s}return s!==t.length?(this.times=t.slice(0,s),this.values=e.slice(0,s*n)):(this.times=t,this.values=e),this}clone(){const t=this.times.slice(),e=this.values.slice(),n=new(0,this.constructor)(this.name,t,e);return n.createInterpolant=this.createInterpolant,n}}Fd.prototype.TimeBufferType=Float32Array,Fd.prototype.ValueBufferType=Float32Array,Fd.prototype.DefaultInterpolation=Ue;class Bd extends Fd{constructor(t,e,n){super(t,e,n)}}Bd.prototype.ValueTypeName="bool",Bd.prototype.ValueBufferType=Array,Bd.prototype.DefaultInterpolation=Le,Bd.prototype.InterpolantFactoryMethodLinear=void 0,Bd.prototype.InterpolantFactoryMethodSmooth=void 0;class zd extends Fd{}zd.prototype.ValueTypeName="color";class kd extends Fd{}kd.prototype.ValueTypeName="number";class Vd extends Ud{constructor(t,e,n,i){super(t,e,n,i)}interpolate_(t,e,n,i){const r=this.resultBuffer,s=this.sampleValues,a=this.valueSize,o=(n-e)/(i-e);let l=t*a;for(let t=l+a;l!==t;l+=4)Ii.slerpFlat(r,0,s,l-a,s,l,o);return r}}class Hd extends Fd{InterpolantFactoryMethodLinear(t){return new Vd(this.times,this.values,this.getValueSize(),t)}}Hd.prototype.ValueTypeName="quaternion",Hd.prototype.InterpolantFactoryMethodSmooth=void 0;class Gd extends Fd{constructor(t,e,n){super(t,e,n)}}Gd.prototype.ValueTypeName="string",Gd.prototype.ValueBufferType=Array,Gd.prototype.DefaultInterpolation=Le,Gd.prototype.InterpolantFactoryMethodLinear=void 0,Gd.prototype.InterpolantFactoryMethodSmooth=void 0;class Wd extends Fd{}Wd.prototype.ValueTypeName="vector";class Xd{constructor(t="",e=-1,n=[],i=2500){this.name=t,this.tracks=n,this.duration=e,this.blendMode=i,this.uuid=qn(),this.duration<0&&this.resetDuration()}static parse(t){const e=[],n=t.tracks,i=1/(t.fps||1);for(let t=0,r=n.length;t!==r;++t)e.push(jd(n[t]).scale(i));const r=new this(t.name,t.duration,e,t.blendMode);return r.uuid=t.uuid,r}static toJSON(t){const e=[],n=t.tracks,i={name:t.name,duration:t.duration,tracks:e,uuid:t.uuid,blendMode:t.blendMode};for(let t=0,i=n.length;t!==i;++t)e.push(Fd.toJSON(n[t]));return i}static CreateFromMorphTargetSequence(t,e,n,i){const r=e.length,s=[];for(let t=0;t1){const t=s[1];let e=i[t];e||(i[t]=e=[]),e.push(n)}}const s=[];for(const t in i)s.push(this.CreateFromMorphTargetSequence(t,i[t],e,n));return s}static parseAnimation(t,e){if(!t)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;const n=function(t,e,n,i,r){if(0!==n.length){const s=[],a=[];Id(n,s,a,i),0!==s.length&&r.push(new t(e,s,a))}},i=[],r=t.name||"default",s=t.fps||30,a=t.blendMode;let o=t.length||-1;const l=t.hierarchy||[];for(let t=0;t{e&&e(r),this.manager.itemEnd(t)}),0),r;if(void 0!==Kd[t])return void Kd[t].push({onLoad:e,onProgress:n,onError:i});Kd[t]=[],Kd[t].push({onLoad:e,onProgress:n,onError:i});const s=new Request(t,{headers:new Headers(this.requestHeader),credentials:this.withCredentials?"include":"same-origin"}),a=this.mimeType,o=this.responseType;fetch(s).then((e=>{if(200===e.status||0===e.status){if(0===e.status&&console.warn("THREE.FileLoader: HTTP Status 0 received."),"undefined"==typeof ReadableStream||void 0===e.body||void 0===e.body.getReader)return e;const n=Kd[t],i=e.body.getReader(),r=e.headers.get("X-File-Size")||e.headers.get("Content-Length"),s=r?parseInt(r):0,a=0!==s;let o=0;const l=new ReadableStream({start(t){!function e(){i.read().then((({done:i,value:r})=>{if(i)t.close();else{o+=r.byteLength;const i=new ProgressEvent("progress",{lengthComputable:a,loaded:o,total:s});for(let t=0,e=n.length;t{t.error(e)}))}()}});return new Response(l)}throw new $d(`fetch for "${e.url}" responded with ${e.status}: ${e.statusText}`,e)})).then((t=>{switch(o){case"arraybuffer":return t.arrayBuffer();case"blob":return t.blob();case"document":return t.text().then((t=>(new DOMParser).parseFromString(t,a)));case"json":return t.json();default:if(void 0===a)return t.text();{const e=/charset="?([^;"\s]*)"?/i.exec(a),n=e&&e[1]?e[1].toLowerCase():void 0,i=new TextDecoder(n);return t.arrayBuffer().then((t=>i.decode(t)))}}})).then((e=>{qd.add(t,e);const n=Kd[t];delete Kd[t];for(let t=0,i=n.length;t{const n=Kd[t];if(void 0===n)throw this.manager.itemError(t),e;delete Kd[t];for(let t=0,i=n.length;t{this.manager.itemEnd(t)})),this.manager.itemStart(t)}setResponseType(t){return this.responseType=t,this}setMimeType(t){return this.mimeType=t,this}}class tp extends Jd{constructor(t){super(t)}load(t,e,n,i){const r=this,s=new Qd(this.manager);s.setPath(this.path),s.setRequestHeader(this.requestHeader),s.setWithCredentials(this.withCredentials),s.load(t,(function(n){try{e(r.parse(JSON.parse(n)))}catch(e){i?i(e):console.error(e),r.manager.itemError(t)}}),n,i)}parse(t){const e=[];for(let n=0;n0:i.vertexColors=t.vertexColors),void 0!==t.uniforms)for(const e in t.uniforms){const r=t.uniforms[e];switch(i.uniforms[e]={},r.type){case"t":i.uniforms[e].value=n(r.value);break;case"c":i.uniforms[e].value=(new Kr).setHex(r.value);break;case"v2":i.uniforms[e].value=(new ti).fromArray(r.value);break;case"v3":i.uniforms[e].value=(new Li).fromArray(r.value);break;case"v4":i.uniforms[e].value=(new wi).fromArray(r.value);break;case"m3":i.uniforms[e].value=(new ei).fromArray(r.value);break;case"m4":i.uniforms[e].value=(new lr).fromArray(r.value);break;default:i.uniforms[e].value=r.value}}if(void 0!==t.defines&&(i.defines=t.defines),void 0!==t.vertexShader&&(i.vertexShader=t.vertexShader),void 0!==t.fragmentShader&&(i.fragmentShader=t.fragmentShader),void 0!==t.glslVersion&&(i.glslVersion=t.glslVersion),void 0!==t.extensions)for(const e in t.extensions)i.extensions[e]=t.extensions[e];if(void 0!==t.lights&&(i.lights=t.lights),void 0!==t.clipping&&(i.clipping=t.clipping),void 0!==t.size&&(i.size=t.size),void 0!==t.sizeAttenuation&&(i.sizeAttenuation=t.sizeAttenuation),void 0!==t.map&&(i.map=n(t.map)),void 0!==t.matcap&&(i.matcap=n(t.matcap)),void 0!==t.alphaMap&&(i.alphaMap=n(t.alphaMap)),void 0!==t.bumpMap&&(i.bumpMap=n(t.bumpMap)),void 0!==t.bumpScale&&(i.bumpScale=t.bumpScale),void 0!==t.normalMap&&(i.normalMap=n(t.normalMap)),void 0!==t.normalMapType&&(i.normalMapType=t.normalMapType),void 0!==t.normalScale){let e=t.normalScale;!1===Array.isArray(e)&&(e=[e,e]),i.normalScale=(new ti).fromArray(e)}return void 0!==t.displacementMap&&(i.displacementMap=n(t.displacementMap)),void 0!==t.displacementScale&&(i.displacementScale=t.displacementScale),void 0!==t.displacementBias&&(i.displacementBias=t.displacementBias),void 0!==t.roughnessMap&&(i.roughnessMap=n(t.roughnessMap)),void 0!==t.metalnessMap&&(i.metalnessMap=n(t.metalnessMap)),void 0!==t.emissiveMap&&(i.emissiveMap=n(t.emissiveMap)),void 0!==t.emissiveIntensity&&(i.emissiveIntensity=t.emissiveIntensity),void 0!==t.specularMap&&(i.specularMap=n(t.specularMap)),void 0!==t.specularIntensityMap&&(i.specularIntensityMap=n(t.specularIntensityMap)),void 0!==t.specularColorMap&&(i.specularColorMap=n(t.specularColorMap)),void 0!==t.envMap&&(i.envMap=n(t.envMap)),void 0!==t.envMapRotation&&i.envMapRotation.fromArray(t.envMapRotation),void 0!==t.envMapIntensity&&(i.envMapIntensity=t.envMapIntensity),void 0!==t.reflectivity&&(i.reflectivity=t.reflectivity),void 0!==t.refractionRatio&&(i.refractionRatio=t.refractionRatio),void 0!==t.lightMap&&(i.lightMap=n(t.lightMap)),void 0!==t.lightMapIntensity&&(i.lightMapIntensity=t.lightMapIntensity),void 0!==t.aoMap&&(i.aoMap=n(t.aoMap)),void 0!==t.aoMapIntensity&&(i.aoMapIntensity=t.aoMapIntensity),void 0!==t.gradientMap&&(i.gradientMap=n(t.gradientMap)),void 0!==t.clearcoatMap&&(i.clearcoatMap=n(t.clearcoatMap)),void 0!==t.clearcoatRoughnessMap&&(i.clearcoatRoughnessMap=n(t.clearcoatRoughnessMap)),void 0!==t.clearcoatNormalMap&&(i.clearcoatNormalMap=n(t.clearcoatNormalMap)),void 0!==t.clearcoatNormalScale&&(i.clearcoatNormalScale=(new ti).fromArray(t.clearcoatNormalScale)),void 0!==t.iridescenceMap&&(i.iridescenceMap=n(t.iridescenceMap)),void 0!==t.iridescenceThicknessMap&&(i.iridescenceThicknessMap=n(t.iridescenceThicknessMap)),void 0!==t.transmissionMap&&(i.transmissionMap=n(t.transmissionMap)),void 0!==t.thicknessMap&&(i.thicknessMap=n(t.thicknessMap)),void 0!==t.anisotropyMap&&(i.anisotropyMap=n(t.anisotropyMap)),void 0!==t.sheenColorMap&&(i.sheenColorMap=n(t.sheenColorMap)),void 0!==t.sheenRoughnessMap&&(i.sheenRoughnessMap=n(t.sheenRoughnessMap)),i}setTextures(t){return this.textures=t,this}static createMaterialFromType(t){return new{ShadowMaterial:vd,SpriteMaterial:pc,RawShaderMaterial:_d,ShaderMaterial:Ks,PointsMaterial:Dh,MeshPhysicalMaterial:yd,MeshStandardMaterial:xd,MeshPhongMaterial:Md,MeshToonMaterial:Sd,MeshNormalMaterial:bd,MeshLambertMaterial:wd,MeshDepthMaterial:Hl,MeshDistanceMaterial:Gl,MeshBasicMaterial:es,MeshMatcapMaterial:Td,LineDashedMaterial:Ed,LineBasicMaterial:Mh,Material:ts}[t]}}class Ep{static decodeText(t){if(console.warn("THREE.LoaderUtils: decodeText() has been deprecated with r165 and will be removed with r175. Use TextDecoder instead."),"undefined"!=typeof TextDecoder)return(new TextDecoder).decode(t);let e="";for(let n=0,i=t.length;n0){const n=new Yd(e);r=new np(n),r.setCrossOrigin(this.crossOrigin);for(let e=0,n=t.length;e0){i=new np(this.manager),i.setCrossOrigin(this.crossOrigin);for(let e=0,i=t.length;e{const e=new Di;e.min.fromArray(t.boxMin),e.max.fromArray(t.boxMax);const n=new Qi;return n.radius=t.sphereRadius,n.center.fromArray(t.sphereCenter),{boxInitialized:t.boxInitialized,box:e,sphereInitialized:t.sphereInitialized,sphere:n}})),s._maxInstanceCount=t.maxInstanceCount,s._maxVertexCount=t.maxVertexCount,s._maxIndexCount=t.maxIndexCount,s._geometryInitialized=t.geometryInitialized,s._geometryCount=t.geometryCount,s._matricesTexture=h(t.matricesTexture.uuid),void 0!==t.colorsTexture&&(s._colorsTexture=h(t.colorsTexture.uuid));break;case"LOD":s=new Ic;break;case"Line":s=new Ch(l(t.geometry),c(t.material));break;case"LineLoop":s=new Nh(l(t.geometry),c(t.material));break;case"LineSegments":s=new Uh(l(t.geometry),c(t.material));break;case"PointCloud":case"Points":s=new kh(l(t.geometry),c(t.material));break;case"Sprite":s=new Ac(c(t.material));break;case"Group":s=new Kl;break;case"Bone":s=new Hc;break;default:s=new Dr}if(s.uuid=t.uuid,void 0!==t.name&&(s.name=t.name),void 0!==t.matrix?(s.matrix.fromArray(t.matrix),void 0!==t.matrixAutoUpdate&&(s.matrixAutoUpdate=t.matrixAutoUpdate),s.matrixAutoUpdate&&s.matrix.decompose(s.position,s.quaternion,s.scale)):(void 0!==t.position&&s.position.fromArray(t.position),void 0!==t.rotation&&s.rotation.fromArray(t.rotation),void 0!==t.quaternion&&s.quaternion.fromArray(t.quaternion),void 0!==t.scale&&s.scale.fromArray(t.scale)),void 0!==t.up&&s.up.fromArray(t.up),void 0!==t.castShadow&&(s.castShadow=t.castShadow),void 0!==t.receiveShadow&&(s.receiveShadow=t.receiveShadow),t.shadow&&(void 0!==t.shadow.intensity&&(s.shadow.intensity=t.shadow.intensity),void 0!==t.shadow.bias&&(s.shadow.bias=t.shadow.bias),void 0!==t.shadow.normalBias&&(s.shadow.normalBias=t.shadow.normalBias),void 0!==t.shadow.radius&&(s.shadow.radius=t.shadow.radius),void 0!==t.shadow.mapSize&&s.shadow.mapSize.fromArray(t.shadow.mapSize),void 0!==t.shadow.camera&&(s.shadow.camera=this.parseObject(t.shadow.camera))),void 0!==t.visible&&(s.visible=t.visible),void 0!==t.frustumCulled&&(s.frustumCulled=t.frustumCulled),void 0!==t.renderOrder&&(s.renderOrder=t.renderOrder),void 0!==t.userData&&(s.userData=t.userData),void 0!==t.layers&&(s.layers.mask=t.layers),void 0!==t.children){const a=t.children;for(let t=0;t{e&&e(n),r.manager.itemEnd(t)})).catch((t=>{i&&i(t)})):(setTimeout((function(){e&&e(s),r.manager.itemEnd(t)}),0),s);const a={};a.credentials="anonymous"===this.crossOrigin?"same-origin":"include",a.headers=this.requestHeader;const o=fetch(t,a).then((function(t){return t.blob()})).then((function(t){return createImageBitmap(t,Object.assign(r.options,{colorSpaceConversion:"none"}))})).then((function(n){return qd.add(t,n),e&&e(n),r.manager.itemEnd(t),n})).catch((function(e){i&&i(e),qd.remove(t),r.manager.itemError(t),r.manager.itemEnd(t)}));qd.add(t,o),r.manager.itemStart(t)}}let Np;class Dp{static getContext(){return void 0===Np&&(Np=new(window.AudioContext||window.webkitAudioContext)),Np}static setContext(t){Np=t}}class Op extends Jd{constructor(t){super(t)}load(t,e,n,i){const r=this,s=new Qd(this.manager);function a(e){i?i(e):console.error(e),r.manager.itemError(t)}s.setResponseType("arraybuffer"),s.setPath(this.path),s.setRequestHeader(this.requestHeader),s.setWithCredentials(this.withCredentials),s.load(t,(function(t){try{const n=t.slice(0);Dp.getContext().decodeAudioData(n,(function(t){e(t)})).catch(a)}catch(t){a(t)}}),n,i)}}const Fp=new lr,Bp=new lr,zp=new lr;class kp{constructor(){this.type="StereoCamera",this.aspect=1,this.eyeSep=.064,this.cameraL=new na,this.cameraL.layers.enable(1),this.cameraL.matrixAutoUpdate=!1,this.cameraR=new na,this.cameraR.layers.enable(2),this.cameraR.matrixAutoUpdate=!1,this._cache={focus:null,fov:null,aspect:null,near:null,far:null,zoom:null,eyeSep:null}}update(t){const e=this._cache;if(e.focus!==t.focus||e.fov!==t.fov||e.aspect!==t.aspect*this.aspect||e.near!==t.near||e.far!==t.far||e.zoom!==t.zoom||e.eyeSep!==this.eyeSep){e.focus=t.focus,e.fov=t.fov,e.aspect=t.aspect*this.aspect,e.near=t.near,e.far=t.far,e.zoom=t.zoom,e.eyeSep=this.eyeSep,zp.copy(t.projectionMatrix);const n=e.eyeSep/2,i=n*e.near/e.focus,r=e.near*Math.tan(Xn*e.fov*.5)/e.zoom;let s,a;Bp.elements[12]=-n,Fp.elements[12]=n,s=-r*e.aspect+i,a=r*e.aspect+i,zp.elements[0]=2*e.near/(a-s),zp.elements[8]=(a+s)/(a-s),this.cameraL.projectionMatrix.copy(zp),s=-r*e.aspect-i,a=r*e.aspect-i,zp.elements[0]=2*e.near/(a-s),zp.elements[8]=(a+s)/(a-s),this.cameraR.projectionMatrix.copy(zp)}this.cameraL.matrixWorld.copy(t.matrixWorld).multiply(Bp),this.cameraR.matrixWorld.copy(t.matrixWorld).multiply(Fp)}}class Vp{constructor(t=!0){this.autoStart=t,this.startTime=0,this.oldTime=0,this.elapsedTime=0,this.running=!1}start(){this.startTime=Hp(),this.oldTime=this.startTime,this.elapsedTime=0,this.running=!0}stop(){this.getElapsedTime(),this.running=!1,this.autoStart=!1}getElapsedTime(){return this.getDelta(),this.elapsedTime}getDelta(){let t=0;if(this.autoStart&&!this.running)return this.start(),0;if(this.running){const e=Hp();t=(e-this.oldTime)/1e3,this.oldTime=e,this.elapsedTime+=t}return t}}function Hp(){return("undefined"==typeof performance?Date:performance).now()}const Gp=new Li,Wp=new Ii,Xp=new Li,jp=new Li;class qp extends Dr{constructor(){super(),this.type="AudioListener",this.context=Dp.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._clock=new Vp}getInput(){return this.gain}removeFilter(){return null!==this.filter&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null),this}getFilter(){return this.filter}setFilter(t){return null!==this.filter?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination),this.filter=t,this.gain.connect(this.filter),this.filter.connect(this.context.destination),this}getMasterVolume(){return this.gain.gain.value}setMasterVolume(t){return this.gain.gain.setTargetAtTime(t,this.context.currentTime,.01),this}updateMatrixWorld(t){super.updateMatrixWorld(t);const e=this.context.listener,n=this.up;if(this.timeDelta=this._clock.getDelta(),this.matrixWorld.decompose(Gp,Wp,Xp),jp.set(0,0,-1).applyQuaternion(Wp),e.positionX){const t=this.context.currentTime+this.timeDelta;e.positionX.linearRampToValueAtTime(Gp.x,t),e.positionY.linearRampToValueAtTime(Gp.y,t),e.positionZ.linearRampToValueAtTime(Gp.z,t),e.forwardX.linearRampToValueAtTime(jp.x,t),e.forwardY.linearRampToValueAtTime(jp.y,t),e.forwardZ.linearRampToValueAtTime(jp.z,t),e.upX.linearRampToValueAtTime(n.x,t),e.upY.linearRampToValueAtTime(n.y,t),e.upZ.linearRampToValueAtTime(n.z,t)}else e.setPosition(Gp.x,Gp.y,Gp.z),e.setOrientation(jp.x,jp.y,jp.z,n.x,n.y,n.z)}}class Yp extends Dr{constructor(t){super(),this.type="Audio",this.listener=t,this.context=t.context,this.gain=this.context.createGain(),this.gain.connect(t.getInput()),this.autoplay=!1,this.buffer=null,this.detune=0,this.loop=!1,this.loopStart=0,this.loopEnd=0,this.offset=0,this.duration=void 0,this.playbackRate=1,this.isPlaying=!1,this.hasPlaybackControl=!0,this.source=null,this.sourceType="empty",this._startedAt=0,this._progress=0,this._connected=!1,this.filters=[]}getOutput(){return this.gain}setNodeSource(t){return this.hasPlaybackControl=!1,this.sourceType="audioNode",this.source=t,this.connect(),this}setMediaElementSource(t){return this.hasPlaybackControl=!1,this.sourceType="mediaNode",this.source=this.context.createMediaElementSource(t),this.connect(),this}setMediaStreamSource(t){return this.hasPlaybackControl=!1,this.sourceType="mediaStreamNode",this.source=this.context.createMediaStreamSource(t),this.connect(),this}setBuffer(t){return this.buffer=t,this.sourceType="buffer",this.autoplay&&this.play(),this}play(t=0){if(!0===this.isPlaying)return void console.warn("THREE.Audio: Audio is already playing.");if(!1===this.hasPlaybackControl)return void console.warn("THREE.Audio: this Audio has no playback control.");this._startedAt=this.context.currentTime+t;const e=this.context.createBufferSource();return e.buffer=this.buffer,e.loop=this.loop,e.loopStart=this.loopStart,e.loopEnd=this.loopEnd,e.onended=this.onEnded.bind(this),e.start(this._startedAt,this._progress+this.offset,this.duration),this.isPlaying=!0,this.source=e,this.setDetune(this.detune),this.setPlaybackRate(this.playbackRate),this.connect()}pause(){if(!1!==this.hasPlaybackControl)return!0===this.isPlaying&&(this._progress+=Math.max(this.context.currentTime-this._startedAt,0)*this.playbackRate,!0===this.loop&&(this._progress=this._progress%(this.duration||this.buffer.duration)),this.source.stop(),this.source.onended=null,this.isPlaying=!1),this;console.warn("THREE.Audio: this Audio has no playback control.")}stop(){if(!1!==this.hasPlaybackControl)return this._progress=0,null!==this.source&&(this.source.stop(),this.source.onended=null),this.isPlaying=!1,this;console.warn("THREE.Audio: this Audio has no playback control.")}connect(){if(this.filters.length>0){this.source.connect(this.filters[0]);for(let t=1,e=this.filters.length;t0){this.source.disconnect(this.filters[0]);for(let t=1,e=this.filters.length;t0&&this._mixBufferRegionAdditive(n,i,this._addIndex*e,1,e);for(let t=e,r=e+e;t!==r;++t)if(n[t]!==n[t+e]){a.setValue(n,i);break}}saveOriginalState(){const t=this.binding,e=this.buffer,n=this.valueSize,i=n*this._origIndex;t.getValue(e,i);for(let t=n,r=i;t!==r;++t)e[t]=e[i+t%n];this._setIdentity(),this.cumulativeWeight=0,this.cumulativeWeightAdditive=0}restoreOriginalState(){const t=3*this.valueSize;this.binding.setValue(this.buffer,t)}_setAdditiveIdentityNumeric(){const t=this._addIndex*this.valueSize,e=t+this.valueSize;for(let n=t;n=.5)for(let i=0;i!==r;++i)t[e+i]=t[n+i]}_slerp(t,e,n,i){Ii.slerpFlat(t,e,t,e,t,n,i)}_slerpAdditive(t,e,n,i,r){const s=this._workIndex*r;Ii.multiplyQuaternionsFlat(t,s,t,e,t,n),Ii.slerpFlat(t,e,t,e,t,s,i)}_lerp(t,e,n,i,r){const s=1-i;for(let a=0;a!==r;++a){const r=e+a;t[r]=t[r]*s+t[n+a]*i}}_lerpAdditive(t,e,n,i,r){for(let s=0;s!==r;++s){const r=e+s;t[r]=t[r]+t[n+s]*i}}}const nm="\\[\\]\\.:\\/",im=new RegExp("["+nm+"]","g"),rm="[^"+nm+"]",sm="[^"+nm.replace("\\.","")+"]",am=new RegExp("^"+/((?:WC+[\/:])*)/.source.replace("WC",rm)+/(WCOD+)?/.source.replace("WCOD",sm)+/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",rm)+/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",rm)+"$"),om=["material","materials","bones","map"];class lm{constructor(t,e,n){this.path=e,this.parsedPath=n||lm.parseTrackName(e),this.node=lm.findNode(t,this.parsedPath.nodeName),this.rootNode=t,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(t,e,n){return t&&t.isAnimationObjectGroup?new lm.Composite(t,e,n):new lm(t,e,n)}static sanitizeNodeName(t){return t.replace(/\s/g,"_").replace(im,"")}static parseTrackName(t){const e=am.exec(t);if(null===e)throw new Error("PropertyBinding: Cannot parse trackName: "+t);const n={nodeName:e[2],objectName:e[3],objectIndex:e[4],propertyName:e[5],propertyIndex:e[6]},i=n.nodeName&&n.nodeName.lastIndexOf(".");if(void 0!==i&&-1!==i){const t=n.nodeName.substring(i+1);-1!==om.indexOf(t)&&(n.nodeName=n.nodeName.substring(0,i),n.objectName=t)}if(null===n.propertyName||0===n.propertyName.length)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+t);return n}static findNode(t,e){if(void 0===e||""===e||"."===e||-1===e||e===t.name||e===t.uuid)return t;if(t.skeleton){const n=t.skeleton.getBoneByName(e);if(void 0!==n)return n}if(t.children){const n=function(t){for(let i=0;i=r){const s=r++,c=t[s];e[c.uuid]=l,t[l]=c,e[o]=s,t[s]=a;for(let t=0,e=i;t!==e;++t){const e=n[t],i=e[s],r=e[l];e[l]=i,e[s]=r}}}this.nCachedObjects_=r}uncache(){const t=this._objects,e=this._indicesByUUID,n=this._bindings,i=n.length;let r=this.nCachedObjects_,s=t.length;for(let a=0,o=arguments.length;a!==o;++a){const o=arguments[a].uuid,l=e[o];if(void 0!==l)if(delete e[o],l0&&(e[a.uuid]=l),t[l]=a,t.pop();for(let t=0,e=i;t!==e;++t){const e=n[t];e[l]=e[r],e.pop()}}}this.nCachedObjects_=r}subscribe_(t,e){const n=this._bindingsIndicesByPath;let i=n[t];const r=this._bindings;if(void 0!==i)return r[i];const s=this._paths,a=this._parsedPaths,o=this._objects,l=o.length,c=this.nCachedObjects_,h=new Array(l);i=r.length,n[t]=i,s.push(t),a.push(e),r.push(h);for(let n=c,i=o.length;n!==i;++n){const i=o[n];h[n]=new lm(i,t,e)}return h}unsubscribe_(t){const e=this._bindingsIndicesByPath,n=e[t];if(void 0!==n){const i=this._paths,r=this._parsedPaths,s=this._bindings,a=s.length-1,o=s[a];e[t[a]]=n,s[n]=o,s.pop(),r[n]=r[a],r.pop(),i[n]=i[a],i.pop()}}}class hm{constructor(t,e,n=null,i=e.blendMode){this._mixer=t,this._clip=e,this._localRoot=n,this.blendMode=i;const r=e.tracks,s=r.length,a=new Array(s),o={endingStart:De,endingEnd:De};for(let t=0;t!==s;++t){const e=r[t].createInterpolant(null);a[t]=e,e.settings=o}this._interpolantSettings=o,this._interpolants=a,this._propertyBindings=new Array(s),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=2201,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}play(){return this._mixer._activateAction(this),this}stop(){return this._mixer._deactivateAction(this),this.reset()}reset(){return this.paused=!1,this.enabled=!0,this.time=0,this._loopCount=-1,this._startTime=null,this.stopFading().stopWarping()}isRunning(){return this.enabled&&!this.paused&&0!==this.timeScale&&null===this._startTime&&this._mixer._isActiveAction(this)}isScheduled(){return this._mixer._isActiveAction(this)}startAt(t){return this._startTime=t,this}setLoop(t,e){return this.loop=t,this.repetitions=e,this}setEffectiveWeight(t){return this.weight=t,this._effectiveWeight=this.enabled?t:0,this.stopFading()}getEffectiveWeight(){return this._effectiveWeight}fadeIn(t){return this._scheduleFading(t,0,1)}fadeOut(t){return this._scheduleFading(t,1,0)}crossFadeFrom(t,e,n){if(t.fadeOut(e),this.fadeIn(e),n){const n=this._clip.duration,i=t._clip.duration,r=i/n,s=n/i;t.warp(1,r,e),this.warp(s,1,e)}return this}crossFadeTo(t,e,n){return t.crossFadeFrom(this,e,n)}stopFading(){const t=this._weightInterpolant;return null!==t&&(this._weightInterpolant=null,this._mixer._takeBackControlInterpolant(t)),this}setEffectiveTimeScale(t){return this.timeScale=t,this._effectiveTimeScale=this.paused?0:t,this.stopWarping()}getEffectiveTimeScale(){return this._effectiveTimeScale}setDuration(t){return this.timeScale=this._clip.duration/t,this.stopWarping()}syncWith(t){return this.time=t.time,this.timeScale=t.timeScale,this.stopWarping()}halt(t){return this.warp(this._effectiveTimeScale,0,t)}warp(t,e,n){const i=this._mixer,r=i.time,s=this.timeScale;let a=this._timeScaleInterpolant;null===a&&(a=i._lendControlInterpolant(),this._timeScaleInterpolant=a);const o=a.parameterPositions,l=a.sampleValues;return o[0]=r,o[1]=r+n,l[0]=t/s,l[1]=e/s,this}stopWarping(){const t=this._timeScaleInterpolant;return null!==t&&(this._timeScaleInterpolant=null,this._mixer._takeBackControlInterpolant(t)),this}getMixer(){return this._mixer}getClip(){return this._clip}getRoot(){return this._localRoot||this._mixer._root}_update(t,e,n,i){if(!this.enabled)return void this._updateWeight(t);const r=this._startTime;if(null!==r){const i=(t-r)*n;i<0||0===n?e=0:(this._startTime=null,e=n*i)}e*=this._updateTimeScale(t);const s=this._updateTime(e),a=this._updateWeight(t);if(a>0){const t=this._interpolants,e=this._propertyBindings;if(this.blendMode===ze)for(let n=0,i=t.length;n!==i;++n)t[n].evaluate(s),e[n].accumulateAdditive(a);else for(let n=0,r=t.length;n!==r;++n)t[n].evaluate(s),e[n].accumulate(i,a)}}_updateWeight(t){let e=0;if(this.enabled){e=this.weight;const n=this._weightInterpolant;if(null!==n){const i=n.evaluate(t)[0];e*=i,t>n.parameterPositions[1]&&(this.stopFading(),0===i&&(this.enabled=!1))}}return this._effectiveWeight=e,e}_updateTimeScale(t){let e=0;if(!this.paused){e=this.timeScale;const n=this._timeScaleInterpolant;if(null!==n){e*=n.evaluate(t)[0],t>n.parameterPositions[1]&&(this.stopWarping(),0===e?this.paused=!0:this.timeScale=e)}}return this._effectiveTimeScale=e,e}_updateTime(t){const e=this._clip.duration,n=this.loop;let i=this.time+t,r=this._loopCount;const s=2202===n;if(0===t)return-1===r?i:s&&1==(1&r)?e-i:i;if(2200===n){-1===r&&(this._loopCount=0,this._setEndings(!0,!0,!1));t:{if(i>=e)i=e;else{if(!(i<0)){this.time=i;break t}i=0}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:t<0?-1:1})}}else{if(-1===r&&(t>=0?(r=0,this._setEndings(!0,0===this.repetitions,s)):this._setEndings(0===this.repetitions,!0,s)),i>=e||i<0){const n=Math.floor(i/e);i-=e*n,r+=Math.abs(n);const a=this.repetitions-r;if(a<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,i=t>0?e:0,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:t>0?1:-1});else{if(1===a){const e=t<0;this._setEndings(e,!e,s)}else this._setEndings(!1,!1,s);this._loopCount=r,this.time=i,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:n})}}else this.time=i;if(s&&1==(1&r))return e-i}return i}_setEndings(t,e,n){const i=this._interpolantSettings;n?(i.endingStart=Oe,i.endingEnd=Oe):(i.endingStart=t?this.zeroSlopeAtStart?Oe:De:Fe,i.endingEnd=e?this.zeroSlopeAtEnd?Oe:De:Fe)}_scheduleFading(t,e,n){const i=this._mixer,r=i.time;let s=this._weightInterpolant;null===s&&(s=i._lendControlInterpolant(),this._weightInterpolant=s);const a=s.parameterPositions,o=s.sampleValues;return a[0]=r,o[0]=e,a[1]=r+t,o[1]=n,this}}const um=new Float32Array(1);class dm extends Hn{constructor(t){super(),this._root=t,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}_bindAction(t,e){const n=t._localRoot||this._root,i=t._clip.tracks,r=i.length,s=t._propertyBindings,a=t._interpolants,o=n.uuid,l=this._bindingsByRootAndName;let c=l[o];void 0===c&&(c={},l[o]=c);for(let t=0;t!==r;++t){const r=i[t],l=r.name;let h=c[l];if(void 0!==h)++h.referenceCount,s[t]=h;else{if(h=s[t],void 0!==h){null===h._cacheIndex&&(++h.referenceCount,this._addInactiveBinding(h,o,l));continue}const i=e&&e._propertyBindings[t].binding.parsedPath;h=new em(lm.create(n,l,i),r.ValueTypeName,r.getValueSize()),++h.referenceCount,this._addInactiveBinding(h,o,l),s[t]=h}a[t].resultBuffer=h.buffer}}_activateAction(t){if(!this._isActiveAction(t)){if(null===t._cacheIndex){const e=(t._localRoot||this._root).uuid,n=t._clip.uuid,i=this._actionsByClip[n];this._bindAction(t,i&&i.knownActions[0]),this._addInactiveAction(t,n,e)}const e=t._propertyBindings;for(let t=0,n=e.length;t!==n;++t){const n=e[t];0==n.useCount++&&(this._lendBinding(n),n.saveOriginalState())}this._lendAction(t)}}_deactivateAction(t){if(this._isActiveAction(t)){const e=t._propertyBindings;for(let t=0,n=e.length;t!==n;++t){const n=e[t];0==--n.useCount&&(n.restoreOriginalState(),this._takeBackBinding(n))}this._takeBackAction(t)}}_initMemoryManager(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;const t=this;this.stats={actions:{get total(){return t._actions.length},get inUse(){return t._nActiveActions}},bindings:{get total(){return t._bindings.length},get inUse(){return t._nActiveBindings}},controlInterpolants:{get total(){return t._controlInterpolants.length},get inUse(){return t._nActiveControlInterpolants}}}}_isActiveAction(t){const e=t._cacheIndex;return null!==e&&e=0;--e)t[e].stop();return this}update(t){t*=this.timeScale;const e=this._actions,n=this._nActiveActions,i=this.time+=t,r=Math.sign(t),s=this._accuIndex^=1;for(let a=0;a!==n;++a){e[a]._update(i,t,r,s)}const a=this._bindings,o=this._nActiveBindings;for(let t=0;t!==o;++t)a[t].apply(s);return this}setTime(t){this.time=0;for(let t=0;t=this.min.x&&t.x<=this.max.x&&t.y>=this.min.y&&t.y<=this.max.y}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y}getParameter(t,e){return e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y))}intersectsBox(t){return t.max.x>=this.min.x&&t.min.x<=this.max.x&&t.max.y>=this.min.y&&t.min.y<=this.max.y}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return this.clampPoint(t,Tm).distanceTo(t)}intersect(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}}const Am=new Li,Rm=new Li;class Cm{constructor(t=new Li,e=new Li){this.start=t,this.end=e}set(t,e){return this.start.copy(t),this.end.copy(e),this}copy(t){return this.start.copy(t.start),this.end.copy(t.end),this}getCenter(t){return t.addVectors(this.start,this.end).multiplyScalar(.5)}delta(t){return t.subVectors(this.end,this.start)}distanceSq(){return this.start.distanceToSquared(this.end)}distance(){return this.start.distanceTo(this.end)}at(t,e){return this.delta(e).multiplyScalar(t).add(this.start)}closestPointToPointParameter(t,e){Am.subVectors(t,this.start),Rm.subVectors(this.end,this.start);const n=Rm.dot(Rm);let i=Rm.dot(Am)/n;return e&&(i=Yn(i,0,1)),i}closestPointToPoint(t,e,n){const i=this.closestPointToPointParameter(t,e);return this.delta(n).multiplyScalar(i).add(this.start)}applyMatrix4(t){return this.start.applyMatrix4(t),this.end.applyMatrix4(t),this}equals(t){return t.start.equals(this.start)&&t.end.equals(this.end)}clone(){return(new this.constructor).copy(this)}}const Pm=new Li;class Im extends Dr{constructor(t,e){super(),this.light=t,this.matrixAutoUpdate=!1,this.color=e,this.type="SpotLightHelper";const n=new Es,i=[0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,-1,0,1,0,0,0,0,1,1,0,0,0,0,-1,1];for(let t=0,e=1,n=32;t1)for(let n=0;n.99999)this.quaternion.set(0,0,0,1);else if(t.y<-.99999)this.quaternion.set(1,0,0,0);else{nf.set(t.z,0,-t.x).normalize();const e=Math.acos(t.y);this.quaternion.setFromAxisAngle(nf,e)}}setLength(t,e=.2*t,n=.2*e){this.line.scale.set(1,Math.max(1e-4,t-e),1),this.line.updateMatrix(),this.cone.scale.set(n,e,n),this.cone.position.y=t,this.cone.updateMatrix()}setColor(t){this.line.material.color.set(t),this.cone.material.color.set(t)}copy(t){return super.copy(t,!1),this.line.copy(t.line),this.cone.copy(t.cone),this}dispose(){this.line.geometry.dispose(),this.line.material.dispose(),this.cone.geometry.dispose(),this.cone.material.dispose()}}class of extends Uh{constructor(t=1){const e=[0,0,0,t,0,0,0,0,0,0,t,0,0,0,0,0,0,t],n=new Es;n.setAttribute("position",new _s(e,3)),n.setAttribute("color",new _s([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1],3));super(n,new Mh({vertexColors:!0,toneMapped:!1})),this.type="AxesHelper"}setColors(t,e,n){const i=new Kr,r=this.geometry.attributes.color.array;return i.set(t),i.toArray(r,0),i.toArray(r,3),i.set(e),i.toArray(r,6),i.toArray(r,9),i.set(n),i.toArray(r,12),i.toArray(r,15),this.geometry.attributes.color.needsUpdate=!0,this}dispose(){this.geometry.dispose(),this.material.dispose()}}class lf{constructor(){this.type="ShapePath",this.color=new Kr,this.subPaths=[],this.currentPath=null}moveTo(t,e){return this.currentPath=new fu,this.subPaths.push(this.currentPath),this.currentPath.moveTo(t,e),this}lineTo(t,e){return this.currentPath.lineTo(t,e),this}quadraticCurveTo(t,e,n,i){return this.currentPath.quadraticCurveTo(t,e,n,i),this}bezierCurveTo(t,e,n,i,r,s){return this.currentPath.bezierCurveTo(t,e,n,i,r,s),this}splineThru(t){return this.currentPath.splineThru(t),this}toShapes(t){function e(t,e){const n=e.length;let i=!1;for(let r=n-1,s=0;sNumber.EPSILON){if(l<0&&(n=e[s],o=-o,a=e[r],l=-l),t.ya.y)continue;if(t.y===n.y){if(t.x===n.x)return!0}else{const e=l*(t.x-n.x)-o*(t.y-n.y);if(0===e)return!0;if(e<0)continue;i=!i}}else{if(t.y!==n.y)continue;if(a.x<=t.x&&t.x<=n.x||n.x<=t.x&&t.x<=a.x)return!0}}return i}const n=td.isClockWise,i=this.subPaths;if(0===i.length)return[];let r,s,a;const o=[];if(1===i.length)return s=i[0],a=new Ru,a.curves=s.curves,o.push(a),o;let l=!n(i[0].getPoints());l=t?!l:l;const c=[],h=[];let u,d,p=[],m=0;h[m]=void 0,p[m]=[];for(let e=0,a=i.length;e1){let t=!1,n=0;for(let t=0,e=h.length;t0&&!1===t&&(p=c)}for(let t=0,e=h.length;t>8&255]+Gn[t>>16&255]+Gn[t>>24&255]+"-"+Gn[255&e]+Gn[e>>8&255]+"-"+Gn[e>>16&15|64]+Gn[e>>24&255]+"-"+Gn[63&n|128]+Gn[n>>8&255]+"-"+Gn[n>>16&255]+Gn[n>>24&255]+Gn[255&i]+Gn[i>>8&255]+Gn[i>>16&255]+Gn[i>>24&255]).toLowerCase()}function Yn(t,e,n){return Math.max(e,Math.min(n,t))}function Zn(t,e){return(t%e+e)%e}function Jn(t,e,n){return(1-n)*t+n*e}function Kn(t,e){switch(e.constructor){case Float32Array:return t;case Uint32Array:return t/4294967295;case Uint16Array:return t/65535;case Uint8Array:return t/255;case Int32Array:return Math.max(t/2147483647,-1);case Int16Array:return Math.max(t/32767,-1);case Int8Array:return Math.max(t/127,-1);default:throw new Error("Invalid component type.")}}function $n(t,e){switch(e.constructor){case Float32Array:return t;case Uint32Array:return Math.round(4294967295*t);case Uint16Array:return Math.round(65535*t);case Uint8Array:return Math.round(255*t);case Int32Array:return Math.round(2147483647*t);case Int16Array:return Math.round(32767*t);case Int8Array:return Math.round(127*t);default:throw new Error("Invalid component type.")}}const Qn={DEG2RAD:Xn,RAD2DEG:jn,generateUUID:qn,clamp:Yn,euclideanModulo:Zn,mapLinear:function(t,e,n,i,r){return i+(t-e)*(r-i)/(n-e)},inverseLerp:function(t,e,n){return t!==e?(n-t)/(e-t):0},lerp:Jn,damp:function(t,e,n,i){return Jn(t,e,1-Math.exp(-n*i))},pingpong:function(t,e=1){return e-Math.abs(Zn(t,2*e)-e)},smoothstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*(3-2*t)},smootherstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*t*(t*(6*t-15)+10)},randInt:function(t,e){return t+Math.floor(Math.random()*(e-t+1))},randFloat:function(t,e){return t+Math.random()*(e-t)},randFloatSpread:function(t){return t*(.5-Math.random())},seededRandom:function(t){void 0!==t&&(Wn=t);let e=Wn+=1831565813;return e=Math.imul(e^e>>>15,1|e),e^=e+Math.imul(e^e>>>7,61|e),((e^e>>>14)>>>0)/4294967296},degToRad:function(t){return t*Xn},radToDeg:function(t){return t*jn},isPowerOfTwo:function(t){return 0==(t&t-1)&&0!==t},ceilPowerOfTwo:function(t){return Math.pow(2,Math.ceil(Math.log(t)/Math.LN2))},floorPowerOfTwo:function(t){return Math.pow(2,Math.floor(Math.log(t)/Math.LN2))},setQuaternionFromProperEuler:function(t,e,n,i,r){const s=Math.cos,a=Math.sin,o=s(n/2),l=a(n/2),c=s((e+i)/2),h=a((e+i)/2),u=s((e-i)/2),d=a((e-i)/2),p=s((i-e)/2),m=a((i-e)/2);switch(r){case"XYX":t.set(o*h,l*u,l*d,o*c);break;case"YZY":t.set(l*d,o*h,l*u,o*c);break;case"ZXZ":t.set(l*u,l*d,o*h,o*c);break;case"XZX":t.set(o*h,l*m,l*p,o*c);break;case"YXY":t.set(l*p,o*h,l*m,o*c);break;case"ZYZ":t.set(l*m,l*p,o*h,o*c);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+r)}},normalize:$n,denormalize:Kn};class ti{constructor(t=0,e=0){ti.prototype.isVector2=!0,this.x=t,this.y=e}get width(){return this.x}set width(t){this.x=t}get height(){return this.y}set height(t){this.y=t}set(t,e){return this.x=t,this.y=e,this}setScalar(t){return this.x=t,this.y=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y)}copy(t){return this.x=t.x,this.y=t.y,this}add(t){return this.x+=t.x,this.y+=t.y,this}addScalar(t){return this.x+=t,this.y+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this}subScalar(t){return this.x-=t,this.y-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}multiplyScalar(t){return this.x*=t,this.y*=t,this}divide(t){return this.x/=t.x,this.y/=t.y,this}divideScalar(t){return this.multiplyScalar(1/t)}applyMatrix3(t){const e=this.x,n=this.y,i=t.elements;return this.x=i[0]*e+i[3]*n+i[6],this.y=i[1]*e+i[4]*n+i[7],this}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this}clamp(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this}clampScalar(t,e){return this.x=Math.max(t,Math.min(e,this.x)),this.y=Math.max(t,Math.min(e,this.y)),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(t,Math.min(e,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(t){return this.x*t.x+this.y*t.y}cross(t){return this.x*t.y-this.y*t.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(0===e)return Math.PI/2;const n=this.dot(t)/e;return Math.acos(Yn(n,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y;return e*e+n*n}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this}equals(t){return t.x===this.x&&t.y===this.y}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this}rotateAround(t,e){const n=Math.cos(e),i=Math.sin(e),r=this.x-t.x,s=this.y-t.y;return this.x=r*n-s*i+t.x,this.y=r*i+s*n+t.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class ei{constructor(t,e,n,i,r,s,a,o,l){ei.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],void 0!==t&&this.set(t,e,n,i,r,s,a,o,l)}set(t,e,n,i,r,s,a,o,l){const c=this.elements;return c[0]=t,c[1]=i,c[2]=a,c[3]=e,c[4]=r,c[5]=o,c[6]=n,c[7]=s,c[8]=l,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(t){const e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],this}extractBasis(t,e,n){return t.setFromMatrix3Column(this,0),e.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(t){const e=t.elements;return this.set(e[0],e[4],e[8],e[1],e[5],e[9],e[2],e[6],e[10]),this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const n=t.elements,i=e.elements,r=this.elements,s=n[0],a=n[3],o=n[6],l=n[1],c=n[4],h=n[7],u=n[2],d=n[5],p=n[8],m=i[0],f=i[3],g=i[6],v=i[1],_=i[4],x=i[7],y=i[2],M=i[5],S=i[8];return r[0]=s*m+a*v+o*y,r[3]=s*f+a*_+o*M,r[6]=s*g+a*x+o*S,r[1]=l*m+c*v+h*y,r[4]=l*f+c*_+h*M,r[7]=l*g+c*x+h*S,r[2]=u*m+d*v+p*y,r[5]=u*f+d*_+p*M,r[8]=u*g+d*x+p*S,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[3]*=t,e[6]*=t,e[1]*=t,e[4]*=t,e[7]*=t,e[2]*=t,e[5]*=t,e[8]*=t,this}determinant(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8];return e*s*c-e*a*l-n*r*c+n*a*o+i*r*l-i*s*o}invert(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8],h=c*s-a*l,u=a*o-c*r,d=l*r-s*o,p=e*h+n*u+i*d;if(0===p)return this.set(0,0,0,0,0,0,0,0,0);const m=1/p;return t[0]=h*m,t[1]=(i*l-c*n)*m,t[2]=(a*n-i*s)*m,t[3]=u*m,t[4]=(c*e-i*o)*m,t[5]=(i*r-a*e)*m,t[6]=d*m,t[7]=(n*o-l*e)*m,t[8]=(s*e-n*r)*m,this}transpose(){let t;const e=this.elements;return t=e[1],e[1]=e[3],e[3]=t,t=e[2],e[2]=e[6],e[6]=t,t=e[5],e[5]=e[7],e[7]=t,this}getNormalMatrix(t){return this.setFromMatrix4(t).invert().transpose()}transposeIntoArray(t){const e=this.elements;return t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8],this}setUvTransform(t,e,n,i,r,s,a){const o=Math.cos(r),l=Math.sin(r);return this.set(n*o,n*l,-n*(o*s+l*a)+s+t,-i*l,i*o,-i*(-l*s+o*a)+a+e,0,0,1),this}scale(t,e){return this.premultiply(ni.makeScale(t,e)),this}rotate(t){return this.premultiply(ni.makeRotation(-t)),this}translate(t,e){return this.premultiply(ni.makeTranslation(t,e)),this}makeTranslation(t,e){return t.isVector2?this.set(1,0,t.x,0,1,t.y,0,0,1):this.set(1,0,t,0,1,e,0,0,1),this}makeRotation(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,-n,0,n,e,0,0,0,1),this}makeScale(t,e){return this.set(t,0,0,0,e,0,0,0,1),this}equals(t){const e=this.elements,n=t.elements;for(let t=0;t<9;t++)if(e[t]!==n[t])return!1;return!0}fromArray(t,e=0){for(let n=0;n<9;n++)this.elements[n]=t[n+e];return this}toArray(t=[],e=0){const n=this.elements;return t[e]=n[0],t[e+1]=n[1],t[e+2]=n[2],t[e+3]=n[3],t[e+4]=n[4],t[e+5]=n[5],t[e+6]=n[6],t[e+7]=n[7],t[e+8]=n[8],t}clone(){return(new this.constructor).fromArray(this.elements)}}const ni=new ei;function ii(t){for(let e=t.length-1;e>=0;--e)if(t[e]>=65535)return!0;return!1}const ri={Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:Uint8ClampedArray,Int16Array:Int16Array,Uint16Array:Uint16Array,Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array};function si(t,e){return new ri[t](e)}function ai(t){return document.createElementNS("http://www.w3.org/1999/xhtml",t)}function oi(){const t=ai("canvas");return t.style.display="block",t}const li={};function ci(t){t in li||(li[t]=!0,console.warn(t))}const hi=(new ei).set(.8224621,.177538,0,.0331941,.9668058,0,.0170827,.0723974,.9105199),ui=(new ei).set(1.2249401,-.2249404,0,-.0420569,1.0420571,0,-.0196376,-.0786361,1.0982735),di={[Ke]:{transfer:tn,primaries:nn,luminanceCoefficients:[.2126,.7152,.0722],toReference:t=>t,fromReference:t=>t},[Je]:{transfer:en,primaries:nn,luminanceCoefficients:[.2126,.7152,.0722],toReference:t=>t.convertSRGBToLinear(),fromReference:t=>t.convertLinearToSRGB()},[Qe]:{transfer:tn,primaries:rn,luminanceCoefficients:[.2289,.6917,.0793],toReference:t=>t.applyMatrix3(ui),fromReference:t=>t.applyMatrix3(hi)},[$e]:{transfer:en,primaries:rn,luminanceCoefficients:[.2289,.6917,.0793],toReference:t=>t.convertSRGBToLinear().applyMatrix3(ui),fromReference:t=>t.applyMatrix3(hi).convertLinearToSRGB()}},pi=new Set([Ke,Qe]),mi={enabled:!0,_workingColorSpace:Ke,get workingColorSpace(){return this._workingColorSpace},set workingColorSpace(t){if(!pi.has(t))throw new Error(`Unsupported working color space, "${t}".`);this._workingColorSpace=t},convert:function(t,e,n){if(!1===this.enabled||e===n||!e||!n)return t;const i=di[e].toReference;return(0,di[n].fromReference)(i(t))},fromWorkingColorSpace:function(t,e){return this.convert(t,this._workingColorSpace,e)},toWorkingColorSpace:function(t,e){return this.convert(t,e,this._workingColorSpace)},getPrimaries:function(t){return di[t].primaries},getTransfer:function(t){return t===Ze?tn:di[t].transfer},getLuminanceCoefficients:function(t,e=this._workingColorSpace){return t.fromArray(di[e].luminanceCoefficients)}};function fi(t){return t<.04045?.0773993808*t:Math.pow(.9478672986*t+.0521327014,2.4)}function gi(t){return t<.0031308?12.92*t:1.055*Math.pow(t,.41666)-.055}let vi;class _i{static getDataURL(t){if(/^data:/i.test(t.src))return t.src;if("undefined"==typeof HTMLCanvasElement)return t.src;let e;if(t instanceof HTMLCanvasElement)e=t;else{void 0===vi&&(vi=ai("canvas")),vi.width=t.width,vi.height=t.height;const n=vi.getContext("2d");t instanceof ImageData?n.putImageData(t,0,0):n.drawImage(t,0,0,t.width,t.height),e=vi}return e.width>2048||e.height>2048?(console.warn("THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons",t),e.toDataURL("image/jpeg",.6)):e.toDataURL("image/png")}static sRGBToLinear(t){if("undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&t instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&t instanceof ImageBitmap){const e=ai("canvas");e.width=t.width,e.height=t.height;const n=e.getContext("2d");n.drawImage(t,0,0,t.width,t.height);const i=n.getImageData(0,0,t.width,t.height),r=i.data;for(let t=0;t0&&(n.userData=this.userData),e||(t.textures[this.uuid]=n),n}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(t){if(this.mapping!==ot)return t;if(t.applyMatrix3(this.matrix),t.x<0||t.x>1)switch(this.wrapS){case pt:t.x=t.x-Math.floor(t.x);break;case mt:t.x=t.x<0?0:1;break;case ft:1===Math.abs(Math.floor(t.x)%2)?t.x=Math.ceil(t.x)-t.x:t.x=t.x-Math.floor(t.x)}if(t.y<0||t.y>1)switch(this.wrapT){case pt:t.y=t.y-Math.floor(t.y);break;case mt:t.y=t.y<0?0:1;break;case ft:1===Math.abs(Math.floor(t.y)%2)?t.y=Math.ceil(t.y)-t.y:t.y=t.y-Math.floor(t.y)}return this.flipY&&(t.y=1-t.y),t}set needsUpdate(t){!0===t&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(t){!0===t&&this.pmremVersion++}}bi.DEFAULT_IMAGE=null,bi.DEFAULT_MAPPING=ot,bi.DEFAULT_ANISOTROPY=1;class wi{constructor(t=0,e=0,n=0,i=1){wi.prototype.isVector4=!0,this.x=t,this.y=e,this.z=n,this.w=i}get width(){return this.z}set width(t){this.z=t}get height(){return this.w}set height(t){this.w=t}set(t,e,n,i){return this.x=t,this.y=e,this.z=n,this.w=i,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this.w=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setW(t){return this.w=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;case 3:this.w=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this.w=void 0!==t.w?t.w:1,this}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this.w+=t.w,this}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this.w+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this.w=t.w+e.w,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this.w+=t.w*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this.w-=t.w,this}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this.w-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this.w=t.w-e.w,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this.w*=t.w,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this.w*=t,this}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=this.w,s=t.elements;return this.x=s[0]*e+s[4]*n+s[8]*i+s[12]*r,this.y=s[1]*e+s[5]*n+s[9]*i+s[13]*r,this.z=s[2]*e+s[6]*n+s[10]*i+s[14]*r,this.w=s[3]*e+s[7]*n+s[11]*i+s[15]*r,this}divideScalar(t){return this.multiplyScalar(1/t)}setAxisAngleFromQuaternion(t){this.w=2*Math.acos(t.w);const e=Math.sqrt(1-t.w*t.w);return e<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=t.x/e,this.y=t.y/e,this.z=t.z/e),this}setAxisAngleFromRotationMatrix(t){let e,n,i,r;const s=.01,a=.1,o=t.elements,l=o[0],c=o[4],h=o[8],u=o[1],d=o[5],p=o[9],m=o[2],f=o[6],g=o[10];if(Math.abs(c-u)o&&t>v?tv?o=0?1:-1,i=1-e*e;if(i>Number.EPSILON){const r=Math.sqrt(i),s=Math.atan2(r,e*n);t=Math.sin(t*s)/r,a=Math.sin(a*s)/r}const r=a*n;if(o=o*t+u*r,l=l*t+d*r,c=c*t+p*r,h=h*t+m*r,t===1-a){const t=1/Math.sqrt(o*o+l*l+c*c+h*h);o*=t,l*=t,c*=t,h*=t}}t[e]=o,t[e+1]=l,t[e+2]=c,t[e+3]=h}static multiplyQuaternionsFlat(t,e,n,i,r,s){const a=n[i],o=n[i+1],l=n[i+2],c=n[i+3],h=r[s],u=r[s+1],d=r[s+2],p=r[s+3];return t[e]=a*p+c*h+o*d-l*u,t[e+1]=o*p+c*u+l*h-a*d,t[e+2]=l*p+c*d+a*u-o*h,t[e+3]=c*p-a*h-o*u-l*d,t}get x(){return this._x}set x(t){this._x=t,this._onChangeCallback()}get y(){return this._y}set y(t){this._y=t,this._onChangeCallback()}get z(){return this._z}set z(t){this._z=t,this._onChangeCallback()}get w(){return this._w}set w(t){this._w=t,this._onChangeCallback()}set(t,e,n,i){return this._x=t,this._y=e,this._z=n,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(t){return this._x=t.x,this._y=t.y,this._z=t.z,this._w=t.w,this._onChangeCallback(),this}setFromEuler(t,e=!0){const n=t._x,i=t._y,r=t._z,s=t._order,a=Math.cos,o=Math.sin,l=a(n/2),c=a(i/2),h=a(r/2),u=o(n/2),d=o(i/2),p=o(r/2);switch(s){case"XYZ":this._x=u*c*h+l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h-u*d*p;break;case"YXZ":this._x=u*c*h+l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h+u*d*p;break;case"ZXY":this._x=u*c*h-l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h-u*d*p;break;case"ZYX":this._x=u*c*h-l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h+u*d*p;break;case"YZX":this._x=u*c*h+l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h-u*d*p;break;case"XZY":this._x=u*c*h-l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h+u*d*p;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+s)}return!0===e&&this._onChangeCallback(),this}setFromAxisAngle(t,e){const n=e/2,i=Math.sin(n);return this._x=t.x*i,this._y=t.y*i,this._z=t.z*i,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(t){const e=t.elements,n=e[0],i=e[4],r=e[8],s=e[1],a=e[5],o=e[9],l=e[2],c=e[6],h=e[10],u=n+a+h;if(u>0){const t=.5/Math.sqrt(u+1);this._w=.25/t,this._x=(c-o)*t,this._y=(r-l)*t,this._z=(s-i)*t}else if(n>a&&n>h){const t=2*Math.sqrt(1+n-a-h);this._w=(c-o)/t,this._x=.25*t,this._y=(i+s)/t,this._z=(r+l)/t}else if(a>h){const t=2*Math.sqrt(1+a-n-h);this._w=(r-l)/t,this._x=(i+s)/t,this._y=.25*t,this._z=(o+c)/t}else{const t=2*Math.sqrt(1+h-n-a);this._w=(s-i)/t,this._x=(r+l)/t,this._y=(o+c)/t,this._z=.25*t}return this._onChangeCallback(),this}setFromUnitVectors(t,e){let n=t.dot(e)+1;return nMath.abs(t.z)?(this._x=-t.y,this._y=t.x,this._z=0,this._w=n):(this._x=0,this._y=-t.z,this._z=t.y,this._w=n)):(this._x=t.y*e.z-t.z*e.y,this._y=t.z*e.x-t.x*e.z,this._z=t.x*e.y-t.y*e.x,this._w=n),this.normalize()}angleTo(t){return 2*Math.acos(Math.abs(Yn(this.dot(t),-1,1)))}rotateTowards(t,e){const n=this.angleTo(t);if(0===n)return this;const i=Math.min(1,e/n);return this.slerp(t,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(t){return this._x*t._x+this._y*t._y+this._z*t._z+this._w*t._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let t=this.length();return 0===t?(this._x=0,this._y=0,this._z=0,this._w=1):(t=1/t,this._x=this._x*t,this._y=this._y*t,this._z=this._z*t,this._w=this._w*t),this._onChangeCallback(),this}multiply(t){return this.multiplyQuaternions(this,t)}premultiply(t){return this.multiplyQuaternions(t,this)}multiplyQuaternions(t,e){const n=t._x,i=t._y,r=t._z,s=t._w,a=e._x,o=e._y,l=e._z,c=e._w;return this._x=n*c+s*a+i*l-r*o,this._y=i*c+s*o+r*a-n*l,this._z=r*c+s*l+n*o-i*a,this._w=s*c-n*a-i*o-r*l,this._onChangeCallback(),this}slerp(t,e){if(0===e)return this;if(1===e)return this.copy(t);const n=this._x,i=this._y,r=this._z,s=this._w;let a=s*t._w+n*t._x+i*t._y+r*t._z;if(a<0?(this._w=-t._w,this._x=-t._x,this._y=-t._y,this._z=-t._z,a=-a):this.copy(t),a>=1)return this._w=s,this._x=n,this._y=i,this._z=r,this;const o=1-a*a;if(o<=Number.EPSILON){const t=1-e;return this._w=t*s+e*this._w,this._x=t*n+e*this._x,this._y=t*i+e*this._y,this._z=t*r+e*this._z,this.normalize(),this}const l=Math.sqrt(o),c=Math.atan2(l,a),h=Math.sin((1-e)*c)/l,u=Math.sin(e*c)/l;return this._w=s*h+this._w*u,this._x=n*h+this._x*u,this._y=i*h+this._y*u,this._z=r*h+this._z*u,this._onChangeCallback(),this}slerpQuaternions(t,e,n){return this.copy(t).slerp(e,n)}random(){const t=2*Math.PI*Math.random(),e=2*Math.PI*Math.random(),n=Math.random(),i=Math.sqrt(1-n),r=Math.sqrt(n);return this.set(i*Math.sin(t),i*Math.cos(t),r*Math.sin(e),r*Math.cos(e))}equals(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._w===this._w}fromArray(t,e=0){return this._x=t[e],this._y=t[e+1],this._z=t[e+2],this._w=t[e+3],this._onChangeCallback(),this}toArray(t=[],e=0){return t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._w,t}fromBufferAttribute(t,e){return this._x=t.getX(e),this._y=t.getY(e),this._z=t.getZ(e),this._w=t.getW(e),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(t){return this._onChangeCallback=t,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}class Li{constructor(t=0,e=0,n=0){Li.prototype.isVector3=!0,this.x=t,this.y=e,this.z=n}set(t,e,n){return void 0===n&&(n=this.z),this.x=t,this.y=e,this.z=n,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this}multiplyVectors(t,e){return this.x=t.x*e.x,this.y=t.y*e.y,this.z=t.z*e.z,this}applyEuler(t){return this.applyQuaternion(Ni.setFromEuler(t))}applyAxisAngle(t,e){return this.applyQuaternion(Ni.setFromAxisAngle(t,e))}applyMatrix3(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[3]*n+r[6]*i,this.y=r[1]*e+r[4]*n+r[7]*i,this.z=r[2]*e+r[5]*n+r[8]*i,this}applyNormalMatrix(t){return this.applyMatrix3(t).normalize()}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=t.elements,s=1/(r[3]*e+r[7]*n+r[11]*i+r[15]);return this.x=(r[0]*e+r[4]*n+r[8]*i+r[12])*s,this.y=(r[1]*e+r[5]*n+r[9]*i+r[13])*s,this.z=(r[2]*e+r[6]*n+r[10]*i+r[14])*s,this}applyQuaternion(t){const e=this.x,n=this.y,i=this.z,r=t.x,s=t.y,a=t.z,o=t.w,l=2*(s*i-a*n),c=2*(a*e-r*i),h=2*(r*n-s*e);return this.x=e+o*l+s*h-a*c,this.y=n+o*c+a*l-r*h,this.z=i+o*h+r*c-s*l,this}project(t){return this.applyMatrix4(t.matrixWorldInverse).applyMatrix4(t.projectionMatrix)}unproject(t){return this.applyMatrix4(t.projectionMatrixInverse).applyMatrix4(t.matrixWorld)}transformDirection(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[4]*n+r[8]*i,this.y=r[1]*e+r[5]*n+r[9]*i,this.z=r[2]*e+r[6]*n+r[10]*i,this.normalize()}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this}divideScalar(t){return this.multiplyScalar(1/t)}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this.z=Math.min(this.z,t.z),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this.z=Math.max(this.z,t.z),this}clamp(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this.z=Math.max(t.z,Math.min(e.z,this.z)),this}clampScalar(t,e){return this.x=Math.max(t,Math.min(e,this.x)),this.y=Math.max(t,Math.min(e,this.y)),this.z=Math.max(t,Math.min(e,this.z)),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(t,Math.min(e,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(t){return this.x*t.x+this.y*t.y+this.z*t.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this.z+=(t.z-this.z)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this.z=t.z+(e.z-t.z)*n,this}cross(t){return this.crossVectors(this,t)}crossVectors(t,e){const n=t.x,i=t.y,r=t.z,s=e.x,a=e.y,o=e.z;return this.x=i*o-r*a,this.y=r*s-n*o,this.z=n*a-i*s,this}projectOnVector(t){const e=t.lengthSq();if(0===e)return this.set(0,0,0);const n=t.dot(this)/e;return this.copy(t).multiplyScalar(n)}projectOnPlane(t){return Ui.copy(this).projectOnVector(t),this.sub(Ui)}reflect(t){return this.sub(Ui.copy(t).multiplyScalar(2*this.dot(t)))}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(0===e)return Math.PI/2;const n=this.dot(t)/e;return Math.acos(Yn(n,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y,i=this.z-t.z;return e*e+n*n+i*i}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)+Math.abs(this.z-t.z)}setFromSpherical(t){return this.setFromSphericalCoords(t.radius,t.phi,t.theta)}setFromSphericalCoords(t,e,n){const i=Math.sin(e)*t;return this.x=i*Math.sin(n),this.y=Math.cos(e)*t,this.z=i*Math.cos(n),this}setFromCylindrical(t){return this.setFromCylindricalCoords(t.radius,t.theta,t.y)}setFromCylindricalCoords(t,e,n){return this.x=t*Math.sin(e),this.y=n,this.z=t*Math.cos(e),this}setFromMatrixPosition(t){const e=t.elements;return this.x=e[12],this.y=e[13],this.z=e[14],this}setFromMatrixScale(t){const e=this.setFromMatrixColumn(t,0).length(),n=this.setFromMatrixColumn(t,1).length(),i=this.setFromMatrixColumn(t,2).length();return this.x=e,this.y=n,this.z=i,this}setFromMatrixColumn(t,e){return this.fromArray(t.elements,4*e)}setFromMatrix3Column(t,e){return this.fromArray(t.elements,3*e)}setFromEuler(t){return this.x=t._x,this.y=t._y,this.z=t._z,this}setFromColor(t){return this.x=t.r,this.y=t.g,this.z=t.b,this}equals(t){return t.x===this.x&&t.y===this.y&&t.z===this.z}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this.z=t[e+2],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t[e+2]=this.z,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this.z=t.getZ(e),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const t=Math.random()*Math.PI*2,e=2*Math.random()-1,n=Math.sqrt(1-e*e);return this.x=n*Math.cos(t),this.y=e,this.z=n*Math.sin(t),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const Ui=new Li,Ni=new Ii;class Di{constructor(t=new Li(1/0,1/0,1/0),e=new Li(-1/0,-1/0,-1/0)){this.isBox3=!0,this.min=t,this.max=e}set(t,e){return this.min.copy(t),this.max.copy(e),this}setFromArray(t){this.makeEmpty();for(let e=0,n=t.length;e=this.min.x&&t.x<=this.max.x&&t.y>=this.min.y&&t.y<=this.max.y&&t.z>=this.min.z&&t.z<=this.max.z}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y&&this.min.z<=t.min.z&&t.max.z<=this.max.z}getParameter(t,e){return e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y),(t.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(t){return t.max.x>=this.min.x&&t.min.x<=this.max.x&&t.max.y>=this.min.y&&t.min.y<=this.max.y&&t.max.z>=this.min.z&&t.min.z<=this.max.z}intersectsSphere(t){return this.clampPoint(t.center,Fi),Fi.distanceToSquared(t.center)<=t.radius*t.radius}intersectsPlane(t){let e,n;return t.normal.x>0?(e=t.normal.x*this.min.x,n=t.normal.x*this.max.x):(e=t.normal.x*this.max.x,n=t.normal.x*this.min.x),t.normal.y>0?(e+=t.normal.y*this.min.y,n+=t.normal.y*this.max.y):(e+=t.normal.y*this.max.y,n+=t.normal.y*this.min.y),t.normal.z>0?(e+=t.normal.z*this.min.z,n+=t.normal.z*this.max.z):(e+=t.normal.z*this.max.z,n+=t.normal.z*this.min.z),e<=-t.constant&&n>=-t.constant}intersectsTriangle(t){if(this.isEmpty())return!1;this.getCenter(Xi),ji.subVectors(this.max,Xi),zi.subVectors(t.a,Xi),ki.subVectors(t.b,Xi),Vi.subVectors(t.c,Xi),Hi.subVectors(ki,zi),Gi.subVectors(Vi,ki),Wi.subVectors(zi,Vi);let e=[0,-Hi.z,Hi.y,0,-Gi.z,Gi.y,0,-Wi.z,Wi.y,Hi.z,0,-Hi.x,Gi.z,0,-Gi.x,Wi.z,0,-Wi.x,-Hi.y,Hi.x,0,-Gi.y,Gi.x,0,-Wi.y,Wi.x,0];return!!Zi(e,zi,ki,Vi,ji)&&(e=[1,0,0,0,1,0,0,0,1],!!Zi(e,zi,ki,Vi,ji)&&(qi.crossVectors(Hi,Gi),e=[qi.x,qi.y,qi.z],Zi(e,zi,ki,Vi,ji)))}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return this.clampPoint(t,Fi).distanceTo(t)}getBoundingSphere(t){return this.isEmpty()?t.makeEmpty():(this.getCenter(t.center),t.radius=.5*this.getSize(Fi).length()),t}intersect(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}applyMatrix4(t){return this.isEmpty()||(Oi[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(t),Oi[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(t),Oi[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(t),Oi[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(t),Oi[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(t),Oi[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(t),Oi[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(t),Oi[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(t),this.setFromPoints(Oi)),this}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}}const Oi=[new Li,new Li,new Li,new Li,new Li,new Li,new Li,new Li],Fi=new Li,Bi=new Di,zi=new Li,ki=new Li,Vi=new Li,Hi=new Li,Gi=new Li,Wi=new Li,Xi=new Li,ji=new Li,qi=new Li,Yi=new Li;function Zi(t,e,n,i,r){for(let s=0,a=t.length-3;s<=a;s+=3){Yi.fromArray(t,s);const a=r.x*Math.abs(Yi.x)+r.y*Math.abs(Yi.y)+r.z*Math.abs(Yi.z),o=e.dot(Yi),l=n.dot(Yi),c=i.dot(Yi);if(Math.max(-Math.max(o,l,c),Math.min(o,l,c))>a)return!1}return!0}const Ji=new Di,Ki=new Li,$i=new Li;class Qi{constructor(t=new Li,e=-1){this.isSphere=!0,this.center=t,this.radius=e}set(t,e){return this.center.copy(t),this.radius=e,this}setFromPoints(t,e){const n=this.center;void 0!==e?n.copy(e):Ji.setFromPoints(t).getCenter(n);let i=0;for(let e=0,r=t.length;ethis.radius*this.radius&&(e.sub(this.center).normalize(),e.multiplyScalar(this.radius).add(this.center)),e}getBoundingBox(t){return this.isEmpty()?(t.makeEmpty(),t):(t.set(this.center,this.center),t.expandByScalar(this.radius),t)}applyMatrix4(t){return this.center.applyMatrix4(t),this.radius=this.radius*t.getMaxScaleOnAxis(),this}translate(t){return this.center.add(t),this}expandByPoint(t){if(this.isEmpty())return this.center.copy(t),this.radius=0,this;Ki.subVectors(t,this.center);const e=Ki.lengthSq();if(e>this.radius*this.radius){const t=Math.sqrt(e),n=.5*(t-this.radius);this.center.addScaledVector(Ki,n/t),this.radius+=n}return this}union(t){return t.isEmpty()?this:this.isEmpty()?(this.copy(t),this):(!0===this.center.equals(t.center)?this.radius=Math.max(this.radius,t.radius):($i.subVectors(t.center,this.center).setLength(t.radius),this.expandByPoint(Ki.copy(t.center).add($i)),this.expandByPoint(Ki.copy(t.center).sub($i))),this)}equals(t){return t.center.equals(this.center)&&t.radius===this.radius}clone(){return(new this.constructor).copy(this)}}const tr=new Li,er=new Li,nr=new Li,ir=new Li,rr=new Li,sr=new Li,ar=new Li;class or{constructor(t=new Li,e=new Li(0,0,-1)){this.origin=t,this.direction=e}set(t,e){return this.origin.copy(t),this.direction.copy(e),this}copy(t){return this.origin.copy(t.origin),this.direction.copy(t.direction),this}at(t,e){return e.copy(this.origin).addScaledVector(this.direction,t)}lookAt(t){return this.direction.copy(t).sub(this.origin).normalize(),this}recast(t){return this.origin.copy(this.at(t,tr)),this}closestPointToPoint(t,e){e.subVectors(t,this.origin);const n=e.dot(this.direction);return n<0?e.copy(this.origin):e.copy(this.origin).addScaledVector(this.direction,n)}distanceToPoint(t){return Math.sqrt(this.distanceSqToPoint(t))}distanceSqToPoint(t){const e=tr.subVectors(t,this.origin).dot(this.direction);return e<0?this.origin.distanceToSquared(t):(tr.copy(this.origin).addScaledVector(this.direction,e),tr.distanceToSquared(t))}distanceSqToSegment(t,e,n,i){er.copy(t).add(e).multiplyScalar(.5),nr.copy(e).sub(t).normalize(),ir.copy(this.origin).sub(er);const r=.5*t.distanceTo(e),s=-this.direction.dot(nr),a=ir.dot(this.direction),o=-ir.dot(nr),l=ir.lengthSq(),c=Math.abs(1-s*s);let h,u,d,p;if(c>0)if(h=s*o-a,u=s*a-o,p=r*c,h>=0)if(u>=-p)if(u<=p){const t=1/c;h*=t,u*=t,d=h*(h+s*u+2*a)+u*(s*h+u+2*o)+l}else u=r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;else u=-r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;else u<=-p?(h=Math.max(0,-(-s*r+a)),u=h>0?-r:Math.min(Math.max(-r,-o),r),d=-h*h+u*(u+2*o)+l):u<=p?(h=0,u=Math.min(Math.max(-r,-o),r),d=u*(u+2*o)+l):(h=Math.max(0,-(s*r+a)),u=h>0?r:Math.min(Math.max(-r,-o),r),d=-h*h+u*(u+2*o)+l);else u=s>0?-r:r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;return n&&n.copy(this.origin).addScaledVector(this.direction,h),i&&i.copy(er).addScaledVector(nr,u),d}intersectSphere(t,e){tr.subVectors(t.center,this.origin);const n=tr.dot(this.direction),i=tr.dot(tr)-n*n,r=t.radius*t.radius;if(i>r)return null;const s=Math.sqrt(r-i),a=n-s,o=n+s;return o<0?null:a<0?this.at(o,e):this.at(a,e)}intersectsSphere(t){return this.distanceSqToPoint(t.center)<=t.radius*t.radius}distanceToPlane(t){const e=t.normal.dot(this.direction);if(0===e)return 0===t.distanceToPoint(this.origin)?0:null;const n=-(this.origin.dot(t.normal)+t.constant)/e;return n>=0?n:null}intersectPlane(t,e){const n=this.distanceToPlane(t);return null===n?null:this.at(n,e)}intersectsPlane(t){const e=t.distanceToPoint(this.origin);if(0===e)return!0;return t.normal.dot(this.direction)*e<0}intersectBox(t,e){let n,i,r,s,a,o;const l=1/this.direction.x,c=1/this.direction.y,h=1/this.direction.z,u=this.origin;return l>=0?(n=(t.min.x-u.x)*l,i=(t.max.x-u.x)*l):(n=(t.max.x-u.x)*l,i=(t.min.x-u.x)*l),c>=0?(r=(t.min.y-u.y)*c,s=(t.max.y-u.y)*c):(r=(t.max.y-u.y)*c,s=(t.min.y-u.y)*c),n>s||r>i?null:((r>n||isNaN(n))&&(n=r),(s=0?(a=(t.min.z-u.z)*h,o=(t.max.z-u.z)*h):(a=(t.max.z-u.z)*h,o=(t.min.z-u.z)*h),n>o||a>i?null:((a>n||n!=n)&&(n=a),(o=0?n:i,e)))}intersectsBox(t){return null!==this.intersectBox(t,tr)}intersectTriangle(t,e,n,i,r){rr.subVectors(e,t),sr.subVectors(n,t),ar.crossVectors(rr,sr);let s,a=this.direction.dot(ar);if(a>0){if(i)return null;s=1}else{if(!(a<0))return null;s=-1,a=-a}ir.subVectors(this.origin,t);const o=s*this.direction.dot(sr.crossVectors(ir,sr));if(o<0)return null;const l=s*this.direction.dot(rr.cross(ir));if(l<0)return null;if(o+l>a)return null;const c=-s*ir.dot(ar);return c<0?null:this.at(c/a,r)}applyMatrix4(t){return this.origin.applyMatrix4(t),this.direction.transformDirection(t),this}equals(t){return t.origin.equals(this.origin)&&t.direction.equals(this.direction)}clone(){return(new this.constructor).copy(this)}}class lr{constructor(t,e,n,i,r,s,a,o,l,c,h,u,d,p,m,f){lr.prototype.isMatrix4=!0,this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],void 0!==t&&this.set(t,e,n,i,r,s,a,o,l,c,h,u,d,p,m,f)}set(t,e,n,i,r,s,a,o,l,c,h,u,d,p,m,f){const g=this.elements;return g[0]=t,g[4]=e,g[8]=n,g[12]=i,g[1]=r,g[5]=s,g[9]=a,g[13]=o,g[2]=l,g[6]=c,g[10]=h,g[14]=u,g[3]=d,g[7]=p,g[11]=m,g[15]=f,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return(new lr).fromArray(this.elements)}copy(t){const e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],e[9]=n[9],e[10]=n[10],e[11]=n[11],e[12]=n[12],e[13]=n[13],e[14]=n[14],e[15]=n[15],this}copyPosition(t){const e=this.elements,n=t.elements;return e[12]=n[12],e[13]=n[13],e[14]=n[14],this}setFromMatrix3(t){const e=t.elements;return this.set(e[0],e[3],e[6],0,e[1],e[4],e[7],0,e[2],e[5],e[8],0,0,0,0,1),this}extractBasis(t,e,n){return t.setFromMatrixColumn(this,0),e.setFromMatrixColumn(this,1),n.setFromMatrixColumn(this,2),this}makeBasis(t,e,n){return this.set(t.x,e.x,n.x,0,t.y,e.y,n.y,0,t.z,e.z,n.z,0,0,0,0,1),this}extractRotation(t){const e=this.elements,n=t.elements,i=1/cr.setFromMatrixColumn(t,0).length(),r=1/cr.setFromMatrixColumn(t,1).length(),s=1/cr.setFromMatrixColumn(t,2).length();return e[0]=n[0]*i,e[1]=n[1]*i,e[2]=n[2]*i,e[3]=0,e[4]=n[4]*r,e[5]=n[5]*r,e[6]=n[6]*r,e[7]=0,e[8]=n[8]*s,e[9]=n[9]*s,e[10]=n[10]*s,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this}makeRotationFromEuler(t){const e=this.elements,n=t.x,i=t.y,r=t.z,s=Math.cos(n),a=Math.sin(n),o=Math.cos(i),l=Math.sin(i),c=Math.cos(r),h=Math.sin(r);if("XYZ"===t.order){const t=s*c,n=s*h,i=a*c,r=a*h;e[0]=o*c,e[4]=-o*h,e[8]=l,e[1]=n+i*l,e[5]=t-r*l,e[9]=-a*o,e[2]=r-t*l,e[6]=i+n*l,e[10]=s*o}else if("YXZ"===t.order){const t=o*c,n=o*h,i=l*c,r=l*h;e[0]=t+r*a,e[4]=i*a-n,e[8]=s*l,e[1]=s*h,e[5]=s*c,e[9]=-a,e[2]=n*a-i,e[6]=r+t*a,e[10]=s*o}else if("ZXY"===t.order){const t=o*c,n=o*h,i=l*c,r=l*h;e[0]=t-r*a,e[4]=-s*h,e[8]=i+n*a,e[1]=n+i*a,e[5]=s*c,e[9]=r-t*a,e[2]=-s*l,e[6]=a,e[10]=s*o}else if("ZYX"===t.order){const t=s*c,n=s*h,i=a*c,r=a*h;e[0]=o*c,e[4]=i*l-n,e[8]=t*l+r,e[1]=o*h,e[5]=r*l+t,e[9]=n*l-i,e[2]=-l,e[6]=a*o,e[10]=s*o}else if("YZX"===t.order){const t=s*o,n=s*l,i=a*o,r=a*l;e[0]=o*c,e[4]=r-t*h,e[8]=i*h+n,e[1]=h,e[5]=s*c,e[9]=-a*c,e[2]=-l*c,e[6]=n*h+i,e[10]=t-r*h}else if("XZY"===t.order){const t=s*o,n=s*l,i=a*o,r=a*l;e[0]=o*c,e[4]=-h,e[8]=l*c,e[1]=t*h+r,e[5]=s*c,e[9]=n*h-i,e[2]=i*h-n,e[6]=a*c,e[10]=r*h+t}return e[3]=0,e[7]=0,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this}makeRotationFromQuaternion(t){return this.compose(ur,t,dr)}lookAt(t,e,n){const i=this.elements;return fr.subVectors(t,e),0===fr.lengthSq()&&(fr.z=1),fr.normalize(),pr.crossVectors(n,fr),0===pr.lengthSq()&&(1===Math.abs(n.z)?fr.x+=1e-4:fr.z+=1e-4,fr.normalize(),pr.crossVectors(n,fr)),pr.normalize(),mr.crossVectors(fr,pr),i[0]=pr.x,i[4]=mr.x,i[8]=fr.x,i[1]=pr.y,i[5]=mr.y,i[9]=fr.y,i[2]=pr.z,i[6]=mr.z,i[10]=fr.z,this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const n=t.elements,i=e.elements,r=this.elements,s=n[0],a=n[4],o=n[8],l=n[12],c=n[1],h=n[5],u=n[9],d=n[13],p=n[2],m=n[6],f=n[10],g=n[14],v=n[3],_=n[7],x=n[11],y=n[15],M=i[0],S=i[4],b=i[8],w=i[12],T=i[1],E=i[5],A=i[9],R=i[13],C=i[2],P=i[6],I=i[10],L=i[14],U=i[3],N=i[7],D=i[11],O=i[15];return r[0]=s*M+a*T+o*C+l*U,r[4]=s*S+a*E+o*P+l*N,r[8]=s*b+a*A+o*I+l*D,r[12]=s*w+a*R+o*L+l*O,r[1]=c*M+h*T+u*C+d*U,r[5]=c*S+h*E+u*P+d*N,r[9]=c*b+h*A+u*I+d*D,r[13]=c*w+h*R+u*L+d*O,r[2]=p*M+m*T+f*C+g*U,r[6]=p*S+m*E+f*P+g*N,r[10]=p*b+m*A+f*I+g*D,r[14]=p*w+m*R+f*L+g*O,r[3]=v*M+_*T+x*C+y*U,r[7]=v*S+_*E+x*P+y*N,r[11]=v*b+_*A+x*I+y*D,r[15]=v*w+_*R+x*L+y*O,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[4]*=t,e[8]*=t,e[12]*=t,e[1]*=t,e[5]*=t,e[9]*=t,e[13]*=t,e[2]*=t,e[6]*=t,e[10]*=t,e[14]*=t,e[3]*=t,e[7]*=t,e[11]*=t,e[15]*=t,this}determinant(){const t=this.elements,e=t[0],n=t[4],i=t[8],r=t[12],s=t[1],a=t[5],o=t[9],l=t[13],c=t[2],h=t[6],u=t[10],d=t[14];return t[3]*(+r*o*h-i*l*h-r*a*u+n*l*u+i*a*d-n*o*d)+t[7]*(+e*o*d-e*l*u+r*s*u-i*s*d+i*l*c-r*o*c)+t[11]*(+e*l*h-e*a*d-r*s*h+n*s*d+r*a*c-n*l*c)+t[15]*(-i*a*c-e*o*h+e*a*u+i*s*h-n*s*u+n*o*c)}transpose(){const t=this.elements;let e;return e=t[1],t[1]=t[4],t[4]=e,e=t[2],t[2]=t[8],t[8]=e,e=t[6],t[6]=t[9],t[9]=e,e=t[3],t[3]=t[12],t[12]=e,e=t[7],t[7]=t[13],t[13]=e,e=t[11],t[11]=t[14],t[14]=e,this}setPosition(t,e,n){const i=this.elements;return t.isVector3?(i[12]=t.x,i[13]=t.y,i[14]=t.z):(i[12]=t,i[13]=e,i[14]=n),this}invert(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8],h=t[9],u=t[10],d=t[11],p=t[12],m=t[13],f=t[14],g=t[15],v=h*f*l-m*u*l+m*o*d-a*f*d-h*o*g+a*u*g,_=p*u*l-c*f*l-p*o*d+s*f*d+c*o*g-s*u*g,x=c*m*l-p*h*l+p*a*d-s*m*d-c*a*g+s*h*g,y=p*h*o-c*m*o-p*a*u+s*m*u+c*a*f-s*h*f,M=e*v+n*_+i*x+r*y;if(0===M)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const S=1/M;return t[0]=v*S,t[1]=(m*u*r-h*f*r-m*i*d+n*f*d+h*i*g-n*u*g)*S,t[2]=(a*f*r-m*o*r+m*i*l-n*f*l-a*i*g+n*o*g)*S,t[3]=(h*o*r-a*u*r-h*i*l+n*u*l+a*i*d-n*o*d)*S,t[4]=_*S,t[5]=(c*f*r-p*u*r+p*i*d-e*f*d-c*i*g+e*u*g)*S,t[6]=(p*o*r-s*f*r-p*i*l+e*f*l+s*i*g-e*o*g)*S,t[7]=(s*u*r-c*o*r+c*i*l-e*u*l-s*i*d+e*o*d)*S,t[8]=x*S,t[9]=(p*h*r-c*m*r-p*n*d+e*m*d+c*n*g-e*h*g)*S,t[10]=(s*m*r-p*a*r+p*n*l-e*m*l-s*n*g+e*a*g)*S,t[11]=(c*a*r-s*h*r-c*n*l+e*h*l+s*n*d-e*a*d)*S,t[12]=y*S,t[13]=(c*m*i-p*h*i+p*n*u-e*m*u-c*n*f+e*h*f)*S,t[14]=(p*a*i-s*m*i-p*n*o+e*m*o+s*n*f-e*a*f)*S,t[15]=(s*h*i-c*a*i+c*n*o-e*h*o-s*n*u+e*a*u)*S,this}scale(t){const e=this.elements,n=t.x,i=t.y,r=t.z;return e[0]*=n,e[4]*=i,e[8]*=r,e[1]*=n,e[5]*=i,e[9]*=r,e[2]*=n,e[6]*=i,e[10]*=r,e[3]*=n,e[7]*=i,e[11]*=r,this}getMaxScaleOnAxis(){const t=this.elements,e=t[0]*t[0]+t[1]*t[1]+t[2]*t[2],n=t[4]*t[4]+t[5]*t[5]+t[6]*t[6],i=t[8]*t[8]+t[9]*t[9]+t[10]*t[10];return Math.sqrt(Math.max(e,n,i))}makeTranslation(t,e,n){return t.isVector3?this.set(1,0,0,t.x,0,1,0,t.y,0,0,1,t.z,0,0,0,1):this.set(1,0,0,t,0,1,0,e,0,0,1,n,0,0,0,1),this}makeRotationX(t){const e=Math.cos(t),n=Math.sin(t);return this.set(1,0,0,0,0,e,-n,0,0,n,e,0,0,0,0,1),this}makeRotationY(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,0,n,0,0,1,0,0,-n,0,e,0,0,0,0,1),this}makeRotationZ(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,-n,0,0,n,e,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(t,e){const n=Math.cos(e),i=Math.sin(e),r=1-n,s=t.x,a=t.y,o=t.z,l=r*s,c=r*a;return this.set(l*s+n,l*a-i*o,l*o+i*a,0,l*a+i*o,c*a+n,c*o-i*s,0,l*o-i*a,c*o+i*s,r*o*o+n,0,0,0,0,1),this}makeScale(t,e,n){return this.set(t,0,0,0,0,e,0,0,0,0,n,0,0,0,0,1),this}makeShear(t,e,n,i,r,s){return this.set(1,n,r,0,t,1,s,0,e,i,1,0,0,0,0,1),this}compose(t,e,n){const i=this.elements,r=e._x,s=e._y,a=e._z,o=e._w,l=r+r,c=s+s,h=a+a,u=r*l,d=r*c,p=r*h,m=s*c,f=s*h,g=a*h,v=o*l,_=o*c,x=o*h,y=n.x,M=n.y,S=n.z;return i[0]=(1-(m+g))*y,i[1]=(d+x)*y,i[2]=(p-_)*y,i[3]=0,i[4]=(d-x)*M,i[5]=(1-(u+g))*M,i[6]=(f+v)*M,i[7]=0,i[8]=(p+_)*S,i[9]=(f-v)*S,i[10]=(1-(u+m))*S,i[11]=0,i[12]=t.x,i[13]=t.y,i[14]=t.z,i[15]=1,this}decompose(t,e,n){const i=this.elements;let r=cr.set(i[0],i[1],i[2]).length();const s=cr.set(i[4],i[5],i[6]).length(),a=cr.set(i[8],i[9],i[10]).length();this.determinant()<0&&(r=-r),t.x=i[12],t.y=i[13],t.z=i[14],hr.copy(this);const o=1/r,l=1/s,c=1/a;return hr.elements[0]*=o,hr.elements[1]*=o,hr.elements[2]*=o,hr.elements[4]*=l,hr.elements[5]*=l,hr.elements[6]*=l,hr.elements[8]*=c,hr.elements[9]*=c,hr.elements[10]*=c,e.setFromRotationMatrix(hr),n.x=r,n.y=s,n.z=a,this}makePerspective(t,e,n,i,r,s,a=2e3){const o=this.elements,l=2*r/(e-t),c=2*r/(n-i),h=(e+t)/(e-t),u=(n+i)/(n-i);let d,p;if(a===kn)d=-(s+r)/(s-r),p=-2*s*r/(s-r);else{if(a!==Vn)throw new Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: "+a);d=-s/(s-r),p=-s*r/(s-r)}return o[0]=l,o[4]=0,o[8]=h,o[12]=0,o[1]=0,o[5]=c,o[9]=u,o[13]=0,o[2]=0,o[6]=0,o[10]=d,o[14]=p,o[3]=0,o[7]=0,o[11]=-1,o[15]=0,this}makeOrthographic(t,e,n,i,r,s,a=2e3){const o=this.elements,l=1/(e-t),c=1/(n-i),h=1/(s-r),u=(e+t)*l,d=(n+i)*c;let p,m;if(a===kn)p=(s+r)*h,m=-2*h;else{if(a!==Vn)throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+a);p=r*h,m=-1*h}return o[0]=2*l,o[4]=0,o[8]=0,o[12]=-u,o[1]=0,o[5]=2*c,o[9]=0,o[13]=-d,o[2]=0,o[6]=0,o[10]=m,o[14]=-p,o[3]=0,o[7]=0,o[11]=0,o[15]=1,this}equals(t){const e=this.elements,n=t.elements;for(let t=0;t<16;t++)if(e[t]!==n[t])return!1;return!0}fromArray(t,e=0){for(let n=0;n<16;n++)this.elements[n]=t[n+e];return this}toArray(t=[],e=0){const n=this.elements;return t[e]=n[0],t[e+1]=n[1],t[e+2]=n[2],t[e+3]=n[3],t[e+4]=n[4],t[e+5]=n[5],t[e+6]=n[6],t[e+7]=n[7],t[e+8]=n[8],t[e+9]=n[9],t[e+10]=n[10],t[e+11]=n[11],t[e+12]=n[12],t[e+13]=n[13],t[e+14]=n[14],t[e+15]=n[15],t}}const cr=new Li,hr=new lr,ur=new Li(0,0,0),dr=new Li(1,1,1),pr=new Li,mr=new Li,fr=new Li,gr=new lr,vr=new Ii;class _r{constructor(t=0,e=0,n=0,i=_r.DEFAULT_ORDER){this.isEuler=!0,this._x=t,this._y=e,this._z=n,this._order=i}get x(){return this._x}set x(t){this._x=t,this._onChangeCallback()}get y(){return this._y}set y(t){this._y=t,this._onChangeCallback()}get z(){return this._z}set z(t){this._z=t,this._onChangeCallback()}get order(){return this._order}set order(t){this._order=t,this._onChangeCallback()}set(t,e,n,i=this._order){return this._x=t,this._y=e,this._z=n,this._order=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(t){return this._x=t._x,this._y=t._y,this._z=t._z,this._order=t._order,this._onChangeCallback(),this}setFromRotationMatrix(t,e=this._order,n=!0){const i=t.elements,r=i[0],s=i[4],a=i[8],o=i[1],l=i[5],c=i[9],h=i[2],u=i[6],d=i[10];switch(e){case"XYZ":this._y=Math.asin(Yn(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(-c,d),this._z=Math.atan2(-s,r)):(this._x=Math.atan2(u,l),this._z=0);break;case"YXZ":this._x=Math.asin(-Yn(c,-1,1)),Math.abs(c)<.9999999?(this._y=Math.atan2(a,d),this._z=Math.atan2(o,l)):(this._y=Math.atan2(-h,r),this._z=0);break;case"ZXY":this._x=Math.asin(Yn(u,-1,1)),Math.abs(u)<.9999999?(this._y=Math.atan2(-h,d),this._z=Math.atan2(-s,l)):(this._y=0,this._z=Math.atan2(o,r));break;case"ZYX":this._y=Math.asin(-Yn(h,-1,1)),Math.abs(h)<.9999999?(this._x=Math.atan2(u,d),this._z=Math.atan2(o,r)):(this._x=0,this._z=Math.atan2(-s,l));break;case"YZX":this._z=Math.asin(Yn(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-c,l),this._y=Math.atan2(-h,r)):(this._x=0,this._y=Math.atan2(a,d));break;case"XZY":this._z=Math.asin(-Yn(s,-1,1)),Math.abs(s)<.9999999?(this._x=Math.atan2(u,l),this._y=Math.atan2(a,r)):(this._x=Math.atan2(-c,d),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+e)}return this._order=e,!0===n&&this._onChangeCallback(),this}setFromQuaternion(t,e,n){return gr.makeRotationFromQuaternion(t),this.setFromRotationMatrix(gr,e,n)}setFromVector3(t,e=this._order){return this.set(t.x,t.y,t.z,e)}reorder(t){return vr.setFromEuler(this),this.setFromQuaternion(vr,t)}equals(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._order===this._order}fromArray(t){return this._x=t[0],this._y=t[1],this._z=t[2],void 0!==t[3]&&(this._order=t[3]),this._onChangeCallback(),this}toArray(t=[],e=0){return t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._order,t}_onChange(t){return this._onChangeCallback=t,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._order}}_r.DEFAULT_ORDER="XYZ";class xr{constructor(){this.mask=1}set(t){this.mask=(1<>>0}enable(t){this.mask|=1<1){for(let t=0;t1){for(let t=0;t0&&(i.userData=this.userData),i.layers=this.layers.mask,i.matrix=this.matrix.toArray(),i.up=this.up.toArray(),!1===this.matrixAutoUpdate&&(i.matrixAutoUpdate=!1),this.isInstancedMesh&&(i.type="InstancedMesh",i.count=this.count,i.instanceMatrix=this.instanceMatrix.toJSON(),null!==this.instanceColor&&(i.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(i.type="BatchedMesh",i.perObjectFrustumCulled=this.perObjectFrustumCulled,i.sortObjects=this.sortObjects,i.drawRanges=this._drawRanges,i.reservedRanges=this._reservedRanges,i.visibility=this._visibility,i.active=this._active,i.bounds=this._bounds.map((t=>({boxInitialized:t.boxInitialized,boxMin:t.box.min.toArray(),boxMax:t.box.max.toArray(),sphereInitialized:t.sphereInitialized,sphereRadius:t.sphere.radius,sphereCenter:t.sphere.center.toArray()}))),i.maxInstanceCount=this._maxInstanceCount,i.maxVertexCount=this._maxVertexCount,i.maxIndexCount=this._maxIndexCount,i.geometryInitialized=this._geometryInitialized,i.geometryCount=this._geometryCount,i.matricesTexture=this._matricesTexture.toJSON(t),null!==this._colorsTexture&&(i.colorsTexture=this._colorsTexture.toJSON(t)),null!==this.boundingSphere&&(i.boundingSphere={center:i.boundingSphere.center.toArray(),radius:i.boundingSphere.radius}),null!==this.boundingBox&&(i.boundingBox={min:i.boundingBox.min.toArray(),max:i.boundingBox.max.toArray()})),this.isScene)this.background&&(this.background.isColor?i.background=this.background.toJSON():this.background.isTexture&&(i.background=this.background.toJSON(t).uuid)),this.environment&&this.environment.isTexture&&!0!==this.environment.isRenderTargetTexture&&(i.environment=this.environment.toJSON(t).uuid);else if(this.isMesh||this.isLine||this.isPoints){i.geometry=r(t.geometries,this.geometry);const e=this.geometry.parameters;if(void 0!==e&&void 0!==e.shapes){const n=e.shapes;if(Array.isArray(n))for(let e=0,i=n.length;e0){i.children=[];for(let e=0;e0){i.animations=[];for(let e=0;e0&&(n.geometries=e),i.length>0&&(n.materials=i),r.length>0&&(n.textures=r),a.length>0&&(n.images=a),o.length>0&&(n.shapes=o),l.length>0&&(n.skeletons=l),c.length>0&&(n.animations=c),h.length>0&&(n.nodes=h)}return n.object=i,n;function s(t){const e=[];for(const n in t){const i=t[n];delete i.metadata,e.push(i)}return e}}clone(t){return(new this.constructor).copy(this,t)}copy(t,e=!0){if(this.name=t.name,this.up.copy(t.up),this.position.copy(t.position),this.rotation.order=t.rotation.order,this.quaternion.copy(t.quaternion),this.scale.copy(t.scale),this.matrix.copy(t.matrix),this.matrixWorld.copy(t.matrixWorld),this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrixWorldAutoUpdate=t.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=t.matrixWorldNeedsUpdate,this.layers.mask=t.layers.mask,this.visible=t.visible,this.castShadow=t.castShadow,this.receiveShadow=t.receiveShadow,this.frustumCulled=t.frustumCulled,this.renderOrder=t.renderOrder,this.animations=t.animations.slice(),this.userData=JSON.parse(JSON.stringify(t.userData)),!0===e)for(let e=0;e0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(t,e,n,i,r){Or.subVectors(i,e),Fr.subVectors(n,e),Br.subVectors(t,e);const s=Or.dot(Or),a=Or.dot(Fr),o=Or.dot(Br),l=Fr.dot(Fr),c=Fr.dot(Br),h=s*l-a*a;if(0===h)return r.set(0,0,0),null;const u=1/h,d=(l*o-a*c)*u,p=(s*c-a*o)*u;return r.set(1-d-p,p,d)}static containsPoint(t,e,n,i){return null!==this.getBarycoord(t,e,n,i,zr)&&(zr.x>=0&&zr.y>=0&&zr.x+zr.y<=1)}static getInterpolation(t,e,n,i,r,s,a,o){return null===this.getBarycoord(t,e,n,i,zr)?(o.x=0,o.y=0,"z"in o&&(o.z=0),"w"in o&&(o.w=0),null):(o.setScalar(0),o.addScaledVector(r,zr.x),o.addScaledVector(s,zr.y),o.addScaledVector(a,zr.z),o)}static getInterpolatedAttribute(t,e,n,i,r,s){return jr.setScalar(0),qr.setScalar(0),Yr.setScalar(0),jr.fromBufferAttribute(t,e),qr.fromBufferAttribute(t,n),Yr.fromBufferAttribute(t,i),s.setScalar(0),s.addScaledVector(jr,r.x),s.addScaledVector(qr,r.y),s.addScaledVector(Yr,r.z),s}static isFrontFacing(t,e,n,i){return Or.subVectors(n,e),Fr.subVectors(t,e),Or.cross(Fr).dot(i)<0}set(t,e,n){return this.a.copy(t),this.b.copy(e),this.c.copy(n),this}setFromPointsAndIndices(t,e,n,i){return this.a.copy(t[e]),this.b.copy(t[n]),this.c.copy(t[i]),this}setFromAttributeAndIndices(t,e,n,i){return this.a.fromBufferAttribute(t,e),this.b.fromBufferAttribute(t,n),this.c.fromBufferAttribute(t,i),this}clone(){return(new this.constructor).copy(this)}copy(t){return this.a.copy(t.a),this.b.copy(t.b),this.c.copy(t.c),this}getArea(){return Or.subVectors(this.c,this.b),Fr.subVectors(this.a,this.b),.5*Or.cross(Fr).length()}getMidpoint(t){return t.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(t){return Zr.getNormal(this.a,this.b,this.c,t)}getPlane(t){return t.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(t,e){return Zr.getBarycoord(t,this.a,this.b,this.c,e)}getInterpolation(t,e,n,i,r){return Zr.getInterpolation(t,this.a,this.b,this.c,e,n,i,r)}containsPoint(t){return Zr.containsPoint(t,this.a,this.b,this.c)}isFrontFacing(t){return Zr.isFrontFacing(this.a,this.b,this.c,t)}intersectsBox(t){return t.intersectsTriangle(this)}closestPointToPoint(t,e){const n=this.a,i=this.b,r=this.c;let s,a;kr.subVectors(i,n),Vr.subVectors(r,n),Gr.subVectors(t,n);const o=kr.dot(Gr),l=Vr.dot(Gr);if(o<=0&&l<=0)return e.copy(n);Wr.subVectors(t,i);const c=kr.dot(Wr),h=Vr.dot(Wr);if(c>=0&&h<=c)return e.copy(i);const u=o*h-c*l;if(u<=0&&o>=0&&c<=0)return s=o/(o-c),e.copy(n).addScaledVector(kr,s);Xr.subVectors(t,r);const d=kr.dot(Xr),p=Vr.dot(Xr);if(p>=0&&d<=p)return e.copy(r);const m=d*l-o*p;if(m<=0&&l>=0&&p<=0)return a=l/(l-p),e.copy(n).addScaledVector(Vr,a);const f=c*p-d*h;if(f<=0&&h-c>=0&&d-p>=0)return Hr.subVectors(r,i),a=(h-c)/(h-c+(d-p)),e.copy(i).addScaledVector(Hr,a);const g=1/(f+m+u);return s=m*g,a=u*g,e.copy(n).addScaledVector(kr,s).addScaledVector(Vr,a)}equals(t){return t.a.equals(this.a)&&t.b.equals(this.b)&&t.c.equals(this.c)}}const Jr={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},Kr={h:0,s:0,l:0},$r={h:0,s:0,l:0};function Qr(t,e,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?t+6*(e-t)*n:n<.5?e:n<2/3?t+6*(e-t)*(2/3-n):t}class ts{constructor(t,e,n){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(t,e,n)}set(t,e,n){if(void 0===e&&void 0===n){const e=t;e&&e.isColor?this.copy(e):"number"==typeof e?this.setHex(e):"string"==typeof e&&this.setStyle(e)}else this.setRGB(t,e,n);return this}setScalar(t){return this.r=t,this.g=t,this.b=t,this}setHex(t,e=Je){return t=Math.floor(t),this.r=(t>>16&255)/255,this.g=(t>>8&255)/255,this.b=(255&t)/255,mi.toWorkingColorSpace(this,e),this}setRGB(t,e,n,i=mi.workingColorSpace){return this.r=t,this.g=e,this.b=n,mi.toWorkingColorSpace(this,i),this}setHSL(t,e,n,i=mi.workingColorSpace){if(t=Zn(t,1),e=Yn(e,0,1),n=Yn(n,0,1),0===e)this.r=this.g=this.b=n;else{const i=n<=.5?n*(1+e):n+e-n*e,r=2*n-i;this.r=Qr(r,i,t+1/3),this.g=Qr(r,i,t),this.b=Qr(r,i,t-1/3)}return mi.toWorkingColorSpace(this,i),this}setStyle(t,e=Je){function n(e){void 0!==e&&parseFloat(e)<1&&console.warn("THREE.Color: Alpha component of "+t+" will be ignored.")}let i;if(i=/^(\w+)\(([^\)]*)\)/.exec(t)){let r;const s=i[1],a=i[2];switch(s){case"rgb":case"rgba":if(r=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setRGB(Math.min(255,parseInt(r[1],10))/255,Math.min(255,parseInt(r[2],10))/255,Math.min(255,parseInt(r[3],10))/255,e);if(r=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setRGB(Math.min(100,parseInt(r[1],10))/100,Math.min(100,parseInt(r[2],10))/100,Math.min(100,parseInt(r[3],10))/100,e);break;case"hsl":case"hsla":if(r=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setHSL(parseFloat(r[1])/360,parseFloat(r[2])/100,parseFloat(r[3])/100,e);break;default:console.warn("THREE.Color: Unknown color model "+t)}}else if(i=/^\#([A-Fa-f\d]+)$/.exec(t)){const n=i[1],r=n.length;if(3===r)return this.setRGB(parseInt(n.charAt(0),16)/15,parseInt(n.charAt(1),16)/15,parseInt(n.charAt(2),16)/15,e);if(6===r)return this.setHex(parseInt(n,16),e);console.warn("THREE.Color: Invalid hex color "+t)}else if(t&&t.length>0)return this.setColorName(t,e);return this}setColorName(t,e=Je){const n=Jr[t.toLowerCase()];return void 0!==n?this.setHex(n,e):console.warn("THREE.Color: Unknown color "+t),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(t){return this.r=t.r,this.g=t.g,this.b=t.b,this}copySRGBToLinear(t){return this.r=fi(t.r),this.g=fi(t.g),this.b=fi(t.b),this}copyLinearToSRGB(t){return this.r=gi(t.r),this.g=gi(t.g),this.b=gi(t.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(t=Je){return mi.fromWorkingColorSpace(es.copy(this),t),65536*Math.round(Yn(255*es.r,0,255))+256*Math.round(Yn(255*es.g,0,255))+Math.round(Yn(255*es.b,0,255))}getHexString(t=Je){return("000000"+this.getHex(t).toString(16)).slice(-6)}getHSL(t,e=mi.workingColorSpace){mi.fromWorkingColorSpace(es.copy(this),e);const n=es.r,i=es.g,r=es.b,s=Math.max(n,i,r),a=Math.min(n,i,r);let o,l;const c=(a+s)/2;if(a===s)o=0,l=0;else{const t=s-a;switch(l=c<=.5?t/(s+a):t/(2-s-a),s){case n:o=(i-r)/t+(i0!=t>0&&this.version++,this._alphaTest=t}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(t){if(void 0!==t)for(const e in t){const n=t[e];if(void 0===n){console.warn(`THREE.Material: parameter '${e}' has value of undefined.`);continue}const i=this[e];void 0!==i?i&&i.isColor?i.set(n):i&&i.isVector3&&n&&n.isVector3?i.copy(n):this[e]=n:console.warn(`THREE.Material: '${e}' is not a property of THREE.${this.type}.`)}}toJSON(t){const e=void 0===t||"string"==typeof t;e&&(t={textures:{},images:{}});const n={metadata:{version:4.6,type:"Material",generator:"Material.toJSON"}};function i(t){const e=[];for(const n in t){const i=t[n];delete i.metadata,e.push(i)}return e}if(n.uuid=this.uuid,n.type=this.type,""!==this.name&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),void 0!==this.roughness&&(n.roughness=this.roughness),void 0!==this.metalness&&(n.metalness=this.metalness),void 0!==this.sheen&&(n.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(n.sheenColor=this.sheenColor.getHex()),void 0!==this.sheenRoughness&&(n.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),void 0!==this.emissiveIntensity&&1!==this.emissiveIntensity&&(n.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),void 0!==this.specularIntensity&&(n.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(n.specularColor=this.specularColor.getHex()),void 0!==this.shininess&&(n.shininess=this.shininess),void 0!==this.clearcoat&&(n.clearcoat=this.clearcoat),void 0!==this.clearcoatRoughness&&(n.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(n.clearcoatMap=this.clearcoatMap.toJSON(t).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(t).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(t).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),void 0!==this.dispersion&&(n.dispersion=this.dispersion),void 0!==this.iridescence&&(n.iridescence=this.iridescence),void 0!==this.iridescenceIOR&&(n.iridescenceIOR=this.iridescenceIOR),void 0!==this.iridescenceThicknessRange&&(n.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(n.iridescenceMap=this.iridescenceMap.toJSON(t).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(n.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(t).uuid),void 0!==this.anisotropy&&(n.anisotropy=this.anisotropy),void 0!==this.anisotropyRotation&&(n.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(n.anisotropyMap=this.anisotropyMap.toJSON(t).uuid),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(t).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(t).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(t).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(t).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(t).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(t).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(t).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(t).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(t).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(t).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(t).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(t).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(n.specularIntensityMap=this.specularIntensityMap.toJSON(t).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(n.specularColorMap=this.specularColorMap.toJSON(t).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(t).uuid,void 0!==this.combine&&(n.combine=this.combine)),void 0!==this.envMapRotation&&(n.envMapRotation=this.envMapRotation.toArray()),void 0!==this.envMapIntensity&&(n.envMapIntensity=this.envMapIntensity),void 0!==this.reflectivity&&(n.reflectivity=this.reflectivity),void 0!==this.refractionRatio&&(n.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(t).uuid),void 0!==this.transmission&&(n.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(n.transmissionMap=this.transmissionMap.toJSON(t).uuid),void 0!==this.thickness&&(n.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(n.thicknessMap=this.thicknessMap.toJSON(t).uuid),void 0!==this.attenuationDistance&&this.attenuationDistance!==1/0&&(n.attenuationDistance=this.attenuationDistance),void 0!==this.attenuationColor&&(n.attenuationColor=this.attenuationColor.getHex()),void 0!==this.size&&(n.size=this.size),null!==this.shadowSide&&(n.shadowSide=this.shadowSide),void 0!==this.sizeAttenuation&&(n.sizeAttenuation=this.sizeAttenuation),1!==this.blending&&(n.blending=this.blending),this.side!==u&&(n.side=this.side),!0===this.vertexColors&&(n.vertexColors=!0),this.opacity<1&&(n.opacity=this.opacity),!0===this.transparent&&(n.transparent=!0),this.blendSrc!==C&&(n.blendSrc=this.blendSrc),this.blendDst!==P&&(n.blendDst=this.blendDst),this.blendEquation!==y&&(n.blendEquation=this.blendEquation),null!==this.blendSrcAlpha&&(n.blendSrcAlpha=this.blendSrcAlpha),null!==this.blendDstAlpha&&(n.blendDstAlpha=this.blendDstAlpha),null!==this.blendEquationAlpha&&(n.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(n.blendColor=this.blendColor.getHex()),0!==this.blendAlpha&&(n.blendAlpha=this.blendAlpha),3!==this.depthFunc&&(n.depthFunc=this.depthFunc),!1===this.depthTest&&(n.depthTest=this.depthTest),!1===this.depthWrite&&(n.depthWrite=this.depthWrite),!1===this.colorWrite&&(n.colorWrite=this.colorWrite),255!==this.stencilWriteMask&&(n.stencilWriteMask=this.stencilWriteMask),519!==this.stencilFunc&&(n.stencilFunc=this.stencilFunc),0!==this.stencilRef&&(n.stencilRef=this.stencilRef),255!==this.stencilFuncMask&&(n.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==an&&(n.stencilFail=this.stencilFail),this.stencilZFail!==an&&(n.stencilZFail=this.stencilZFail),this.stencilZPass!==an&&(n.stencilZPass=this.stencilZPass),!0===this.stencilWrite&&(n.stencilWrite=this.stencilWrite),void 0!==this.rotation&&0!==this.rotation&&(n.rotation=this.rotation),!0===this.polygonOffset&&(n.polygonOffset=!0),0!==this.polygonOffsetFactor&&(n.polygonOffsetFactor=this.polygonOffsetFactor),0!==this.polygonOffsetUnits&&(n.polygonOffsetUnits=this.polygonOffsetUnits),void 0!==this.linewidth&&1!==this.linewidth&&(n.linewidth=this.linewidth),void 0!==this.dashSize&&(n.dashSize=this.dashSize),void 0!==this.gapSize&&(n.gapSize=this.gapSize),void 0!==this.scale&&(n.scale=this.scale),!0===this.dithering&&(n.dithering=!0),this.alphaTest>0&&(n.alphaTest=this.alphaTest),!0===this.alphaHash&&(n.alphaHash=!0),!0===this.alphaToCoverage&&(n.alphaToCoverage=!0),!0===this.premultipliedAlpha&&(n.premultipliedAlpha=!0),!0===this.forceSinglePass&&(n.forceSinglePass=!0),!0===this.wireframe&&(n.wireframe=!0),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),"round"!==this.wireframeLinecap&&(n.wireframeLinecap=this.wireframeLinecap),"round"!==this.wireframeLinejoin&&(n.wireframeLinejoin=this.wireframeLinejoin),!0===this.flatShading&&(n.flatShading=!0),!1===this.visible&&(n.visible=!1),!1===this.toneMapped&&(n.toneMapped=!1),!1===this.fog&&(n.fog=!1),Object.keys(this.userData).length>0&&(n.userData=this.userData),e){const e=i(t.textures),r=i(t.images);e.length>0&&(n.textures=e),r.length>0&&(n.images=r)}return n}clone(){return(new this.constructor).copy(this)}copy(t){this.name=t.name,this.blending=t.blending,this.side=t.side,this.vertexColors=t.vertexColors,this.opacity=t.opacity,this.transparent=t.transparent,this.blendSrc=t.blendSrc,this.blendDst=t.blendDst,this.blendEquation=t.blendEquation,this.blendSrcAlpha=t.blendSrcAlpha,this.blendDstAlpha=t.blendDstAlpha,this.blendEquationAlpha=t.blendEquationAlpha,this.blendColor.copy(t.blendColor),this.blendAlpha=t.blendAlpha,this.depthFunc=t.depthFunc,this.depthTest=t.depthTest,this.depthWrite=t.depthWrite,this.stencilWriteMask=t.stencilWriteMask,this.stencilFunc=t.stencilFunc,this.stencilRef=t.stencilRef,this.stencilFuncMask=t.stencilFuncMask,this.stencilFail=t.stencilFail,this.stencilZFail=t.stencilZFail,this.stencilZPass=t.stencilZPass,this.stencilWrite=t.stencilWrite;const e=t.clippingPlanes;let n=null;if(null!==e){const t=e.length;n=new Array(t);for(let i=0;i!==t;++i)n[i]=e[i].clone()}return this.clippingPlanes=n,this.clipIntersection=t.clipIntersection,this.clipShadows=t.clipShadows,this.shadowSide=t.shadowSide,this.colorWrite=t.colorWrite,this.precision=t.precision,this.polygonOffset=t.polygonOffset,this.polygonOffsetFactor=t.polygonOffsetFactor,this.polygonOffsetUnits=t.polygonOffsetUnits,this.dithering=t.dithering,this.alphaTest=t.alphaTest,this.alphaHash=t.alphaHash,this.alphaToCoverage=t.alphaToCoverage,this.premultipliedAlpha=t.premultipliedAlpha,this.forceSinglePass=t.forceSinglePass,this.visible=t.visible,this.toneMapped=t.toneMapped,this.userData=JSON.parse(JSON.stringify(t.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(t){!0===t&&this.version++}onBuild(){console.warn("Material: onBuild() has been removed.")}}class rs extends is{constructor(t){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new ts(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new _r,this.combine=Y,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.fog=t.fog,this}}const ss=as();function as(){const t=new ArrayBuffer(4),e=new Float32Array(t),n=new Uint32Array(t),i=new Uint32Array(512),r=new Uint32Array(512);for(let t=0;t<256;++t){const e=t-127;e<-27?(i[t]=0,i[256|t]=32768,r[t]=24,r[256|t]=24):e<-14?(i[t]=1024>>-e-14,i[256|t]=1024>>-e-14|32768,r[t]=-e-1,r[256|t]=-e-1):e<=15?(i[t]=e+15<<10,i[256|t]=e+15<<10|32768,r[t]=13,r[256|t]=13):e<128?(i[t]=31744,i[256|t]=64512,r[t]=24,r[256|t]=24):(i[t]=31744,i[256|t]=64512,r[t]=13,r[256|t]=13)}const s=new Uint32Array(2048),a=new Uint32Array(64),o=new Uint32Array(64);for(let t=1;t<1024;++t){let e=t<<13,n=0;for(;0==(8388608&e);)e<<=1,n-=8388608;e&=-8388609,n+=947912704,s[t]=e|n}for(let t=1024;t<2048;++t)s[t]=939524096+(t-1024<<13);for(let t=1;t<31;++t)a[t]=t<<23;a[31]=1199570944,a[32]=2147483648;for(let t=33;t<63;++t)a[t]=2147483648+(t-32<<23);a[63]=3347054592;for(let t=1;t<64;++t)32!==t&&(o[t]=1024);return{floatView:e,uint32View:n,baseTable:i,shiftTable:r,mantissaTable:s,exponentTable:a,offsetTable:o}}function os(t){Math.abs(t)>65504&&console.warn("THREE.DataUtils.toHalfFloat(): Value out of range."),t=Yn(t,-65504,65504),ss.floatView[0]=t;const e=ss.uint32View[0],n=e>>23&511;return ss.baseTable[n]+((8388607&e)>>ss.shiftTable[n])}function ls(t){const e=t>>10;return ss.uint32View[0]=ss.mantissaTable[ss.offsetTable[e]+(1023&t)]+ss.exponentTable[e],ss.floatView[0]}const cs={toHalfFloat:os,fromHalfFloat:ls},hs=new Li,us=new ti;class ds{constructor(t,e,n=!1){if(Array.isArray(t))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,this.name="",this.array=t,this.itemSize=e,this.count=void 0!==t?t.length/e:0,this.normalized=n,this.usage=Cn,this.updateRanges=[],this.gpuType=Lt,this.version=0}onUploadCallback(){}set needsUpdate(t){!0===t&&this.version++}setUsage(t){return this.usage=t,this}addUpdateRange(t,e){this.updateRanges.push({start:t,count:e})}clearUpdateRanges(){this.updateRanges.length=0}copy(t){return this.name=t.name,this.array=new t.array.constructor(t.array),this.itemSize=t.itemSize,this.count=t.count,this.normalized=t.normalized,this.usage=t.usage,this.gpuType=t.gpuType,this}copyAt(t,e,n){t*=this.itemSize,n*=e.itemSize;for(let i=0,r=this.itemSize;i0&&(t.userData=this.userData),void 0!==this.parameters){const e=this.parameters;for(const n in e)void 0!==e[n]&&(t[n]=e[n]);return t}t.data={attributes:{}};const e=this.index;null!==e&&(t.data.index={type:e.array.constructor.name,array:Array.prototype.slice.call(e.array)});const n=this.attributes;for(const e in n){const i=n[e];t.data.attributes[e]=i.toJSON(t.data)}const i={};let r=!1;for(const e in this.morphAttributes){const n=this.morphAttributes[e],s=[];for(let e=0,i=n.length;e0&&(i[e]=s,r=!0)}r&&(t.data.morphAttributes=i,t.data.morphTargetsRelative=this.morphTargetsRelative);const s=this.groups;s.length>0&&(t.data.groups=JSON.parse(JSON.stringify(s)));const a=this.boundingSphere;return null!==a&&(t.data.boundingSphere={center:a.center.toArray(),radius:a.radius}),t}clone(){return(new this.constructor).copy(this)}copy(t){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const e={};this.name=t.name;const n=t.index;null!==n&&this.setIndex(n.clone(e));const i=t.attributes;for(const t in i){const n=i[t];this.setAttribute(t,n.clone(e))}const r=t.morphAttributes;for(const t in r){const n=[],i=r[t];for(let t=0,r=i.length;t0){const n=t[e[0]];if(void 0!==n){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=n.length;t(t.far-t.near)**2)return}Ps.copy(r).invert(),Is.copy(t.ray).applyMatrix4(Ps),null!==n.boundingBox&&!1===Is.intersectsBox(n.boundingBox)||this._computeIntersections(t,e,Is)}}_computeIntersections(t,e,n){let i;const r=this.geometry,s=this.material,a=r.index,o=r.attributes.position,l=r.attributes.uv,c=r.attributes.uv1,h=r.attributes.normal,u=r.groups,d=r.drawRange;if(null!==a)if(Array.isArray(s))for(let r=0,o=u.length;rn.far?null:{distance:c,point:ks.clone(),object:t}}(t,e,n,i,Ns,Ds,Os,zs);if(h){const t=new Li;Zr.getBarycoord(zs,Ns,Ds,Os,t),r&&(h.uv=Zr.getInterpolatedAttribute(r,o,l,c,t,new ti)),s&&(h.uv1=Zr.getInterpolatedAttribute(s,o,l,c,t,new ti)),a&&(h.normal=Zr.getInterpolatedAttribute(a,o,l,c,t,new Li),h.normal.dot(i.direction)>0&&h.normal.multiplyScalar(-1));const e={a:o,b:l,c:c,normal:new Li,materialIndex:0};Zr.getNormal(Ns,Ds,Os,e.normal),h.face=e,h.barycoord=t}return h}class Gs extends Cs{constructor(t=1,e=1,n=1,i=1,r=1,s=1){super(),this.type="BoxGeometry",this.parameters={width:t,height:e,depth:n,widthSegments:i,heightSegments:r,depthSegments:s};const a=this;i=Math.floor(i),r=Math.floor(r),s=Math.floor(s);const o=[],l=[],c=[],h=[];let u=0,d=0;function p(t,e,n,i,r,s,p,m,f,g,v){const _=s/f,x=p/g,y=s/2,M=p/2,S=m/2,b=f+1,w=g+1;let T=0,E=0;const A=new Li;for(let s=0;s0?1:-1,c.push(A.x,A.y,A.z),h.push(o/f),h.push(1-s/g),T+=1}}for(let t=0;t0&&(e.defines=this.defines),e.vertexShader=this.vertexShader,e.fragmentShader=this.fragmentShader,e.lights=this.lights,e.clipping=this.clipping;const n={};for(const t in this.extensions)!0===this.extensions[t]&&(n[t]=!0);return Object.keys(n).length>0&&(e.extensions=n),e}}class Zs extends Dr{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new lr,this.projectionMatrix=new lr,this.projectionMatrixInverse=new lr,this.coordinateSystem=kn}copy(t,e){return super.copy(t,e),this.matrixWorldInverse.copy(t.matrixWorldInverse),this.projectionMatrix.copy(t.projectionMatrix),this.projectionMatrixInverse.copy(t.projectionMatrixInverse),this.coordinateSystem=t.coordinateSystem,this}getWorldDirection(t){return super.getWorldDirection(t).negate()}updateMatrixWorld(t){super.updateMatrixWorld(t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(t,e){super.updateWorldMatrix(t,e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return(new this.constructor).copy(this)}}const Js=new Li,Ks=new ti,$s=new ti;class Qs extends Zs{constructor(t=50,e=1,n=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=t,this.zoom=1,this.near=n,this.far=i,this.focus=10,this.aspect=e,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(t,e){return super.copy(t,e),this.fov=t.fov,this.zoom=t.zoom,this.near=t.near,this.far=t.far,this.focus=t.focus,this.aspect=t.aspect,this.view=null===t.view?null:Object.assign({},t.view),this.filmGauge=t.filmGauge,this.filmOffset=t.filmOffset,this}setFocalLength(t){const e=.5*this.getFilmHeight()/t;this.fov=2*jn*Math.atan(e),this.updateProjectionMatrix()}getFocalLength(){const t=Math.tan(.5*Xn*this.fov);return.5*this.getFilmHeight()/t}getEffectiveFOV(){return 2*jn*Math.atan(Math.tan(.5*Xn*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(t,e,n){Js.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),e.set(Js.x,Js.y).multiplyScalar(-t/Js.z),Js.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),n.set(Js.x,Js.y).multiplyScalar(-t/Js.z)}getViewSize(t,e){return this.getViewBounds(t,Ks,$s),e.subVectors($s,Ks)}setViewOffset(t,e,n,i,r,s){this.aspect=t/e,null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=t,this.view.fullHeight=e,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=s,this.updateProjectionMatrix()}clearViewOffset(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const t=this.near;let e=t*Math.tan(.5*Xn*this.fov)/this.zoom,n=2*e,i=this.aspect*n,r=-.5*i;const s=this.view;if(null!==this.view&&this.view.enabled){const t=s.fullWidth,a=s.fullHeight;r+=s.offsetX*i/t,e-=s.offsetY*n/a,i*=s.width/t,n*=s.height/a}const a=this.filmOffset;0!==a&&(r+=t*a/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,e,e-n,t,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(t){const e=super.toJSON(t);return e.object.fov=this.fov,e.object.zoom=this.zoom,e.object.near=this.near,e.object.far=this.far,e.object.focus=this.focus,e.object.aspect=this.aspect,null!==this.view&&(e.object.view=Object.assign({},this.view)),e.object.filmGauge=this.filmGauge,e.object.filmOffset=this.filmOffset,e}}const ta=-90;class ea extends Dr{constructor(t,e,n){super(),this.type="CubeCamera",this.renderTarget=n,this.coordinateSystem=null,this.activeMipmapLevel=0;const i=new Qs(ta,1,t,e);i.layers=this.layers,this.add(i);const r=new Qs(ta,1,t,e);r.layers=this.layers,this.add(r);const s=new Qs(ta,1,t,e);s.layers=this.layers,this.add(s);const a=new Qs(ta,1,t,e);a.layers=this.layers,this.add(a);const o=new Qs(ta,1,t,e);o.layers=this.layers,this.add(o);const l=new Qs(ta,1,t,e);l.layers=this.layers,this.add(l)}updateCoordinateSystem(){const t=this.coordinateSystem,e=this.children.concat(),[n,i,r,s,a,o]=e;for(const t of e)this.remove(t);if(t===kn)n.up.set(0,1,0),n.lookAt(1,0,0),i.up.set(0,1,0),i.lookAt(-1,0,0),r.up.set(0,0,-1),r.lookAt(0,1,0),s.up.set(0,0,1),s.lookAt(0,-1,0),a.up.set(0,1,0),a.lookAt(0,0,1),o.up.set(0,1,0),o.lookAt(0,0,-1);else{if(t!==Vn)throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+t);n.up.set(0,-1,0),n.lookAt(-1,0,0),i.up.set(0,-1,0),i.lookAt(1,0,0),r.up.set(0,0,1),r.lookAt(0,1,0),s.up.set(0,0,-1),s.lookAt(0,-1,0),a.up.set(0,-1,0),a.lookAt(0,0,1),o.up.set(0,-1,0),o.lookAt(0,0,-1)}for(const t of e)this.add(t),t.updateMatrixWorld()}update(t,e){null===this.parent&&this.updateMatrixWorld();const{renderTarget:n,activeMipmapLevel:i}=this;this.coordinateSystem!==t.coordinateSystem&&(this.coordinateSystem=t.coordinateSystem,this.updateCoordinateSystem());const[r,s,a,o,l,c]=this.children,h=t.getRenderTarget(),u=t.getActiveCubeFace(),d=t.getActiveMipmapLevel(),p=t.xr.enabled;t.xr.enabled=!1;const m=n.texture.generateMipmaps;n.texture.generateMipmaps=!1,t.setRenderTarget(n,0,i),t.render(e,r),t.setRenderTarget(n,1,i),t.render(e,s),t.setRenderTarget(n,2,i),t.render(e,a),t.setRenderTarget(n,3,i),t.render(e,o),t.setRenderTarget(n,4,i),t.render(e,l),n.texture.generateMipmaps=m,t.setRenderTarget(n,5,i),t.render(e,c),t.setRenderTarget(h,u,d),t.xr.enabled=p,n.texture.needsPMREMUpdate=!0}}class na extends bi{constructor(t,e,n,i,r,s,a,o,l,c){super(t=void 0!==t?t:[],e=void 0!==e?e:lt,n,i,r,s,a,o,l,c),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(t){this.image=t}}class ia extends Ei{constructor(t=1,e={}){super(t,t,e),this.isWebGLCubeRenderTarget=!0;const n={width:t,height:t,depth:1},i=[n,n,n,n,n,n];this.texture=new na(i,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.format,e.type,e.anisotropy,e.colorSpace),this.texture.isRenderTargetTexture=!0,this.texture.generateMipmaps=void 0!==e.generateMipmaps&&e.generateMipmaps,this.texture.minFilter=void 0!==e.minFilter?e.minFilter:Mt}fromEquirectangularTexture(t,e){this.texture.type=e.type,this.texture.colorSpace=e.colorSpace,this.texture.generateMipmaps=e.generateMipmaps,this.texture.minFilter=e.minFilter,this.texture.magFilter=e.magFilter;const n={uniforms:{tEquirect:{value:null}},vertexShader:"\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\tvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\n\t\t\t\t\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvWorldDirection = transformDirection( position, modelMatrix );\n\n\t\t\t\t\t#include \n\t\t\t\t\t#include \n\n\t\t\t\t}\n\t\t\t",fragmentShader:"\n\n\t\t\t\tuniform sampler2D tEquirect;\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\t#include \n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvec3 direction = normalize( vWorldDirection );\n\n\t\t\t\t\tvec2 sampleUV = equirectUv( direction );\n\n\t\t\t\t\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\n\t\t\t\t}\n\t\t\t"},i=new Gs(5,5,5),r=new Ys({name:"CubemapFromEquirect",uniforms:Ws(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:d,blending:0});r.uniforms.tEquirect.value=e;const s=new Vs(i,r),a=e.minFilter;e.minFilter===wt&&(e.minFilter=Mt);return new ea(1,10,this).update(t,s),e.minFilter=a,s.geometry.dispose(),s.material.dispose(),this}clear(t,e,n,i){const r=t.getRenderTarget();for(let r=0;r<6;r++)t.setRenderTarget(this,r),t.clear(e,n,i);t.setRenderTarget(r)}}const ra=new Li,sa=new Li,aa=new ei;class oa{constructor(t=new Li(1,0,0),e=0){this.isPlane=!0,this.normal=t,this.constant=e}set(t,e){return this.normal.copy(t),this.constant=e,this}setComponents(t,e,n,i){return this.normal.set(t,e,n),this.constant=i,this}setFromNormalAndCoplanarPoint(t,e){return this.normal.copy(t),this.constant=-e.dot(this.normal),this}setFromCoplanarPoints(t,e,n){const i=ra.subVectors(n,e).cross(sa.subVectors(t,e)).normalize();return this.setFromNormalAndCoplanarPoint(i,t),this}copy(t){return this.normal.copy(t.normal),this.constant=t.constant,this}normalize(){const t=1/this.normal.length();return this.normal.multiplyScalar(t),this.constant*=t,this}negate(){return this.constant*=-1,this.normal.negate(),this}distanceToPoint(t){return this.normal.dot(t)+this.constant}distanceToSphere(t){return this.distanceToPoint(t.center)-t.radius}projectPoint(t,e){return e.copy(t).addScaledVector(this.normal,-this.distanceToPoint(t))}intersectLine(t,e){const n=t.delta(ra),i=this.normal.dot(n);if(0===i)return 0===this.distanceToPoint(t.start)?e.copy(t.start):null;const r=-(t.start.dot(this.normal)+this.constant)/i;return r<0||r>1?null:e.copy(t.start).addScaledVector(n,r)}intersectsLine(t){const e=this.distanceToPoint(t.start),n=this.distanceToPoint(t.end);return e<0&&n>0||n<0&&e>0}intersectsBox(t){return t.intersectsPlane(this)}intersectsSphere(t){return t.intersectsPlane(this)}coplanarPoint(t){return t.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(t,e){const n=e||aa.getNormalMatrix(t),i=this.coplanarPoint(ra).applyMatrix4(t),r=this.normal.applyMatrix3(n).normalize();return this.constant=-i.dot(r),this}translate(t){return this.constant-=t.dot(this.normal),this}equals(t){return t.normal.equals(this.normal)&&t.constant===this.constant}clone(){return(new this.constructor).copy(this)}}const la=new Qi,ca=new Li;class ha{constructor(t=new oa,e=new oa,n=new oa,i=new oa,r=new oa,s=new oa){this.planes=[t,e,n,i,r,s]}set(t,e,n,i,r,s){const a=this.planes;return a[0].copy(t),a[1].copy(e),a[2].copy(n),a[3].copy(i),a[4].copy(r),a[5].copy(s),this}copy(t){const e=this.planes;for(let n=0;n<6;n++)e[n].copy(t.planes[n]);return this}setFromProjectionMatrix(t,e=2e3){const n=this.planes,i=t.elements,r=i[0],s=i[1],a=i[2],o=i[3],l=i[4],c=i[5],h=i[6],u=i[7],d=i[8],p=i[9],m=i[10],f=i[11],g=i[12],v=i[13],_=i[14],x=i[15];if(n[0].setComponents(o-r,u-l,f-d,x-g).normalize(),n[1].setComponents(o+r,u+l,f+d,x+g).normalize(),n[2].setComponents(o+s,u+c,f+p,x+v).normalize(),n[3].setComponents(o-s,u-c,f-p,x-v).normalize(),n[4].setComponents(o-a,u-h,f-m,x-_).normalize(),e===kn)n[5].setComponents(o+a,u+h,f+m,x+_).normalize();else{if(e!==Vn)throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+e);n[5].setComponents(a,h,m,_).normalize()}return this}intersectsObject(t){if(void 0!==t.boundingSphere)null===t.boundingSphere&&t.computeBoundingSphere(),la.copy(t.boundingSphere).applyMatrix4(t.matrixWorld);else{const e=t.geometry;null===e.boundingSphere&&e.computeBoundingSphere(),la.copy(e.boundingSphere).applyMatrix4(t.matrixWorld)}return this.intersectsSphere(la)}intersectsSprite(t){return la.center.set(0,0,0),la.radius=.7071067811865476,la.applyMatrix4(t.matrixWorld),this.intersectsSphere(la)}intersectsSphere(t){const e=this.planes,n=t.center,i=-t.radius;for(let t=0;t<6;t++){if(e[t].distanceToPoint(n)0?t.max.x:t.min.x,ca.y=i.normal.y>0?t.max.y:t.min.y,ca.z=i.normal.z>0?t.max.z:t.min.z,i.distanceToPoint(ca)<0)return!1}return!0}containsPoint(t){const e=this.planes;for(let n=0;n<6;n++)if(e[n].distanceToPoint(t)<0)return!1;return!0}clone(){return(new this.constructor).copy(this)}}function ua(){let t=null,e=!1,n=null,i=null;function r(e,s){n(e,s),i=t.requestAnimationFrame(r)}return{start:function(){!0!==e&&null!==n&&(i=t.requestAnimationFrame(r),e=!0)},stop:function(){t.cancelAnimationFrame(i),e=!1},setAnimationLoop:function(t){n=t},setContext:function(e){t=e}}}function da(t){const e=new WeakMap;return{get:function(t){return t.isInterleavedBufferAttribute&&(t=t.data),e.get(t)},remove:function(n){n.isInterleavedBufferAttribute&&(n=n.data);const i=e.get(n);i&&(t.deleteBuffer(i.buffer),e.delete(n))},update:function(n,i){if(n.isInterleavedBufferAttribute&&(n=n.data),n.isGLBufferAttribute){const t=e.get(n);return void((!t||t.versiont.start-e.start));let e=0;for(let t=1;t 0\n\tvec4 plane;\n\t#ifdef ALPHA_TO_COVERAGE\n\t\tfloat distanceToPlane, distanceGradient;\n\t\tfloat clipOpacity = 1.0;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\tclipOpacity *= smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\tif ( clipOpacity == 0.0 ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tfloat unionClipOpacity = 1.0;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\t\tunionClipOpacity *= 1.0 - smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tclipOpacity *= 1.0 - unionClipOpacity;\n\t\t#endif\n\t\tdiffuseColor.a *= clipOpacity;\n\t\tif ( diffuseColor.a == 0.0 ) discard;\n\t#else\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tbool clipped = true;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tif ( clipped ) discard;\n\t\t#endif\n\t#endif\n#endif",clipping_planes_pars_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif",color_fragment:"#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif",color_pars_fragment:"#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif",color_pars_vertex:"#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )\n\tvarying vec3 vColor;\n#endif",color_vertex:"#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif\n#ifdef USE_BATCHING_COLOR\n\tvec3 batchingColor = getBatchingColor( getIndirectIndex( gl_DrawID ) );\n\tvColor.xyz *= batchingColor.xyz;\n#endif",common:"#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\n#ifdef USE_ALPHAHASH\n\tvarying vec3 vPosition;\n#endif\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}\nvec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n} // validated",cube_uv_reflection_fragment:"#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\thighp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif",defaultnormal_vertex:"vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );\n\ttransformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );\n\ttransformedNormal = bm * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = bm * transformedTangent;\n\t#endif\n#endif\n#ifdef USE_INSTANCING\n\tmat3 im = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) );\n\ttransformedNormal = im * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = im * transformedTangent;\n\t#endif\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\ttransformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif",displacementmap_pars_vertex:"#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif",displacementmap_vertex:"#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif",emissivemap_fragment:"#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif",emissivemap_pars_fragment:"#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif",colorspace_fragment:"gl_FragColor = linearToOutputTexel( gl_FragColor );",colorspace_pars_fragment:"\nconst mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3(\n\tvec3( 0.8224621, 0.177538, 0.0 ),\n\tvec3( 0.0331941, 0.9668058, 0.0 ),\n\tvec3( 0.0170827, 0.0723974, 0.9105199 )\n);\nconst mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.2249401, - 0.2249404, 0.0 ),\n\tvec3( - 0.0420569, 1.0420571, 0.0 ),\n\tvec3( - 0.0196376, - 0.0786361, 1.0982735 )\n);\nvec4 LinearSRGBToLinearDisplayP3( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a );\n}\nvec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a );\n}\nvec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferOETF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}",envmap_fragment:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, envMapRotation * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif",envmap_common_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform mat3 envMapRotation;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif",envmap_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif",envmap_pars_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif",envmap_physical_pars_fragment:"#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, envMapRotation * worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, envMapRotation * reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\treturn getIBLRadiance( viewDir, bentNormal, roughness );\n\t\t\t#else\n\t\t\t\treturn vec3( 0.0 );\n\t\t\t#endif\n\t\t}\n\t#endif\n#endif",envmap_vertex:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif",fog_vertex:"#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif",fog_pars_vertex:"#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif",fog_fragment:"#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, vFogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif",fog_pars_fragment:"#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif",gradientmap_pars_fragment:"#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn vec3( texture2D( gradientMap, coord ).r );\n\t#else\n\t\tvec2 fw = fwidth( coord ) * 0.5;\n\t\treturn mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) );\n\t#endif\n}",lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif",lights_lambert_fragment:"LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;",lights_lambert_pars_fragment:"varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert",lights_pars_begin:"uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif ( cutoffDistance > 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif",lights_toon_fragment:"ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;",lights_toon_pars_fragment:"varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon",lights_phong_fragment:"BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;",lights_phong_pars_fragment:"varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong",lights_physical_fragment:"PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_DISPERSION\n\tmaterial.dispersion = dispersion;\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\t#ifdef USE_ANISOTROPYMAP\n\t\tmat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x );\n\t\tvec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb;\n\t\tvec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b;\n\t#else\n\t\tvec2 anisotropyV = anisotropyVector;\n\t#endif\n\tmaterial.anisotropy = length( anisotropyV );\n\tif( material.anisotropy == 0.0 ) {\n\t\tanisotropyV = vec2( 1.0, 0.0 );\n\t} else {\n\t\tanisotropyV /= material.anisotropy;\n\t\tmaterial.anisotropy = saturate( material.anisotropy );\n\t}\n\tmaterial.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) );\n\tmaterial.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y;\n\tmaterial.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y;\n#endif",lights_physical_pars_fragment:"struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\tfloat dispersion;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\tfloat v = 0.5 / ( gv + gl );\n\t\treturn saturate(v);\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColor;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}",lights_fragment_begin:"\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowIntensity, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometryPosition, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowIntensity, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowIntensity, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif",lights_fragment_maps:"#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tradiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tradiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif",lights_fragment_end:"#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif",logdepthbuf_fragment:"#if defined( USE_LOGDEPTHBUF )\n\tgl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif",logdepthbuf_pars_fragment:"#if defined( USE_LOGDEPTHBUF )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif",logdepthbuf_pars_vertex:"#ifdef USE_LOGDEPTHBUF\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif",logdepthbuf_vertex:"#ifdef USE_LOGDEPTHBUF\n\tvFragDepth = 1.0 + gl_Position.w;\n\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n#endif",map_fragment:"#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif",map_pars_fragment:"#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif",map_particle_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t#if defined( USE_POINTS_UV )\n\t\tvec2 uv = vUv;\n\t#else\n\t\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif",map_particle_pars_fragment:"#if defined( USE_POINTS_UV )\n\tvarying vec2 vUv;\n#else\n\t#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t\tuniform mat3 uvTransform;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif",metalnessmap_fragment:"float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif",metalnessmap_pars_fragment:"#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif",morphinstance_vertex:"#ifdef USE_INSTANCING_MORPH\n\tfloat morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\tfloat morphTargetBaseInfluence = texelFetch( morphTexture, ivec2( 0, gl_InstanceID ), 0 ).r;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\tmorphTargetInfluences[i] = texelFetch( morphTexture, ivec2( i + 1, gl_InstanceID ), 0 ).r;\n\t}\n#endif",morphcolor_vertex:"#if defined( USE_MORPHCOLORS )\n\tvColor *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t#if defined( USE_COLOR_ALPHA )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ];\n\t\t#elif defined( USE_COLOR )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ];\n\t\t#endif\n\t}\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\n\t}\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n\t#ifndef USE_INSTANCING_MORPH\n\t\tuniform float morphTargetBaseInfluence;\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\t#endif\n\tuniform sampler2DArray morphTargetsTexture;\n\tuniform ivec2 morphTargetsTextureSize;\n\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\n\t\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\n\t\tint y = texelIndex / morphTargetsTextureSize.x;\n\t\tint x = texelIndex - y * morphTargetsTextureSize.x;\n\t\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\n\t\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\n\t}\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t}\n#endif",normal_fragment_begin:"float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal *= faceDirection;\n\t#endif\n#endif\n#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY )\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn = getTangentFrame( - vViewPosition, normal,\n\t\t#if defined( USE_NORMALMAP )\n\t\t\tvNormalMapUv\n\t\t#elif defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tvClearcoatNormalMapUv\n\t\t#else\n\t\t\tvUv\n\t\t#endif\n\t\t);\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn[0] *= faceDirection;\n\t\ttbn[1] *= faceDirection;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;",normal_fragment_maps:"#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif",normal_pars_fragment:"#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif",normal_pars_vertex:"#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif",normal_vertex:"#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif",normalmap_pars_fragment:"#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef USE_NORMALMAP_OBJECTSPACE\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) )\n\tmat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( uv.st );\n\t\tvec2 st1 = dFdy( uv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det );\n\t\treturn mat3( T * scale, B * scale, N );\n\t}\n#endif",clearcoat_normal_fragment_begin:"#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif",clearcoat_normal_fragment_maps:"#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\tclearcoatNormal = normalize( tbn2 * clearcoatMapN );\n#endif",clearcoat_pars_fragment:"#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif",iridescence_pars_fragment:"#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif",opaque_fragment:"#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );",packing:"vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;const float ShiftRight8 = 1. / 256.;\nconst float Inv255 = 1. / 255.;\nconst vec4 PackFactors = vec4( 1.0, 256.0, 256.0 * 256.0, 256.0 * 256.0 * 256.0 );\nconst vec2 UnpackFactors2 = vec2( UnpackDownscale, 1.0 / PackFactors.g );\nconst vec3 UnpackFactors3 = vec3( UnpackDownscale / PackFactors.rg, 1.0 / PackFactors.b );\nconst vec4 UnpackFactors4 = vec4( UnpackDownscale / PackFactors.rgb, 1.0 / PackFactors.a );\nvec4 packDepthToRGBA( const in float v ) {\n\tif( v <= 0.0 )\n\t\treturn vec4( 0., 0., 0., 0. );\n\tif( v >= 1.0 )\n\t\treturn vec4( 1., 1., 1., 1. );\n\tfloat vuf;\n\tfloat af = modf( v * PackFactors.a, vuf );\n\tfloat bf = modf( vuf * ShiftRight8, vuf );\n\tfloat gf = modf( vuf * ShiftRight8, vuf );\n\treturn vec4( vuf * Inv255, gf * PackUpscale, bf * PackUpscale, af );\n}\nvec3 packDepthToRGB( const in float v ) {\n\tif( v <= 0.0 )\n\t\treturn vec3( 0., 0., 0. );\n\tif( v >= 1.0 )\n\t\treturn vec3( 1., 1., 1. );\n\tfloat vuf;\n\tfloat bf = modf( v * PackFactors.b, vuf );\n\tfloat gf = modf( vuf * ShiftRight8, vuf );\n\treturn vec3( vuf * Inv255, gf * PackUpscale, bf );\n}\nvec2 packDepthToRG( const in float v ) {\n\tif( v <= 0.0 )\n\t\treturn vec2( 0., 0. );\n\tif( v >= 1.0 )\n\t\treturn vec2( 1., 1. );\n\tfloat vuf;\n\tfloat gf = modf( v * 256., vuf );\n\treturn vec2( vuf * Inv255, gf );\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors4 );\n}\nfloat unpackRGBToDepth( const in vec3 v ) {\n\treturn dot( v, UnpackFactors3 );\n}\nfloat unpackRGToDepth( const in vec2 v ) {\n\treturn v.r * UnpackFactors2.r + v.g * UnpackFactors2.g;\n}\nvec4 pack2HalfToRGBA( const in vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( const in vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn depth * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * depth - far );\n}",premultiplied_alpha_fragment:"#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif",project_vertex:"vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_BATCHING\n\tmvPosition = batchingMatrix * mvPosition;\n#endif\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;",dithering_fragment:"#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif",dithering_pars_fragment:"#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif",roughnessmap_fragment:"float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif",roughnessmap_pars_fragment:"#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif",shadowmap_pars_fragment:"#if NUM_SPOT_LIGHT_COORDS > 0\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n\tuniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn mix( 1.0, shadow, shadowIntensity );\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tfloat shadow = 1.0;\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\t\n\t\tfloat lightToPositionLength = length( lightToPosition );\n\t\tif ( lightToPositionLength - shadowCameraFar <= 0.0 && lightToPositionLength - shadowCameraNear >= 0.0 ) {\n\t\t\tfloat dp = ( lightToPositionLength - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\t\tdp += shadowBias;\n\t\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\t\tshadow = (\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t\t) * ( 1.0 / 9.0 );\n\t\t\t#else\n\t\t\t\tshadow = texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t\t#endif\n\t\t}\n\t\treturn mix( 1.0, shadow, shadowIntensity );\n\t}\n#endif",shadowmap_pars_vertex:"#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif",shadowmap_vertex:"#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif",shadowmask_pars_fragment:"float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowIntensity, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowIntensity, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowIntensity, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}",skinbase_vertex:"#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tint size = textureSize( boneTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif",skinning_vertex:"#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif",skinnormal_vertex:"#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif",specularmap_fragment:"float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vSpecularMapUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif",specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif",tonemapping_fragment:"#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif",tonemapping_pars_fragment:"#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn saturate( toneMappingExposure * color );\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 CineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nconst mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.6605, - 0.1246, - 0.0182 ),\n\tvec3( - 0.5876, 1.1329, - 0.1006 ),\n\tvec3( - 0.0728, - 0.0083, 1.1187 )\n);\nconst mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(\n\tvec3( 0.6274, 0.0691, 0.0164 ),\n\tvec3( 0.3293, 0.9195, 0.0880 ),\n\tvec3( 0.0433, 0.0113, 0.8956 )\n);\nvec3 agxDefaultContrastApprox( vec3 x ) {\n\tvec3 x2 = x * x;\n\tvec3 x4 = x2 * x2;\n\treturn + 15.5 * x4 * x2\n\t\t- 40.14 * x4 * x\n\t\t+ 31.96 * x4\n\t\t- 6.868 * x2 * x\n\t\t+ 0.4298 * x2\n\t\t+ 0.1191 * x\n\t\t- 0.00232;\n}\nvec3 AgXToneMapping( vec3 color ) {\n\tconst mat3 AgXInsetMatrix = mat3(\n\t\tvec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),\n\t\tvec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),\n\t\tvec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 )\n\t);\n\tconst mat3 AgXOutsetMatrix = mat3(\n\t\tvec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ),\n\t\tvec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ),\n\t\tvec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 )\n\t);\n\tconst float AgxMinEv = - 12.47393;\tconst float AgxMaxEv = 4.026069;\n\tcolor *= toneMappingExposure;\n\tcolor = LINEAR_SRGB_TO_LINEAR_REC2020 * color;\n\tcolor = AgXInsetMatrix * color;\n\tcolor = max( color, 1e-10 );\tcolor = log2( color );\n\tcolor = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv );\n\tcolor = clamp( color, 0.0, 1.0 );\n\tcolor = agxDefaultContrastApprox( color );\n\tcolor = AgXOutsetMatrix * color;\n\tcolor = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) );\n\tcolor = LINEAR_REC2020_TO_LINEAR_SRGB * color;\n\tcolor = clamp( color, 0.0, 1.0 );\n\treturn color;\n}\nvec3 NeutralToneMapping( vec3 color ) {\n\tconst float StartCompression = 0.8 - 0.04;\n\tconst float Desaturation = 0.15;\n\tcolor *= toneMappingExposure;\n\tfloat x = min( color.r, min( color.g, color.b ) );\n\tfloat offset = x < 0.08 ? x - 6.25 * x * x : 0.04;\n\tcolor -= offset;\n\tfloat peak = max( color.r, max( color.g, color.b ) );\n\tif ( peak < StartCompression ) return color;\n\tfloat d = 1. - StartCompression;\n\tfloat newPeak = 1. - d * d / ( peak + d - StartCompression );\n\tcolor *= newPeak / peak;\n\tfloat g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. );\n\treturn mix( color, vec3( newPeak ), g );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }",transmission_fragment:"#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmitted = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.dispersion, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission );\n#endif",transmission_pars_fragment:"#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tfloat w0( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 );\n\t}\n\tfloat w1( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 );\n\t}\n\tfloat w2( float a ){\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 );\n\t}\n\tfloat w3( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * a );\n\t}\n\tfloat g0( float a ) {\n\t\treturn w0( a ) + w1( a );\n\t}\n\tfloat g1( float a ) {\n\t\treturn w2( a ) + w3( a );\n\t}\n\tfloat h0( float a ) {\n\t\treturn - 1.0 + w1( a ) / ( w0( a ) + w1( a ) );\n\t}\n\tfloat h1( float a ) {\n\t\treturn 1.0 + w3( a ) / ( w2( a ) + w3( a ) );\n\t}\n\tvec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) {\n\t\tuv = uv * texelSize.zw + 0.5;\n\t\tvec2 iuv = floor( uv );\n\t\tvec2 fuv = fract( uv );\n\t\tfloat g0x = g0( fuv.x );\n\t\tfloat g1x = g1( fuv.x );\n\t\tfloat h0x = h0( fuv.x );\n\t\tfloat h1x = h1( fuv.x );\n\t\tfloat h0y = h0( fuv.y );\n\t\tfloat h1y = h1( fuv.y );\n\t\tvec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\treturn g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) +\n\t\t\tg1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) );\n\t}\n\tvec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) {\n\t\tvec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) );\n\t\tvec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) );\n\t\tvec2 fLodSizeInv = 1.0 / fLodSize;\n\t\tvec2 cLodSizeInv = 1.0 / cLodSize;\n\t\tvec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) );\n\t\tvec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) );\n\t\treturn mix( fSample, cSample, fract( lod ) );\n\t}\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\treturn textureBicubic( transmissionSamplerMap, fragCoord.xy, lod );\n\t}\n\tvec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn vec3( 1.0 );\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float dispersion, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec4 transmittedLight;\n\t\tvec3 transmittance;\n\t\t#ifdef USE_DISPERSION\n\t\t\tfloat halfSpread = ( ior - 1.0 ) * 0.025 * dispersion;\n\t\t\tvec3 iors = vec3( ior - halfSpread, ior, ior + halfSpread );\n\t\t\tfor ( int i = 0; i < 3; i ++ ) {\n\t\t\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, iors[ i ], modelMatrix );\n\t\t\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\t\n\t\t\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\t\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\t\t\trefractionCoords += 1.0;\n\t\t\t\trefractionCoords /= 2.0;\n\t\t\n\t\t\t\tvec4 transmissionSample = getTransmissionSample( refractionCoords, roughness, iors[ i ] );\n\t\t\t\ttransmittedLight[ i ] = transmissionSample[ i ];\n\t\t\t\ttransmittedLight.a += transmissionSample.a;\n\t\t\t\ttransmittance[ i ] = diffuseColor[ i ] * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance )[ i ];\n\t\t\t}\n\t\t\ttransmittedLight.a /= 3.0;\n\t\t\n\t\t#else\n\t\t\n\t\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\t\trefractionCoords += 1.0;\n\t\t\trefractionCoords /= 2.0;\n\t\t\ttransmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\t\ttransmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\t\n\t\t#endif\n\t\tvec3 attenuatedColor = transmittance * transmittedLight.rgb;\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\tfloat transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0;\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor );\n\t}\n#endif",uv_pars_fragment:"#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif",uv_pars_vertex:"#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tuniform mat3 mapTransform;\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform mat3 alphaMapTransform;\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tuniform mat3 lightMapTransform;\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tuniform mat3 aoMapTransform;\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tuniform mat3 bumpMapTransform;\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tuniform mat3 normalMapTransform;\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tuniform mat3 displacementMapTransform;\n\tvarying vec2 vDisplacementMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tuniform mat3 emissiveMapTransform;\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tuniform mat3 metalnessMapTransform;\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tuniform mat3 roughnessMapTransform;\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tuniform mat3 anisotropyMapTransform;\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tuniform mat3 clearcoatMapTransform;\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform mat3 clearcoatNormalMapTransform;\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform mat3 clearcoatRoughnessMapTransform;\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tuniform mat3 sheenColorMapTransform;\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tuniform mat3 sheenRoughnessMapTransform;\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tuniform mat3 iridescenceMapTransform;\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform mat3 iridescenceThicknessMapTransform;\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tuniform mat3 specularMapTransform;\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tuniform mat3 specularColorMapTransform;\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tuniform mat3 specularIntensityMapTransform;\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif",uv_vertex:"#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvUv = vec3( uv, 1 ).xy;\n#endif\n#ifdef USE_MAP\n\tvMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ALPHAMAP\n\tvAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_LIGHTMAP\n\tvLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_AOMAP\n\tvAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_BUMPMAP\n\tvBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_NORMALMAP\n\tvNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tvDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_METALNESSMAP\n\tvMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULARMAP\n\tvSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tvTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_THICKNESSMAP\n\tvThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy;\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_BATCHING\n\t\tworldPosition = batchingMatrix * worldPosition;\n\t#endif\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif",background_vert:"varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}",background_frag:"uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}",backgroundCube_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}",backgroundCube_frag:"#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nuniform mat3 backgroundRotation;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, backgroundRotation * vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, backgroundRotation * vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}",cube_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}",cube_frag:"uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}",depth_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}",depth_frag:"#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#elif DEPTH_PACKING == 3202\n\t\tgl_FragColor = vec4( packDepthToRGB( fragCoordZ ), 1.0 );\n\t#elif DEPTH_PACKING == 3203\n\t\tgl_FragColor = vec4( packDepthToRG( fragCoordZ ), 0.0, 1.0 );\n\t#endif\n}",distanceRGBA_vert:"#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}",distanceRGBA_frag:"#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}",equirect_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}",equirect_frag:"uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include \n\t#include \n}",linedashed_vert:"uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",linedashed_frag:"uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshbasic_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshbasic_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_vert:"#define LAMBERT\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_frag:"#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshmatcap_vert:"#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}",meshmatcap_frag:"#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshnormal_vert:"#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}",meshnormal_frag:"#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( 0.0, 0.0, 0.0, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), diffuseColor.a );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}",meshphong_vert:"#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphong_frag:"#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphysical_vert:"#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}",meshphysical_frag:"#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define USE_SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef USE_SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULAR_COLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_DISPERSION\n\tuniform float dispersion;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\tuniform vec2 anisotropyVector;\n\t#ifdef USE_ANISOTROPYMAP\n\t\tuniform sampler2D anisotropyMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshtoon_vert:"#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}",meshtoon_frag:"#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",points_vert:"uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef USE_POINTS_UV\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\nvoid main() {\n\t#ifdef USE_POINTS_UV\n\t\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}",points_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",shadow_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",shadow_frag:"uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}",sprite_vert:"uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix[ 3 ];\n\tvec2 scale = vec2( length( modelMatrix[ 0 ].xyz ), length( modelMatrix[ 1 ].xyz ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}",sprite_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"},fa={common:{diffuse:{value:new ts(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new ei},alphaMap:{value:null},alphaMapTransform:{value:new ei},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new ei}},envmap:{envMap:{value:null},envMapRotation:{value:new ei},flipEnvMap:{value:-1},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new ei}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new ei}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new ei},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new ei},normalScale:{value:new ti(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new ei},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new ei}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new ei}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new ei}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new ts(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotLightMap:{value:[]},spotShadowMap:{value:[]},spotLightMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null}},points:{diffuse:{value:new ts(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new ei},alphaTest:{value:0},uvTransform:{value:new ei}},sprite:{diffuse:{value:new ts(16777215)},opacity:{value:1},center:{value:new ti(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new ei},alphaMap:{value:null},alphaMapTransform:{value:new ei},alphaTest:{value:0}}},ga={basic:{uniforms:Xs([fa.common,fa.specularmap,fa.envmap,fa.aomap,fa.lightmap,fa.fog]),vertexShader:ma.meshbasic_vert,fragmentShader:ma.meshbasic_frag},lambert:{uniforms:Xs([fa.common,fa.specularmap,fa.envmap,fa.aomap,fa.lightmap,fa.emissivemap,fa.bumpmap,fa.normalmap,fa.displacementmap,fa.fog,fa.lights,{emissive:{value:new ts(0)}}]),vertexShader:ma.meshlambert_vert,fragmentShader:ma.meshlambert_frag},phong:{uniforms:Xs([fa.common,fa.specularmap,fa.envmap,fa.aomap,fa.lightmap,fa.emissivemap,fa.bumpmap,fa.normalmap,fa.displacementmap,fa.fog,fa.lights,{emissive:{value:new ts(0)},specular:{value:new ts(1118481)},shininess:{value:30}}]),vertexShader:ma.meshphong_vert,fragmentShader:ma.meshphong_frag},standard:{uniforms:Xs([fa.common,fa.envmap,fa.aomap,fa.lightmap,fa.emissivemap,fa.bumpmap,fa.normalmap,fa.displacementmap,fa.roughnessmap,fa.metalnessmap,fa.fog,fa.lights,{emissive:{value:new ts(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:ma.meshphysical_vert,fragmentShader:ma.meshphysical_frag},toon:{uniforms:Xs([fa.common,fa.aomap,fa.lightmap,fa.emissivemap,fa.bumpmap,fa.normalmap,fa.displacementmap,fa.gradientmap,fa.fog,fa.lights,{emissive:{value:new ts(0)}}]),vertexShader:ma.meshtoon_vert,fragmentShader:ma.meshtoon_frag},matcap:{uniforms:Xs([fa.common,fa.bumpmap,fa.normalmap,fa.displacementmap,fa.fog,{matcap:{value:null}}]),vertexShader:ma.meshmatcap_vert,fragmentShader:ma.meshmatcap_frag},points:{uniforms:Xs([fa.points,fa.fog]),vertexShader:ma.points_vert,fragmentShader:ma.points_frag},dashed:{uniforms:Xs([fa.common,fa.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:ma.linedashed_vert,fragmentShader:ma.linedashed_frag},depth:{uniforms:Xs([fa.common,fa.displacementmap]),vertexShader:ma.depth_vert,fragmentShader:ma.depth_frag},normal:{uniforms:Xs([fa.common,fa.bumpmap,fa.normalmap,fa.displacementmap,{opacity:{value:1}}]),vertexShader:ma.meshnormal_vert,fragmentShader:ma.meshnormal_frag},sprite:{uniforms:Xs([fa.sprite,fa.fog]),vertexShader:ma.sprite_vert,fragmentShader:ma.sprite_frag},background:{uniforms:{uvTransform:{value:new ei},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:ma.background_vert,fragmentShader:ma.background_frag},backgroundCube:{uniforms:{envMap:{value:null},flipEnvMap:{value:-1},backgroundBlurriness:{value:0},backgroundIntensity:{value:1},backgroundRotation:{value:new ei}},vertexShader:ma.backgroundCube_vert,fragmentShader:ma.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:ma.cube_vert,fragmentShader:ma.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:ma.equirect_vert,fragmentShader:ma.equirect_frag},distanceRGBA:{uniforms:Xs([fa.common,fa.displacementmap,{referencePosition:{value:new Li},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:ma.distanceRGBA_vert,fragmentShader:ma.distanceRGBA_frag},shadow:{uniforms:Xs([fa.lights,fa.fog,{color:{value:new ts(0)},opacity:{value:1}}]),vertexShader:ma.shadow_vert,fragmentShader:ma.shadow_frag}};ga.physical={uniforms:Xs([ga.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new ei},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new ei},clearcoatNormalScale:{value:new ti(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new ei},dispersion:{value:0},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new ei},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new ei},sheen:{value:0},sheenColor:{value:new ts(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new ei},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new ei},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new ei},transmissionSamplerSize:{value:new ti},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new ei},attenuationDistance:{value:0},attenuationColor:{value:new ts(0)},specularColor:{value:new ts(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new ei},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new ei},anisotropyVector:{value:new ti},anisotropyMap:{value:null},anisotropyMapTransform:{value:new ei}}]),vertexShader:ma.meshphysical_vert,fragmentShader:ma.meshphysical_frag};const va={r:0,b:0,g:0},_a=new _r,xa=new lr;function ya(t,e,n,i,r,s,a){const o=new ts(0);let l,c,h=!0===s?0:1,p=null,m=0,f=null;function g(t){let i=!0===t.isScene?t.background:null;if(i&&i.isTexture){i=(t.backgroundBlurriness>0?n:e).get(i)}return i}function v(e,n){e.getRGB(va,js(t)),i.buffers.color.setClear(va.r,va.g,va.b,n,a)}return{getClearColor:function(){return o},setClearColor:function(t,e=1){o.set(t),h=e,v(o,h)},getClearAlpha:function(){return h},setClearAlpha:function(t){h=t,v(o,h)},render:function(e){let n=!1;const r=g(e);null===r?v(o,h):r&&r.isColor&&(v(r,1),n=!0);const s=t.xr.getEnvironmentBlendMode();"additive"===s?i.buffers.color.setClear(0,0,0,1,a):"alpha-blend"===s&&i.buffers.color.setClear(0,0,0,0,a),(t.autoClear||n)&&(i.buffers.depth.setTest(!0),i.buffers.depth.setMask(!0),i.buffers.color.setMask(!0),t.clear(t.autoClearColor,t.autoClearDepth,t.autoClearStencil))},addToRenderList:function(e,n){const i=g(n);i&&(i.isCubeTexture||i.mapping===dt)?(void 0===c&&(c=new Vs(new Gs(1,1,1),new Ys({name:"BackgroundCubeMaterial",uniforms:Ws(ga.backgroundCube.uniforms),vertexShader:ga.backgroundCube.vertexShader,fragmentShader:ga.backgroundCube.fragmentShader,side:d,depthTest:!1,depthWrite:!1,fog:!1})),c.geometry.deleteAttribute("normal"),c.geometry.deleteAttribute("uv"),c.onBeforeRender=function(t,e,n){this.matrixWorld.copyPosition(n.matrixWorld)},Object.defineProperty(c.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),r.update(c)),_a.copy(n.backgroundRotation),_a.x*=-1,_a.y*=-1,_a.z*=-1,i.isCubeTexture&&!1===i.isRenderTargetTexture&&(_a.y*=-1,_a.z*=-1),c.material.uniforms.envMap.value=i,c.material.uniforms.flipEnvMap.value=i.isCubeTexture&&!1===i.isRenderTargetTexture?-1:1,c.material.uniforms.backgroundBlurriness.value=n.backgroundBlurriness,c.material.uniforms.backgroundIntensity.value=n.backgroundIntensity,c.material.uniforms.backgroundRotation.value.setFromMatrix4(xa.makeRotationFromEuler(_a)),c.material.toneMapped=mi.getTransfer(i.colorSpace)!==en,p===i&&m===i.version&&f===t.toneMapping||(c.material.needsUpdate=!0,p=i,m=i.version,f=t.toneMapping),c.layers.enableAll(),e.unshift(c,c.geometry,c.material,0,0,null)):i&&i.isTexture&&(void 0===l&&(l=new Vs(new pa(2,2),new Ys({name:"BackgroundMaterial",uniforms:Ws(ga.background.uniforms),vertexShader:ga.background.vertexShader,fragmentShader:ga.background.fragmentShader,side:u,depthTest:!1,depthWrite:!1,fog:!1})),l.geometry.deleteAttribute("normal"),Object.defineProperty(l.material,"map",{get:function(){return this.uniforms.t2D.value}}),r.update(l)),l.material.uniforms.t2D.value=i,l.material.uniforms.backgroundIntensity.value=n.backgroundIntensity,l.material.toneMapped=mi.getTransfer(i.colorSpace)!==en,!0===i.matrixAutoUpdate&&i.updateMatrix(),l.material.uniforms.uvTransform.value.copy(i.matrix),p===i&&m===i.version&&f===t.toneMapping||(l.material.needsUpdate=!0,p=i,m=i.version,f=t.toneMapping),l.layers.enableAll(),e.unshift(l,l.geometry,l.material,0,0,null))}}}function Ma(t,e){const n=t.getParameter(t.MAX_VERTEX_ATTRIBS),i={},r=c(null);let s=r,a=!1;function o(e){return t.bindVertexArray(e)}function l(e){return t.deleteVertexArray(e)}function c(t){const e=[],i=[],r=[];for(let t=0;t=0){const n=r[e];let i=a[e];if(void 0===i&&("instanceMatrix"===e&&t.instanceMatrix&&(i=t.instanceMatrix),"instanceColor"===e&&t.instanceColor&&(i=t.instanceColor)),void 0===n)return!0;if(n.attribute!==i)return!0;if(i&&n.data!==i.data)return!0;o++}}return s.attributesNum!==o||s.index!==i}(n,f,l,g),v&&function(t,e,n,i){const r={},a=e.attributes;let o=0;const l=n.getAttributes();for(const e in l){if(l[e].location>=0){let n=a[e];void 0===n&&("instanceMatrix"===e&&t.instanceMatrix&&(n=t.instanceMatrix),"instanceColor"===e&&t.instanceColor&&(n=t.instanceColor));const i={};i.attribute=n,n&&n.data&&(i.data=n.data),r[e]=i,o++}}s.attributes=r,s.attributesNum=o,s.index=i}(n,f,l,g),null!==g&&e.update(g,t.ELEMENT_ARRAY_BUFFER),(v||a)&&(a=!1,function(n,i,r,s){h();const a=s.attributes,o=r.getAttributes(),l=i.defaultAttributeValues;for(const i in o){const r=o[i];if(r.location>=0){let o=a[i];if(void 0===o&&("instanceMatrix"===i&&n.instanceMatrix&&(o=n.instanceMatrix),"instanceColor"===i&&n.instanceColor&&(o=n.instanceColor)),void 0!==o){const i=o.normalized,a=o.itemSize,l=e.get(o);if(void 0===l)continue;const c=l.buffer,h=l.type,p=l.bytesPerElement,f=h===t.INT||h===t.UNSIGNED_INT||o.gpuType===Pt;if(o.isInterleavedBufferAttribute){const e=o.data,l=e.stride,g=o.offset;if(e.isInstancedInterleavedBuffer){for(let t=0;t0&&t.getShaderPrecisionFormat(t.FRAGMENT_SHADER,t.HIGH_FLOAT).precision>0)return"highp";e="mediump"}return"mediump"===e&&t.getShaderPrecisionFormat(t.VERTEX_SHADER,t.MEDIUM_FLOAT).precision>0&&t.getShaderPrecisionFormat(t.FRAGMENT_SHADER,t.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}let a=void 0!==n.precision?n.precision:"highp";const o=s(a);o!==a&&(console.warn("THREE.WebGLRenderer:",a,"not supported, using",o,"instead."),a=o);const l=!0===n.logarithmicDepthBuffer,c=!0===n.reverseDepthBuffer&&e.has("EXT_clip_control");if(!0===c){const t=e.get("EXT_clip_control");t.clipControlEXT(t.LOWER_LEFT_EXT,t.ZERO_TO_ONE_EXT)}const h=t.getParameter(t.MAX_TEXTURE_IMAGE_UNITS),u=t.getParameter(t.MAX_VERTEX_TEXTURE_IMAGE_UNITS);return{isWebGL2:!0,getMaxAnisotropy:function(){if(void 0!==r)return r;if(!0===e.has("EXT_texture_filter_anisotropic")){const n=e.get("EXT_texture_filter_anisotropic");r=t.getParameter(n.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else r=0;return r},getMaxPrecision:s,textureFormatReadable:function(e){return e===kt||i.convert(e)===t.getParameter(t.IMPLEMENTATION_COLOR_READ_FORMAT)},textureTypeReadable:function(n){const r=n===Ut&&(e.has("EXT_color_buffer_half_float")||e.has("EXT_color_buffer_float"));return!(n!==Et&&i.convert(n)!==t.getParameter(t.IMPLEMENTATION_COLOR_READ_TYPE)&&n!==Lt&&!r)},precision:a,logarithmicDepthBuffer:l,reverseDepthBuffer:c,maxTextures:h,maxVertexTextures:u,maxTextureSize:t.getParameter(t.MAX_TEXTURE_SIZE),maxCubemapSize:t.getParameter(t.MAX_CUBE_MAP_TEXTURE_SIZE),maxAttributes:t.getParameter(t.MAX_VERTEX_ATTRIBS),maxVertexUniforms:t.getParameter(t.MAX_VERTEX_UNIFORM_VECTORS),maxVaryings:t.getParameter(t.MAX_VARYING_VECTORS),maxFragmentUniforms:t.getParameter(t.MAX_FRAGMENT_UNIFORM_VECTORS),vertexTextures:u>0,maxSamples:t.getParameter(t.MAX_SAMPLES)}}function wa(t){const e=this;let n=null,i=0,r=!1,s=!1;const a=new oa,o=new ei,l={value:null,needsUpdate:!1};function c(t,n,i,r){const s=null!==t?t.length:0;let c=null;if(0!==s){if(c=l.value,!0!==r||null===c){const e=i+4*s,r=n.matrixWorldInverse;o.getNormalMatrix(r),(null===c||c.length0);e.numPlanes=i,e.numIntersection=0}();else{const t=s?0:i,e=4*t;let r=m.clippingState||null;l.value=r,r=c(u,o,e,h);for(let t=0;t!==e;++t)r[t]=n[t];m.clippingState=r,this.numIntersection=d?this.numPlanes:0,this.numPlanes+=t}}}function Ta(t){let e=new WeakMap;function n(t,e){return e===ht?t.mapping=lt:e===ut&&(t.mapping=ct),t}function i(t){const n=t.target;n.removeEventListener("dispose",i);const r=e.get(n);void 0!==r&&(e.delete(n),r.dispose())}return{get:function(r){if(r&&r.isTexture){const s=r.mapping;if(s===ht||s===ut){if(e.has(r)){return n(e.get(r).texture,r.mapping)}{const s=r.image;if(s&&s.height>0){const a=new ia(s.height);return a.fromEquirectangularTexture(t,r),e.set(r,a),r.addEventListener("dispose",i),n(a.texture,r.mapping)}return null}}}return r},dispose:function(){e=new WeakMap}}}class Ea extends Zs{constructor(t=-1,e=1,n=1,i=-1,r=.1,s=2e3){super(),this.isOrthographicCamera=!0,this.type="OrthographicCamera",this.zoom=1,this.view=null,this.left=t,this.right=e,this.top=n,this.bottom=i,this.near=r,this.far=s,this.updateProjectionMatrix()}copy(t,e){return super.copy(t,e),this.left=t.left,this.right=t.right,this.top=t.top,this.bottom=t.bottom,this.near=t.near,this.far=t.far,this.zoom=t.zoom,this.view=null===t.view?null:Object.assign({},t.view),this}setViewOffset(t,e,n,i,r,s){null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=t,this.view.fullHeight=e,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=s,this.updateProjectionMatrix()}clearViewOffset(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const t=(this.right-this.left)/(2*this.zoom),e=(this.top-this.bottom)/(2*this.zoom),n=(this.right+this.left)/2,i=(this.top+this.bottom)/2;let r=n-t,s=n+t,a=i+e,o=i-e;if(null!==this.view&&this.view.enabled){const t=(this.right-this.left)/this.view.fullWidth/this.zoom,e=(this.top-this.bottom)/this.view.fullHeight/this.zoom;r+=t*this.view.offsetX,s=r+t*this.view.width,a-=e*this.view.offsetY,o=a-e*this.view.height}this.projectionMatrix.makeOrthographic(r,s,a,o,this.near,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(t){const e=super.toJSON(t);return e.object.zoom=this.zoom,e.object.left=this.left,e.object.right=this.right,e.object.top=this.top,e.object.bottom=this.bottom,e.object.near=this.near,e.object.far=this.far,null!==this.view&&(e.object.view=Object.assign({},this.view)),e}}const Aa=[.125,.215,.35,.446,.526,.582],Ra=20,Ca=new Ea,Pa=new ts;let Ia=null,La=0,Ua=0,Na=!1;const Da=(1+Math.sqrt(5))/2,Oa=1/Da,Fa=[new Li(-Da,Oa,0),new Li(Da,Oa,0),new Li(-Oa,0,Da),new Li(Oa,0,Da),new Li(0,Da,-Oa),new Li(0,Da,Oa),new Li(-1,1,-1),new Li(1,1,-1),new Li(-1,1,1),new Li(1,1,1)];class Ba{constructor(t){this._renderer=t,this._pingPongRenderTarget=null,this._lodMax=0,this._cubeSize=0,this._lodPlanes=[],this._sizeLods=[],this._sigmas=[],this._blurMaterial=null,this._cubemapMaterial=null,this._equirectMaterial=null,this._compileMaterial(this._blurMaterial)}fromScene(t,e=0,n=.1,i=100){Ia=this._renderer.getRenderTarget(),La=this._renderer.getActiveCubeFace(),Ua=this._renderer.getActiveMipmapLevel(),Na=this._renderer.xr.enabled,this._renderer.xr.enabled=!1,this._setSize(256);const r=this._allocateTargets();return r.depthBuffer=!0,this._sceneToCubeUV(t,n,i,r),e>0&&this._blur(r,0,0,e),this._applyPMREM(r),this._cleanup(r),r}fromEquirectangular(t,e=null){return this._fromTexture(t,e)}fromCubemap(t,e=null){return this._fromTexture(t,e)}compileCubemapShader(){null===this._cubemapMaterial&&(this._cubemapMaterial=Ha(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){null===this._equirectMaterial&&(this._equirectMaterial=Va(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),null!==this._cubemapMaterial&&this._cubemapMaterial.dispose(),null!==this._equirectMaterial&&this._equirectMaterial.dispose()}_setSize(t){this._lodMax=Math.floor(Math.log2(t)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){null!==this._blurMaterial&&this._blurMaterial.dispose(),null!==this._pingPongRenderTarget&&this._pingPongRenderTarget.dispose();for(let t=0;tt-4?o=Aa[a-t+4-1]:0===a&&(o=0),i.push(o);const l=1/(s-2),c=-l,h=1+l,u=[c,c,h,c,h,h,c,c,h,h,c,h],d=6,p=6,m=3,f=2,g=1,v=new Float32Array(m*p*d),_=new Float32Array(f*p*d),x=new Float32Array(g*p*d);for(let t=0;t2?0:-1,i=[e,n,0,e+2/3,n,0,e+2/3,n+1,0,e,n,0,e+2/3,n+1,0,e,n+1,0];v.set(i,m*p*t),_.set(u,f*p*t);const r=[t,t,t,t,t,t];x.set(r,g*p*t)}const y=new Cs;y.setAttribute("position",new ds(v,m)),y.setAttribute("uv",new ds(_,f)),y.setAttribute("faceIndex",new ds(x,g)),e.push(y),r>4&&r--}return{lodPlanes:e,sizeLods:n,sigmas:i}}(i)),this._blurMaterial=function(t,e,n){const i=new Float32Array(Ra),r=new Li(0,1,0),s=new Ys({name:"SphericalGaussianBlur",defines:{n:Ra,CUBEUV_TEXEL_WIDTH:1/e,CUBEUV_TEXEL_HEIGHT:1/n,CUBEUV_MAX_MIP:`${t}.0`},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:i},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:r}},vertexShader:Ga(),fragmentShader:"\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform sampler2D envMap;\n\t\t\tuniform int samples;\n\t\t\tuniform float weights[ n ];\n\t\t\tuniform bool latitudinal;\n\t\t\tuniform float dTheta;\n\t\t\tuniform float mipInt;\n\t\t\tuniform vec3 poleAxis;\n\n\t\t\t#define ENVMAP_TYPE_CUBE_UV\n\t\t\t#include \n\n\t\t\tvec3 getSample( float theta, vec3 axis ) {\n\n\t\t\t\tfloat cosTheta = cos( theta );\n\t\t\t\t// Rodrigues' axis-angle rotation\n\t\t\t\tvec3 sampleDirection = vOutputDirection * cosTheta\n\t\t\t\t\t+ cross( axis, vOutputDirection ) * sin( theta )\n\t\t\t\t\t+ axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );\n\n\t\t\t\treturn bilinearCubeUV( envMap, sampleDirection, mipInt );\n\n\t\t\t}\n\n\t\t\tvoid main() {\n\n\t\t\t\tvec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );\n\n\t\t\t\tif ( all( equal( axis, vec3( 0.0 ) ) ) ) {\n\n\t\t\t\t\taxis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );\n\n\t\t\t\t}\n\n\t\t\t\taxis = normalize( axis );\n\n\t\t\t\tgl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t\t\t\tgl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );\n\n\t\t\t\tfor ( int i = 1; i < n; i++ ) {\n\n\t\t\t\t\tif ( i >= samples ) {\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfloat theta = dTheta * float( i );\n\t\t\t\t\tgl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );\n\t\t\t\t\tgl_FragColor.rgb += weights[ i ] * getSample( theta, axis );\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t",blending:0,depthTest:!1,depthWrite:!1});return s}(i,t,e)}return i}_compileMaterial(t){const e=new Vs(this._lodPlanes[0],t);this._renderer.compile(e,Ca)}_sceneToCubeUV(t,e,n,i){const r=new Qs(90,1,e,n),s=[1,-1,1,1,1,1],a=[1,1,1,-1,-1,-1],o=this._renderer,l=o.autoClear,c=o.toneMapping;o.getClearColor(Pa),o.toneMapping=K,o.autoClear=!1;const h=new rs({name:"PMREM.Background",side:d,depthWrite:!1,depthTest:!1}),u=new Vs(new Gs,h);let p=!1;const m=t.background;m?m.isColor&&(h.color.copy(m),t.background=null,p=!0):(h.color.copy(Pa),p=!0);for(let e=0;e<6;e++){const n=e%3;0===n?(r.up.set(0,s[e],0),r.lookAt(a[e],0,0)):1===n?(r.up.set(0,0,s[e]),r.lookAt(0,a[e],0)):(r.up.set(0,s[e],0),r.lookAt(0,0,a[e]));const l=this._cubeSize;ka(i,n*l,e>2?l:0,l,l),o.setRenderTarget(i),p&&o.render(u,r),o.render(t,r)}u.geometry.dispose(),u.material.dispose(),o.toneMapping=c,o.autoClear=l,t.background=m}_textureToCubeUV(t,e){const n=this._renderer,i=t.mapping===lt||t.mapping===ct;i?(null===this._cubemapMaterial&&(this._cubemapMaterial=Ha()),this._cubemapMaterial.uniforms.flipEnvMap.value=!1===t.isRenderTargetTexture?-1:1):null===this._equirectMaterial&&(this._equirectMaterial=Va());const r=i?this._cubemapMaterial:this._equirectMaterial,s=new Vs(this._lodPlanes[0],r);r.uniforms.envMap.value=t;const a=this._cubeSize;ka(e,0,0,3*a,2*a),n.setRenderTarget(e),n.render(s,Ca)}_applyPMREM(t){const e=this._renderer,n=e.autoClear;e.autoClear=!1;const i=this._lodPlanes.length;for(let e=1;eRa&&console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${m} samples when the maximum is set to 20`);const f=[];let g=0;for(let t=0;tv-4?i-v+4:0),4*(this._cubeSize-_),3*_,2*_),o.setRenderTarget(e),o.render(c,Ca)}}function za(t,e,n){const i=new Ei(t,e,n);return i.texture.mapping=dt,i.texture.name="PMREM.cubeUv",i.scissorTest=!0,i}function ka(t,e,n,i,r){t.viewport.set(e,n,i,r),t.scissor.set(e,n,i,r)}function Va(){return new Ys({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:Ga(),fragmentShader:"\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform sampler2D envMap;\n\n\t\t\t#include \n\n\t\t\tvoid main() {\n\n\t\t\t\tvec3 outputDirection = normalize( vOutputDirection );\n\t\t\t\tvec2 uv = equirectUv( outputDirection );\n\n\t\t\t\tgl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 );\n\n\t\t\t}\n\t\t",blending:0,depthTest:!1,depthWrite:!1})}function Ha(){return new Ys({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:Ga(),fragmentShader:"\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tuniform float flipEnvMap;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform samplerCube envMap;\n\n\t\t\tvoid main() {\n\n\t\t\t\tgl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) );\n\n\t\t\t}\n\t\t",blending:0,depthTest:!1,depthWrite:!1})}function Ga(){return"\n\n\t\tprecision mediump float;\n\t\tprecision mediump int;\n\n\t\tattribute float faceIndex;\n\n\t\tvarying vec3 vOutputDirection;\n\n\t\t// RH coordinate system; PMREM face-indexing convention\n\t\tvec3 getDirection( vec2 uv, float face ) {\n\n\t\t\tuv = 2.0 * uv - 1.0;\n\n\t\t\tvec3 direction = vec3( uv, 1.0 );\n\n\t\t\tif ( face == 0.0 ) {\n\n\t\t\t\tdirection = direction.zyx; // ( 1, v, u ) pos x\n\n\t\t\t} else if ( face == 1.0 ) {\n\n\t\t\t\tdirection = direction.xzy;\n\t\t\t\tdirection.xz *= -1.0; // ( -u, 1, -v ) pos y\n\n\t\t\t} else if ( face == 2.0 ) {\n\n\t\t\t\tdirection.x *= -1.0; // ( -u, v, 1 ) pos z\n\n\t\t\t} else if ( face == 3.0 ) {\n\n\t\t\t\tdirection = direction.zyx;\n\t\t\t\tdirection.xz *= -1.0; // ( -1, v, -u ) neg x\n\n\t\t\t} else if ( face == 4.0 ) {\n\n\t\t\t\tdirection = direction.xzy;\n\t\t\t\tdirection.xy *= -1.0; // ( -u, -1, v ) neg y\n\n\t\t\t} else if ( face == 5.0 ) {\n\n\t\t\t\tdirection.z *= -1.0; // ( u, v, -1 ) neg z\n\n\t\t\t}\n\n\t\t\treturn direction;\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tvOutputDirection = getDirection( uv, faceIndex );\n\t\t\tgl_Position = vec4( position, 1.0 );\n\n\t\t}\n\t"}function Wa(t){let e=new WeakMap,n=null;function i(t){const n=t.target;n.removeEventListener("dispose",i);const r=e.get(n);void 0!==r&&(e.delete(n),r.dispose())}return{get:function(r){if(r&&r.isTexture){const s=r.mapping,a=s===ht||s===ut,o=s===lt||s===ct;if(a||o){let s=e.get(r);const l=void 0!==s?s.texture.pmremVersion:0;if(r.isRenderTargetTexture&&r.pmremVersion!==l)return null===n&&(n=new Ba(t)),s=a?n.fromEquirectangular(r,s):n.fromCubemap(r,s),s.texture.pmremVersion=r.pmremVersion,e.set(r,s),s.texture;if(void 0!==s)return s.texture;{const l=r.image;return a&&l&&l.height>0||o&&l&&function(t){let e=0;const n=6;for(let i=0;ie.maxTextureSize&&(y=Math.ceil(x/e.maxTextureSize),x=e.maxTextureSize);const M=new Float32Array(x*y*4*h),S=new Ai(M,x,y,h);S.type=Lt,S.needsUpdate=!0;const b=4*_;for(let T=0;T0)return t;const r=e*n;let s=io[r];if(void 0===s&&(s=new Float32Array(r),io[r]=s),0!==e){i.toArray(s,0);for(let i=1,r=0;i!==e;++i)r+=n,t[i].toArray(s,r)}return s}function co(t,e){if(t.length!==e.length)return!1;for(let n=0,i=t.length;n":" "} ${r}: ${n[t]}`)}return i.join("\n")}(t.getShaderSource(e),i)}return r}function ll(t,e){const n=function(t){const e=mi.getPrimaries(mi.workingColorSpace),n=mi.getPrimaries(t);let i;switch(e===n?i="":e===rn&&n===nn?i="LinearDisplayP3ToLinearSRGB":e===nn&&n===rn&&(i="LinearSRGBToLinearDisplayP3"),t){case Ke:case Qe:return[i,"LinearTransferOETF"];case Je:case $e:return[i,"sRGBTransferOETF"];default:return console.warn("THREE.WebGLProgram: Unsupported color space:",t),[i,"LinearTransferOETF"]}}(e);return`vec4 ${t}( vec4 value ) { return ${n[0]}( ${n[1]}( value ) ); }`}function cl(t,e){let n;switch(e){case $:n="Linear";break;case Q:n="Reinhard";break;case tt:n="Cineon";break;case et:n="ACESFilmic";break;case it:n="AgX";break;case rt:n="Neutral";break;case nt:n="Custom";break;default:console.warn("THREE.WebGLProgram: Unsupported toneMapping:",e),n="Linear"}return"vec3 "+t+"( vec3 color ) { return "+n+"ToneMapping( color ); }"}const hl=new Li;function ul(){mi.getLuminanceCoefficients(hl);return["float luminance( const in vec3 rgb ) {",`\tconst vec3 weights = vec3( ${hl.x.toFixed(4)}, ${hl.y.toFixed(4)}, ${hl.z.toFixed(4)} );`,"\treturn dot( weights, rgb );","}"].join("\n")}function dl(t){return""!==t}function pl(t,e){const n=e.numSpotLightShadows+e.numSpotLightMaps-e.numSpotLightShadowsWithMaps;return t.replace(/NUM_DIR_LIGHTS/g,e.numDirLights).replace(/NUM_SPOT_LIGHTS/g,e.numSpotLights).replace(/NUM_SPOT_LIGHT_MAPS/g,e.numSpotLightMaps).replace(/NUM_SPOT_LIGHT_COORDS/g,n).replace(/NUM_RECT_AREA_LIGHTS/g,e.numRectAreaLights).replace(/NUM_POINT_LIGHTS/g,e.numPointLights).replace(/NUM_HEMI_LIGHTS/g,e.numHemiLights).replace(/NUM_DIR_LIGHT_SHADOWS/g,e.numDirLightShadows).replace(/NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g,e.numSpotLightShadowsWithMaps).replace(/NUM_SPOT_LIGHT_SHADOWS/g,e.numSpotLightShadows).replace(/NUM_POINT_LIGHT_SHADOWS/g,e.numPointLightShadows)}function ml(t,e){return t.replace(/NUM_CLIPPING_PLANES/g,e.numClippingPlanes).replace(/UNION_CLIPPING_PLANES/g,e.numClippingPlanes-e.numClipIntersection)}const fl=/^[ \t]*#include +<([\w\d./]+)>/gm;function gl(t){return t.replace(fl,_l)}const vl=new Map;function _l(t,e){let n=ma[e];if(void 0===n){const t=vl.get(e);if(void 0===t)throw new Error("Can not resolve #include <"+e+">");n=ma[t],console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',e,t)}return gl(n)}const xl=/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;function yl(t){return t.replace(xl,Ml)}function Ml(t,e,n,i){let r="";for(let t=parseInt(e);t0&&(x+="\n"),y=["#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,v].filter(dl).join("\n"),y.length>0&&(y+="\n")):(x=[Sl(n),"#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,v,n.extensionClipCullDistance?"#define USE_CLIP_DISTANCE":"",n.batching?"#define USE_BATCHING":"",n.batchingColor?"#define USE_BATCHING_COLOR":"",n.instancing?"#define USE_INSTANCING":"",n.instancingColor?"#define USE_INSTANCING_COLOR":"",n.instancingMorph?"#define USE_INSTANCING_MORPH":"",n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.map?"#define USE_MAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+p:"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",n.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",n.displacementMap?"#define USE_DISPLACEMENTMAP":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.anisotropy?"#define USE_ANISOTROPY":"",n.anisotropyMap?"#define USE_ANISOTROPYMAP":"",n.clearcoatMap?"#define USE_CLEARCOATMAP":"",n.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",n.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",n.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.alphaHash?"#define USE_ALPHAHASH":"",n.transmission?"#define USE_TRANSMISSION":"",n.transmissionMap?"#define USE_TRANSMISSIONMAP":"",n.thicknessMap?"#define USE_THICKNESSMAP":"",n.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",n.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",n.mapUv?"#define MAP_UV "+n.mapUv:"",n.alphaMapUv?"#define ALPHAMAP_UV "+n.alphaMapUv:"",n.lightMapUv?"#define LIGHTMAP_UV "+n.lightMapUv:"",n.aoMapUv?"#define AOMAP_UV "+n.aoMapUv:"",n.emissiveMapUv?"#define EMISSIVEMAP_UV "+n.emissiveMapUv:"",n.bumpMapUv?"#define BUMPMAP_UV "+n.bumpMapUv:"",n.normalMapUv?"#define NORMALMAP_UV "+n.normalMapUv:"",n.displacementMapUv?"#define DISPLACEMENTMAP_UV "+n.displacementMapUv:"",n.metalnessMapUv?"#define METALNESSMAP_UV "+n.metalnessMapUv:"",n.roughnessMapUv?"#define ROUGHNESSMAP_UV "+n.roughnessMapUv:"",n.anisotropyMapUv?"#define ANISOTROPYMAP_UV "+n.anisotropyMapUv:"",n.clearcoatMapUv?"#define CLEARCOATMAP_UV "+n.clearcoatMapUv:"",n.clearcoatNormalMapUv?"#define CLEARCOAT_NORMALMAP_UV "+n.clearcoatNormalMapUv:"",n.clearcoatRoughnessMapUv?"#define CLEARCOAT_ROUGHNESSMAP_UV "+n.clearcoatRoughnessMapUv:"",n.iridescenceMapUv?"#define IRIDESCENCEMAP_UV "+n.iridescenceMapUv:"",n.iridescenceThicknessMapUv?"#define IRIDESCENCE_THICKNESSMAP_UV "+n.iridescenceThicknessMapUv:"",n.sheenColorMapUv?"#define SHEEN_COLORMAP_UV "+n.sheenColorMapUv:"",n.sheenRoughnessMapUv?"#define SHEEN_ROUGHNESSMAP_UV "+n.sheenRoughnessMapUv:"",n.specularMapUv?"#define SPECULARMAP_UV "+n.specularMapUv:"",n.specularColorMapUv?"#define SPECULAR_COLORMAP_UV "+n.specularColorMapUv:"",n.specularIntensityMapUv?"#define SPECULAR_INTENSITYMAP_UV "+n.specularIntensityMapUv:"",n.transmissionMapUv?"#define TRANSMISSIONMAP_UV "+n.transmissionMapUv:"",n.thicknessMapUv?"#define THICKNESSMAP_UV "+n.thicknessMapUv:"",n.vertexTangents&&!1===n.flatShading?"#define USE_TANGENT":"",n.vertexColors?"#define USE_COLOR":"",n.vertexAlphas?"#define USE_COLOR_ALPHA":"",n.vertexUv1s?"#define USE_UV1":"",n.vertexUv2s?"#define USE_UV2":"",n.vertexUv3s?"#define USE_UV3":"",n.pointsUvs?"#define USE_POINTS_UV":"",n.flatShading?"#define FLAT_SHADED":"",n.skinning?"#define USE_SKINNING":"",n.morphTargets?"#define USE_MORPHTARGETS":"",n.morphNormals&&!1===n.flatShading?"#define USE_MORPHNORMALS":"",n.morphColors?"#define USE_MORPHCOLORS":"",n.morphTargetsCount>0?"#define MORPHTARGETS_TEXTURE_STRIDE "+n.morphTextureStride:"",n.morphTargetsCount>0?"#define MORPHTARGETS_COUNT "+n.morphTargetsCount:"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+u:"",n.sizeAttenuation?"#define USE_SIZEATTENUATION":"",n.numLightProbes>0?"#define USE_LIGHT_PROBES":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.reverseDepthBuffer?"#define USE_REVERSEDEPTHBUF":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING","\tattribute mat4 instanceMatrix;","#endif","#ifdef USE_INSTANCING_COLOR","\tattribute vec3 instanceColor;","#endif","#ifdef USE_INSTANCING_MORPH","\tuniform sampler2D morphTexture;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_UV1","\tattribute vec2 uv1;","#endif","#ifdef USE_UV2","\tattribute vec2 uv2;","#endif","#ifdef USE_UV3","\tattribute vec2 uv3;","#endif","#ifdef USE_TANGENT","\tattribute vec4 tangent;","#endif","#if defined( USE_COLOR_ALPHA )","\tattribute vec4 color;","#elif defined( USE_COLOR )","\tattribute vec3 color;","#endif","#ifdef USE_SKINNING","\tattribute vec4 skinIndex;","\tattribute vec4 skinWeight;","#endif","\n"].filter(dl).join("\n"),y=[Sl(n),"#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,v,n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.alphaToCoverage?"#define ALPHA_TO_COVERAGE":"",n.map?"#define USE_MAP":"",n.matcap?"#define USE_MATCAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+d:"",n.envMap?"#define "+p:"",n.envMap?"#define "+m:"",f?"#define CUBEUV_TEXEL_WIDTH "+f.texelWidth:"",f?"#define CUBEUV_TEXEL_HEIGHT "+f.texelHeight:"",f?"#define CUBEUV_MAX_MIP "+f.maxMip+".0":"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",n.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.anisotropy?"#define USE_ANISOTROPY":"",n.anisotropyMap?"#define USE_ANISOTROPYMAP":"",n.clearcoat?"#define USE_CLEARCOAT":"",n.clearcoatMap?"#define USE_CLEARCOATMAP":"",n.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.dispersion?"#define USE_DISPERSION":"",n.iridescence?"#define USE_IRIDESCENCE":"",n.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",n.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",n.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.alphaTest?"#define USE_ALPHATEST":"",n.alphaHash?"#define USE_ALPHAHASH":"",n.sheen?"#define USE_SHEEN":"",n.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",n.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",n.transmission?"#define USE_TRANSMISSION":"",n.transmissionMap?"#define USE_TRANSMISSIONMAP":"",n.thicknessMap?"#define USE_THICKNESSMAP":"",n.vertexTangents&&!1===n.flatShading?"#define USE_TANGENT":"",n.vertexColors||n.instancingColor||n.batchingColor?"#define USE_COLOR":"",n.vertexAlphas?"#define USE_COLOR_ALPHA":"",n.vertexUv1s?"#define USE_UV1":"",n.vertexUv2s?"#define USE_UV2":"",n.vertexUv3s?"#define USE_UV3":"",n.pointsUvs?"#define USE_POINTS_UV":"",n.gradientMap?"#define USE_GRADIENTMAP":"",n.flatShading?"#define FLAT_SHADED":"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+u:"",n.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",n.numLightProbes>0?"#define USE_LIGHT_PROBES":"",n.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.reverseDepthBuffer?"#define USE_REVERSEDEPTHBUF":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",n.toneMapping!==K?"#define TONE_MAPPING":"",n.toneMapping!==K?ma.tonemapping_pars_fragment:"",n.toneMapping!==K?cl("toneMapping",n.toneMapping):"",n.dithering?"#define DITHERING":"",n.opaque?"#define OPAQUE":"",ma.colorspace_pars_fragment,ll("linearToOutputTexel",n.outputColorSpace),ul(),n.useDepthPacking?"#define DEPTH_PACKING "+n.depthPacking:"","\n"].filter(dl).join("\n")),a=gl(a),a=pl(a,n),a=ml(a,n),o=gl(o),o=pl(o,n),o=ml(o,n),a=yl(a),o=yl(o),!0!==n.isRawShaderMaterial&&(M="#version 300 es\n",x=[g,"#define attribute in","#define varying out","#define texture2D texture"].join("\n")+"\n"+x,y=["#define varying in",n.glslVersion===zn?"":"layout(location = 0) out highp vec4 pc_fragColor;",n.glslVersion===zn?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join("\n")+"\n"+y);const S=M+x+a,b=M+y+o,w=rl(r,r.VERTEX_SHADER,S),T=rl(r,r.FRAGMENT_SHADER,b);function E(e){if(t.debug.checkShaderErrors){const n=r.getProgramInfoLog(_).trim(),i=r.getShaderInfoLog(w).trim(),s=r.getShaderInfoLog(T).trim();let a=!0,o=!0;if(!1===r.getProgramParameter(_,r.LINK_STATUS))if(a=!1,"function"==typeof t.debug.onShaderError)t.debug.onShaderError(r,_,w,T);else{const t=ol(r,w,"vertex"),i=ol(r,T,"fragment");console.error("THREE.WebGLProgram: Shader Error "+r.getError()+" - VALIDATE_STATUS "+r.getProgramParameter(_,r.VALIDATE_STATUS)+"\n\nMaterial Name: "+e.name+"\nMaterial Type: "+e.type+"\n\nProgram Info Log: "+n+"\n"+t+"\n"+i)}else""!==n?console.warn("THREE.WebGLProgram: Program Info Log:",n):""!==i&&""!==s||(o=!1);o&&(e.diagnostics={runnable:a,programLog:n,vertexShader:{log:i,prefix:x},fragmentShader:{log:s,prefix:y}})}r.deleteShader(w),r.deleteShader(T),A=new il(r,_),R=function(t,e){const n={},i=t.getProgramParameter(e,t.ACTIVE_ATTRIBUTES);for(let r=0;r0,Y=s.clearcoat>0,Z=s.dispersion>0,J=s.iridescence>0,$=s.sheen>0,Q=s.transmission>0,tt=q&&!!s.anisotropyMap,et=Y&&!!s.clearcoatMap,nt=Y&&!!s.clearcoatNormalMap,it=Y&&!!s.clearcoatRoughnessMap,rt=J&&!!s.iridescenceMap,st=J&&!!s.iridescenceThicknessMap,at=$&&!!s.sheenColorMap,ot=$&&!!s.sheenRoughnessMap,lt=!!s.specularMap,ct=!!s.specularColorMap,ht=!!s.specularIntensityMap,ut=Q&&!!s.transmissionMap,pt=Q&&!!s.thicknessMap,mt=!!s.gradientMap,ft=!!s.alphaMap,gt=s.alphaTest>0,vt=!!s.alphaHash,_t=!!s.extensions;let xt=K;s.toneMapped&&(null!==U&&!0!==U.isXRRenderTarget||(xt=t.toneMapping));const yt={shaderID:T,shaderType:s.type,shaderName:s.name,vertexShader:R,fragmentShader:C,defines:s.defines,customVertexShaderID:P,customFragmentShaderID:I,isRawShaderMaterial:!0===s.isRawShaderMaterial,glslVersion:s.glslVersion,precision:f,batching:D,batchingColor:D&&null!==x._colorsTexture,instancing:N,instancingColor:N&&null!==x.instanceColor,instancingMorph:N&&null!==x.morphTexture,supportsVertexTextures:m,outputColorSpace:null===U?t.outputColorSpace:!0===U.isXRRenderTarget?U.texture.colorSpace:Ke,alphaToCoverage:!!s.alphaToCoverage,map:O,matcap:F,envMap:B,envMapMode:B&&b.mapping,envMapCubeUVHeight:w,aoMap:z,lightMap:k,bumpMap:V,normalMap:H,displacementMap:m&&G,emissiveMap:W,normalMapObjectSpace:H&&1===s.normalMapType,normalMapTangentSpace:H&&0===s.normalMapType,metalnessMap:X,roughnessMap:j,anisotropy:q,anisotropyMap:tt,clearcoat:Y,clearcoatMap:et,clearcoatNormalMap:nt,clearcoatRoughnessMap:it,dispersion:Z,iridescence:J,iridescenceMap:rt,iridescenceThicknessMap:st,sheen:$,sheenColorMap:at,sheenRoughnessMap:ot,specularMap:lt,specularColorMap:ct,specularIntensityMap:ht,transmission:Q,transmissionMap:ut,thicknessMap:pt,gradientMap:mt,opaque:!1===s.transparent&&1===s.blending&&!1===s.alphaToCoverage,alphaMap:ft,alphaTest:gt,alphaHash:vt,combine:s.combine,mapUv:O&&v(s.map.channel),aoMapUv:z&&v(s.aoMap.channel),lightMapUv:k&&v(s.lightMap.channel),bumpMapUv:V&&v(s.bumpMap.channel),normalMapUv:H&&v(s.normalMap.channel),displacementMapUv:G&&v(s.displacementMap.channel),emissiveMapUv:W&&v(s.emissiveMap.channel),metalnessMapUv:X&&v(s.metalnessMap.channel),roughnessMapUv:j&&v(s.roughnessMap.channel),anisotropyMapUv:tt&&v(s.anisotropyMap.channel),clearcoatMapUv:et&&v(s.clearcoatMap.channel),clearcoatNormalMapUv:nt&&v(s.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:it&&v(s.clearcoatRoughnessMap.channel),iridescenceMapUv:rt&&v(s.iridescenceMap.channel),iridescenceThicknessMapUv:st&&v(s.iridescenceThicknessMap.channel),sheenColorMapUv:at&&v(s.sheenColorMap.channel),sheenRoughnessMapUv:ot&&v(s.sheenRoughnessMap.channel),specularMapUv:lt&&v(s.specularMap.channel),specularColorMapUv:ct&&v(s.specularColorMap.channel),specularIntensityMapUv:ht&&v(s.specularIntensityMap.channel),transmissionMapUv:ut&&v(s.transmissionMap.channel),thicknessMapUv:pt&&v(s.thicknessMap.channel),alphaMapUv:ft&&v(s.alphaMap.channel),vertexTangents:!!M.attributes.tangent&&(H||q),vertexColors:s.vertexColors,vertexAlphas:!0===s.vertexColors&&!!M.attributes.color&&4===M.attributes.color.itemSize,pointsUvs:!0===x.isPoints&&!!M.attributes.uv&&(O||ft),fog:!!y,useFog:!0===s.fog,fogExp2:!!y&&y.isFogExp2,flatShading:!0===s.flatShading,sizeAttenuation:!0===s.sizeAttenuation,logarithmicDepthBuffer:u,reverseDepthBuffer:p,skinning:!0===x.isSkinnedMesh,morphTargets:void 0!==M.morphAttributes.position,morphNormals:void 0!==M.morphAttributes.normal,morphColors:void 0!==M.morphAttributes.color,morphTargetsCount:A,morphTextureStride:L,numDirLights:o.directional.length,numPointLights:o.point.length,numSpotLights:o.spot.length,numSpotLightMaps:o.spotLightMap.length,numRectAreaLights:o.rectArea.length,numHemiLights:o.hemi.length,numDirLightShadows:o.directionalShadowMap.length,numPointLightShadows:o.pointShadowMap.length,numSpotLightShadows:o.spotShadowMap.length,numSpotLightShadowsWithMaps:o.numSpotLightShadowsWithMaps,numLightProbes:o.numLightProbes,numClippingPlanes:a.numPlanes,numClipIntersection:a.numIntersection,dithering:s.dithering,shadowMapEnabled:t.shadowMap.enabled&&h.length>0,shadowMapType:t.shadowMap.type,toneMapping:xt,decodeVideoTexture:O&&!0===s.map.isVideoTexture&&mi.getTransfer(s.map.colorSpace)===en,premultipliedAlpha:s.premultipliedAlpha,doubleSided:2===s.side,flipSided:s.side===d,useDepthPacking:s.depthPacking>=0,depthPacking:s.depthPacking||0,index0AttributeName:s.index0AttributeName,extensionClipCullDistance:_t&&!0===s.extensions.clipCullDistance&&i.has("WEBGL_clip_cull_distance"),extensionMultiDraw:(_t&&!0===s.extensions.multiDraw||D)&&i.has("WEBGL_multi_draw"),rendererExtensionParallelShaderCompile:i.has("KHR_parallel_shader_compile"),customProgramCacheKey:s.customProgramCacheKey()};return yt.vertexUv1s=c.has(1),yt.vertexUv2s=c.has(2),yt.vertexUv3s=c.has(3),c.clear(),yt},getProgramCacheKey:function(e){const n=[];if(e.shaderID?n.push(e.shaderID):(n.push(e.customVertexShaderID),n.push(e.customFragmentShaderID)),void 0!==e.defines)for(const t in e.defines)n.push(t),n.push(e.defines[t]);return!1===e.isRawShaderMaterial&&(!function(t,e){t.push(e.precision),t.push(e.outputColorSpace),t.push(e.envMapMode),t.push(e.envMapCubeUVHeight),t.push(e.mapUv),t.push(e.alphaMapUv),t.push(e.lightMapUv),t.push(e.aoMapUv),t.push(e.bumpMapUv),t.push(e.normalMapUv),t.push(e.displacementMapUv),t.push(e.emissiveMapUv),t.push(e.metalnessMapUv),t.push(e.roughnessMapUv),t.push(e.anisotropyMapUv),t.push(e.clearcoatMapUv),t.push(e.clearcoatNormalMapUv),t.push(e.clearcoatRoughnessMapUv),t.push(e.iridescenceMapUv),t.push(e.iridescenceThicknessMapUv),t.push(e.sheenColorMapUv),t.push(e.sheenRoughnessMapUv),t.push(e.specularMapUv),t.push(e.specularColorMapUv),t.push(e.specularIntensityMapUv),t.push(e.transmissionMapUv),t.push(e.thicknessMapUv),t.push(e.combine),t.push(e.fogExp2),t.push(e.sizeAttenuation),t.push(e.morphTargetsCount),t.push(e.morphAttributeCount),t.push(e.numDirLights),t.push(e.numPointLights),t.push(e.numSpotLights),t.push(e.numSpotLightMaps),t.push(e.numHemiLights),t.push(e.numRectAreaLights),t.push(e.numDirLightShadows),t.push(e.numPointLightShadows),t.push(e.numSpotLightShadows),t.push(e.numSpotLightShadowsWithMaps),t.push(e.numLightProbes),t.push(e.shadowMapType),t.push(e.toneMapping),t.push(e.numClippingPlanes),t.push(e.numClipIntersection),t.push(e.depthPacking)}(n,e),function(t,e){o.disableAll(),e.supportsVertexTextures&&o.enable(0);e.instancing&&o.enable(1);e.instancingColor&&o.enable(2);e.instancingMorph&&o.enable(3);e.matcap&&o.enable(4);e.envMap&&o.enable(5);e.normalMapObjectSpace&&o.enable(6);e.normalMapTangentSpace&&o.enable(7);e.clearcoat&&o.enable(8);e.iridescence&&o.enable(9);e.alphaTest&&o.enable(10);e.vertexColors&&o.enable(11);e.vertexAlphas&&o.enable(12);e.vertexUv1s&&o.enable(13);e.vertexUv2s&&o.enable(14);e.vertexUv3s&&o.enable(15);e.vertexTangents&&o.enable(16);e.anisotropy&&o.enable(17);e.alphaHash&&o.enable(18);e.batching&&o.enable(19);e.dispersion&&o.enable(20);e.batchingColor&&o.enable(21);t.push(o.mask),o.disableAll(),e.fog&&o.enable(0);e.useFog&&o.enable(1);e.flatShading&&o.enable(2);e.logarithmicDepthBuffer&&o.enable(3);e.reverseDepthBuffer&&o.enable(4);e.skinning&&o.enable(5);e.morphTargets&&o.enable(6);e.morphNormals&&o.enable(7);e.morphColors&&o.enable(8);e.premultipliedAlpha&&o.enable(9);e.shadowMapEnabled&&o.enable(10);e.doubleSided&&o.enable(11);e.flipSided&&o.enable(12);e.useDepthPacking&&o.enable(13);e.dithering&&o.enable(14);e.transmission&&o.enable(15);e.sheen&&o.enable(16);e.opaque&&o.enable(17);e.pointsUvs&&o.enable(18);e.decodeVideoTexture&&o.enable(19);e.alphaToCoverage&&o.enable(20);t.push(o.mask)}(n,e),n.push(t.outputColorSpace)),n.push(e.customProgramCacheKey),n.join()},getUniforms:function(t){const e=g[t.type];let n;if(e){const t=ga[e];n=qs.clone(t.uniforms)}else n=t.uniforms;return n},acquireProgram:function(e,n){let i;for(let t=0,e=h.length;t0?i.push(h):!0===a.transparent?r.push(h):n.push(h)},unshift:function(t,e,a,o,l,c){const h=s(t,e,a,o,l,c);a.transmission>0?i.unshift(h):!0===a.transparent?r.unshift(h):n.unshift(h)},finish:function(){for(let n=e,i=t.length;n1&&n.sort(t||Cl),i.length>1&&i.sort(e||Pl),r.length>1&&r.sort(e||Pl)}}}function Ll(){let t=new WeakMap;return{get:function(e,n){const i=t.get(e);let r;return void 0===i?(r=new Il,t.set(e,[r])):n>=i.length?(r=new Il,i.push(r)):r=i[n],r},dispose:function(){t=new WeakMap}}}function Ul(){const t={};return{get:function(e){if(void 0!==t[e.id])return t[e.id];let n;switch(e.type){case"DirectionalLight":n={direction:new Li,color:new ts};break;case"SpotLight":n={position:new Li,direction:new Li,color:new ts,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":n={position:new Li,color:new ts,distance:0,decay:0};break;case"HemisphereLight":n={direction:new Li,skyColor:new ts,groundColor:new ts};break;case"RectAreaLight":n={color:new ts,position:new Li,halfWidth:new Li,halfHeight:new Li}}return t[e.id]=n,n}}}let Nl=0;function Dl(t,e){return(e.castShadow?2:0)-(t.castShadow?2:0)+(e.map?1:0)-(t.map?1:0)}function Ol(t){const e=new Ul,n=function(){const t={};return{get:function(e){if(void 0!==t[e.id])return t[e.id];let n;switch(e.type){case"DirectionalLight":case"SpotLight":n={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new ti};break;case"PointLight":n={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new ti,shadowCameraNear:1,shadowCameraFar:1e3}}return t[e.id]=n,n}}}(),i={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1,numSpotMaps:-1,numLightProbes:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotLightMap:[],spotShadow:[],spotShadowMap:[],spotLightMatrix:[],rectArea:[],rectAreaLTC1:null,rectAreaLTC2:null,point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[],numSpotLightShadowsWithMaps:0,numLightProbes:0};for(let t=0;t<9;t++)i.probe.push(new Li);const r=new Li,s=new lr,a=new lr;return{setup:function(r){let s=0,a=0,o=0;for(let t=0;t<9;t++)i.probe[t].set(0,0,0);let l=0,c=0,h=0,u=0,d=0,p=0,m=0,f=0,g=0,v=0,_=0;r.sort(Dl);for(let t=0,x=r.length;t0&&(!0===t.has("OES_texture_float_linear")?(i.rectAreaLTC1=fa.LTC_FLOAT_1,i.rectAreaLTC2=fa.LTC_FLOAT_2):(i.rectAreaLTC1=fa.LTC_HALF_1,i.rectAreaLTC2=fa.LTC_HALF_2)),i.ambient[0]=s,i.ambient[1]=a,i.ambient[2]=o;const x=i.hash;x.directionalLength===l&&x.pointLength===c&&x.spotLength===h&&x.rectAreaLength===u&&x.hemiLength===d&&x.numDirectionalShadows===p&&x.numPointShadows===m&&x.numSpotShadows===f&&x.numSpotMaps===g&&x.numLightProbes===_||(i.directional.length=l,i.spot.length=h,i.rectArea.length=u,i.point.length=c,i.hemi.length=d,i.directionalShadow.length=p,i.directionalShadowMap.length=p,i.pointShadow.length=m,i.pointShadowMap.length=m,i.spotShadow.length=f,i.spotShadowMap.length=f,i.directionalShadowMatrix.length=p,i.pointShadowMatrix.length=m,i.spotLightMatrix.length=f+g-v,i.spotLightMap.length=g,i.numSpotLightShadowsWithMaps=v,i.numLightProbes=_,x.directionalLength=l,x.pointLength=c,x.spotLength=h,x.rectAreaLength=u,x.hemiLength=d,x.numDirectionalShadows=p,x.numPointShadows=m,x.numSpotShadows=f,x.numSpotMaps=g,x.numLightProbes=_,i.version=Nl++)},setupView:function(t,e){let n=0,o=0,l=0,c=0,h=0;const u=e.matrixWorldInverse;for(let e=0,d=t.length;e=r.length?(s=new Fl(t),r.push(s)):s=r[i],s},dispose:function(){e=new WeakMap}}}class zl extends is{constructor(t){super(),this.isMeshDepthMaterial=!0,this.type="MeshDepthMaterial",this.depthPacking=3200,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.setValues(t)}copy(t){return super.copy(t),this.depthPacking=t.depthPacking,this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this}}class kl extends is{constructor(t){super(),this.isMeshDistanceMaterial=!0,this.type="MeshDistanceMaterial",this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.setValues(t)}copy(t){return super.copy(t),this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this}}function Vl(t,e,n){let i=new ha;const r=new ti,s=new ti,a=new wi,o=new zl({depthPacking:3201}),c=new kl,p={},m=n.maxTextureSize,f={[u]:d,[d]:u,2:2},g=new Ys({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new ti},radius:{value:4}},vertexShader:"void main() {\n\tgl_Position = vec4( position, 1.0 );\n}",fragmentShader:"uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include \nvoid main() {\n\tconst float samples = float( VSM_SAMPLES );\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"}),v=g.clone();v.defines.HORIZONTAL_PASS=1;const _=new Cs;_.setAttribute("position",new ds(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const x=new Vs(_,g),y=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=l;let M=this.type;function S(n,i){const s=e.update(x);g.defines.VSM_SAMPLES!==n.blurSamples&&(g.defines.VSM_SAMPLES=n.blurSamples,v.defines.VSM_SAMPLES=n.blurSamples,g.needsUpdate=!0,v.needsUpdate=!0),null===n.mapPass&&(n.mapPass=new Ei(r.x,r.y)),g.uniforms.shadow_pass.value=n.map.texture,g.uniforms.resolution.value=n.mapSize,g.uniforms.radius.value=n.radius,t.setRenderTarget(n.mapPass),t.clear(),t.renderBufferDirect(i,null,s,g,x,null),v.uniforms.shadow_pass.value=n.mapPass.texture,v.uniforms.resolution.value=n.mapSize,v.uniforms.radius.value=n.radius,t.setRenderTarget(n.map),t.clear(),t.renderBufferDirect(i,null,s,v,x,null)}function b(e,n,i,r){let s=null;const a=!0===i.isPointLight?e.customDistanceMaterial:e.customDepthMaterial;if(void 0!==a)s=a;else if(s=!0===i.isPointLight?c:o,t.localClippingEnabled&&!0===n.clipShadows&&Array.isArray(n.clippingPlanes)&&0!==n.clippingPlanes.length||n.displacementMap&&0!==n.displacementScale||n.alphaMap&&n.alphaTest>0||n.map&&n.alphaTest>0){const t=s.uuid,e=n.uuid;let i=p[t];void 0===i&&(i={},p[t]=i);let r=i[e];void 0===r&&(r=s.clone(),i[e]=r,n.addEventListener("dispose",T)),s=r}if(s.visible=n.visible,s.wireframe=n.wireframe,s.side=r===h?null!==n.shadowSide?n.shadowSide:n.side:null!==n.shadowSide?n.shadowSide:f[n.side],s.alphaMap=n.alphaMap,s.alphaTest=n.alphaTest,s.map=n.map,s.clipShadows=n.clipShadows,s.clippingPlanes=n.clippingPlanes,s.clipIntersection=n.clipIntersection,s.displacementMap=n.displacementMap,s.displacementScale=n.displacementScale,s.displacementBias=n.displacementBias,s.wireframeLinewidth=n.wireframeLinewidth,s.linewidth=n.linewidth,!0===i.isPointLight&&!0===s.isMeshDistanceMaterial){t.properties.get(s).light=i}return s}function w(n,r,s,a,o){if(!1===n.visible)return;if(n.layers.test(r.layers)&&(n.isMesh||n.isLine||n.isPoints)&&(n.castShadow||n.receiveShadow&&o===h)&&(!n.frustumCulled||i.intersectsObject(n))){n.modelViewMatrix.multiplyMatrices(s.matrixWorldInverse,n.matrixWorld);const i=e.update(n),l=n.material;if(Array.isArray(l)){const e=i.groups;for(let c=0,h=e.length;cm||r.y>m)&&(r.x>m&&(s.x=Math.floor(m/g.x),r.x=s.x*g.x,u.mapSize.x=s.x),r.y>m&&(s.y=Math.floor(m/g.y),r.y=s.y*g.y,u.mapSize.y=s.y)),null===u.map||!0===p||!0===f){const t=this.type!==h?{minFilter:gt,magFilter:gt}:{};null!==u.map&&u.map.dispose(),u.map=new Ei(r.x,r.y,t),u.map.texture.name=c.name+".shadowMap",u.camera.updateProjectionMatrix()}t.setRenderTarget(u.map),t.clear();const v=u.getViewportCount();for(let t=0;t=1):-1!==N.indexOf("OpenGL ES")&&(U=parseFloat(/^OpenGL ES (\d)/.exec(N)[1]),L=U>=2);let D=null,O={};const F=t.getParameter(t.SCISSOR_BOX),B=t.getParameter(t.VIEWPORT),z=(new wi).fromArray(F),k=(new wi).fromArray(B);function V(e,n,i,r){const s=new Uint8Array(4),a=t.createTexture();t.bindTexture(e,a),t.texParameteri(e,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(e,t.TEXTURE_MAG_FILTER,t.NEAREST);for(let a=0;ae?(t.repeat.x=1,t.repeat.y=n/e,t.offset.x=0,t.offset.y=(1-t.repeat.y)/2):(t.repeat.x=e/n,t.repeat.y=1,t.offset.x=(1-t.repeat.x)/2,t.offset.y=0),t},cover:function(t,e){const n=t.image&&t.image.width?t.image.width/t.image.height:1;return n>e?(t.repeat.x=e/n,t.repeat.y=1,t.offset.x=(1-t.repeat.x)/2,t.offset.y=0):(t.repeat.x=1,t.repeat.y=n/e,t.offset.x=0,t.offset.y=(1-t.repeat.y)/2),t},fill:function(t){return t.repeat.x=1,t.repeat.y=1,t.offset.x=0,t.offset.y=0,t},getByteLength:Wl};function jl(t,e,n,i,r,s,a){const o=e.has("WEBGL_multisampled_render_to_texture")?e.get("WEBGL_multisampled_render_to_texture"):null,l="undefined"!=typeof navigator&&/OculusBrowser/g.test(navigator.userAgent),c=new ti,h=new WeakMap;let u;const d=new WeakMap;let p=!1;try{p="undefined"!=typeof OffscreenCanvas&&null!==new OffscreenCanvas(1,1).getContext("2d")}catch(t){}function m(t,e){return p?new OffscreenCanvas(t,e):ai("canvas")}function f(t,e,n){let i=1;const r=k(t);if((r.width>n||r.height>n)&&(i=n/Math.max(r.width,r.height)),i<1){if("undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&t instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&t instanceof ImageBitmap||"undefined"!=typeof VideoFrame&&t instanceof VideoFrame){const n=Math.floor(i*r.width),s=Math.floor(i*r.height);void 0===u&&(u=m(n,s));const a=e?m(n,s):u;a.width=n,a.height=s;return a.getContext("2d").drawImage(t,0,0,n,s),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+r.width+"x"+r.height+") to ("+n+"x"+s+")."),a}return"data"in t&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+r.width+"x"+r.height+")."),t}return t}function g(t){return t.generateMipmaps&&t.minFilter!==gt&&t.minFilter!==Mt}function v(e){t.generateMipmap(e)}function _(n,i,r,s,a=!1){if(null!==n){if(void 0!==t[n])return t[n];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+n+"'")}let o=i;if(i===t.RED&&(r===t.FLOAT&&(o=t.R32F),r===t.HALF_FLOAT&&(o=t.R16F),r===t.UNSIGNED_BYTE&&(o=t.R8)),i===t.RED_INTEGER&&(r===t.UNSIGNED_BYTE&&(o=t.R8UI),r===t.UNSIGNED_SHORT&&(o=t.R16UI),r===t.UNSIGNED_INT&&(o=t.R32UI),r===t.BYTE&&(o=t.R8I),r===t.SHORT&&(o=t.R16I),r===t.INT&&(o=t.R32I)),i===t.RG&&(r===t.FLOAT&&(o=t.RG32F),r===t.HALF_FLOAT&&(o=t.RG16F),r===t.UNSIGNED_BYTE&&(o=t.RG8)),i===t.RG_INTEGER&&(r===t.UNSIGNED_BYTE&&(o=t.RG8UI),r===t.UNSIGNED_SHORT&&(o=t.RG16UI),r===t.UNSIGNED_INT&&(o=t.RG32UI),r===t.BYTE&&(o=t.RG8I),r===t.SHORT&&(o=t.RG16I),r===t.INT&&(o=t.RG32I)),i===t.RGB_INTEGER&&(r===t.UNSIGNED_BYTE&&(o=t.RGB8UI),r===t.UNSIGNED_SHORT&&(o=t.RGB16UI),r===t.UNSIGNED_INT&&(o=t.RGB32UI),r===t.BYTE&&(o=t.RGB8I),r===t.SHORT&&(o=t.RGB16I),r===t.INT&&(o=t.RGB32I)),i===t.RGBA_INTEGER&&(r===t.UNSIGNED_BYTE&&(o=t.RGBA8UI),r===t.UNSIGNED_SHORT&&(o=t.RGBA16UI),r===t.UNSIGNED_INT&&(o=t.RGBA32UI),r===t.BYTE&&(o=t.RGBA8I),r===t.SHORT&&(o=t.RGBA16I),r===t.INT&&(o=t.RGBA32I)),i===t.RGB&&r===t.UNSIGNED_INT_5_9_9_9_REV&&(o=t.RGB9_E5),i===t.RGBA){const e=a?tn:mi.getTransfer(s);r===t.FLOAT&&(o=t.RGBA32F),r===t.HALF_FLOAT&&(o=t.RGBA16F),r===t.UNSIGNED_BYTE&&(o=e===en?t.SRGB8_ALPHA8:t.RGBA8),r===t.UNSIGNED_SHORT_4_4_4_4&&(o=t.RGBA4),r===t.UNSIGNED_SHORT_5_5_5_1&&(o=t.RGB5_A1)}return o!==t.R16F&&o!==t.R32F&&o!==t.RG16F&&o!==t.RG32F&&o!==t.RGBA16F&&o!==t.RGBA32F||e.get("EXT_color_buffer_float"),o}function x(e,n){let i;return e?null===n||n===It||n===Ot?i=t.DEPTH24_STENCIL8:n===Lt?i=t.DEPTH32F_STENCIL8:n===Ct&&(i=t.DEPTH24_STENCIL8,console.warn("DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.")):null===n||n===It||n===Ot?i=t.DEPTH_COMPONENT24:n===Lt?i=t.DEPTH_COMPONENT32F:n===Ct&&(i=t.DEPTH_COMPONENT16),i}function y(t,e){return!0===g(t)||t.isFramebufferTexture&&t.minFilter!==gt&&t.minFilter!==Mt?Math.log2(Math.max(e.width,e.height))+1:void 0!==t.mipmaps&&t.mipmaps.length>0?t.mipmaps.length:t.isCompressedTexture&&Array.isArray(t.image)?e.mipmaps.length:1}function M(t){const e=t.target;e.removeEventListener("dispose",M),function(t){const e=i.get(t);if(void 0===e.__webglInit)return;const n=t.source,r=d.get(n);if(r){const i=r[e.__cacheKey];i.usedTimes--,0===i.usedTimes&&b(t),0===Object.keys(r).length&&d.delete(n)}i.remove(t)}(e),e.isVideoTexture&&h.delete(e)}function S(e){const n=e.target;n.removeEventListener("dispose",S),function(e){const n=i.get(e);e.depthTexture&&e.depthTexture.dispose();if(e.isWebGLCubeRenderTarget)for(let e=0;e<6;e++){if(Array.isArray(n.__webglFramebuffer[e]))for(let i=0;i0&&s.__version!==e.version){const t=e.image;if(null===t)console.warn("THREE.WebGLRenderer: Texture marked for update but no image data found.");else{if(!1!==t.complete)return void I(s,e,r);console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete")}}n.bindTexture(t.TEXTURE_2D,s.__webglTexture,t.TEXTURE0+r)}const E={[pt]:t.REPEAT,[mt]:t.CLAMP_TO_EDGE,[ft]:t.MIRRORED_REPEAT},A={[gt]:t.NEAREST,[vt]:t.NEAREST_MIPMAP_NEAREST,[xt]:t.NEAREST_MIPMAP_LINEAR,[Mt]:t.LINEAR,[St]:t.LINEAR_MIPMAP_NEAREST,[wt]:t.LINEAR_MIPMAP_LINEAR},R={512:t.NEVER,519:t.ALWAYS,513:t.LESS,[wn]:t.LEQUAL,514:t.EQUAL,518:t.GEQUAL,516:t.GREATER,517:t.NOTEQUAL};function C(n,s){if(s.type!==Lt||!1!==e.has("OES_texture_float_linear")||s.magFilter!==Mt&&s.magFilter!==St&&s.magFilter!==xt&&s.magFilter!==wt&&s.minFilter!==Mt&&s.minFilter!==St&&s.minFilter!==xt&&s.minFilter!==wt||console.warn("THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device."),t.texParameteri(n,t.TEXTURE_WRAP_S,E[s.wrapS]),t.texParameteri(n,t.TEXTURE_WRAP_T,E[s.wrapT]),n!==t.TEXTURE_3D&&n!==t.TEXTURE_2D_ARRAY||t.texParameteri(n,t.TEXTURE_WRAP_R,E[s.wrapR]),t.texParameteri(n,t.TEXTURE_MAG_FILTER,A[s.magFilter]),t.texParameteri(n,t.TEXTURE_MIN_FILTER,A[s.minFilter]),s.compareFunction&&(t.texParameteri(n,t.TEXTURE_COMPARE_MODE,t.COMPARE_REF_TO_TEXTURE),t.texParameteri(n,t.TEXTURE_COMPARE_FUNC,R[s.compareFunction])),!0===e.has("EXT_texture_filter_anisotropic")){if(s.magFilter===gt)return;if(s.minFilter!==xt&&s.minFilter!==wt)return;if(s.type===Lt&&!1===e.has("OES_texture_float_linear"))return;if(s.anisotropy>1||i.get(s).__currentAnisotropy){const a=e.get("EXT_texture_filter_anisotropic");t.texParameterf(n,a.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(s.anisotropy,r.getMaxAnisotropy())),i.get(s).__currentAnisotropy=s.anisotropy}}}function P(e,n){let i=!1;void 0===e.__webglInit&&(e.__webglInit=!0,n.addEventListener("dispose",M));const r=n.source;let s=d.get(r);void 0===s&&(s={},d.set(r,s));const o=function(t){const e=[];return e.push(t.wrapS),e.push(t.wrapT),e.push(t.wrapR||0),e.push(t.magFilter),e.push(t.minFilter),e.push(t.anisotropy),e.push(t.internalFormat),e.push(t.format),e.push(t.type),e.push(t.generateMipmaps),e.push(t.premultiplyAlpha),e.push(t.flipY),e.push(t.unpackAlignment),e.push(t.colorSpace),e.join()}(n);if(o!==e.__cacheKey){void 0===s[o]&&(s[o]={texture:t.createTexture(),usedTimes:0},a.memory.textures++,i=!0),s[o].usedTimes++;const r=s[e.__cacheKey];void 0!==r&&(s[e.__cacheKey].usedTimes--,0===r.usedTimes&&b(n)),e.__cacheKey=o,e.__webglTexture=s[o].texture}return i}function I(e,a,o){let l=t.TEXTURE_2D;(a.isDataArrayTexture||a.isCompressedArrayTexture)&&(l=t.TEXTURE_2D_ARRAY),a.isData3DTexture&&(l=t.TEXTURE_3D);const c=P(e,a),h=a.source;n.bindTexture(l,e.__webglTexture,t.TEXTURE0+o);const u=i.get(h);if(h.version!==u.__version||!0===c){n.activeTexture(t.TEXTURE0+o);const e=mi.getPrimaries(mi.workingColorSpace),i=a.colorSpace===Ze?null:mi.getPrimaries(a.colorSpace),d=a.colorSpace===Ze||e===i?t.NONE:t.BROWSER_DEFAULT_WEBGL;t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,a.flipY),t.pixelStorei(t.UNPACK_PREMULTIPLY_ALPHA_WEBGL,a.premultiplyAlpha),t.pixelStorei(t.UNPACK_ALIGNMENT,a.unpackAlignment),t.pixelStorei(t.UNPACK_COLORSPACE_CONVERSION_WEBGL,d);let p=f(a.image,!1,r.maxTextureSize);p=z(a,p);const m=s.convert(a.format,a.colorSpace),M=s.convert(a.type);let S,b=_(a.internalFormat,m,M,a.colorSpace,a.isVideoTexture);C(l,a);const w=a.mipmaps,T=!0!==a.isVideoTexture,E=void 0===u.__version||!0===c,A=h.dataReady,R=y(a,p);if(a.isDepthTexture)b=x(a.format===Wt,a.type),E&&(T?n.texStorage2D(t.TEXTURE_2D,1,b,p.width,p.height):n.texImage2D(t.TEXTURE_2D,0,b,p.width,p.height,0,m,M,null));else if(a.isDataTexture)if(w.length>0){T&&E&&n.texStorage2D(t.TEXTURE_2D,R,b,w[0].width,w[0].height);for(let e=0,i=w.length;e0){const i=Wl(S.width,S.height,a.format,a.type);for(const r of a.layerUpdates){const s=S.data.subarray(r*i/S.data.BYTES_PER_ELEMENT,(r+1)*i/S.data.BYTES_PER_ELEMENT);n.compressedTexSubImage3D(t.TEXTURE_2D_ARRAY,e,0,0,r,S.width,S.height,1,m,s,0,0)}a.clearLayerUpdates()}else n.compressedTexSubImage3D(t.TEXTURE_2D_ARRAY,e,0,0,0,S.width,S.height,p.depth,m,S.data,0,0)}else n.compressedTexImage3D(t.TEXTURE_2D_ARRAY,e,b,S.width,S.height,p.depth,0,S.data,0,0);else console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()");else T?A&&n.texSubImage3D(t.TEXTURE_2D_ARRAY,e,0,0,0,S.width,S.height,p.depth,m,M,S.data):n.texImage3D(t.TEXTURE_2D_ARRAY,e,b,S.width,S.height,p.depth,0,m,M,S.data)}else{T&&E&&n.texStorage2D(t.TEXTURE_2D,R,b,w[0].width,w[0].height);for(let e=0,i=w.length;e0){const e=Wl(p.width,p.height,a.format,a.type);for(const i of a.layerUpdates){const r=p.data.subarray(i*e/p.data.BYTES_PER_ELEMENT,(i+1)*e/p.data.BYTES_PER_ELEMENT);n.texSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,i,p.width,p.height,1,m,M,r)}a.clearLayerUpdates()}else n.texSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,0,p.width,p.height,p.depth,m,M,p.data)}else n.texImage3D(t.TEXTURE_2D_ARRAY,0,b,p.width,p.height,p.depth,0,m,M,p.data);else if(a.isData3DTexture)T?(E&&n.texStorage3D(t.TEXTURE_3D,R,b,p.width,p.height,p.depth),A&&n.texSubImage3D(t.TEXTURE_3D,0,0,0,0,p.width,p.height,p.depth,m,M,p.data)):n.texImage3D(t.TEXTURE_3D,0,b,p.width,p.height,p.depth,0,m,M,p.data);else if(a.isFramebufferTexture){if(E)if(T)n.texStorage2D(t.TEXTURE_2D,R,b,p.width,p.height);else{let e=p.width,i=p.height;for(let r=0;r>=1,i>>=1}}else if(w.length>0){if(T&&E){const e=k(w[0]);n.texStorage2D(t.TEXTURE_2D,R,b,e.width,e.height)}for(let e=0,i=w.length;e>h),i=Math.max(1,r.height>>h);c===t.TEXTURE_3D||c===t.TEXTURE_2D_ARRAY?n.texImage3D(c,h,p,e,i,r.depth,0,u,d,null):n.texImage2D(c,h,p,e,i,0,u,d,null)}n.bindFramebuffer(t.FRAMEBUFFER,e),B(r)?o.framebufferTexture2DMultisampleEXT(t.FRAMEBUFFER,l,c,i.get(a).__webglTexture,0,F(r)):(c===t.TEXTURE_2D||c>=t.TEXTURE_CUBE_MAP_POSITIVE_X&&c<=t.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&t.framebufferTexture2D(t.FRAMEBUFFER,l,c,i.get(a).__webglTexture,h),n.bindFramebuffer(t.FRAMEBUFFER,null)}function U(e,n,i){if(t.bindRenderbuffer(t.RENDERBUFFER,e),n.depthBuffer){const r=n.depthTexture,s=r&&r.isDepthTexture?r.type:null,a=x(n.stencilBuffer,s),l=n.stencilBuffer?t.DEPTH_STENCIL_ATTACHMENT:t.DEPTH_ATTACHMENT,c=F(n);B(n)?o.renderbufferStorageMultisampleEXT(t.RENDERBUFFER,c,a,n.width,n.height):i?t.renderbufferStorageMultisample(t.RENDERBUFFER,c,a,n.width,n.height):t.renderbufferStorage(t.RENDERBUFFER,a,n.width,n.height),t.framebufferRenderbuffer(t.FRAMEBUFFER,l,t.RENDERBUFFER,e)}else{const e=n.textures;for(let r=0;r{delete r.__boundDepthTexture,delete r.__depthDisposeCallback,t.removeEventListener("dispose",e)};t.addEventListener("dispose",e),r.__depthDisposeCallback=e}r.__boundDepthTexture=t}if(e.depthTexture&&!r.__autoAllocateDepthBuffer){if(s)throw new Error("target.depthTexture not supported in Cube render targets");!function(e,r){if(r&&r.isWebGLCubeRenderTarget)throw new Error("Depth Texture with cube render targets is not supported");if(n.bindFramebuffer(t.FRAMEBUFFER,e),!r.depthTexture||!r.depthTexture.isDepthTexture)throw new Error("renderTarget.depthTexture must be an instance of THREE.DepthTexture");i.get(r.depthTexture).__webglTexture&&r.depthTexture.image.width===r.width&&r.depthTexture.image.height===r.height||(r.depthTexture.image.width=r.width,r.depthTexture.image.height=r.height,r.depthTexture.needsUpdate=!0),T(r.depthTexture,0);const s=i.get(r.depthTexture).__webglTexture,a=F(r);if(r.depthTexture.format===Gt)B(r)?o.framebufferTexture2DMultisampleEXT(t.FRAMEBUFFER,t.DEPTH_ATTACHMENT,t.TEXTURE_2D,s,0,a):t.framebufferTexture2D(t.FRAMEBUFFER,t.DEPTH_ATTACHMENT,t.TEXTURE_2D,s,0);else{if(r.depthTexture.format!==Wt)throw new Error("Unknown depthTexture format");B(r)?o.framebufferTexture2DMultisampleEXT(t.FRAMEBUFFER,t.DEPTH_STENCIL_ATTACHMENT,t.TEXTURE_2D,s,0,a):t.framebufferTexture2D(t.FRAMEBUFFER,t.DEPTH_STENCIL_ATTACHMENT,t.TEXTURE_2D,s,0)}}(r.__webglFramebuffer,e)}else if(s){r.__webglDepthbuffer=[];for(let i=0;i<6;i++)if(n.bindFramebuffer(t.FRAMEBUFFER,r.__webglFramebuffer[i]),void 0===r.__webglDepthbuffer[i])r.__webglDepthbuffer[i]=t.createRenderbuffer(),U(r.__webglDepthbuffer[i],e,!1);else{const n=e.stencilBuffer?t.DEPTH_STENCIL_ATTACHMENT:t.DEPTH_ATTACHMENT,s=r.__webglDepthbuffer[i];t.bindRenderbuffer(t.RENDERBUFFER,s),t.framebufferRenderbuffer(t.FRAMEBUFFER,n,t.RENDERBUFFER,s)}}else if(n.bindFramebuffer(t.FRAMEBUFFER,r.__webglFramebuffer),void 0===r.__webglDepthbuffer)r.__webglDepthbuffer=t.createRenderbuffer(),U(r.__webglDepthbuffer,e,!1);else{const n=e.stencilBuffer?t.DEPTH_STENCIL_ATTACHMENT:t.DEPTH_ATTACHMENT,i=r.__webglDepthbuffer;t.bindRenderbuffer(t.RENDERBUFFER,i),t.framebufferRenderbuffer(t.FRAMEBUFFER,n,t.RENDERBUFFER,i)}n.bindFramebuffer(t.FRAMEBUFFER,null)}const D=[],O=[];function F(t){return Math.min(r.maxSamples,t.samples)}function B(t){const n=i.get(t);return t.samples>0&&!0===e.has("WEBGL_multisampled_render_to_texture")&&!1!==n.__useRenderToTexture}function z(t,e){const n=t.colorSpace,i=t.format,r=t.type;return!0===t.isCompressedTexture||!0===t.isVideoTexture||n!==Ke&&n!==Ze&&(mi.getTransfer(n)===en?i===kt&&r===Et||console.warn("THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):console.error("THREE.WebGLTextures: Unsupported texture color space:",n)),e}function k(t){return"undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement?(c.width=t.naturalWidth||t.width,c.height=t.naturalHeight||t.height):"undefined"!=typeof VideoFrame&&t instanceof VideoFrame?(c.width=t.displayWidth,c.height=t.displayHeight):(c.width=t.width,c.height=t.height),c}this.allocateTextureUnit=function(){const t=w;return t>=r.maxTextures&&console.warn("THREE.WebGLTextures: Trying to use "+t+" texture units while this GPU supports only "+r.maxTextures),w+=1,t},this.resetTextureUnits=function(){w=0},this.setTexture2D=T,this.setTexture2DArray=function(e,r){const s=i.get(e);e.version>0&&s.__version!==e.version?I(s,e,r):n.bindTexture(t.TEXTURE_2D_ARRAY,s.__webglTexture,t.TEXTURE0+r)},this.setTexture3D=function(e,r){const s=i.get(e);e.version>0&&s.__version!==e.version?I(s,e,r):n.bindTexture(t.TEXTURE_3D,s.__webglTexture,t.TEXTURE0+r)},this.setTextureCube=function(e,a){const o=i.get(e);e.version>0&&o.__version!==e.version?function(e,a,o){if(6!==a.image.length)return;const l=P(e,a),c=a.source;n.bindTexture(t.TEXTURE_CUBE_MAP,e.__webglTexture,t.TEXTURE0+o);const h=i.get(c);if(c.version!==h.__version||!0===l){n.activeTexture(t.TEXTURE0+o);const e=mi.getPrimaries(mi.workingColorSpace),i=a.colorSpace===Ze?null:mi.getPrimaries(a.colorSpace),u=a.colorSpace===Ze||e===i?t.NONE:t.BROWSER_DEFAULT_WEBGL;t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,a.flipY),t.pixelStorei(t.UNPACK_PREMULTIPLY_ALPHA_WEBGL,a.premultiplyAlpha),t.pixelStorei(t.UNPACK_ALIGNMENT,a.unpackAlignment),t.pixelStorei(t.UNPACK_COLORSPACE_CONVERSION_WEBGL,u);const d=a.isCompressedTexture||a.image[0].isCompressedTexture,p=a.image[0]&&a.image[0].isDataTexture,m=[];for(let t=0;t<6;t++)m[t]=d||p?p?a.image[t].image:a.image[t]:f(a.image[t],!0,r.maxCubemapSize),m[t]=z(a,m[t]);const x=m[0],M=s.convert(a.format,a.colorSpace),S=s.convert(a.type),b=_(a.internalFormat,M,S,a.colorSpace),w=!0!==a.isVideoTexture,T=void 0===h.__version||!0===l,E=c.dataReady;let A,R=y(a,x);if(C(t.TEXTURE_CUBE_MAP,a),d){w&&T&&n.texStorage2D(t.TEXTURE_CUBE_MAP,R,b,x.width,x.height);for(let e=0;e<6;e++){A=m[e].mipmaps;for(let i=0;i0&&R++;const e=k(m[0]);n.texStorage2D(t.TEXTURE_CUBE_MAP,R,b,e.width,e.height)}for(let e=0;e<6;e++)if(p){w?E&&n.texSubImage2D(t.TEXTURE_CUBE_MAP_POSITIVE_X+e,0,0,0,m[e].width,m[e].height,M,S,m[e].data):n.texImage2D(t.TEXTURE_CUBE_MAP_POSITIVE_X+e,0,b,m[e].width,m[e].height,0,M,S,m[e].data);for(let i=0;i1;if(u||(void 0===l.__webglTexture&&(l.__webglTexture=t.createTexture()),l.__version=r.version,a.memory.textures++),h){o.__webglFramebuffer=[];for(let e=0;e<6;e++)if(r.mipmaps&&r.mipmaps.length>0){o.__webglFramebuffer[e]=[];for(let n=0;n0){o.__webglFramebuffer=[];for(let e=0;e0&&!1===B(e)){o.__webglMultisampledFramebuffer=t.createFramebuffer(),o.__webglColorRenderbuffer=[],n.bindFramebuffer(t.FRAMEBUFFER,o.__webglMultisampledFramebuffer);for(let n=0;n0)for(let i=0;i0)for(let n=0;n0)if(!1===B(e)){const r=e.textures,s=e.width,a=e.height;let o=t.COLOR_BUFFER_BIT;const c=e.stencilBuffer?t.DEPTH_STENCIL_ATTACHMENT:t.DEPTH_ATTACHMENT,h=i.get(e),u=r.length>1;if(u)for(let e=0;eo+c?(l.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:t.handedness,target:this})):!l.inputState.pinching&&a<=o-c&&(l.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:t.handedness,target:this}))}else null!==o&&t.gripSpace&&(r=e.getPose(t.gripSpace,n),null!==r&&(o.matrix.fromArray(r.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),o.matrixWorldNeedsUpdate=!0,r.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(r.linearVelocity)):o.hasLinearVelocity=!1,r.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(r.angularVelocity)):o.hasAngularVelocity=!1));null!==a&&(i=e.getPose(t.targetRaySpace,n),null===i&&null!==r&&(i=r),null!==i&&(a.matrix.fromArray(i.transform.matrix),a.matrix.decompose(a.position,a.rotation,a.scale),a.matrixWorldNeedsUpdate=!0,i.linearVelocity?(a.hasLinearVelocity=!0,a.linearVelocity.copy(i.linearVelocity)):a.hasLinearVelocity=!1,i.angularVelocity?(a.hasAngularVelocity=!0,a.angularVelocity.copy(i.angularVelocity)):a.hasAngularVelocity=!1,this.dispatchEvent(Jl)))}return null!==a&&(a.visible=null!==i),null!==o&&(o.visible=null!==r),null!==l&&(l.visible=null!==s),this}_getHandJoint(t,e){if(void 0===t.joints[e.jointName]){const n=new Zl;n.matrixAutoUpdate=!1,n.visible=!1,t.joints[e.jointName]=n,t.add(n)}return t.joints[e.jointName]}}class $l{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(t,e,n){if(null===this.texture){const i=new bi;t.properties.get(i).__webglTexture=e.texture,e.depthNear==n.depthNear&&e.depthFar==n.depthFar||(this.depthNear=e.depthNear,this.depthFar=e.depthFar),this.texture=i}}getMesh(t){if(null!==this.texture&&null===this.mesh){const e=t.cameras[0].viewport,n=new Ys({vertexShader:"\nvoid main() {\n\n\tgl_Position = vec4( position, 1.0 );\n\n}",fragmentShader:"\nuniform sampler2DArray depthColor;\nuniform float depthWidth;\nuniform float depthHeight;\n\nvoid main() {\n\n\tvec2 coord = vec2( gl_FragCoord.x / depthWidth, gl_FragCoord.y / depthHeight );\n\n\tif ( coord.x >= 1.0 ) {\n\n\t\tgl_FragDepth = texture( depthColor, vec3( coord.x - 1.0, coord.y, 1 ) ).r;\n\n\t} else {\n\n\t\tgl_FragDepth = texture( depthColor, vec3( coord.x, coord.y, 0 ) ).r;\n\n\t}\n\n}",uniforms:{depthColor:{value:this.texture},depthWidth:{value:e.z},depthHeight:{value:e.w}}});this.mesh=new Vs(new pa(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}}class Ql extends Hn{constructor(t,e){super();const n=this;let i=null,r=1,s=null,a="local-floor",o=1,l=null,c=null,h=null,u=null,d=null,p=null;const m=new $l,f=e.getContextAttributes();let g=null,v=null;const _=[],x=[],y=new ti;let M=null;const S=new Qs;S.layers.enable(1),S.viewport=new wi;const b=new Qs;b.layers.enable(2),b.viewport=new wi;const w=[S,b],T=new Yl;T.layers.enable(1),T.layers.enable(2);let E=null,A=null;function R(t){const e=x.indexOf(t.inputSource);if(-1===e)return;const n=_[e];void 0!==n&&(n.update(t.inputSource,t.frame,l||s),n.dispatchEvent({type:t.type,data:t.inputSource}))}function C(){i.removeEventListener("select",R),i.removeEventListener("selectstart",R),i.removeEventListener("selectend",R),i.removeEventListener("squeeze",R),i.removeEventListener("squeezestart",R),i.removeEventListener("squeezeend",R),i.removeEventListener("end",C),i.removeEventListener("inputsourceschange",P);for(let t=0;t<_.length;t++){const e=x[t];null!==e&&(x[t]=null,_[t].disconnect(e))}E=null,A=null,m.reset(),t.setRenderTarget(g),d=null,u=null,h=null,i=null,v=null,D.stop(),n.isPresenting=!1,t.setPixelRatio(M),t.setSize(y.width,y.height,!1),n.dispatchEvent({type:"sessionend"})}function P(t){for(let e=0;e=0&&(x[i]=null,_[i].disconnect(n))}for(let e=0;e=x.length){x.push(n),i=t;break}if(null===x[t]){x[t]=n,i=t;break}}if(-1===i)break}const r=_[i];r&&r.connect(n)}}this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(t){let e=_[t];return void 0===e&&(e=new Kl,_[t]=e),e.getTargetRaySpace()},this.getControllerGrip=function(t){let e=_[t];return void 0===e&&(e=new Kl,_[t]=e),e.getGripSpace()},this.getHand=function(t){let e=_[t];return void 0===e&&(e=new Kl,_[t]=e),e.getHandSpace()},this.setFramebufferScaleFactor=function(t){r=t,!0===n.isPresenting&&console.warn("THREE.WebXRManager: Cannot change framebuffer scale while presenting.")},this.setReferenceSpaceType=function(t){a=t,!0===n.isPresenting&&console.warn("THREE.WebXRManager: Cannot change reference space type while presenting.")},this.getReferenceSpace=function(){return l||s},this.setReferenceSpace=function(t){l=t},this.getBaseLayer=function(){return null!==u?u:d},this.getBinding=function(){return h},this.getFrame=function(){return p},this.getSession=function(){return i},this.setSession=async function(c){if(i=c,null!==i){if(g=t.getRenderTarget(),i.addEventListener("select",R),i.addEventListener("selectstart",R),i.addEventListener("selectend",R),i.addEventListener("squeeze",R),i.addEventListener("squeezestart",R),i.addEventListener("squeezeend",R),i.addEventListener("end",C),i.addEventListener("inputsourceschange",P),!0!==f.xrCompatible&&await e.makeXRCompatible(),M=t.getPixelRatio(),t.getSize(y),void 0===i.renderState.layers){const n={antialias:f.antialias,alpha:!0,depth:f.depth,stencil:f.stencil,framebufferScaleFactor:r};d=new XRWebGLLayer(i,e,n),i.updateRenderState({baseLayer:d}),t.setPixelRatio(1),t.setSize(d.framebufferWidth,d.framebufferHeight,!1),v=new Ei(d.framebufferWidth,d.framebufferHeight,{format:kt,type:Et,colorSpace:t.outputColorSpace,stencilBuffer:f.stencil})}else{let n=null,s=null,a=null;f.depth&&(a=f.stencil?e.DEPTH24_STENCIL8:e.DEPTH_COMPONENT24,n=f.stencil?Wt:Gt,s=f.stencil?Ot:It);const o={colorFormat:e.RGBA8,depthFormat:a,scaleFactor:r};h=new XRWebGLBinding(i,e),u=h.createProjectionLayer(o),i.updateRenderState({layers:[u]}),t.setPixelRatio(1),t.setSize(u.textureWidth,u.textureHeight,!1),v=new Ei(u.textureWidth,u.textureHeight,{format:kt,type:Et,depthTexture:new Ka(u.textureWidth,u.textureHeight,s,void 0,void 0,void 0,void 0,void 0,void 0,n),stencilBuffer:f.stencil,colorSpace:t.outputColorSpace,samples:f.antialias?4:0,resolveDepthBuffer:!1===u.ignoreDepthValues})}v.isXRRenderTarget=!0,this.setFoveation(o),l=null,s=await i.requestReferenceSpace(a),D.setContext(i),D.start(),n.isPresenting=!0,n.dispatchEvent({type:"sessionstart"})}},this.getEnvironmentBlendMode=function(){if(null!==i)return i.environmentBlendMode},this.getDepthTexture=function(){return m.getDepthTexture()};const I=new Li,L=new Li;function U(t,e){null===e?t.matrixWorld.copy(t.matrix):t.matrixWorld.multiplyMatrices(e.matrixWorld,t.matrix),t.matrixWorldInverse.copy(t.matrixWorld).invert()}this.updateCamera=function(t){if(null===i)return;let e=t.near,n=t.far;null!==m.texture&&(m.depthNear>0&&(e=m.depthNear),m.depthFar>0&&(n=m.depthFar)),T.near=b.near=S.near=e,T.far=b.far=S.far=n,E===T.near&&A===T.far||(i.updateRenderState({depthNear:T.near,depthFar:T.far}),E=T.near,A=T.far);const r=t.parent,s=T.cameras;U(T,r);for(let t=0;t0&&(t.alphaTest.value=i.alphaTest);const r=e.get(i),s=r.envMap,a=r.envMapRotation;s&&(t.envMap.value=s,tc.copy(a),tc.x*=-1,tc.y*=-1,tc.z*=-1,s.isCubeTexture&&!1===s.isRenderTargetTexture&&(tc.y*=-1,tc.z*=-1),t.envMapRotation.value.setFromMatrix4(ec.makeRotationFromEuler(tc)),t.flipEnvMap.value=s.isCubeTexture&&!1===s.isRenderTargetTexture?-1:1,t.reflectivity.value=i.reflectivity,t.ior.value=i.ior,t.refractionRatio.value=i.refractionRatio),i.lightMap&&(t.lightMap.value=i.lightMap,t.lightMapIntensity.value=i.lightMapIntensity,n(i.lightMap,t.lightMapTransform)),i.aoMap&&(t.aoMap.value=i.aoMap,t.aoMapIntensity.value=i.aoMapIntensity,n(i.aoMap,t.aoMapTransform))}return{refreshFogUniforms:function(e,n){n.color.getRGB(e.fogColor.value,js(t)),n.isFog?(e.fogNear.value=n.near,e.fogFar.value=n.far):n.isFogExp2&&(e.fogDensity.value=n.density)},refreshMaterialUniforms:function(t,r,s,a,o){r.isMeshBasicMaterial||r.isMeshLambertMaterial?i(t,r):r.isMeshToonMaterial?(i(t,r),function(t,e){e.gradientMap&&(t.gradientMap.value=e.gradientMap)}(t,r)):r.isMeshPhongMaterial?(i(t,r),function(t,e){t.specular.value.copy(e.specular),t.shininess.value=Math.max(e.shininess,1e-4)}(t,r)):r.isMeshStandardMaterial?(i(t,r),function(t,e){t.metalness.value=e.metalness,e.metalnessMap&&(t.metalnessMap.value=e.metalnessMap,n(e.metalnessMap,t.metalnessMapTransform));t.roughness.value=e.roughness,e.roughnessMap&&(t.roughnessMap.value=e.roughnessMap,n(e.roughnessMap,t.roughnessMapTransform));e.envMap&&(t.envMapIntensity.value=e.envMapIntensity)}(t,r),r.isMeshPhysicalMaterial&&function(t,e,i){t.ior.value=e.ior,e.sheen>0&&(t.sheenColor.value.copy(e.sheenColor).multiplyScalar(e.sheen),t.sheenRoughness.value=e.sheenRoughness,e.sheenColorMap&&(t.sheenColorMap.value=e.sheenColorMap,n(e.sheenColorMap,t.sheenColorMapTransform)),e.sheenRoughnessMap&&(t.sheenRoughnessMap.value=e.sheenRoughnessMap,n(e.sheenRoughnessMap,t.sheenRoughnessMapTransform)));e.clearcoat>0&&(t.clearcoat.value=e.clearcoat,t.clearcoatRoughness.value=e.clearcoatRoughness,e.clearcoatMap&&(t.clearcoatMap.value=e.clearcoatMap,n(e.clearcoatMap,t.clearcoatMapTransform)),e.clearcoatRoughnessMap&&(t.clearcoatRoughnessMap.value=e.clearcoatRoughnessMap,n(e.clearcoatRoughnessMap,t.clearcoatRoughnessMapTransform)),e.clearcoatNormalMap&&(t.clearcoatNormalMap.value=e.clearcoatNormalMap,n(e.clearcoatNormalMap,t.clearcoatNormalMapTransform),t.clearcoatNormalScale.value.copy(e.clearcoatNormalScale),e.side===d&&t.clearcoatNormalScale.value.negate()));e.dispersion>0&&(t.dispersion.value=e.dispersion);e.iridescence>0&&(t.iridescence.value=e.iridescence,t.iridescenceIOR.value=e.iridescenceIOR,t.iridescenceThicknessMinimum.value=e.iridescenceThicknessRange[0],t.iridescenceThicknessMaximum.value=e.iridescenceThicknessRange[1],e.iridescenceMap&&(t.iridescenceMap.value=e.iridescenceMap,n(e.iridescenceMap,t.iridescenceMapTransform)),e.iridescenceThicknessMap&&(t.iridescenceThicknessMap.value=e.iridescenceThicknessMap,n(e.iridescenceThicknessMap,t.iridescenceThicknessMapTransform)));e.transmission>0&&(t.transmission.value=e.transmission,t.transmissionSamplerMap.value=i.texture,t.transmissionSamplerSize.value.set(i.width,i.height),e.transmissionMap&&(t.transmissionMap.value=e.transmissionMap,n(e.transmissionMap,t.transmissionMapTransform)),t.thickness.value=e.thickness,e.thicknessMap&&(t.thicknessMap.value=e.thicknessMap,n(e.thicknessMap,t.thicknessMapTransform)),t.attenuationDistance.value=e.attenuationDistance,t.attenuationColor.value.copy(e.attenuationColor));e.anisotropy>0&&(t.anisotropyVector.value.set(e.anisotropy*Math.cos(e.anisotropyRotation),e.anisotropy*Math.sin(e.anisotropyRotation)),e.anisotropyMap&&(t.anisotropyMap.value=e.anisotropyMap,n(e.anisotropyMap,t.anisotropyMapTransform)));t.specularIntensity.value=e.specularIntensity,t.specularColor.value.copy(e.specularColor),e.specularColorMap&&(t.specularColorMap.value=e.specularColorMap,n(e.specularColorMap,t.specularColorMapTransform));e.specularIntensityMap&&(t.specularIntensityMap.value=e.specularIntensityMap,n(e.specularIntensityMap,t.specularIntensityMapTransform))}(t,r,o)):r.isMeshMatcapMaterial?(i(t,r),function(t,e){e.matcap&&(t.matcap.value=e.matcap)}(t,r)):r.isMeshDepthMaterial?i(t,r):r.isMeshDistanceMaterial?(i(t,r),function(t,n){const i=e.get(n).light;t.referencePosition.value.setFromMatrixPosition(i.matrixWorld),t.nearDistance.value=i.shadow.camera.near,t.farDistance.value=i.shadow.camera.far}(t,r)):r.isMeshNormalMaterial?i(t,r):r.isLineBasicMaterial?(function(t,e){t.diffuse.value.copy(e.color),t.opacity.value=e.opacity,e.map&&(t.map.value=e.map,n(e.map,t.mapTransform))}(t,r),r.isLineDashedMaterial&&function(t,e){t.dashSize.value=e.dashSize,t.totalSize.value=e.dashSize+e.gapSize,t.scale.value=e.scale}(t,r)):r.isPointsMaterial?function(t,e,i,r){t.diffuse.value.copy(e.color),t.opacity.value=e.opacity,t.size.value=e.size*i,t.scale.value=.5*r,e.map&&(t.map.value=e.map,n(e.map,t.uvTransform));e.alphaMap&&(t.alphaMap.value=e.alphaMap,n(e.alphaMap,t.alphaMapTransform));e.alphaTest>0&&(t.alphaTest.value=e.alphaTest)}(t,r,s,a):r.isSpriteMaterial?function(t,e){t.diffuse.value.copy(e.color),t.opacity.value=e.opacity,t.rotation.value=e.rotation,e.map&&(t.map.value=e.map,n(e.map,t.mapTransform));e.alphaMap&&(t.alphaMap.value=e.alphaMap,n(e.alphaMap,t.alphaMapTransform));e.alphaTest>0&&(t.alphaTest.value=e.alphaTest)}(t,r):r.isShadowMaterial?(t.color.value.copy(r.color),t.opacity.value=r.opacity):r.isShaderMaterial&&(r.uniformsNeedUpdate=!1)}}}function ic(t,e,n,i){let r={},s={},a=[];const o=t.getParameter(t.MAX_UNIFORM_BUFFER_BINDINGS);function l(t,e,n,i){const r=t.value,s=e+"_"+n;if(void 0===i[s])return i[s]="number"==typeof r||"boolean"==typeof r?r:r.clone(),!0;{const t=i[s];if("number"==typeof r||"boolean"==typeof r){if(t!==r)return i[s]=r,!0}else if(!1===t.equals(r))return t.copy(r),!0}return!1}function c(t){const e={boundary:0,storage:0};return"number"==typeof t||"boolean"==typeof t?(e.boundary=4,e.storage=4):t.isVector2?(e.boundary=8,e.storage=8):t.isVector3||t.isColor?(e.boundary=16,e.storage=12):t.isVector4?(e.boundary=16,e.storage=16):t.isMatrix3?(e.boundary=48,e.storage=48):t.isMatrix4?(e.boundary=64,e.storage=64):t.isTexture?console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group."):console.warn("THREE.WebGLRenderer: Unsupported uniform value type.",t),e}function h(e){const n=e.target;n.removeEventListener("dispose",h);const i=a.indexOf(n.__bindingPointIndex);a.splice(i,1),t.deleteBuffer(r[n.id]),delete r[n.id],delete s[n.id]}return{bind:function(t,e){const n=e.program;i.uniformBlockBinding(t,n)},update:function(n,u){let d=r[n.id];void 0===d&&(!function(t){const e=t.uniforms;let n=0;const i=16;for(let t=0,r=e.length;t0&&(n+=i-r);t.__size=n,t.__cache={}}(n),d=function(e){const n=function(){for(let t=0;t0),u=!!n.morphAttributes.position,d=!!n.morphAttributes.normal,p=!!n.morphAttributes.color;let m=K;i.toneMapped&&(null!==T&&!0!==T.isXRRenderTarget||(m=M.toneMapping));const f=n.morphAttributes.position||n.morphAttributes.normal||n.morphAttributes.color,g=void 0!==f?f.length:0,v=nt.get(i),x=_.state.lights;if(!0===H&&(!0===G||t!==A)){const e=t===A&&i.id===E;pt.setState(i,t,e)}let y=!1;i.version===v.__version?v.needsLights&&v.lightsStateVersion!==x.state.version||v.outputColorSpace!==o||r.isBatchedMesh&&!1===v.batching?y=!0:r.isBatchedMesh||!0!==v.batching?r.isBatchedMesh&&!0===v.batchingColor&&null===r.colorTexture||r.isBatchedMesh&&!1===v.batchingColor&&null!==r.colorTexture||r.isInstancedMesh&&!1===v.instancing?y=!0:r.isInstancedMesh||!0!==v.instancing?r.isSkinnedMesh&&!1===v.skinning?y=!0:r.isSkinnedMesh||!0!==v.skinning?r.isInstancedMesh&&!0===v.instancingColor&&null===r.instanceColor||r.isInstancedMesh&&!1===v.instancingColor&&null!==r.instanceColor||r.isInstancedMesh&&!0===v.instancingMorph&&null===r.morphTexture||r.isInstancedMesh&&!1===v.instancingMorph&&null!==r.morphTexture||v.envMap!==l||!0===i.fog&&v.fog!==s?y=!0:void 0===v.numClippingPlanes||v.numClippingPlanes===pt.numPlanes&&v.numIntersection===pt.numIntersection?(v.vertexAlphas!==c||v.vertexTangents!==h||v.morphTargets!==u||v.morphNormals!==d||v.morphColors!==p||v.toneMapping!==m||v.morphTargetsCount!==g)&&(y=!0):y=!0:y=!0:y=!0:y=!0:(y=!0,v.__version=i.version);let S=v.currentProgram;!0===y&&(S=Kt(i,e,r));let b=!1,w=!1,R=!1;const C=S.getUniforms(),P=v.uniforms;tt.useProgram(S.program)&&(b=!0,w=!0,R=!0);i.id!==E&&(E=i.id,w=!0);if(b||A!==t){Q.reverseDepthBuffer?(W.copy(t.projectionMatrix),function(t){const e=t.elements;e[2]=.5*e[2]+.5*e[3],e[6]=.5*e[6]+.5*e[7],e[10]=.5*e[10]+.5*e[11],e[14]=.5*e[14]+.5*e[15]}(W),function(t){const e=t.elements;-1===e[11]?(e[10]=-e[10]-1,e[14]=-e[14]):(e[10]=-e[10],e[14]=1-e[14])}(W),C.setValue(St,"projectionMatrix",W)):C.setValue(St,"projectionMatrix",t.projectionMatrix),C.setValue(St,"viewMatrix",t.matrixWorldInverse);const e=C.map.cameraPosition;void 0!==e&&e.setValue(St,j.setFromMatrixPosition(t.matrixWorld)),Q.logarithmicDepthBuffer&&C.setValue(St,"logDepthBufFC",2/(Math.log(t.far+1)/Math.LN2)),(i.isMeshPhongMaterial||i.isMeshToonMaterial||i.isMeshLambertMaterial||i.isMeshBasicMaterial||i.isMeshStandardMaterial||i.isShaderMaterial)&&C.setValue(St,"isOrthographic",!0===t.isOrthographicCamera),A!==t&&(A=t,w=!0,R=!0)}if(r.isSkinnedMesh){C.setOptional(St,r,"bindMatrix"),C.setOptional(St,r,"bindMatrixInverse");const t=r.skeleton;t&&(null===t.boneTexture&&t.computeBoneTexture(),C.setValue(St,"boneTexture",t.boneTexture,it))}r.isBatchedMesh&&(C.setOptional(St,r,"batchingTexture"),C.setValue(St,"batchingTexture",r._matricesTexture,it),C.setOptional(St,r,"batchingIdTexture"),C.setValue(St,"batchingIdTexture",r._indirectTexture,it),C.setOptional(St,r,"batchingColorTexture"),null!==r._colorsTexture&&C.setValue(St,"batchingColorTexture",r._colorsTexture,it));const I=n.morphAttributes;void 0===I.position&&void 0===I.normal&&void 0===I.color||gt.update(r,n,S);(w||v.receiveShadow!==r.receiveShadow)&&(v.receiveShadow=r.receiveShadow,C.setValue(St,"receiveShadow",r.receiveShadow));i.isMeshGouraudMaterial&&null!==i.envMap&&(P.envMap.value=l,P.flipEnvMap.value=l.isCubeTexture&&!1===l.isRenderTargetTexture?-1:1);i.isMeshStandardMaterial&&null===i.envMap&&null!==e.environment&&(P.envMapIntensity.value=e.environmentIntensity);w&&(C.setValue(St,"toneMappingExposure",M.toneMappingExposure),v.needsLights&&(U=R,(L=P).ambientLightColor.needsUpdate=U,L.lightProbe.needsUpdate=U,L.directionalLights.needsUpdate=U,L.directionalLightShadows.needsUpdate=U,L.pointLights.needsUpdate=U,L.pointLightShadows.needsUpdate=U,L.spotLights.needsUpdate=U,L.spotLightShadows.needsUpdate=U,L.rectAreaLights.needsUpdate=U,L.hemisphereLights.needsUpdate=U),s&&!0===i.fog&&ht.refreshFogUniforms(P,s),ht.refreshMaterialUniforms(P,i,D,N,_.state.transmissionRenderTarget[t.id]),il.upload(St,$t(v),P,it));var L,U;i.isShaderMaterial&&!0===i.uniformsNeedUpdate&&(il.upload(St,$t(v),P,it),i.uniformsNeedUpdate=!1);i.isSpriteMaterial&&C.setValue(St,"center",r.center);if(C.setValue(St,"modelViewMatrix",r.modelViewMatrix),C.setValue(St,"normalMatrix",r.normalMatrix),C.setValue(St,"modelMatrix",r.matrixWorld),i.isShaderMaterial||i.isRawShaderMaterial){const t=i.uniformsGroups;for(let e=0,n=t.length;e{function n(){i.forEach((function(t){nt.get(t).currentProgram.isReady()&&i.delete(t)})),0!==i.size?setTimeout(n,10):e(t)}null!==$.get("KHR_parallel_shader_compile")?n():setTimeout(n,10)}))};let zt=null;function kt(){Ht.stop()}function Vt(){Ht.start()}const Ht=new ua;function Gt(t,e,n,i){if(!1===t.visible)return;if(t.layers.test(e.layers))if(t.isGroup)n=t.renderOrder;else if(t.isLOD)!0===t.autoUpdate&&t.update(e);else if(t.isLight)_.pushLight(t),t.castShadow&&_.pushShadow(t);else if(t.isSprite){if(!t.frustumCulled||V.intersectsSprite(t)){i&&q.setFromMatrixPosition(t.matrixWorld).applyMatrix4(X);const e=lt.update(t),r=t.material;r.visible&&v.push(t,e,r,n,q.z,null)}}else if((t.isMesh||t.isLine||t.isPoints)&&(!t.frustumCulled||V.intersectsObject(t))){const e=lt.update(t),r=t.material;if(i&&(void 0!==t.boundingSphere?(null===t.boundingSphere&&t.computeBoundingSphere(),q.copy(t.boundingSphere.center)):(null===e.boundingSphere&&e.computeBoundingSphere(),q.copy(e.boundingSphere.center)),q.applyMatrix4(t.matrixWorld).applyMatrix4(X)),Array.isArray(r)){const i=e.groups;for(let s=0,a=i.length;s0&&qt(r,e,n),s.length>0&&qt(s,e,n),a.length>0&&qt(a,e,n),tt.buffers.depth.setTest(!0),tt.buffers.depth.setMask(!0),tt.buffers.color.setMask(!0),tt.setPolygonOffset(!1)}function Xt(t,e,n,i){if(null!==(!0===n.isScene?n.overrideMaterial:null))return;void 0===_.state.transmissionRenderTarget[i.id]&&(_.state.transmissionRenderTarget[i.id]=new Ei(1,1,{generateMipmaps:!0,type:$.has("EXT_color_buffer_half_float")||$.has("EXT_color_buffer_float")?Ut:Et,minFilter:wt,samples:4,stencilBuffer:s,resolveDepthBuffer:!1,resolveStencilBuffer:!1,colorSpace:mi.workingColorSpace}));const r=_.state.transmissionRenderTarget[i.id],a=i.viewport||R;r.setSize(a.z,a.w);const o=M.getRenderTarget();M.setRenderTarget(r),M.getClearColor(I),L=M.getClearAlpha(),L<1&&M.setClearColor(16777215,.5),M.clear(),Z&&ft.render(n);const l=M.toneMapping;M.toneMapping=K;const c=i.viewport;if(void 0!==i.viewport&&(i.viewport=void 0),_.setupLightsView(i),!0===H&&pt.setGlobalState(M.clippingPlanes,i),qt(t,n,i),it.updateMultisampleRenderTarget(r),it.updateRenderTargetMipmap(r),!1===$.has("WEBGL_multisampled_render_to_texture")){let t=!1;for(let r=0,s=e.length;r0)for(let e=0,s=n.length;e0&&Xt(i,r,t,e),Z&&ft.render(t),Wt(v,t,e);null!==T&&(it.updateMultisampleRenderTarget(T),it.updateRenderTargetMipmap(T)),!0===t.isScene&&t.onAfterRender(M,t,e),yt.resetDefaultState(),E=-1,A=null,y.pop(),y.length>0?(_=y[y.length-1],!0===H&&pt.setGlobalState(M.clippingPlanes,_.state.camera)):_=null,x.pop(),v=x.length>0?x[x.length-1]:null},this.getActiveCubeFace=function(){return b},this.getActiveMipmapLevel=function(){return w},this.getRenderTarget=function(){return T},this.setRenderTargetTextures=function(t,e,n){nt.get(t.texture).__webglTexture=e,nt.get(t.depthTexture).__webglTexture=n;const i=nt.get(t);i.__hasExternalTextures=!0,i.__autoAllocateDepthBuffer=void 0===n,i.__autoAllocateDepthBuffer||!0===$.has("WEBGL_multisampled_render_to_texture")&&(console.warn("THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided"),i.__useRenderToTexture=!1)},this.setRenderTargetFramebuffer=function(t,e){const n=nt.get(t);n.__webglFramebuffer=e,n.__useDefaultFramebuffer=void 0===e},this.setRenderTarget=function(t,e=0,n=0){T=t,b=e,w=n;let i=!0,r=null,s=!1,a=!1;if(t){const o=nt.get(t);if(void 0!==o.__useDefaultFramebuffer)tt.bindFramebuffer(St.FRAMEBUFFER,null),i=!1;else if(void 0===o.__webglFramebuffer)it.setupRenderTarget(t);else if(o.__hasExternalTextures)it.rebindTextures(t,nt.get(t.texture).__webglTexture,nt.get(t.depthTexture).__webglTexture);else if(t.depthBuffer){const e=t.depthTexture;if(o.__boundDepthTexture!==e){if(null!==e&&nt.has(e)&&(t.width!==e.image.width||t.height!==e.image.height))throw new Error("WebGLRenderTarget: Attached DepthTexture is initialized to the incorrect size.");it.setupDepthRenderbuffer(t)}}const l=t.texture;(l.isData3DTexture||l.isDataArrayTexture||l.isCompressedArrayTexture)&&(a=!0);const c=nt.get(t).__webglFramebuffer;t.isWebGLCubeRenderTarget?(r=Array.isArray(c[e])?c[e][n]:c[e],s=!0):r=t.samples>0&&!1===it.useMultisampledRTT(t)?nt.get(t).__webglMultisampledFramebuffer:Array.isArray(c)?c[n]:c,R.copy(t.viewport),C.copy(t.scissor),P=t.scissorTest}else R.copy(B).multiplyScalar(D).floor(),C.copy(z).multiplyScalar(D).floor(),P=k;if(tt.bindFramebuffer(St.FRAMEBUFFER,r)&&i&&tt.drawBuffers(t,r),tt.viewport(R),tt.scissor(C),tt.setScissorTest(P),s){const i=nt.get(t.texture);St.framebufferTexture2D(St.FRAMEBUFFER,St.COLOR_ATTACHMENT0,St.TEXTURE_CUBE_MAP_POSITIVE_X+e,i.__webglTexture,n)}else if(a){const i=nt.get(t.texture),r=e||0;St.framebufferTextureLayer(St.FRAMEBUFFER,St.COLOR_ATTACHMENT0,i.__webglTexture,n||0,r)}E=-1},this.readRenderTargetPixels=function(t,e,n,i,r,s,a){if(!t||!t.isWebGLRenderTarget)return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let o=nt.get(t).__webglFramebuffer;if(t.isWebGLCubeRenderTarget&&void 0!==a&&(o=o[a]),o){tt.bindFramebuffer(St.FRAMEBUFFER,o);try{const a=t.texture,o=a.format,l=a.type;if(!Q.textureFormatReadable(o))return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");if(!Q.textureTypeReadable(l))return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");e>=0&&e<=t.width-i&&n>=0&&n<=t.height-r&&St.readPixels(e,n,i,r,xt.convert(o),xt.convert(l),s)}finally{const t=null!==T?nt.get(T).__webglFramebuffer:null;tt.bindFramebuffer(St.FRAMEBUFFER,t)}}},this.readRenderTargetPixelsAsync=async function(t,e,n,i,r,s,a){if(!t||!t.isWebGLRenderTarget)throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let o=nt.get(t).__webglFramebuffer;if(t.isWebGLCubeRenderTarget&&void 0!==a&&(o=o[a]),o){const a=t.texture,l=a.format,c=a.type;if(!Q.textureFormatReadable(l))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(!Q.textureTypeReadable(c))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");if(e>=0&&e<=t.width-i&&n>=0&&n<=t.height-r){tt.bindFramebuffer(St.FRAMEBUFFER,o);const t=St.createBuffer();St.bindBuffer(St.PIXEL_PACK_BUFFER,t),St.bufferData(St.PIXEL_PACK_BUFFER,s.byteLength,St.STREAM_READ),St.readPixels(e,n,i,r,xt.convert(l),xt.convert(c),0);const a=null!==T?nt.get(T).__webglFramebuffer:null;tt.bindFramebuffer(St.FRAMEBUFFER,a);const h=St.fenceSync(St.SYNC_GPU_COMMANDS_COMPLETE,0);return St.flush(),await function(t,e,n){return new Promise((function(i,r){setTimeout((function s(){switch(t.clientWaitSync(e,t.SYNC_FLUSH_COMMANDS_BIT,0)){case t.WAIT_FAILED:r();break;case t.TIMEOUT_EXPIRED:setTimeout(s,n);break;default:i()}}),n)}))}(St,h,4),St.bindBuffer(St.PIXEL_PACK_BUFFER,t),St.getBufferSubData(St.PIXEL_PACK_BUFFER,0,s),St.deleteBuffer(t),St.deleteSync(h),s}throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.")}},this.copyFramebufferToTexture=function(t,e=null,n=0){!0!==t.isTexture&&(ci("WebGLRenderer: copyFramebufferToTexture function signature has changed."),e=arguments[0]||null,t=arguments[1]);const i=Math.pow(2,-n),r=Math.floor(t.image.width*i),s=Math.floor(t.image.height*i),a=null!==e?e.x:0,o=null!==e?e.y:0;it.setTexture2D(t,0),St.copyTexSubImage2D(St.TEXTURE_2D,n,0,0,a,o,r,s),tt.unbindTexture()},this.copyTextureToTexture=function(t,e,n=null,i=null,r=0){let s,a,o,l,c,h;!0!==t.isTexture&&(ci("WebGLRenderer: copyTextureToTexture function signature has changed."),i=arguments[0]||null,t=arguments[1],e=arguments[2],r=arguments[3]||0,n=null),null!==n?(s=n.max.x-n.min.x,a=n.max.y-n.min.y,o=n.min.x,l=n.min.y):(s=t.image.width,a=t.image.height,o=0,l=0),null!==i?(c=i.x,h=i.y):(c=0,h=0);const u=xt.convert(e.format),d=xt.convert(e.type);it.setTexture2D(e,0),St.pixelStorei(St.UNPACK_FLIP_Y_WEBGL,e.flipY),St.pixelStorei(St.UNPACK_PREMULTIPLY_ALPHA_WEBGL,e.premultiplyAlpha),St.pixelStorei(St.UNPACK_ALIGNMENT,e.unpackAlignment);const p=St.getParameter(St.UNPACK_ROW_LENGTH),m=St.getParameter(St.UNPACK_IMAGE_HEIGHT),f=St.getParameter(St.UNPACK_SKIP_PIXELS),g=St.getParameter(St.UNPACK_SKIP_ROWS),v=St.getParameter(St.UNPACK_SKIP_IMAGES),_=t.isCompressedTexture?t.mipmaps[r]:t.image;St.pixelStorei(St.UNPACK_ROW_LENGTH,_.width),St.pixelStorei(St.UNPACK_IMAGE_HEIGHT,_.height),St.pixelStorei(St.UNPACK_SKIP_PIXELS,o),St.pixelStorei(St.UNPACK_SKIP_ROWS,l),t.isDataTexture?St.texSubImage2D(St.TEXTURE_2D,r,c,h,s,a,u,d,_.data):t.isCompressedTexture?St.compressedTexSubImage2D(St.TEXTURE_2D,r,c,h,_.width,_.height,u,_.data):St.texSubImage2D(St.TEXTURE_2D,r,c,h,s,a,u,d,_),St.pixelStorei(St.UNPACK_ROW_LENGTH,p),St.pixelStorei(St.UNPACK_IMAGE_HEIGHT,m),St.pixelStorei(St.UNPACK_SKIP_PIXELS,f),St.pixelStorei(St.UNPACK_SKIP_ROWS,g),St.pixelStorei(St.UNPACK_SKIP_IMAGES,v),0===r&&e.generateMipmaps&&St.generateMipmap(St.TEXTURE_2D),tt.unbindTexture()},this.copyTextureToTexture3D=function(t,e,n=null,i=null,r=0){let s,a,o,l,c,h,u,d,p;!0!==t.isTexture&&(ci("WebGLRenderer: copyTextureToTexture3D function signature has changed."),n=arguments[0]||null,i=arguments[1]||null,t=arguments[2],e=arguments[3],r=arguments[4]||0);const m=t.isCompressedTexture?t.mipmaps[r]:t.image;null!==n?(s=n.max.x-n.min.x,a=n.max.y-n.min.y,o=n.max.z-n.min.z,l=n.min.x,c=n.min.y,h=n.min.z):(s=m.width,a=m.height,o=m.depth,l=0,c=0,h=0),null!==i?(u=i.x,d=i.y,p=i.z):(u=0,d=0,p=0);const f=xt.convert(e.format),g=xt.convert(e.type);let v;if(e.isData3DTexture)it.setTexture3D(e,0),v=St.TEXTURE_3D;else{if(!e.isDataArrayTexture&&!e.isCompressedArrayTexture)return void console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.");it.setTexture2DArray(e,0),v=St.TEXTURE_2D_ARRAY}St.pixelStorei(St.UNPACK_FLIP_Y_WEBGL,e.flipY),St.pixelStorei(St.UNPACK_PREMULTIPLY_ALPHA_WEBGL,e.premultiplyAlpha),St.pixelStorei(St.UNPACK_ALIGNMENT,e.unpackAlignment);const _=St.getParameter(St.UNPACK_ROW_LENGTH),x=St.getParameter(St.UNPACK_IMAGE_HEIGHT),y=St.getParameter(St.UNPACK_SKIP_PIXELS),M=St.getParameter(St.UNPACK_SKIP_ROWS),S=St.getParameter(St.UNPACK_SKIP_IMAGES);St.pixelStorei(St.UNPACK_ROW_LENGTH,m.width),St.pixelStorei(St.UNPACK_IMAGE_HEIGHT,m.height),St.pixelStorei(St.UNPACK_SKIP_PIXELS,l),St.pixelStorei(St.UNPACK_SKIP_ROWS,c),St.pixelStorei(St.UNPACK_SKIP_IMAGES,h),t.isDataTexture||t.isData3DTexture?St.texSubImage3D(v,r,u,d,p,s,a,o,f,g,m.data):e.isCompressedArrayTexture?St.compressedTexSubImage3D(v,r,u,d,p,s,a,o,f,m.data):St.texSubImage3D(v,r,u,d,p,s,a,o,f,g,m),St.pixelStorei(St.UNPACK_ROW_LENGTH,_),St.pixelStorei(St.UNPACK_IMAGE_HEIGHT,x),St.pixelStorei(St.UNPACK_SKIP_PIXELS,y),St.pixelStorei(St.UNPACK_SKIP_ROWS,M),St.pixelStorei(St.UNPACK_SKIP_IMAGES,S),0===r&&e.generateMipmaps&&St.generateMipmap(v),tt.unbindTexture()},this.initRenderTarget=function(t){void 0===nt.get(t).__webglFramebuffer&&it.setupRenderTarget(t)},this.initTexture=function(t){t.isCubeTexture?it.setTextureCube(t,0):t.isData3DTexture?it.setTexture3D(t,0):t.isDataArrayTexture||t.isCompressedArrayTexture?it.setTexture2DArray(t,0):it.setTexture2D(t,0),tt.unbindTexture()},this.resetState=function(){b=0,w=0,T=null,tt.reset(),yt.reset()},"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}get coordinateSystem(){return kn}get outputColorSpace(){return this._outputColorSpace}set outputColorSpace(t){this._outputColorSpace=t;const e=this.getContext();e.drawingBufferColorSpace=t===$e?"display-p3":"srgb",e.unpackColorSpace=mi.workingColorSpace===Qe?"display-p3":"srgb"}}class sc{constructor(t,e=25e-5){this.isFogExp2=!0,this.name="",this.color=new ts(t),this.density=e}clone(){return new sc(this.color,this.density)}toJSON(){return{type:"FogExp2",name:this.name,color:this.color.getHex(),density:this.density}}}class ac{constructor(t,e=1,n=1e3){this.isFog=!0,this.name="",this.color=new ts(t),this.near=e,this.far=n}clone(){return new ac(this.color,this.near,this.far)}toJSON(){return{type:"Fog",name:this.name,color:this.color.getHex(),near:this.near,far:this.far}}}class oc extends Dr{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.backgroundRotation=new _r,this.environmentIntensity=1,this.environmentRotation=new _r,this.overrideMaterial=null,"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(t,e){return super.copy(t,e),null!==t.background&&(this.background=t.background.clone()),null!==t.environment&&(this.environment=t.environment.clone()),null!==t.fog&&(this.fog=t.fog.clone()),this.backgroundBlurriness=t.backgroundBlurriness,this.backgroundIntensity=t.backgroundIntensity,this.backgroundRotation.copy(t.backgroundRotation),this.environmentIntensity=t.environmentIntensity,this.environmentRotation.copy(t.environmentRotation),null!==t.overrideMaterial&&(this.overrideMaterial=t.overrideMaterial.clone()),this.matrixAutoUpdate=t.matrixAutoUpdate,this}toJSON(t){const e=super.toJSON(t);return null!==this.fog&&(e.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(e.object.backgroundBlurriness=this.backgroundBlurriness),1!==this.backgroundIntensity&&(e.object.backgroundIntensity=this.backgroundIntensity),e.object.backgroundRotation=this.backgroundRotation.toArray(),1!==this.environmentIntensity&&(e.object.environmentIntensity=this.environmentIntensity),e.object.environmentRotation=this.environmentRotation.toArray(),e}}class lc{constructor(t,e){this.isInterleavedBuffer=!0,this.array=t,this.stride=e,this.count=void 0!==t?t.length/e:0,this.usage=Cn,this.updateRanges=[],this.version=0,this.uuid=qn()}onUploadCallback(){}set needsUpdate(t){!0===t&&this.version++}setUsage(t){return this.usage=t,this}addUpdateRange(t,e){this.updateRanges.push({start:t,count:e})}clearUpdateRanges(){this.updateRanges.length=0}copy(t){return this.array=new t.array.constructor(t.array),this.count=t.count,this.stride=t.stride,this.usage=t.usage,this}copyAt(t,e,n){t*=this.stride,n*=e.stride;for(let i=0,r=this.stride;it.far||e.push({distance:o,point:pc.clone(),uv:Zr.getInterpolation(pc,xc,yc,Mc,Sc,bc,wc,new ti),face:null,object:this})}copy(t,e){return super.copy(t,e),void 0!==t.center&&this.center.copy(t.center),this.material=t.material,this}}function Ec(t,e,n,i,r,s){gc.subVectors(t,n).addScalar(.5).multiply(i),void 0!==r?(vc.x=s*gc.x-r*gc.y,vc.y=r*gc.x+s*gc.y):vc.copy(gc),t.copy(e),t.x+=vc.x,t.y+=vc.y,t.applyMatrix4(_c)}const Ac=new Li,Rc=new Li;class Cc extends Dr{constructor(){super(),this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]},isLOD:{value:!0}}),this.autoUpdate=!0}copy(t){super.copy(t,!1);const e=t.levels;for(let t=0,n=e.length;t0){let n,i;for(n=1,i=e.length;n0){Ac.setFromMatrixPosition(this.matrixWorld);const n=t.ray.origin.distanceTo(Ac);this.getObjectForDistance(n).raycast(t,e)}}update(t){const e=this.levels;if(e.length>1){Ac.setFromMatrixPosition(t.matrixWorld),Rc.setFromMatrixPosition(this.matrixWorld);const n=Ac.distanceTo(Rc)/t.zoom;let i,r;for(e[0].object.visible=!0,i=1,r=e.length;i=t))break;e[i-1].object.visible=!1,e[i].object.visible=!0}for(this._currentLevel=i-1;i=i.length&&i.push({start:-1,count:-1,z:-1,index:-1});const s=i[this.index];r.push(s),this.index++,s.start=t.start,s.count=t.count,s.z=e,s.index=n}reset(){this.list.length=0,this.index=0}}const ih=new lr,rh=new lr,sh=new lr,ah=new ts(1,1,1),oh=new lr,lh=new ha,ch=new Di,hh=new Qi,uh=new Li,dh=new Li,ph=new Li,mh=new nh,fh=new Vs,gh=[];function vh(t,e,n=0){const i=e.itemSize;if(t.isInterleavedBufferAttribute||t.array.constructor!==e.array.constructor){const r=t.count;for(let s=0;s65535?new Uint32Array(i):new Uint16Array(i);e.setIndex(new ds(t,1))}this._geometryInitialized=!0}}_validateGeometry(t){const e=this.geometry;if(Boolean(t.getIndex())!==Boolean(e.getIndex()))throw new Error('BatchedMesh: All geometries must consistently have "index".');for(const n in e.attributes){if(!t.hasAttribute(n))throw new Error(`BatchedMesh: Added geometry missing "${n}". All geometries must have consistent attributes.`);const i=t.getAttribute(n),r=e.getAttribute(n);if(i.itemSize!==r.itemSize||i.normalized!==r.normalized)throw new Error("BatchedMesh: All attributes must have a consistent itemSize and normalized value.")}}setCustomSort(t){return this.customSort=t,this}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new Di);const t=this.boundingBox,e=this._drawInfo;t.makeEmpty();for(let n=0,i=e.length;n=this.maxInstanceCount&&0===this._availableInstanceIds.length)throw new Error("BatchedMesh: Maximum item count reached.");const e={visible:!0,active:!0,geometryIndex:t};let n=null;this._availableInstanceIds.length>0?(n=this._availableInstanceIds.pop(),this._drawInfo[n]=e):(n=this._drawInfo.length,this._drawInfo.push(e));const i=this._matricesTexture,r=i.image.data;sh.toArray(r,16*n),i.needsUpdate=!0;const s=this._colorsTexture;return s&&(ah.toArray(s.image.data,4*n),s.needsUpdate=!0),n}addGeometry(t,e=-1,n=-1){if(this._initializeGeometry(t),this._validateGeometry(t),this._drawInfo.length>=this._maxInstanceCount)throw new Error("BatchedMesh: Maximum item count reached.");const i={vertexStart:-1,vertexCount:-1,indexStart:-1,indexCount:-1};let r=null;const s=this._reservedRanges,a=this._drawRanges,o=this._bounds;0!==this._geometryCount&&(r=s[s.length-1]),i.vertexCount=-1===e?t.getAttribute("position").count:e,i.vertexStart=null===r?0:r.vertexStart+r.vertexCount;const l=t.getIndex(),c=null!==l;if(c&&(i.indexCount=-1===n?l.count:n,i.indexStart=null===r?0:r.indexStart+r.indexCount),-1!==i.indexStart&&i.indexStart+i.indexCount>this._maxIndexCount||i.vertexStart+i.vertexCount>this._maxVertexCount)throw new Error("BatchedMesh: Reserved space request exceeds the maximum buffer size.");const h=this._geometryCount;return this._geometryCount++,s.push(i),a.push({start:c?i.indexStart:i.vertexStart,count:-1}),o.push({boxInitialized:!1,box:new Di,sphereInitialized:!1,sphere:new Qi}),this.setGeometryAt(h,t),h}setGeometryAt(t,e){if(t>=this._geometryCount)throw new Error("BatchedMesh: Maximum geometry count reached.");this._validateGeometry(e);const n=this.geometry,i=null!==n.getIndex(),r=n.getIndex(),s=e.getIndex(),a=this._reservedRanges[t];if(i&&s.count>a.indexCount||e.attributes.position.count>a.vertexCount)throw new Error("BatchedMesh: Reserved space not large enough for provided geometry.");const o=a.vertexStart,l=a.vertexCount;for(const t in n.attributes){const i=e.getAttribute(t),r=n.getAttribute(t);vh(i,r,o);const s=i.itemSize;for(let t=i.count,e=l;t=e.length||!1===e[t].active||(e[t].active=!1,this._availableInstanceIds.push(t),this._visibilityChanged=!0),this}getBoundingBoxAt(t,e){if(t>=this._geometryCount)return null;const n=this._bounds[t],i=n.box,r=this.geometry;if(!1===n.boxInitialized){i.makeEmpty();const e=r.index,s=r.attributes.position,a=this._drawRanges[t];for(let t=a.start,n=a.start+a.count;t=this._geometryCount)return null;const n=this._bounds[t],i=n.sphere,r=this.geometry;if(!1===n.sphereInitialized){i.makeEmpty(),this.getBoundingBoxAt(t,ch),ch.getCenter(i.center);const e=r.index,s=r.attributes.position,a=this._drawRanges[t];let o=0;for(let t=a.start,n=a.start+a.count;t=n.length||!1===n[t].active||(e.toArray(r,16*t),i.needsUpdate=!0),this}getMatrixAt(t,e){const n=this._drawInfo,i=this._matricesTexture.image.data;return t>=n.length||!1===n[t].active?null:e.fromArray(i,16*t)}setColorAt(t,e){null===this._colorsTexture&&this._initColorsTexture();const n=this._colorsTexture,i=this._colorsTexture.image.data,r=this._drawInfo;return t>=r.length||!1===r[t].active||(e.toArray(i,4*t),n.needsUpdate=!0),this}getColorAt(t,e){const n=this._colorsTexture.image.data,i=this._drawInfo;return t>=i.length||!1===i[t].active?null:e.fromArray(n,4*t)}setVisibleAt(t,e){const n=this._drawInfo;return t>=n.length||!1===n[t].active||n[t].visible===e||(n[t].visible=e,this._visibilityChanged=!0),this}getVisibleAt(t){const e=this._drawInfo;return!(t>=e.length||!1===e[t].active)&&e[t].visible}setGeometryIdAt(t,e){const n=this._drawInfo;return t>=n.length||!1===n[t].active||e<0||e>=this._geometryCount?null:(n[t].geometryIndex=e,this)}getGeometryIdAt(t){const e=this._drawInfo;return t>=e.length||!1===e[t].active?-1:e[t].geometryIndex}getGeometryRangeAt(t,e={}){if(t<0||t>=this._geometryCount)return null;const n=this._drawRanges[t];return e.start=n.start,e.count=n.count,e}raycast(t,e){const n=this._drawInfo,i=this._drawRanges,r=this.matrixWorld,s=this.geometry;fh.material=this.material,fh.geometry.index=s.index,fh.geometry.attributes=s.attributes,null===fh.geometry.boundingBox&&(fh.geometry.boundingBox=new Di),null===fh.geometry.boundingSphere&&(fh.geometry.boundingSphere=new Qi);for(let s=0,a=n.length;s({...t}))),this._reservedRanges=t._reservedRanges.map((t=>({...t}))),this._drawInfo=t._drawInfo.map((t=>({...t}))),this._bounds=t._bounds.map((t=>({boxInitialized:t.boxInitialized,box:t.box.clone(),sphereInitialized:t.sphereInitialized,sphere:t.sphere.clone()}))),this._maxInstanceCount=t._maxInstanceCount,this._maxVertexCount=t._maxVertexCount,this._maxIndexCount=t._maxIndexCount,this._geometryInitialized=t._geometryInitialized,this._geometryCount=t._geometryCount,this._multiDrawCounts=t._multiDrawCounts.slice(),this._multiDrawStarts=t._multiDrawStarts.slice(),this._matricesTexture=t._matricesTexture.clone(),this._matricesTexture.image.data=this._matricesTexture.image.data.slice(),null!==this._colorsTexture&&(this._colorsTexture=t._colorsTexture.clone(),this._colorsTexture.image.data=this._colorsTexture.image.data.slice()),this}dispose(){return this.geometry.dispose(),this._matricesTexture.dispose(),this._matricesTexture=null,this._indirectTexture.dispose(),this._indirectTexture=null,null!==this._colorsTexture&&(this._colorsTexture.dispose(),this._colorsTexture=null),this}onBeforeRender(t,e,n,i,r){if(!this._visibilityChanged&&!this.perObjectFrustumCulled&&!this.sortObjects)return;const s=i.getIndex(),a=null===s?1:s.array.BYTES_PER_ELEMENT,o=this._drawInfo,l=this._multiDrawStarts,c=this._multiDrawCounts,h=this._drawRanges,u=this.perObjectFrustumCulled,d=this._indirectTexture,p=d.image.data;u&&(oh.multiplyMatrices(n.projectionMatrix,n.matrixWorldInverse).multiply(this.matrixWorld),lh.setFromProjectionMatrix(oh,t.coordinateSystem));let m=0;if(this.sortObjects){rh.copy(this.matrixWorld).invert(),uh.setFromMatrixPosition(n.matrixWorld).applyMatrix4(rh),dh.set(0,0,-1).transformDirection(n.matrixWorld).transformDirection(rh);for(let t=0,e=o.length;t0){const n=t[e[0]];if(void 0!==n){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=n.length;ti)return;Th.applyMatrix4(t.matrixWorld);const o=e.ray.origin.distanceTo(Th);return oe.far?void 0:{distance:o,point:Eh.clone().applyMatrix4(t.matrixWorld),index:r,face:null,faceIndex:null,barycoord:null,object:t}}const Ch=new Li,Ph=new Li;class Ih extends Ah{constructor(t,e){super(t,e),this.isLineSegments=!0,this.type="LineSegments"}computeLineDistances(){const t=this.geometry;if(null===t.index){const e=t.attributes.position,n=[];for(let t=0,i=e.count;t0){const n=t[e[0]];if(void 0!==n){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=n.length;tr.far)return;s.push({distance:l,distanceToRay:Math.sqrt(o),point:n,index:e,face:null,faceIndex:null,barycoord:null,object:a})}}class kh extends bi{constructor(t,e,n,i,r,s,a,o,l){super(t,e,n,i,r,s,a,o,l),this.isVideoTexture=!0,this.minFilter=void 0!==s?s:Mt,this.magFilter=void 0!==r?r:Mt,this.generateMipmaps=!1;const c=this;"requestVideoFrameCallback"in t&&t.requestVideoFrameCallback((function e(){c.needsUpdate=!0,t.requestVideoFrameCallback(e)}))}clone(){return new this.constructor(this.image).copy(this)}update(){const t=this.image;!1==="requestVideoFrameCallback"in t&&t.readyState>=t.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}}class Vh extends bi{constructor(t,e){super({width:t,height:e}),this.isFramebufferTexture=!0,this.magFilter=gt,this.minFilter=gt,this.generateMipmaps=!1,this.needsUpdate=!0}}class Hh extends bi{constructor(t,e,n,i,r,s,a,o,l,c,h,u){super(null,s,a,o,l,c,i,r,h,u),this.isCompressedTexture=!0,this.image={width:e,height:n},this.mipmaps=t,this.flipY=!1,this.generateMipmaps=!1}}class Gh extends Hh{constructor(t,e,n,i,r,s){super(t,e,n,r,s),this.isCompressedArrayTexture=!0,this.image.depth=i,this.wrapR=mt,this.layerUpdates=new Set}addLayerUpdate(t){this.layerUpdates.add(t)}clearLayerUpdates(){this.layerUpdates.clear()}}class Wh extends Hh{constructor(t,e,n){super(void 0,t[0].width,t[0].height,e,n,lt),this.isCompressedCubeTexture=!0,this.isCubeTexture=!0,this.image=t}}class Xh extends bi{constructor(t,e,n,i,r,s,a,o,l){super(t,e,n,i,r,s,a,o,l),this.isCanvasTexture=!0,this.needsUpdate=!0}}class jh{constructor(){this.type="Curve",this.arcLengthDivisions=200}getPoint(){return console.warn("THREE.Curve: .getPoint() not implemented."),null}getPointAt(t,e){const n=this.getUtoTmapping(t);return this.getPoint(n,e)}getPoints(t=5){const e=[];for(let n=0;n<=t;n++)e.push(this.getPoint(n/t));return e}getSpacedPoints(t=5){const e=[];for(let n=0;n<=t;n++)e.push(this.getPointAt(n/t));return e}getLength(){const t=this.getLengths();return t[t.length-1]}getLengths(t=this.arcLengthDivisions){if(this.cacheArcLengths&&this.cacheArcLengths.length===t+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;const e=[];let n,i=this.getPoint(0),r=0;e.push(0);for(let s=1;s<=t;s++)n=this.getPoint(s/t),r+=n.distanceTo(i),e.push(r),i=n;return this.cacheArcLengths=e,e}updateArcLengths(){this.needsUpdate=!0,this.getLengths()}getUtoTmapping(t,e){const n=this.getLengths();let i=0;const r=n.length;let s;s=e||t*n[r-1];let a,o=0,l=r-1;for(;o<=l;)if(i=Math.floor(o+(l-o)/2),a=n[i]-s,a<0)o=i+1;else{if(!(a>0)){l=i;break}l=i-1}if(i=l,n[i]===s)return i/(r-1);const c=n[i];return(i+(s-c)/(n[i+1]-c))/(r-1)}getTangent(t,e){const n=1e-4;let i=t-n,r=t+n;i<0&&(i=0),r>1&&(r=1);const s=this.getPoint(i),a=this.getPoint(r),o=e||(s.isVector2?new ti:new Li);return o.copy(a).sub(s).normalize(),o}getTangentAt(t,e){const n=this.getUtoTmapping(t);return this.getTangent(n,e)}computeFrenetFrames(t,e){const n=new Li,i=[],r=[],s=[],a=new Li,o=new lr;for(let e=0;e<=t;e++){const n=e/t;i[e]=this.getTangentAt(n,new Li)}r[0]=new Li,s[0]=new Li;let l=Number.MAX_VALUE;const c=Math.abs(i[0].x),h=Math.abs(i[0].y),u=Math.abs(i[0].z);c<=l&&(l=c,n.set(1,0,0)),h<=l&&(l=h,n.set(0,1,0)),u<=l&&n.set(0,0,1),a.crossVectors(i[0],n).normalize(),r[0].crossVectors(i[0],a),s[0].crossVectors(i[0],r[0]);for(let e=1;e<=t;e++){if(r[e]=r[e-1].clone(),s[e]=s[e-1].clone(),a.crossVectors(i[e-1],i[e]),a.length()>Number.EPSILON){a.normalize();const t=Math.acos(Yn(i[e-1].dot(i[e]),-1,1));r[e].applyMatrix4(o.makeRotationAxis(a,t))}s[e].crossVectors(i[e],r[e])}if(!0===e){let e=Math.acos(Yn(r[0].dot(r[t]),-1,1));e/=t,i[0].dot(a.crossVectors(r[0],r[t]))>0&&(e=-e);for(let n=1;n<=t;n++)r[n].applyMatrix4(o.makeRotationAxis(i[n],e*n)),s[n].crossVectors(i[n],r[n])}return{tangents:i,normals:r,binormals:s}}clone(){return(new this.constructor).copy(this)}copy(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}toJSON(){const t={metadata:{version:4.6,type:"Curve",generator:"Curve.toJSON"}};return t.arcLengthDivisions=this.arcLengthDivisions,t.type=this.type,t}fromJSON(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}}class qh extends jh{constructor(t=0,e=0,n=1,i=1,r=0,s=2*Math.PI,a=!1,o=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=t,this.aY=e,this.xRadius=n,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=s,this.aClockwise=a,this.aRotation=o}getPoint(t,e=new ti){const n=e,i=2*Math.PI;let r=this.aEndAngle-this.aStartAngle;const s=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(l)/r)+1)*r:0===c&&l===r-1&&(l=r-2,c=1),this.closed||l>0?a=i[(l-1)%r]:(Jh.subVectors(i[0],i[1]).add(i[0]),a=Jh);const h=i[l%r],u=i[(l+1)%r];if(this.closed||l+2i.length-2?i.length-1:s+1],h=i[s>i.length-3?i.length-1:s+2];return n.set(eu(a,o.x,l.x,c.x,h.x),eu(a,o.y,l.y,c.y,h.y)),n}copy(t){super.copy(t),this.points=[];for(let e=0,n=t.points.length;e=n){const t=i[r]-n,s=this.curves[r],a=s.getLength(),o=0===a?0:1-t/a;return s.getPointAt(o,e)}r++}return null}getLength(){const t=this.getCurveLengths();return t[t.length-1]}updateArcLengths(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()}getCurveLengths(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;const t=[];let e=0;for(let n=0,i=this.curves.length;n1&&!e[e.length-1].equals(e[0])&&e.push(e[0]),e}copy(t){super.copy(t),this.curves=[];for(let e=0,n=t.curves.length;e0){const t=l.getPoint(0);t.equals(this.currentPoint)||this.lineTo(t.x,t.y)}this.curves.push(l);const c=l.getPoint(1);return this.currentPoint.copy(c),this}copy(t){return super.copy(t),this.currentPoint.copy(t.currentPoint),this}toJSON(){const t=super.toJSON();return t.currentPoint=this.currentPoint.toArray(),t}fromJSON(t){return super.fromJSON(t),this.currentPoint.fromArray(t.currentPoint),this}}class mu extends Cs{constructor(t=[new ti(0,-.5),new ti(.5,0),new ti(0,.5)],e=12,n=0,i=2*Math.PI){super(),this.type="LatheGeometry",this.parameters={points:t,segments:e,phiStart:n,phiLength:i},e=Math.floor(e),i=Yn(i,0,2*Math.PI);const r=[],s=[],a=[],o=[],l=[],c=1/e,h=new Li,u=new ti,d=new Li,p=new Li,m=new Li;let f=0,g=0;for(let e=0;e<=t.length-1;e++)switch(e){case 0:f=t[e+1].x-t[e].x,g=t[e+1].y-t[e].y,d.x=1*g,d.y=-f,d.z=0*g,m.copy(d),d.normalize(),o.push(d.x,d.y,d.z);break;case t.length-1:o.push(m.x,m.y,m.z);break;default:f=t[e+1].x-t[e].x,g=t[e+1].y-t[e].y,d.x=1*g,d.y=-f,d.z=0*g,p.copy(d),d.x+=m.x,d.y+=m.y,d.z+=m.z,d.normalize(),o.push(d.x,d.y,d.z),m.copy(p)}for(let r=0;r<=e;r++){const d=n+r*c*i,p=Math.sin(d),m=Math.cos(d);for(let n=0;n<=t.length-1;n++){h.x=t[n].x*p,h.y=t[n].y,h.z=t[n].x*m,s.push(h.x,h.y,h.z),u.x=r/e,u.y=n/(t.length-1),a.push(u.x,u.y);const i=o[3*n+0]*p,c=o[3*n+1],d=o[3*n+0]*m;l.push(i,c,d)}}for(let n=0;n0&&(c.push(r,s,o),_+=3),e>0&&(c.push(s,a,o),_+=3)}l.addGroup(g,_,0),g+=_}(),!1===s&&(t>0&&v(!0),e>0&&v(!1)),this.setIndex(c),this.setAttribute("position",new Ms(h,3)),this.setAttribute("normal",new Ms(u,3)),this.setAttribute("uv",new Ms(d,2))}copy(t){return super.copy(t),this.parameters=Object.assign({},t.parameters),this}static fromJSON(t){return new vu(t.radiusTop,t.radiusBottom,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class _u extends vu{constructor(t=1,e=1,n=32,i=1,r=!1,s=0,a=2*Math.PI){super(0,t,e,n,i,r,s,a),this.type="ConeGeometry",this.parameters={radius:t,height:e,radialSegments:n,heightSegments:i,openEnded:r,thetaStart:s,thetaLength:a}}static fromJSON(t){return new _u(t.radius,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class xu extends Cs{constructor(t=[],e=[],n=1,i=0){super(),this.type="PolyhedronGeometry",this.parameters={vertices:t,indices:e,radius:n,detail:i};const r=[],s=[];function a(t,e,n,i){const r=i+1,s=[];for(let i=0;i<=r;i++){s[i]=[];const a=t.clone().lerp(n,i/r),o=e.clone().lerp(n,i/r),l=r-i;for(let t=0;t<=l;t++)s[i][t]=0===t&&i===r?a:a.clone().lerp(o,t/l)}for(let t=0;t.9&&a<.1&&(e<.2&&(s[t+0]+=1),n<.2&&(s[t+2]+=1),i<.2&&(s[t+4]+=1))}}()}(),this.setAttribute("position",new Ms(r,3)),this.setAttribute("normal",new Ms(r.slice(),3)),this.setAttribute("uv",new Ms(s,2)),0===i?this.computeVertexNormals():this.normalizeNormals()}copy(t){return super.copy(t),this.parameters=Object.assign({},t.parameters),this}static fromJSON(t){return new xu(t.vertices,t.indices,t.radius,t.details)}}class yu extends xu{constructor(t=1,e=0){const n=(1+Math.sqrt(5))/2,i=1/n;super([-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-i,-n,0,-i,n,0,i,-n,0,i,n,-i,-n,0,-i,n,0,i,-n,0,i,n,0,-n,0,-i,n,0,-i,-n,0,i,n,0,i],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],t,e),this.type="DodecahedronGeometry",this.parameters={radius:t,detail:e}}static fromJSON(t){return new yu(t.radius,t.detail)}}const Mu=new Li,Su=new Li,bu=new Li,wu=new Zr;class Tu extends Cs{constructor(t=null,e=1){if(super(),this.type="EdgesGeometry",this.parameters={geometry:t,thresholdAngle:e},null!==t){const n=4,i=Math.pow(10,n),r=Math.cos(Xn*e),s=t.getIndex(),a=t.getAttribute("position"),o=s?s.count:a.count,l=[0,0,0],c=["a","b","c"],h=new Array(3),u={},d=[];for(let t=0;t80*n){o=c=t[0],l=h=t[1];for(let e=n;ec&&(c=u),d>h&&(h=d);p=Math.max(c-o,h-l),p=0!==p?32767/p:0}return Pu(s,a,n,o,l,p,0),a};function Ru(t,e,n,i,r){let s,a;if(r===function(t,e,n,i){let r=0;for(let s=e,a=n-i;s0)for(s=e;s=e;s-=i)a=Zu(s,t[s],t[s+1],a);return a&&Gu(a,a.next)&&(Ju(a),a=a.next),a}function Cu(t,e){if(!t)return t;e||(e=t);let n,i=t;do{if(n=!1,i.steiner||!Gu(i,i.next)&&0!==Hu(i.prev,i,i.next))i=i.next;else{if(Ju(i),i=e=i.prev,i===i.next)break;n=!0}}while(n||i!==e);return e}function Pu(t,e,n,i,r,s,a){if(!t)return;!a&&s&&function(t,e,n,i){let r=t;do{0===r.z&&(r.z=Bu(r.x,r.y,e,n,i)),r.prevZ=r.prev,r.nextZ=r.next,r=r.next}while(r!==t);r.prevZ.nextZ=null,r.prevZ=null,function(t){let e,n,i,r,s,a,o,l,c=1;do{for(n=t,t=null,s=null,a=0;n;){for(a++,i=n,o=0,e=0;e0||l>0&&i;)0!==o&&(0===l||!i||n.z<=i.z)?(r=n,n=n.nextZ,o--):(r=i,i=i.nextZ,l--),s?s.nextZ=r:t=r,r.prevZ=s,s=r;n=i}s.nextZ=null,c*=2}while(a>1)}(r)}(t,i,r,s);let o,l,c=t;for(;t.prev!==t.next;)if(o=t.prev,l=t.next,s?Lu(t,i,r,s):Iu(t))e.push(o.i/n|0),e.push(t.i/n|0),e.push(l.i/n|0),Ju(t),t=l.next,c=l.next;else if((t=l)===c){a?1===a?Pu(t=Uu(Cu(t),e,n),e,n,i,r,s,2):2===a&&Nu(t,e,n,i,r,s):Pu(Cu(t),e,n,i,r,s,1);break}}function Iu(t){const e=t.prev,n=t,i=t.next;if(Hu(e,n,i)>=0)return!1;const r=e.x,s=n.x,a=i.x,o=e.y,l=n.y,c=i.y,h=rs?r>a?r:a:s>a?s:a,p=o>l?o>c?o:c:l>c?l:c;let m=i.next;for(;m!==e;){if(m.x>=h&&m.x<=d&&m.y>=u&&m.y<=p&&ku(r,o,s,l,a,c,m.x,m.y)&&Hu(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function Lu(t,e,n,i){const r=t.prev,s=t,a=t.next;if(Hu(r,s,a)>=0)return!1;const o=r.x,l=s.x,c=a.x,h=r.y,u=s.y,d=a.y,p=ol?o>c?o:c:l>c?l:c,g=h>u?h>d?h:d:u>d?u:d,v=Bu(p,m,e,n,i),_=Bu(f,g,e,n,i);let x=t.prevZ,y=t.nextZ;for(;x&&x.z>=v&&y&&y.z<=_;){if(x.x>=p&&x.x<=f&&x.y>=m&&x.y<=g&&x!==r&&x!==a&&ku(o,h,l,u,c,d,x.x,x.y)&&Hu(x.prev,x,x.next)>=0)return!1;if(x=x.prevZ,y.x>=p&&y.x<=f&&y.y>=m&&y.y<=g&&y!==r&&y!==a&&ku(o,h,l,u,c,d,y.x,y.y)&&Hu(y.prev,y,y.next)>=0)return!1;y=y.nextZ}for(;x&&x.z>=v;){if(x.x>=p&&x.x<=f&&x.y>=m&&x.y<=g&&x!==r&&x!==a&&ku(o,h,l,u,c,d,x.x,x.y)&&Hu(x.prev,x,x.next)>=0)return!1;x=x.prevZ}for(;y&&y.z<=_;){if(y.x>=p&&y.x<=f&&y.y>=m&&y.y<=g&&y!==r&&y!==a&&ku(o,h,l,u,c,d,y.x,y.y)&&Hu(y.prev,y,y.next)>=0)return!1;y=y.nextZ}return!0}function Uu(t,e,n){let i=t;do{const r=i.prev,s=i.next.next;!Gu(r,s)&&Wu(r,i,i.next,s)&&qu(r,s)&&qu(s,r)&&(e.push(r.i/n|0),e.push(i.i/n|0),e.push(s.i/n|0),Ju(i),Ju(i.next),i=t=s),i=i.next}while(i!==t);return Cu(i)}function Nu(t,e,n,i,r,s){let a=t;do{let t=a.next.next;for(;t!==a.prev;){if(a.i!==t.i&&Vu(a,t)){let o=Yu(a,t);return a=Cu(a,a.next),o=Cu(o,o.next),Pu(a,e,n,i,r,s,0),void Pu(o,e,n,i,r,s,0)}t=t.next}a=a.next}while(a!==t)}function Du(t,e){return t.x-e.x}function Ou(t,e){const n=function(t,e){let n,i=e,r=-1/0;const s=t.x,a=t.y;do{if(a<=i.y&&a>=i.next.y&&i.next.y!==i.y){const t=i.x+(a-i.y)*(i.next.x-i.x)/(i.next.y-i.y);if(t<=s&&t>r&&(r=t,n=i.x=i.x&&i.x>=l&&s!==i.x&&ku(an.x||i.x===n.x&&Fu(n,i)))&&(n=i,u=h)),i=i.next}while(i!==o);return n}(t,e);if(!n)return e;const i=Yu(n,t);return Cu(i,i.next),Cu(n,n.next)}function Fu(t,e){return Hu(t.prev,t,e.prev)<0&&Hu(e.next,t,t.next)<0}function Bu(t,e,n,i,r){return(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=(t-n)*r|0)|t<<8))|t<<4))|t<<2))|t<<1))|(e=1431655765&((e=858993459&((e=252645135&((e=16711935&((e=(e-i)*r|0)|e<<8))|e<<4))|e<<2))|e<<1))<<1}function zu(t){let e=t,n=t;do{(e.x=(t-a)*(s-o)&&(t-a)*(i-o)>=(n-a)*(e-o)&&(n-a)*(s-o)>=(r-a)*(i-o)}function Vu(t,e){return t.next.i!==e.i&&t.prev.i!==e.i&&!function(t,e){let n=t;do{if(n.i!==t.i&&n.next.i!==t.i&&n.i!==e.i&&n.next.i!==e.i&&Wu(n,n.next,t,e))return!0;n=n.next}while(n!==t);return!1}(t,e)&&(qu(t,e)&&qu(e,t)&&function(t,e){let n=t,i=!1;const r=(t.x+e.x)/2,s=(t.y+e.y)/2;do{n.y>s!=n.next.y>s&&n.next.y!==n.y&&r<(n.next.x-n.x)*(s-n.y)/(n.next.y-n.y)+n.x&&(i=!i),n=n.next}while(n!==t);return i}(t,e)&&(Hu(t.prev,t,e.prev)||Hu(t,e.prev,e))||Gu(t,e)&&Hu(t.prev,t,t.next)>0&&Hu(e.prev,e,e.next)>0)}function Hu(t,e,n){return(e.y-t.y)*(n.x-e.x)-(e.x-t.x)*(n.y-e.y)}function Gu(t,e){return t.x===e.x&&t.y===e.y}function Wu(t,e,n,i){const r=ju(Hu(t,e,n)),s=ju(Hu(t,e,i)),a=ju(Hu(n,i,t)),o=ju(Hu(n,i,e));return r!==s&&a!==o||(!(0!==r||!Xu(t,n,e))||(!(0!==s||!Xu(t,i,e))||(!(0!==a||!Xu(n,t,i))||!(0!==o||!Xu(n,e,i)))))}function Xu(t,e,n){return e.x<=Math.max(t.x,n.x)&&e.x>=Math.min(t.x,n.x)&&e.y<=Math.max(t.y,n.y)&&e.y>=Math.min(t.y,n.y)}function ju(t){return t>0?1:t<0?-1:0}function qu(t,e){return Hu(t.prev,t,t.next)<0?Hu(t,e,t.next)>=0&&Hu(t,t.prev,e)>=0:Hu(t,e,t.prev)<0||Hu(t,t.next,e)<0}function Yu(t,e){const n=new Ku(t.i,t.x,t.y),i=new Ku(e.i,e.x,e.y),r=t.next,s=e.prev;return t.next=e,e.prev=t,n.next=r,r.prev=n,i.next=n,n.prev=i,s.next=i,i.prev=s,i}function Zu(t,e,n,i){const r=new Ku(t,e,n);return i?(r.next=i.next,r.prev=i,i.next.prev=r,i.next=r):(r.prev=r,r.next=r),r}function Ju(t){t.next.prev=t.prev,t.prev.next=t.next,t.prevZ&&(t.prevZ.nextZ=t.nextZ),t.nextZ&&(t.nextZ.prevZ=t.prevZ)}function Ku(t,e,n){this.i=t,this.x=e,this.y=n,this.prev=null,this.next=null,this.z=0,this.prevZ=null,this.nextZ=null,this.steiner=!1}class $u{static area(t){const e=t.length;let n=0;for(let i=e-1,r=0;r2&&t[e-1].equals(t[0])&&t.pop()}function td(t,e){for(let n=0;nNumber.EPSILON){const u=Math.sqrt(h),d=Math.sqrt(l*l+c*c),p=e.x-o/u,m=e.y+a/u,f=((n.x-c/d-p)*c-(n.y+l/d-m)*l)/(a*c-o*l);i=p+a*f-t.x,r=m+o*f-t.y;const g=i*i+r*r;if(g<=2)return new ti(i,r);s=Math.sqrt(g/2)}else{let t=!1;a>Number.EPSILON?l>Number.EPSILON&&(t=!0):a<-Number.EPSILON?l<-Number.EPSILON&&(t=!0):Math.sign(o)===Math.sign(c)&&(t=!0),t?(i=-o,r=a,s=Math.sqrt(h)):(i=a,r=o,s=Math.sqrt(h/2))}return new ti(i/s,r/s)}const I=[];for(let t=0,e=E.length,n=e-1,i=t+1;t=0;t--){const e=t/p,n=h*Math.cos(e*Math.PI/2),i=u*Math.sin(e*Math.PI/2)+d;for(let t=0,e=E.length;t=0;){const i=n;let r=n-1;r<0&&(r=t.length-1);for(let t=0,n=o+2*p;t0)&&d.push(e,r,l),(t!==n-1||o0!=t>0&&this.version++,this._anisotropy=t}get clearcoat(){return this._clearcoat}set clearcoat(t){this._clearcoat>0!=t>0&&this.version++,this._clearcoat=t}get iridescence(){return this._iridescence}set iridescence(t){this._iridescence>0!=t>0&&this.version++,this._iridescence=t}get dispersion(){return this._dispersion}set dispersion(t){this._dispersion>0!=t>0&&this.version++,this._dispersion=t}get sheen(){return this._sheen}set sheen(t){this._sheen>0!=t>0&&this.version++,this._sheen=t}get transmission(){return this._transmission}set transmission(t){this._transmission>0!=t>0&&this.version++,this._transmission=t}copy(t){return super.copy(t),this.defines={STANDARD:"",PHYSICAL:""},this.anisotropy=t.anisotropy,this.anisotropyRotation=t.anisotropyRotation,this.anisotropyMap=t.anisotropyMap,this.clearcoat=t.clearcoat,this.clearcoatMap=t.clearcoatMap,this.clearcoatRoughness=t.clearcoatRoughness,this.clearcoatRoughnessMap=t.clearcoatRoughnessMap,this.clearcoatNormalMap=t.clearcoatNormalMap,this.clearcoatNormalScale.copy(t.clearcoatNormalScale),this.dispersion=t.dispersion,this.ior=t.ior,this.iridescence=t.iridescence,this.iridescenceMap=t.iridescenceMap,this.iridescenceIOR=t.iridescenceIOR,this.iridescenceThicknessRange=[...t.iridescenceThicknessRange],this.iridescenceThicknessMap=t.iridescenceThicknessMap,this.sheen=t.sheen,this.sheenColor.copy(t.sheenColor),this.sheenColorMap=t.sheenColorMap,this.sheenRoughness=t.sheenRoughness,this.sheenRoughnessMap=t.sheenRoughnessMap,this.transmission=t.transmission,this.transmissionMap=t.transmissionMap,this.thickness=t.thickness,this.thicknessMap=t.thicknessMap,this.attenuationDistance=t.attenuationDistance,this.attenuationColor.copy(t.attenuationColor),this.specularIntensity=t.specularIntensity,this.specularIntensityMap=t.specularIntensityMap,this.specularColor.copy(t.specularColor),this.specularColorMap=t.specularColorMap,this}}class xd extends is{constructor(t){super(),this.isMeshPhongMaterial=!0,this.type="MeshPhongMaterial",this.color=new ts(16777215),this.specular=new ts(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new ts(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new ti(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new _r,this.combine=Y,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.specular.copy(t.specular),this.shininess=t.shininess,this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.flatShading=t.flatShading,this.fog=t.fog,this}}class yd extends is{constructor(t){super(),this.isMeshToonMaterial=!0,this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new ts(16777215),this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new ts(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new ti(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.gradientMap=t.gradientMap,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.alphaMap=t.alphaMap,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.fog=t.fog,this}}class Md extends is{constructor(t){super(),this.isMeshNormalMaterial=!0,this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new ti(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.flatShading=!1,this.setValues(t)}copy(t){return super.copy(t),this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.flatShading=t.flatShading,this}}class Sd extends is{constructor(t){super(),this.isMeshLambertMaterial=!0,this.type="MeshLambertMaterial",this.color=new ts(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new ts(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new ti(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new _r,this.combine=Y,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.flatShading=t.flatShading,this.fog=t.fog,this}}class bd extends is{constructor(t){super(),this.isMeshMatcapMaterial=!0,this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new ts(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new ti(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.defines={MATCAP:""},this.color.copy(t.color),this.matcap=t.matcap,this.map=t.map,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.alphaMap=t.alphaMap,this.flatShading=t.flatShading,this.fog=t.fog,this}}class wd extends xh{constructor(t){super(),this.isLineDashedMaterial=!0,this.type="LineDashedMaterial",this.scale=1,this.dashSize=3,this.gapSize=1,this.setValues(t)}copy(t){return super.copy(t),this.scale=t.scale,this.dashSize=t.dashSize,this.gapSize=t.gapSize,this}}function Td(t,e,n){return!t||!n&&t.constructor===e?t:"number"==typeof e.BYTES_PER_ELEMENT?new e(t):Array.prototype.slice.call(t)}function Ed(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}function Ad(t){const e=t.length,n=new Array(e);for(let t=0;t!==e;++t)n[t]=t;return n.sort((function(e,n){return t[e]-t[n]})),n}function Rd(t,e,n){const i=t.length,r=new t.constructor(i);for(let s=0,a=0;a!==i;++s){const i=n[s]*e;for(let n=0;n!==e;++n)r[a++]=t[i+n]}return r}function Cd(t,e,n,i){let r=1,s=t[0];for(;void 0!==s&&void 0===s[i];)s=t[r++];if(void 0===s)return;let a=s[i];if(void 0!==a)if(Array.isArray(a))do{a=s[i],void 0!==a&&(e.push(s.time),n.push.apply(n,a)),s=t[r++]}while(void 0!==s);else if(void 0!==a.toArray)do{a=s[i],void 0!==a&&(e.push(s.time),a.toArray(n,n.length)),s=t[r++]}while(void 0!==s);else do{a=s[i],void 0!==a&&(e.push(s.time),n.push(a)),s=t[r++]}while(void 0!==s)}const Pd={convertArray:Td,isTypedArray:Ed,getKeyframeOrder:Ad,sortedArray:Rd,flattenJSON:Cd,subclip:function(t,e,n,i,r=30){const s=t.clone();s.name=e;const a=[];for(let t=0;t=i)){l.push(e.times[t]);for(let n=0;ns.tracks[t].times[0]&&(o=s.tracks[t].times[0]);for(let t=0;t=i.times[u]){const t=u*l+o,e=t+l-o;d=i.values.slice(t,e)}else{const t=i.createInterpolant(),e=o,n=l-o;t.evaluate(s),d=t.resultBuffer.slice(e,n)}if("quaternion"===r){(new Ii).fromArray(d).normalize().conjugate().toArray(d)}const p=a.times.length;for(let t=0;t=r)break t;{const a=e[1];t=r)break e}s=n,n=0}}for(;n>>1;te;)--s;if(++s,0!==r||s!==i){r>=s&&(s=Math.max(s,1),r=s-1);const t=this.getValueSize();this.times=n.slice(r,s),this.values=this.values.slice(r*t,s*t)}return this}validate(){let t=!0;const e=this.getValueSize();e-Math.floor(e)!=0&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),t=!1);const n=this.times,i=this.values,r=n.length;0===r&&(console.error("THREE.KeyframeTrack: Track is empty.",this),t=!1);let s=null;for(let e=0;e!==r;e++){const i=n[e];if("number"==typeof i&&isNaN(i)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,e,i),t=!1;break}if(null!==s&&s>i){console.error("THREE.KeyframeTrack: Out of order keys.",this,e,i,s),t=!1;break}s=i}if(void 0!==i&&Ed(i))for(let e=0,n=i.length;e!==n;++e){const n=i[e];if(isNaN(n)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,e,n),t=!1;break}}return t}optimize(){const t=this.times.slice(),e=this.values.slice(),n=this.getValueSize(),i=this.getInterpolation()===Ne,r=t.length-1;let s=1;for(let a=1;a0){t[s]=t[r];for(let t=r*n,i=s*n,a=0;a!==n;++a)e[i+a]=e[t+a];++s}return s!==t.length?(this.times=t.slice(0,s),this.values=e.slice(0,s*n)):(this.times=t,this.values=e),this}clone(){const t=this.times.slice(),e=this.values.slice(),n=new(0,this.constructor)(this.name,t,e);return n.createInterpolant=this.createInterpolant,n}}Dd.prototype.TimeBufferType=Float32Array,Dd.prototype.ValueBufferType=Float32Array,Dd.prototype.DefaultInterpolation=Ue;class Od extends Dd{constructor(t,e,n){super(t,e,n)}}Od.prototype.ValueTypeName="bool",Od.prototype.ValueBufferType=Array,Od.prototype.DefaultInterpolation=Le,Od.prototype.InterpolantFactoryMethodLinear=void 0,Od.prototype.InterpolantFactoryMethodSmooth=void 0;class Fd extends Dd{}Fd.prototype.ValueTypeName="color";class Bd extends Dd{}Bd.prototype.ValueTypeName="number";class zd extends Id{constructor(t,e,n,i){super(t,e,n,i)}interpolate_(t,e,n,i){const r=this.resultBuffer,s=this.sampleValues,a=this.valueSize,o=(n-e)/(i-e);let l=t*a;for(let t=l+a;l!==t;l+=4)Ii.slerpFlat(r,0,s,l-a,s,l,o);return r}}class kd extends Dd{InterpolantFactoryMethodLinear(t){return new zd(this.times,this.values,this.getValueSize(),t)}}kd.prototype.ValueTypeName="quaternion",kd.prototype.InterpolantFactoryMethodSmooth=void 0;class Vd extends Dd{constructor(t,e,n){super(t,e,n)}}Vd.prototype.ValueTypeName="string",Vd.prototype.ValueBufferType=Array,Vd.prototype.DefaultInterpolation=Le,Vd.prototype.InterpolantFactoryMethodLinear=void 0,Vd.prototype.InterpolantFactoryMethodSmooth=void 0;class Hd extends Dd{}Hd.prototype.ValueTypeName="vector";class Gd{constructor(t="",e=-1,n=[],i=2500){this.name=t,this.tracks=n,this.duration=e,this.blendMode=i,this.uuid=qn(),this.duration<0&&this.resetDuration()}static parse(t){const e=[],n=t.tracks,i=1/(t.fps||1);for(let t=0,r=n.length;t!==r;++t)e.push(Wd(n[t]).scale(i));const r=new this(t.name,t.duration,e,t.blendMode);return r.uuid=t.uuid,r}static toJSON(t){const e=[],n=t.tracks,i={name:t.name,duration:t.duration,tracks:e,uuid:t.uuid,blendMode:t.blendMode};for(let t=0,i=n.length;t!==i;++t)e.push(Dd.toJSON(n[t]));return i}static CreateFromMorphTargetSequence(t,e,n,i){const r=e.length,s=[];for(let t=0;t1){const t=s[1];let e=i[t];e||(i[t]=e=[]),e.push(n)}}const s=[];for(const t in i)s.push(this.CreateFromMorphTargetSequence(t,i[t],e,n));return s}static parseAnimation(t,e){if(!t)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;const n=function(t,e,n,i,r){if(0!==n.length){const s=[],a=[];Cd(n,s,a,i),0!==s.length&&r.push(new t(e,s,a))}},i=[],r=t.name||"default",s=t.fps||30,a=t.blendMode;let o=t.length||-1;const l=t.hierarchy||[];for(let t=0;t{e&&e(r),this.manager.itemEnd(t)}),0),r;if(void 0!==Zd[t])return void Zd[t].push({onLoad:e,onProgress:n,onError:i});Zd[t]=[],Zd[t].push({onLoad:e,onProgress:n,onError:i});const s=new Request(t,{headers:new Headers(this.requestHeader),credentials:this.withCredentials?"include":"same-origin"}),a=this.mimeType,o=this.responseType;fetch(s).then((e=>{if(200===e.status||0===e.status){if(0===e.status&&console.warn("THREE.FileLoader: HTTP Status 0 received."),"undefined"==typeof ReadableStream||void 0===e.body||void 0===e.body.getReader)return e;const n=Zd[t],i=e.body.getReader(),r=e.headers.get("X-File-Size")||e.headers.get("Content-Length"),s=r?parseInt(r):0,a=0!==s;let o=0;const l=new ReadableStream({start(t){!function e(){i.read().then((({done:i,value:r})=>{if(i)t.close();else{o+=r.byteLength;const i=new ProgressEvent("progress",{lengthComputable:a,loaded:o,total:s});for(let t=0,e=n.length;t{t.error(e)}))}()}});return new Response(l)}throw new Jd(`fetch for "${e.url}" responded with ${e.status}: ${e.statusText}`,e)})).then((t=>{switch(o){case"arraybuffer":return t.arrayBuffer();case"blob":return t.blob();case"document":return t.text().then((t=>(new DOMParser).parseFromString(t,a)));case"json":return t.json();default:if(void 0===a)return t.text();{const e=/charset="?([^;"\s]*)"?/i.exec(a),n=e&&e[1]?e[1].toLowerCase():void 0,i=new TextDecoder(n);return t.arrayBuffer().then((t=>i.decode(t)))}}})).then((e=>{Xd.add(t,e);const n=Zd[t];delete Zd[t];for(let t=0,i=n.length;t{const n=Zd[t];if(void 0===n)throw this.manager.itemError(t),e;delete Zd[t];for(let t=0,i=n.length;t{this.manager.itemEnd(t)})),this.manager.itemStart(t)}setResponseType(t){return this.responseType=t,this}setMimeType(t){return this.mimeType=t,this}}class $d extends Yd{constructor(t){super(t)}load(t,e,n,i){const r=this,s=new Kd(this.manager);s.setPath(this.path),s.setRequestHeader(this.requestHeader),s.setWithCredentials(this.withCredentials),s.load(t,(function(n){try{e(r.parse(JSON.parse(n)))}catch(e){i?i(e):console.error(e),r.manager.itemError(t)}}),n,i)}parse(t){const e=[];for(let n=0;n0:i.vertexColors=t.vertexColors),void 0!==t.uniforms)for(const e in t.uniforms){const r=t.uniforms[e];switch(i.uniforms[e]={},r.type){case"t":i.uniforms[e].value=n(r.value);break;case"c":i.uniforms[e].value=(new ts).setHex(r.value);break;case"v2":i.uniforms[e].value=(new ti).fromArray(r.value);break;case"v3":i.uniforms[e].value=(new Li).fromArray(r.value);break;case"v4":i.uniforms[e].value=(new wi).fromArray(r.value);break;case"m3":i.uniforms[e].value=(new ei).fromArray(r.value);break;case"m4":i.uniforms[e].value=(new lr).fromArray(r.value);break;default:i.uniforms[e].value=r.value}}if(void 0!==t.defines&&(i.defines=t.defines),void 0!==t.vertexShader&&(i.vertexShader=t.vertexShader),void 0!==t.fragmentShader&&(i.fragmentShader=t.fragmentShader),void 0!==t.glslVersion&&(i.glslVersion=t.glslVersion),void 0!==t.extensions)for(const e in t.extensions)i.extensions[e]=t.extensions[e];if(void 0!==t.lights&&(i.lights=t.lights),void 0!==t.clipping&&(i.clipping=t.clipping),void 0!==t.size&&(i.size=t.size),void 0!==t.sizeAttenuation&&(i.sizeAttenuation=t.sizeAttenuation),void 0!==t.map&&(i.map=n(t.map)),void 0!==t.matcap&&(i.matcap=n(t.matcap)),void 0!==t.alphaMap&&(i.alphaMap=n(t.alphaMap)),void 0!==t.bumpMap&&(i.bumpMap=n(t.bumpMap)),void 0!==t.bumpScale&&(i.bumpScale=t.bumpScale),void 0!==t.normalMap&&(i.normalMap=n(t.normalMap)),void 0!==t.normalMapType&&(i.normalMapType=t.normalMapType),void 0!==t.normalScale){let e=t.normalScale;!1===Array.isArray(e)&&(e=[e,e]),i.normalScale=(new ti).fromArray(e)}return void 0!==t.displacementMap&&(i.displacementMap=n(t.displacementMap)),void 0!==t.displacementScale&&(i.displacementScale=t.displacementScale),void 0!==t.displacementBias&&(i.displacementBias=t.displacementBias),void 0!==t.roughnessMap&&(i.roughnessMap=n(t.roughnessMap)),void 0!==t.metalnessMap&&(i.metalnessMap=n(t.metalnessMap)),void 0!==t.emissiveMap&&(i.emissiveMap=n(t.emissiveMap)),void 0!==t.emissiveIntensity&&(i.emissiveIntensity=t.emissiveIntensity),void 0!==t.specularMap&&(i.specularMap=n(t.specularMap)),void 0!==t.specularIntensityMap&&(i.specularIntensityMap=n(t.specularIntensityMap)),void 0!==t.specularColorMap&&(i.specularColorMap=n(t.specularColorMap)),void 0!==t.envMap&&(i.envMap=n(t.envMap)),void 0!==t.envMapRotation&&i.envMapRotation.fromArray(t.envMapRotation),void 0!==t.envMapIntensity&&(i.envMapIntensity=t.envMapIntensity),void 0!==t.reflectivity&&(i.reflectivity=t.reflectivity),void 0!==t.refractionRatio&&(i.refractionRatio=t.refractionRatio),void 0!==t.lightMap&&(i.lightMap=n(t.lightMap)),void 0!==t.lightMapIntensity&&(i.lightMapIntensity=t.lightMapIntensity),void 0!==t.aoMap&&(i.aoMap=n(t.aoMap)),void 0!==t.aoMapIntensity&&(i.aoMapIntensity=t.aoMapIntensity),void 0!==t.gradientMap&&(i.gradientMap=n(t.gradientMap)),void 0!==t.clearcoatMap&&(i.clearcoatMap=n(t.clearcoatMap)),void 0!==t.clearcoatRoughnessMap&&(i.clearcoatRoughnessMap=n(t.clearcoatRoughnessMap)),void 0!==t.clearcoatNormalMap&&(i.clearcoatNormalMap=n(t.clearcoatNormalMap)),void 0!==t.clearcoatNormalScale&&(i.clearcoatNormalScale=(new ti).fromArray(t.clearcoatNormalScale)),void 0!==t.iridescenceMap&&(i.iridescenceMap=n(t.iridescenceMap)),void 0!==t.iridescenceThicknessMap&&(i.iridescenceThicknessMap=n(t.iridescenceThicknessMap)),void 0!==t.transmissionMap&&(i.transmissionMap=n(t.transmissionMap)),void 0!==t.thicknessMap&&(i.thicknessMap=n(t.thicknessMap)),void 0!==t.anisotropyMap&&(i.anisotropyMap=n(t.anisotropyMap)),void 0!==t.sheenColorMap&&(i.sheenColorMap=n(t.sheenColorMap)),void 0!==t.sheenRoughnessMap&&(i.sheenRoughnessMap=n(t.sheenRoughnessMap)),i}setTextures(t){return this.textures=t,this}createMaterialFromType(t){return bp.createMaterialFromType(t)}static createMaterialFromType(t){return new{ShadowMaterial:fd,SpriteMaterial:uc,RawShaderMaterial:gd,ShaderMaterial:Ys,PointsMaterial:Uh,MeshPhysicalMaterial:_d,MeshStandardMaterial:vd,MeshPhongMaterial:xd,MeshToonMaterial:yd,MeshNormalMaterial:Md,MeshLambertMaterial:Sd,MeshDepthMaterial:zl,MeshDistanceMaterial:kl,MeshBasicMaterial:rs,MeshMatcapMaterial:bd,LineDashedMaterial:wd,LineBasicMaterial:xh,Material:is}[t]}}class wp{static decodeText(t){if(console.warn("THREE.LoaderUtils: decodeText() has been deprecated with r165 and will be removed with r175. Use TextDecoder instead."),"undefined"!=typeof TextDecoder)return(new TextDecoder).decode(t);let e="";for(let n=0,i=t.length;n0){const n=new jd(e);r=new tp(n),r.setCrossOrigin(this.crossOrigin);for(let e=0,n=t.length;e0){i=new tp(this.manager),i.setCrossOrigin(this.crossOrigin);for(let e=0,i=t.length;e{const e=new Di;e.min.fromArray(t.boxMin),e.max.fromArray(t.boxMax);const n=new Qi;return n.radius=t.sphereRadius,n.center.fromArray(t.sphereCenter),{boxInitialized:t.boxInitialized,box:e,sphereInitialized:t.sphereInitialized,sphere:n}})),s._maxInstanceCount=t.maxInstanceCount,s._maxVertexCount=t.maxVertexCount,s._maxIndexCount=t.maxIndexCount,s._geometryInitialized=t.geometryInitialized,s._geometryCount=t.geometryCount,s._matricesTexture=h(t.matricesTexture.uuid),void 0!==t.colorsTexture&&(s._colorsTexture=h(t.colorsTexture.uuid));break;case"LOD":s=new Cc;break;case"Line":s=new Ah(l(t.geometry),c(t.material));break;case"LineLoop":s=new Lh(l(t.geometry),c(t.material));break;case"LineSegments":s=new Ih(l(t.geometry),c(t.material));break;case"PointCloud":case"Points":s=new Bh(l(t.geometry),c(t.material));break;case"Sprite":s=new Tc(c(t.material));break;case"Group":s=new Zl;break;case"Bone":s=new kc;break;default:s=new Dr}if(s.uuid=t.uuid,void 0!==t.name&&(s.name=t.name),void 0!==t.matrix?(s.matrix.fromArray(t.matrix),void 0!==t.matrixAutoUpdate&&(s.matrixAutoUpdate=t.matrixAutoUpdate),s.matrixAutoUpdate&&s.matrix.decompose(s.position,s.quaternion,s.scale)):(void 0!==t.position&&s.position.fromArray(t.position),void 0!==t.rotation&&s.rotation.fromArray(t.rotation),void 0!==t.quaternion&&s.quaternion.fromArray(t.quaternion),void 0!==t.scale&&s.scale.fromArray(t.scale)),void 0!==t.up&&s.up.fromArray(t.up),void 0!==t.castShadow&&(s.castShadow=t.castShadow),void 0!==t.receiveShadow&&(s.receiveShadow=t.receiveShadow),t.shadow&&(void 0!==t.shadow.intensity&&(s.shadow.intensity=t.shadow.intensity),void 0!==t.shadow.bias&&(s.shadow.bias=t.shadow.bias),void 0!==t.shadow.normalBias&&(s.shadow.normalBias=t.shadow.normalBias),void 0!==t.shadow.radius&&(s.shadow.radius=t.shadow.radius),void 0!==t.shadow.mapSize&&s.shadow.mapSize.fromArray(t.shadow.mapSize),void 0!==t.shadow.camera&&(s.shadow.camera=this.parseObject(t.shadow.camera))),void 0!==t.visible&&(s.visible=t.visible),void 0!==t.frustumCulled&&(s.frustumCulled=t.frustumCulled),void 0!==t.renderOrder&&(s.renderOrder=t.renderOrder),void 0!==t.userData&&(s.userData=t.userData),void 0!==t.layers&&(s.layers.mask=t.layers),void 0!==t.children){const a=t.children;for(let t=0;t{e&&e(n),r.manager.itemEnd(t)})).catch((t=>{i&&i(t)})):(setTimeout((function(){e&&e(s),r.manager.itemEnd(t)}),0),s);const a={};a.credentials="anonymous"===this.crossOrigin?"same-origin":"include",a.headers=this.requestHeader;const o=fetch(t,a).then((function(t){return t.blob()})).then((function(t){return createImageBitmap(t,Object.assign(r.options,{colorSpaceConversion:"none"}))})).then((function(n){return Xd.add(t,n),e&&e(n),r.manager.itemEnd(t),n})).catch((function(e){i&&i(e),Xd.remove(t),r.manager.itemError(t),r.manager.itemEnd(t)}));Xd.add(t,o),r.manager.itemStart(t)}}let Lp;class Up{static getContext(){return void 0===Lp&&(Lp=new(window.AudioContext||window.webkitAudioContext)),Lp}static setContext(t){Lp=t}}class Np extends Yd{constructor(t){super(t)}load(t,e,n,i){const r=this,s=new Kd(this.manager);function a(e){i?i(e):console.error(e),r.manager.itemError(t)}s.setResponseType("arraybuffer"),s.setPath(this.path),s.setRequestHeader(this.requestHeader),s.setWithCredentials(this.withCredentials),s.load(t,(function(t){try{const n=t.slice(0);Up.getContext().decodeAudioData(n,(function(t){e(t)})).catch(a)}catch(t){a(t)}}),n,i)}}const Dp=new lr,Op=new lr,Fp=new lr;class Bp{constructor(){this.type="StereoCamera",this.aspect=1,this.eyeSep=.064,this.cameraL=new Qs,this.cameraL.layers.enable(1),this.cameraL.matrixAutoUpdate=!1,this.cameraR=new Qs,this.cameraR.layers.enable(2),this.cameraR.matrixAutoUpdate=!1,this._cache={focus:null,fov:null,aspect:null,near:null,far:null,zoom:null,eyeSep:null}}update(t){const e=this._cache;if(e.focus!==t.focus||e.fov!==t.fov||e.aspect!==t.aspect*this.aspect||e.near!==t.near||e.far!==t.far||e.zoom!==t.zoom||e.eyeSep!==this.eyeSep){e.focus=t.focus,e.fov=t.fov,e.aspect=t.aspect*this.aspect,e.near=t.near,e.far=t.far,e.zoom=t.zoom,e.eyeSep=this.eyeSep,Fp.copy(t.projectionMatrix);const n=e.eyeSep/2,i=n*e.near/e.focus,r=e.near*Math.tan(Xn*e.fov*.5)/e.zoom;let s,a;Op.elements[12]=-n,Dp.elements[12]=n,s=-r*e.aspect+i,a=r*e.aspect+i,Fp.elements[0]=2*e.near/(a-s),Fp.elements[8]=(a+s)/(a-s),this.cameraL.projectionMatrix.copy(Fp),s=-r*e.aspect-i,a=r*e.aspect-i,Fp.elements[0]=2*e.near/(a-s),Fp.elements[8]=(a+s)/(a-s),this.cameraR.projectionMatrix.copy(Fp)}this.cameraL.matrixWorld.copy(t.matrixWorld).multiply(Op),this.cameraR.matrixWorld.copy(t.matrixWorld).multiply(Dp)}}class zp{constructor(t=!0){this.autoStart=t,this.startTime=0,this.oldTime=0,this.elapsedTime=0,this.running=!1}start(){this.startTime=kp(),this.oldTime=this.startTime,this.elapsedTime=0,this.running=!0}stop(){this.getElapsedTime(),this.running=!1,this.autoStart=!1}getElapsedTime(){return this.getDelta(),this.elapsedTime}getDelta(){let t=0;if(this.autoStart&&!this.running)return this.start(),0;if(this.running){const e=kp();t=(e-this.oldTime)/1e3,this.oldTime=e,this.elapsedTime+=t}return t}}function kp(){return performance.now()}const Vp=new Li,Hp=new Ii,Gp=new Li,Wp=new Li;class Xp extends Dr{constructor(){super(),this.type="AudioListener",this.context=Up.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._clock=new zp}getInput(){return this.gain}removeFilter(){return null!==this.filter&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null),this}getFilter(){return this.filter}setFilter(t){return null!==this.filter?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination),this.filter=t,this.gain.connect(this.filter),this.filter.connect(this.context.destination),this}getMasterVolume(){return this.gain.gain.value}setMasterVolume(t){return this.gain.gain.setTargetAtTime(t,this.context.currentTime,.01),this}updateMatrixWorld(t){super.updateMatrixWorld(t);const e=this.context.listener,n=this.up;if(this.timeDelta=this._clock.getDelta(),this.matrixWorld.decompose(Vp,Hp,Gp),Wp.set(0,0,-1).applyQuaternion(Hp),e.positionX){const t=this.context.currentTime+this.timeDelta;e.positionX.linearRampToValueAtTime(Vp.x,t),e.positionY.linearRampToValueAtTime(Vp.y,t),e.positionZ.linearRampToValueAtTime(Vp.z,t),e.forwardX.linearRampToValueAtTime(Wp.x,t),e.forwardY.linearRampToValueAtTime(Wp.y,t),e.forwardZ.linearRampToValueAtTime(Wp.z,t),e.upX.linearRampToValueAtTime(n.x,t),e.upY.linearRampToValueAtTime(n.y,t),e.upZ.linearRampToValueAtTime(n.z,t)}else e.setPosition(Vp.x,Vp.y,Vp.z),e.setOrientation(Wp.x,Wp.y,Wp.z,n.x,n.y,n.z)}}class jp extends Dr{constructor(t){super(),this.type="Audio",this.listener=t,this.context=t.context,this.gain=this.context.createGain(),this.gain.connect(t.getInput()),this.autoplay=!1,this.buffer=null,this.detune=0,this.loop=!1,this.loopStart=0,this.loopEnd=0,this.offset=0,this.duration=void 0,this.playbackRate=1,this.isPlaying=!1,this.hasPlaybackControl=!0,this.source=null,this.sourceType="empty",this._startedAt=0,this._progress=0,this._connected=!1,this.filters=[]}getOutput(){return this.gain}setNodeSource(t){return this.hasPlaybackControl=!1,this.sourceType="audioNode",this.source=t,this.connect(),this}setMediaElementSource(t){return this.hasPlaybackControl=!1,this.sourceType="mediaNode",this.source=this.context.createMediaElementSource(t),this.connect(),this}setMediaStreamSource(t){return this.hasPlaybackControl=!1,this.sourceType="mediaStreamNode",this.source=this.context.createMediaStreamSource(t),this.connect(),this}setBuffer(t){return this.buffer=t,this.sourceType="buffer",this.autoplay&&this.play(),this}play(t=0){if(!0===this.isPlaying)return void console.warn("THREE.Audio: Audio is already playing.");if(!1===this.hasPlaybackControl)return void console.warn("THREE.Audio: this Audio has no playback control.");this._startedAt=this.context.currentTime+t;const e=this.context.createBufferSource();return e.buffer=this.buffer,e.loop=this.loop,e.loopStart=this.loopStart,e.loopEnd=this.loopEnd,e.onended=this.onEnded.bind(this),e.start(this._startedAt,this._progress+this.offset,this.duration),this.isPlaying=!0,this.source=e,this.setDetune(this.detune),this.setPlaybackRate(this.playbackRate),this.connect()}pause(){if(!1!==this.hasPlaybackControl)return!0===this.isPlaying&&(this._progress+=Math.max(this.context.currentTime-this._startedAt,0)*this.playbackRate,!0===this.loop&&(this._progress=this._progress%(this.duration||this.buffer.duration)),this.source.stop(),this.source.onended=null,this.isPlaying=!1),this;console.warn("THREE.Audio: this Audio has no playback control.")}stop(t=0){if(!1!==this.hasPlaybackControl)return this._progress=0,null!==this.source&&(this.source.stop(this.context.currentTime+t),this.source.onended=null),this.isPlaying=!1,this;console.warn("THREE.Audio: this Audio has no playback control.")}connect(){if(this.filters.length>0){this.source.connect(this.filters[0]);for(let t=1,e=this.filters.length;t0){this.source.disconnect(this.filters[0]);for(let t=1,e=this.filters.length;t0&&this._mixBufferRegionAdditive(n,i,this._addIndex*e,1,e);for(let t=e,r=e+e;t!==r;++t)if(n[t]!==n[t+e]){a.setValue(n,i);break}}saveOriginalState(){const t=this.binding,e=this.buffer,n=this.valueSize,i=n*this._origIndex;t.getValue(e,i);for(let t=n,r=i;t!==r;++t)e[t]=e[i+t%n];this._setIdentity(),this.cumulativeWeight=0,this.cumulativeWeightAdditive=0}restoreOriginalState(){const t=3*this.valueSize;this.binding.setValue(this.buffer,t)}_setAdditiveIdentityNumeric(){const t=this._addIndex*this.valueSize,e=t+this.valueSize;for(let n=t;n=.5)for(let i=0;i!==r;++i)t[e+i]=t[n+i]}_slerp(t,e,n,i){Ii.slerpFlat(t,e,t,e,t,n,i)}_slerpAdditive(t,e,n,i,r){const s=this._workIndex*r;Ii.multiplyQuaternionsFlat(t,s,t,e,t,n),Ii.slerpFlat(t,e,t,e,t,s,i)}_lerp(t,e,n,i,r){const s=1-i;for(let a=0;a!==r;++a){const r=e+a;t[r]=t[r]*s+t[n+a]*i}}_lerpAdditive(t,e,n,i,r){for(let s=0;s!==r;++s){const r=e+s;t[r]=t[r]+t[n+s]*i}}}const tm="\\[\\]\\.:\\/",em=new RegExp("["+tm+"]","g"),nm="[^"+tm+"]",im="[^"+tm.replace("\\.","")+"]",rm=new RegExp("^"+/((?:WC+[\/:])*)/.source.replace("WC",nm)+/(WCOD+)?/.source.replace("WCOD",im)+/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",nm)+/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",nm)+"$"),sm=["material","materials","bones","map"];class am{constructor(t,e,n){this.path=e,this.parsedPath=n||am.parseTrackName(e),this.node=am.findNode(t,this.parsedPath.nodeName),this.rootNode=t,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(t,e,n){return t&&t.isAnimationObjectGroup?new am.Composite(t,e,n):new am(t,e,n)}static sanitizeNodeName(t){return t.replace(/\s/g,"_").replace(em,"")}static parseTrackName(t){const e=rm.exec(t);if(null===e)throw new Error("PropertyBinding: Cannot parse trackName: "+t);const n={nodeName:e[2],objectName:e[3],objectIndex:e[4],propertyName:e[5],propertyIndex:e[6]},i=n.nodeName&&n.nodeName.lastIndexOf(".");if(void 0!==i&&-1!==i){const t=n.nodeName.substring(i+1);-1!==sm.indexOf(t)&&(n.nodeName=n.nodeName.substring(0,i),n.objectName=t)}if(null===n.propertyName||0===n.propertyName.length)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+t);return n}static findNode(t,e){if(void 0===e||""===e||"."===e||-1===e||e===t.name||e===t.uuid)return t;if(t.skeleton){const n=t.skeleton.getBoneByName(e);if(void 0!==n)return n}if(t.children){const n=function(t){for(let i=0;i=r){const s=r++,c=t[s];e[c.uuid]=l,t[l]=c,e[o]=s,t[s]=a;for(let t=0,e=i;t!==e;++t){const e=n[t],i=e[s],r=e[l];e[l]=i,e[s]=r}}}this.nCachedObjects_=r}uncache(){const t=this._objects,e=this._indicesByUUID,n=this._bindings,i=n.length;let r=this.nCachedObjects_,s=t.length;for(let a=0,o=arguments.length;a!==o;++a){const o=arguments[a].uuid,l=e[o];if(void 0!==l)if(delete e[o],l0&&(e[a.uuid]=l),t[l]=a,t.pop();for(let t=0,e=i;t!==e;++t){const e=n[t];e[l]=e[r],e.pop()}}}this.nCachedObjects_=r}subscribe_(t,e){const n=this._bindingsIndicesByPath;let i=n[t];const r=this._bindings;if(void 0!==i)return r[i];const s=this._paths,a=this._parsedPaths,o=this._objects,l=o.length,c=this.nCachedObjects_,h=new Array(l);i=r.length,n[t]=i,s.push(t),a.push(e),r.push(h);for(let n=c,i=o.length;n!==i;++n){const i=o[n];h[n]=new am(i,t,e)}return h}unsubscribe_(t){const e=this._bindingsIndicesByPath,n=e[t];if(void 0!==n){const i=this._paths,r=this._parsedPaths,s=this._bindings,a=s.length-1,o=s[a];e[t[a]]=n,s[n]=o,s.pop(),r[n]=r[a],r.pop(),i[n]=i[a],i.pop()}}}class lm{constructor(t,e,n=null,i=e.blendMode){this._mixer=t,this._clip=e,this._localRoot=n,this.blendMode=i;const r=e.tracks,s=r.length,a=new Array(s),o={endingStart:De,endingEnd:De};for(let t=0;t!==s;++t){const e=r[t].createInterpolant(null);a[t]=e,e.settings=o}this._interpolantSettings=o,this._interpolants=a,this._propertyBindings=new Array(s),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=2201,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}play(){return this._mixer._activateAction(this),this}stop(){return this._mixer._deactivateAction(this),this.reset()}reset(){return this.paused=!1,this.enabled=!0,this.time=0,this._loopCount=-1,this._startTime=null,this.stopFading().stopWarping()}isRunning(){return this.enabled&&!this.paused&&0!==this.timeScale&&null===this._startTime&&this._mixer._isActiveAction(this)}isScheduled(){return this._mixer._isActiveAction(this)}startAt(t){return this._startTime=t,this}setLoop(t,e){return this.loop=t,this.repetitions=e,this}setEffectiveWeight(t){return this.weight=t,this._effectiveWeight=this.enabled?t:0,this.stopFading()}getEffectiveWeight(){return this._effectiveWeight}fadeIn(t){return this._scheduleFading(t,0,1)}fadeOut(t){return this._scheduleFading(t,1,0)}crossFadeFrom(t,e,n){if(t.fadeOut(e),this.fadeIn(e),n){const n=this._clip.duration,i=t._clip.duration,r=i/n,s=n/i;t.warp(1,r,e),this.warp(s,1,e)}return this}crossFadeTo(t,e,n){return t.crossFadeFrom(this,e,n)}stopFading(){const t=this._weightInterpolant;return null!==t&&(this._weightInterpolant=null,this._mixer._takeBackControlInterpolant(t)),this}setEffectiveTimeScale(t){return this.timeScale=t,this._effectiveTimeScale=this.paused?0:t,this.stopWarping()}getEffectiveTimeScale(){return this._effectiveTimeScale}setDuration(t){return this.timeScale=this._clip.duration/t,this.stopWarping()}syncWith(t){return this.time=t.time,this.timeScale=t.timeScale,this.stopWarping()}halt(t){return this.warp(this._effectiveTimeScale,0,t)}warp(t,e,n){const i=this._mixer,r=i.time,s=this.timeScale;let a=this._timeScaleInterpolant;null===a&&(a=i._lendControlInterpolant(),this._timeScaleInterpolant=a);const o=a.parameterPositions,l=a.sampleValues;return o[0]=r,o[1]=r+n,l[0]=t/s,l[1]=e/s,this}stopWarping(){const t=this._timeScaleInterpolant;return null!==t&&(this._timeScaleInterpolant=null,this._mixer._takeBackControlInterpolant(t)),this}getMixer(){return this._mixer}getClip(){return this._clip}getRoot(){return this._localRoot||this._mixer._root}_update(t,e,n,i){if(!this.enabled)return void this._updateWeight(t);const r=this._startTime;if(null!==r){const i=(t-r)*n;i<0||0===n?e=0:(this._startTime=null,e=n*i)}e*=this._updateTimeScale(t);const s=this._updateTime(e),a=this._updateWeight(t);if(a>0){const t=this._interpolants,e=this._propertyBindings;if(this.blendMode===ze)for(let n=0,i=t.length;n!==i;++n)t[n].evaluate(s),e[n].accumulateAdditive(a);else for(let n=0,r=t.length;n!==r;++n)t[n].evaluate(s),e[n].accumulate(i,a)}}_updateWeight(t){let e=0;if(this.enabled){e=this.weight;const n=this._weightInterpolant;if(null!==n){const i=n.evaluate(t)[0];e*=i,t>n.parameterPositions[1]&&(this.stopFading(),0===i&&(this.enabled=!1))}}return this._effectiveWeight=e,e}_updateTimeScale(t){let e=0;if(!this.paused){e=this.timeScale;const n=this._timeScaleInterpolant;if(null!==n){e*=n.evaluate(t)[0],t>n.parameterPositions[1]&&(this.stopWarping(),0===e?this.paused=!0:this.timeScale=e)}}return this._effectiveTimeScale=e,e}_updateTime(t){const e=this._clip.duration,n=this.loop;let i=this.time+t,r=this._loopCount;const s=2202===n;if(0===t)return-1===r?i:s&&1==(1&r)?e-i:i;if(2200===n){-1===r&&(this._loopCount=0,this._setEndings(!0,!0,!1));t:{if(i>=e)i=e;else{if(!(i<0)){this.time=i;break t}i=0}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:t<0?-1:1})}}else{if(-1===r&&(t>=0?(r=0,this._setEndings(!0,0===this.repetitions,s)):this._setEndings(0===this.repetitions,!0,s)),i>=e||i<0){const n=Math.floor(i/e);i-=e*n,r+=Math.abs(n);const a=this.repetitions-r;if(a<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,i=t>0?e:0,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:t>0?1:-1});else{if(1===a){const e=t<0;this._setEndings(e,!e,s)}else this._setEndings(!1,!1,s);this._loopCount=r,this.time=i,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:n})}}else this.time=i;if(s&&1==(1&r))return e-i}return i}_setEndings(t,e,n){const i=this._interpolantSettings;n?(i.endingStart=Oe,i.endingEnd=Oe):(i.endingStart=t?this.zeroSlopeAtStart?Oe:De:Fe,i.endingEnd=e?this.zeroSlopeAtEnd?Oe:De:Fe)}_scheduleFading(t,e,n){const i=this._mixer,r=i.time;let s=this._weightInterpolant;null===s&&(s=i._lendControlInterpolant(),this._weightInterpolant=s);const a=s.parameterPositions,o=s.sampleValues;return a[0]=r,o[0]=e,a[1]=r+t,o[1]=n,this}}const cm=new Float32Array(1);class hm extends Hn{constructor(t){super(),this._root=t,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}_bindAction(t,e){const n=t._localRoot||this._root,i=t._clip.tracks,r=i.length,s=t._propertyBindings,a=t._interpolants,o=n.uuid,l=this._bindingsByRootAndName;let c=l[o];void 0===c&&(c={},l[o]=c);for(let t=0;t!==r;++t){const r=i[t],l=r.name;let h=c[l];if(void 0!==h)++h.referenceCount,s[t]=h;else{if(h=s[t],void 0!==h){null===h._cacheIndex&&(++h.referenceCount,this._addInactiveBinding(h,o,l));continue}const i=e&&e._propertyBindings[t].binding.parsedPath;h=new Qp(am.create(n,l,i),r.ValueTypeName,r.getValueSize()),++h.referenceCount,this._addInactiveBinding(h,o,l),s[t]=h}a[t].resultBuffer=h.buffer}}_activateAction(t){if(!this._isActiveAction(t)){if(null===t._cacheIndex){const e=(t._localRoot||this._root).uuid,n=t._clip.uuid,i=this._actionsByClip[n];this._bindAction(t,i&&i.knownActions[0]),this._addInactiveAction(t,n,e)}const e=t._propertyBindings;for(let t=0,n=e.length;t!==n;++t){const n=e[t];0==n.useCount++&&(this._lendBinding(n),n.saveOriginalState())}this._lendAction(t)}}_deactivateAction(t){if(this._isActiveAction(t)){const e=t._propertyBindings;for(let t=0,n=e.length;t!==n;++t){const n=e[t];0==--n.useCount&&(n.restoreOriginalState(),this._takeBackBinding(n))}this._takeBackAction(t)}}_initMemoryManager(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;const t=this;this.stats={actions:{get total(){return t._actions.length},get inUse(){return t._nActiveActions}},bindings:{get total(){return t._bindings.length},get inUse(){return t._nActiveBindings}},controlInterpolants:{get total(){return t._controlInterpolants.length},get inUse(){return t._nActiveControlInterpolants}}}}_isActiveAction(t){const e=t._cacheIndex;return null!==e&&e=0;--e)t[e].stop();return this}update(t){t*=this.timeScale;const e=this._actions,n=this._nActiveActions,i=this.time+=t,r=Math.sign(t),s=this._accuIndex^=1;for(let a=0;a!==n;++a){e[a]._update(i,t,r,s)}const a=this._bindings,o=this._nActiveBindings;for(let t=0;t!==o;++t)a[t].apply(s);return this}setTime(t){this.time=0;for(let t=0;t=this.min.x&&t.x<=this.max.x&&t.y>=this.min.y&&t.y<=this.max.y}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y}getParameter(t,e){return e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y))}intersectsBox(t){return t.max.x>=this.min.x&&t.min.x<=this.max.x&&t.max.y>=this.min.y&&t.min.y<=this.max.y}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return this.clampPoint(t,bm).distanceTo(t)}intersect(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}}const Tm=new Li,Em=new Li;class Am{constructor(t=new Li,e=new Li){this.start=t,this.end=e}set(t,e){return this.start.copy(t),this.end.copy(e),this}copy(t){return this.start.copy(t.start),this.end.copy(t.end),this}getCenter(t){return t.addVectors(this.start,this.end).multiplyScalar(.5)}delta(t){return t.subVectors(this.end,this.start)}distanceSq(){return this.start.distanceToSquared(this.end)}distance(){return this.start.distanceTo(this.end)}at(t,e){return this.delta(e).multiplyScalar(t).add(this.start)}closestPointToPointParameter(t,e){Tm.subVectors(t,this.start),Em.subVectors(this.end,this.start);const n=Em.dot(Em);let i=Em.dot(Tm)/n;return e&&(i=Yn(i,0,1)),i}closestPointToPoint(t,e,n){const i=this.closestPointToPointParameter(t,e);return this.delta(n).multiplyScalar(i).add(this.start)}applyMatrix4(t){return this.start.applyMatrix4(t),this.end.applyMatrix4(t),this}equals(t){return t.start.equals(this.start)&&t.end.equals(this.end)}clone(){return(new this.constructor).copy(this)}}const Rm=new Li;class Cm extends Dr{constructor(t,e){super(),this.light=t,this.matrixAutoUpdate=!1,this.color=e,this.type="SpotLightHelper";const n=new Cs,i=[0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,-1,0,1,0,0,0,0,1,1,0,0,0,0,-1,1];for(let t=0,e=1,n=32;t1)for(let n=0;n.99999)this.quaternion.set(0,0,0,1);else if(t.y<-.99999)this.quaternion.set(1,0,0,0);else{tf.set(t.z,0,-t.x).normalize();const e=Math.acos(t.y);this.quaternion.setFromAxisAngle(tf,e)}}setLength(t,e=.2*t,n=.2*e){this.line.scale.set(1,Math.max(1e-4,t-e),1),this.line.updateMatrix(),this.cone.scale.set(n,e,n),this.cone.position.y=t,this.cone.updateMatrix()}setColor(t){this.line.material.color.set(t),this.cone.material.color.set(t)}copy(t){return super.copy(t,!1),this.line.copy(t.line),this.cone.copy(t.cone),this}dispose(){this.line.geometry.dispose(),this.line.material.dispose(),this.cone.geometry.dispose(),this.cone.material.dispose()}}class sf extends Ih{constructor(t=1){const e=[0,0,0,t,0,0,0,0,0,0,t,0,0,0,0,0,0,t],n=new Cs;n.setAttribute("position",new Ms(e,3)),n.setAttribute("color",new Ms([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1],3));super(n,new xh({vertexColors:!0,toneMapped:!1})),this.type="AxesHelper"}setColors(t,e,n){const i=new ts,r=this.geometry.attributes.color.array;return i.set(t),i.toArray(r,0),i.toArray(r,3),i.set(e),i.toArray(r,6),i.toArray(r,9),i.set(n),i.toArray(r,12),i.toArray(r,15),this.geometry.attributes.color.needsUpdate=!0,this}dispose(){this.geometry.dispose(),this.material.dispose()}}class af{constructor(){this.type="ShapePath",this.color=new ts,this.subPaths=[],this.currentPath=null}moveTo(t,e){return this.currentPath=new pu,this.subPaths.push(this.currentPath),this.currentPath.moveTo(t,e),this}lineTo(t,e){return this.currentPath.lineTo(t,e),this}quadraticCurveTo(t,e,n,i){return this.currentPath.quadraticCurveTo(t,e,n,i),this}bezierCurveTo(t,e,n,i,r,s){return this.currentPath.bezierCurveTo(t,e,n,i,r,s),this}splineThru(t){return this.currentPath.splineThru(t),this}toShapes(t){function e(t,e){const n=e.length;let i=!1;for(let r=n-1,s=0;sNumber.EPSILON){if(l<0&&(n=e[s],o=-o,a=e[r],l=-l),t.ya.y)continue;if(t.y===n.y){if(t.x===n.x)return!0}else{const e=l*(t.x-n.x)-o*(t.y-n.y);if(0===e)return!0;if(e<0)continue;i=!i}}else{if(t.y!==n.y)continue;if(a.x<=t.x&&t.x<=n.x||n.x<=t.x&&t.x<=a.x)return!0}}return i}const n=$u.isClockWise,i=this.subPaths;if(0===i.length)return[];let r,s,a;const o=[];if(1===i.length)return s=i[0],a=new Eu,a.curves=s.curves,o.push(a),o;let l=!n(i[0].getPoints());l=t?!l:l;const c=[],h=[];let u,d,p=[],m=0;h[m]=void 0,p[m]=[];for(let e=0,a=i.length;e1){let t=!1,n=0;for(let t=0,e=h.length;t0&&!1===t&&(p=c)}for(let t=0,e=h.length;t 0 ) { @@ -11931,6 +11929,7 @@ function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, n Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal ); intersection.face = face; + intersection.barycoord = barycoord; } @@ -13177,7 +13176,6 @@ class InterleavedBuffer { this.count = array !== undefined ? array.length / stride : 0; this.usage = StaticDrawUsage; - this._updateRange = { offset: 0, count: - 1 }; this.updateRanges = []; this.version = 0; @@ -13194,13 +13192,6 @@ class InterleavedBuffer { } - get updateRange() { - - warnOnce( 'THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 - return this._updateRange; - - } - setUsage( value ) { this.usage = value; @@ -13965,6 +13956,27 @@ class LOD extends Object3D { } + removeLevel( distance ) { + + const levels = this.levels; + + for ( let i = 0; i < levels.length; i ++ ) { + + if ( levels[ i ].distance === distance ) { + + const removedElements = levels.splice( i, 1 ); + this.remove( removedElements[ 0 ].object ); + + return true; + + } + + } + + return false; + + } + getCurrentLevel() { return this._currentLevel; @@ -14106,7 +14118,7 @@ const _basePosition = /*@__PURE__*/ new Vector3(); const _skinIndex = /*@__PURE__*/ new Vector4(); const _skinWeight = /*@__PURE__*/ new Vector4(); -const _vector3$1 = /*@__PURE__*/ new Vector3(); +const _vector3 = /*@__PURE__*/ new Vector3(); const _matrix4 = /*@__PURE__*/ new Matrix4(); const _vertex = /*@__PURE__*/ new Vector3(); @@ -14336,7 +14348,7 @@ class SkinnedMesh extends Mesh { _matrix4.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] ); - vector.addScaledVector( _vector3$1.copy( _basePosition ).applyMatrix4( _matrix4 ), weight ); + vector.addScaledVector( _vector3.copy( _basePosition ).applyMatrix4( _matrix4 ), weight ); } @@ -15464,6 +15476,9 @@ class BatchedMesh extends Mesh { // stores visible, active, and geometry id per object this._drawInfo = []; + // instance ids that have been set as inactive, and are available to be overwritten + this._availableInstanceIds = []; + // geometry information this._drawRanges = []; this._reservedRanges = []; @@ -15663,23 +15678,36 @@ class BatchedMesh extends Mesh { addInstance( geometryId ) { + const atCapacity = this._drawInfo.length >= this.maxInstanceCount; + // ensure we're not over geometry - if ( this._drawInfo.length >= this._maxInstanceCount ) { + if ( atCapacity && this._availableInstanceIds.length === 0 ) { throw new Error( 'BatchedMesh: Maximum item count reached.' ); } - this._drawInfo.push( { - + const instanceDrawInfo = { visible: true, active: true, geometryIndex: geometryId, + }; - } ); + let drawId = null; + + // Prioritize using previously freed instance ids + if ( this._availableInstanceIds.length > 0 ) { + + drawId = this._availableInstanceIds.pop(); + this._drawInfo[ drawId ] = instanceDrawInfo; + + } else { + + drawId = this._drawInfo.length; + this._drawInfo.push( instanceDrawInfo ); + + } - // initialize the matrix - const drawId = this._drawInfo.length - 1; const matricesTexture = this._matricesTexture; const matricesArray = matricesTexture.image.data; _identityMatrix.toArray( matricesArray, drawId * 16 ); @@ -15928,11 +15956,8 @@ class BatchedMesh extends Mesh { } */ - /* deleteInstance( instanceId ) { - // Note: User needs to call optimize() afterward to pack the data. - const drawInfo = this._drawInfo; if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { @@ -15941,12 +15966,12 @@ class BatchedMesh extends Mesh { } drawInfo[ instanceId ].active = false; + this._availableInstanceIds.push( instanceId ); this._visibilityChanged = true; return this; } - */ // get bounding box and compute it if it doesn't exist getBoundingBoxAt( geometryId, target ) { @@ -16151,6 +16176,59 @@ class BatchedMesh extends Mesh { } + setGeometryIdAt( instanceId, geometryId ) { + + // return early if the geometry is out of range or not active + const drawInfo = this._drawInfo; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return null; + + } + + // check if the provided geometryId is within the valid range + if ( geometryId < 0 || geometryId >= this._geometryCount ) { + + return null; + + } + + drawInfo[ instanceId ].geometryIndex = geometryId; + + return this; + + } + + getGeometryIdAt( instanceId ) { + + const drawInfo = this._drawInfo; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return - 1; + + } + + return drawInfo[ instanceId ].geometryIndex; + + } + + getGeometryRangeAt( geometryId, target = {} ) { + + if ( geometryId < 0 || geometryId >= this._geometryCount ) { + + return null; + + } + + const drawRange = this._drawRanges[ geometryId ]; + + target.start = drawRange.start; + target.count = drawRange.count; + + return target; + + } + raycast( raycaster, intersects ) { const drawInfo = this._drawInfo; @@ -16702,6 +16780,7 @@ function checkIntersection( object, raycaster, ray, thresholdSq, a, b ) { index: a, face: null, faceIndex: null, + barycoord: null, object: object }; @@ -16967,6 +17046,8 @@ function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, inte point: intersectPoint, index: index, face: null, + faceIndex: null, + barycoord: null, object: object } ); @@ -19535,12 +19616,19 @@ class CylinderGeometry extends BufferGeometry { // faces - indices.push( a, b, d ); - indices.push( b, c, d ); + if ( radiusTop > 0 ) { - // update group counter + indices.push( a, b, d ); + groupCount += 3; - groupCount += 6; + } + + if ( radiusBottom > 0 ) { + + indices.push( b, c, d ); + groupCount += 3; + + } } @@ -24269,19580 +24357,19393 @@ class LineDashedMaterial extends LineBasicMaterial { } -function getCacheKey$1( object, force = false ) { +// converts an array to a specific type +function convertArray( array, type, forceClone ) { - let cacheKey = '{'; + if ( ! array || // let 'undefined' and 'null' pass + ! forceClone && array.constructor === type ) return array; - if ( object.isNode === true ) { + if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { - cacheKey += object.id; - object = object.getSelf(); + return new type( array ); // create typed array } - for ( const { property, childNode } of getNodeChildren( object ) ) { - - cacheKey += ',' + property.slice( 0, - 4 ) + ':' + childNode.getCacheKey( force ); + return Array.prototype.slice.call( array ); // create Array - } +} - cacheKey += '}'; +function isTypedArray( object ) { - return cacheKey; + return ArrayBuffer.isView( object ) && + ! ( object instanceof DataView ); } -function* getNodeChildren( node, toJSON = false ) { +// returns an array by which times and values can be sorted +function getKeyframeOrder( times ) { - for ( const property in node ) { + function compareTime( i, j ) { - // Ignore private properties. - if ( property.startsWith( '_' ) === true ) continue; + return times[ i ] - times[ j ]; - const object = node[ property ]; + } - if ( Array.isArray( object ) === true ) { + const n = times.length; + const result = new Array( n ); + for ( let i = 0; i !== n; ++ i ) result[ i ] = i; - for ( let i = 0; i < object.length; i ++ ) { + result.sort( compareTime ); - const child = object[ i ]; + return result; - if ( child && ( child.isNode === true || toJSON && typeof child.toJSON === 'function' ) ) { +} - yield { property, index: i, childNode: child }; +// uses the array previously returned by 'getKeyframeOrder' to sort data +function sortedArray( values, stride, order ) { - } + const nValues = values.length; + const result = new values.constructor( nValues ); - } + for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { - } else if ( object && object.isNode === true ) { + const srcOffset = order[ i ] * stride; - yield { property, childNode: object }; + for ( let j = 0; j !== stride; ++ j ) { - } else if ( typeof object === 'object' ) { + result[ dstOffset ++ ] = values[ srcOffset + j ]; - for ( const subProperty in object ) { + } - const child = object[ subProperty ]; + } - if ( child && ( child.isNode === true || toJSON && typeof child.toJSON === 'function' ) ) { + return result; - yield { property, index: subProperty, childNode: child }; +} - } +// function for parsing AOS keyframe formats +function flattenJSON( jsonKeys, times, values, valuePropertyName ) { - } + let i = 1, key = jsonKeys[ 0 ]; - } + while ( key !== undefined && key[ valuePropertyName ] === undefined ) { + + key = jsonKeys[ i ++ ]; } -} + if ( key === undefined ) return; // no data -function getValueType( value ) { + let value = key[ valuePropertyName ]; + if ( value === undefined ) return; // no data - if ( value === undefined || value === null ) return null; + if ( Array.isArray( value ) ) { - const typeOf = typeof value; + do { - if ( value.isNode === true ) { + value = key[ valuePropertyName ]; - return 'node'; + if ( value !== undefined ) { - } else if ( typeOf === 'number' ) { + times.push( key.time ); + values.push.apply( values, value ); // push all elements - return 'float'; + } - } else if ( typeOf === 'boolean' ) { + key = jsonKeys[ i ++ ]; - return 'bool'; + } while ( key !== undefined ); - } else if ( typeOf === 'string' ) { + } else if ( value.toArray !== undefined ) { - return 'string'; + // ...assume THREE.Math-ish - } else if ( typeOf === 'function' ) { + do { - return 'shader'; + value = key[ valuePropertyName ]; - } else if ( value.isVector2 === true ) { + if ( value !== undefined ) { - return 'vec2'; + times.push( key.time ); + value.toArray( values, values.length ); - } else if ( value.isVector3 === true ) { + } - return 'vec3'; + key = jsonKeys[ i ++ ]; - } else if ( value.isVector4 === true ) { + } while ( key !== undefined ); - return 'vec4'; + } else { - } else if ( value.isMatrix3 === true ) { + // otherwise push as-is - return 'mat3'; + do { - } else if ( value.isMatrix4 === true ) { + value = key[ valuePropertyName ]; - return 'mat4'; + if ( value !== undefined ) { - } else if ( value.isColor === true ) { + times.push( key.time ); + values.push( value ); - return 'color'; + } - } else if ( value instanceof ArrayBuffer ) { + key = jsonKeys[ i ++ ]; - return 'ArrayBuffer'; + } while ( key !== undefined ); } - return null; - } -function getValueFromType( type, ...params ) { - - const last4 = type ? type.slice( - 4 ) : undefined; - - if ( params.length === 1 ) { // ensure same behaviour as in NodeBuilder.format() - - if ( last4 === 'vec2' ) params = [ params[ 0 ], params[ 0 ] ]; - else if ( last4 === 'vec3' ) params = [ params[ 0 ], params[ 0 ], params[ 0 ] ]; - else if ( last4 === 'vec4' ) params = [ params[ 0 ], params[ 0 ], params[ 0 ], params[ 0 ] ]; +function subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) { - } + const clip = sourceClip.clone(); - if ( type === 'color' ) { + clip.name = name; - return new Color( ...params ); + const tracks = []; - } else if ( last4 === 'vec2' ) { + for ( let i = 0; i < clip.tracks.length; ++ i ) { - return new Vector2( ...params ); + const track = clip.tracks[ i ]; + const valueSize = track.getValueSize(); - } else if ( last4 === 'vec3' ) { + const times = []; + const values = []; - return new Vector3( ...params ); + for ( let j = 0; j < track.times.length; ++ j ) { - } else if ( last4 === 'vec4' ) { + const frame = track.times[ j ] * fps; - return new Vector4( ...params ); + if ( frame < startFrame || frame >= endFrame ) continue; - } else if ( last4 === 'mat3' ) { + times.push( track.times[ j ] ); - return new Matrix3( ...params ); + for ( let k = 0; k < valueSize; ++ k ) { - } else if ( last4 === 'mat4' ) { + values.push( track.values[ j * valueSize + k ] ); - return new Matrix4( ...params ); + } - } else if ( type === 'bool' ) { + } - return params[ 0 ] || false; + if ( times.length === 0 ) continue; - } else if ( ( type === 'float' ) || ( type === 'int' ) || ( type === 'uint' ) ) { + track.times = convertArray( times, track.times.constructor ); + track.values = convertArray( values, track.values.constructor ); - return params[ 0 ] || 0; + tracks.push( track ); - } else if ( type === 'string' ) { + } - return params[ 0 ] || ''; + clip.tracks = tracks; - } else if ( type === 'ArrayBuffer' ) { + // find minimum .times value across all tracks in the trimmed clip - return base64ToArrayBuffer( params[ 0 ] ); + let minStartTime = Infinity; - } + for ( let i = 0; i < clip.tracks.length; ++ i ) { - return null; + if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) { -} + minStartTime = clip.tracks[ i ].times[ 0 ]; -function arrayBufferToBase64( arrayBuffer ) { + } - let chars = ''; + } - const array = new Uint8Array( arrayBuffer ); + // shift all tracks such that clip begins at t=0 - for ( let i = 0; i < array.length; i ++ ) { + for ( let i = 0; i < clip.tracks.length; ++ i ) { - chars += String.fromCharCode( array[ i ] ); + clip.tracks[ i ].shift( - 1 * minStartTime ); } - return btoa( chars ); + clip.resetDuration(); + + return clip; } -function base64ToArrayBuffer( base64 ) { +function makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) { - return Uint8Array.from( atob( base64 ), c => c.charCodeAt( 0 ) ).buffer; + if ( fps <= 0 ) fps = 30; -} + const numTracks = referenceClip.tracks.length; + const referenceTime = referenceFrame / fps; -var NodeUtils = /*#__PURE__*/Object.freeze({ - __proto__: null, - arrayBufferToBase64: arrayBufferToBase64, - base64ToArrayBuffer: base64ToArrayBuffer, - getCacheKey: getCacheKey$1, - getNodeChildren: getNodeChildren, - getValueFromType: getValueFromType, - getValueType: getValueType -}); + // Make each track's values relative to the values at the reference frame + for ( let i = 0; i < numTracks; ++ i ) { -const NodeShaderStage = { - VERTEX: 'vertex', - FRAGMENT: 'fragment' -}; + const referenceTrack = referenceClip.tracks[ i ]; + const referenceTrackType = referenceTrack.ValueTypeName; -const NodeUpdateType = { - NONE: 'none', - FRAME: 'frame', - RENDER: 'render', - OBJECT: 'object' -}; + // Skip this track if it's non-numeric + if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue; -const NodeType = { - BOOLEAN: 'bool', - INTEGER: 'int', - FLOAT: 'float', - VECTOR2: 'vec2', - VECTOR3: 'vec3', - VECTOR4: 'vec4', - MATRIX2: 'mat2', - MATRIX3: 'mat3', - MATRIX4: 'mat4' -}; + // Find the track in the target clip whose name and type matches the reference track + const targetTrack = targetClip.tracks.find( function ( track ) { -const defaultShaderStages = [ 'fragment', 'vertex' ]; -const defaultBuildStages = [ 'setup', 'analyze', 'generate' ]; -const shaderStages = [ ...defaultShaderStages, 'compute' ]; -const vectorComponents = [ 'x', 'y', 'z', 'w' ]; + return track.name === referenceTrack.name + && track.ValueTypeName === referenceTrackType; -const Nodes$1 = new Map(); + } ); -let _nodeId = 0; + if ( targetTrack === undefined ) continue; -class Node extends EventDispatcher { + let referenceOffset = 0; + const referenceValueSize = referenceTrack.getValueSize(); - constructor( nodeType = null ) { + if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { - super(); + referenceOffset = referenceValueSize / 3; - this.nodeType = nodeType; + } - this.updateType = NodeUpdateType.NONE; - this.updateBeforeType = NodeUpdateType.NONE; - this.updateAfterType = NodeUpdateType.NONE; + let targetOffset = 0; + const targetValueSize = targetTrack.getValueSize(); - this.uuid = MathUtils.generateUUID(); + if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { - this.version = 0; + targetOffset = targetValueSize / 3; - this._cacheKey = null; - this._cacheKeyVersion = 0; + } - this.global = false; + const lastIndex = referenceTrack.times.length - 1; + let referenceValue; - this.isNode = true; + // Find the value to subtract out of the track + if ( referenceTime <= referenceTrack.times[ 0 ] ) { - Object.defineProperty( this, 'id', { value: _nodeId ++ } ); + // Reference frame is earlier than the first keyframe, so just use the first keyframe + const startIndex = referenceOffset; + const endIndex = referenceValueSize - referenceOffset; + referenceValue = referenceTrack.values.slice( startIndex, endIndex ); - } + } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) { - set needsUpdate( value ) { + // Reference frame is after the last keyframe, so just use the last keyframe + const startIndex = lastIndex * referenceValueSize + referenceOffset; + const endIndex = startIndex + referenceValueSize - referenceOffset; + referenceValue = referenceTrack.values.slice( startIndex, endIndex ); - if ( value === true ) { + } else { - this.version ++; + // Interpolate to the reference value + const interpolant = referenceTrack.createInterpolant(); + const startIndex = referenceOffset; + const endIndex = referenceValueSize - referenceOffset; + interpolant.evaluate( referenceTime ); + referenceValue = interpolant.resultBuffer.slice( startIndex, endIndex ); } - } - - get type() { + // Conjugate the quaternion + if ( referenceTrackType === 'quaternion' ) { - return this.constructor.type; + const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate(); + referenceQuat.toArray( referenceValue ); - } + } - onUpdate( callback, updateType ) { + // Subtract the reference value from all of the track values - this.updateType = updateType; - this.update = callback.bind( this.getSelf() ); + const numTimes = targetTrack.times.length; + for ( let j = 0; j < numTimes; ++ j ) { - return this; + const valueStart = j * targetValueSize + targetOffset; - } + if ( referenceTrackType === 'quaternion' ) { - onFrameUpdate( callback ) { + // Multiply the conjugate for quaternion track types + Quaternion.multiplyQuaternionsFlat( + targetTrack.values, + valueStart, + referenceValue, + 0, + targetTrack.values, + valueStart + ); - return this.onUpdate( callback, NodeUpdateType.FRAME ); + } else { - } + const valueEnd = targetValueSize - targetOffset * 2; - onRenderUpdate( callback ) { + // Subtract each value for all other numeric track types + for ( let k = 0; k < valueEnd; ++ k ) { - return this.onUpdate( callback, NodeUpdateType.RENDER ); + targetTrack.values[ valueStart + k ] -= referenceValue[ k ]; - } + } - onObjectUpdate( callback ) { + } - return this.onUpdate( callback, NodeUpdateType.OBJECT ); + } } - onReference( callback ) { + targetClip.blendMode = AdditiveAnimationBlendMode; - this.updateReference = callback.bind( this.getSelf() ); + return targetClip; - return this; +} - } +const AnimationUtils = { + convertArray: convertArray, + isTypedArray: isTypedArray, + getKeyframeOrder: getKeyframeOrder, + sortedArray: sortedArray, + flattenJSON: flattenJSON, + subclip: subclip, + makeClipAdditive: makeClipAdditive +}; - getSelf() { +/** + * Abstract base class of interpolants over parametric samples. + * + * The parameter domain is one dimensional, typically the time or a path + * along a curve defined by the data. + * + * The sample values can have any dimensionality and derived classes may + * apply special interpretations to the data. + * + * This class provides the interval seek in a Template Method, deferring + * the actual interpolation to derived classes. + * + * Time complexity is O(1) for linear access crossing at most two points + * and O(log N) for random access, where N is the number of positions. + * + * References: + * + * http://www.oodesign.com/template-method-pattern.html + * + */ - // Returns non-node object. +class Interpolant { - return this.self || this; + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - } + this.parameterPositions = parameterPositions; + this._cachedIndex = 0; - updateReference( /*state*/ ) { + this.resultBuffer = resultBuffer !== undefined ? + resultBuffer : new sampleValues.constructor( sampleSize ); + this.sampleValues = sampleValues; + this.valueSize = sampleSize; - return this; + this.settings = null; + this.DefaultSettings_ = {}; } - isGlobal( /*builder*/ ) { + evaluate( t ) { - return this.global; - - } - - * getChildren() { - - for ( const { childNode } of getNodeChildren( this ) ) { - - yield childNode; + const pp = this.parameterPositions; + let i1 = this._cachedIndex, + t1 = pp[ i1 ], + t0 = pp[ i1 - 1 ]; - } + validate_interval: { - } + seek: { - dispose() { + let right; - this.dispatchEvent( { type: 'dispose' } ); + linear_scan: { - } + //- See http://jsperf.com/comparison-to-undefined/3 + //- slower code: + //- + //- if ( t >= t1 || t1 === undefined ) { + forward_scan: if ( ! ( t < t1 ) ) { - traverse( callback ) { + for ( let giveUpAt = i1 + 2; ; ) { - callback( this ); + if ( t1 === undefined ) { - for ( const childNode of this.getChildren() ) { + if ( t < t0 ) break forward_scan; - childNode.traverse( callback ); + // after end - } + i1 = pp.length; + this._cachedIndex = i1; + return this.copySampleValue_( i1 - 1 ); - } + } - getCacheKey( force = false ) { + if ( i1 === giveUpAt ) break; // this loop - force = force || this.version !== this._cacheKeyVersion; + t0 = t1; + t1 = pp[ ++ i1 ]; - if ( force === true || this._cacheKey === null ) { + if ( t < t1 ) { - this._cacheKey = getCacheKey$1( this, force ); - this._cacheKeyVersion = this.version; + // we have arrived at the sought interval + break seek; - } + } - return this._cacheKey; + } - } + // prepare binary search on the right side of the index + right = pp.length; + break linear_scan; - getScope() { + } - return this; + //- slower code: + //- if ( t < t0 || t0 === undefined ) { + if ( ! ( t >= t0 ) ) { - } + // looping? - getHash( /*builder*/ ) { + const t1global = pp[ 1 ]; - return this.uuid; + if ( t < t1global ) { - } + i1 = 2; // + 1, using the scan for the details + t0 = t1global; - getUpdateType() { + } - return this.updateType; + // linear reverse scan - } + for ( let giveUpAt = i1 - 2; ; ) { - getUpdateBeforeType() { + if ( t0 === undefined ) { - return this.updateBeforeType; + // before start - } + this._cachedIndex = 0; + return this.copySampleValue_( 0 ); - getUpdateAfterType() { + } - return this.updateAfterType; + if ( i1 === giveUpAt ) break; // this loop - } + t1 = t0; + t0 = pp[ -- i1 - 1 ]; - getElementType( builder ) { + if ( t >= t0 ) { - const type = this.getNodeType( builder ); - const elementType = builder.getElementType( type ); + // we have arrived at the sought interval + break seek; - return elementType; + } - } + } - getNodeType( builder ) { + // prepare binary search on the left side of the index + right = i1; + i1 = 0; + break linear_scan; - const nodeProperties = builder.getNodeProperties( this ); + } - if ( nodeProperties.outputNode ) { + // the interval is valid - return nodeProperties.outputNode.getNodeType( builder ); + break validate_interval; - } + } // linear scan - return this.nodeType; + // binary search - } + while ( i1 < right ) { - getShared( builder ) { + const mid = ( i1 + right ) >>> 1; - const hash = this.getHash( builder ); - const nodeFromHash = builder.getNodeFromHash( hash ); + if ( t < pp[ mid ] ) { - return nodeFromHash || this; + right = mid; - } + } else { - setup( builder ) { + i1 = mid + 1; - const nodeProperties = builder.getNodeProperties( this ); + } - let index = 0; + } - for ( const childNode of this.getChildren() ) { + t1 = pp[ i1 ]; + t0 = pp[ i1 - 1 ]; - nodeProperties[ 'node' + index ++ ] = childNode; + // check boundary cases, again - } + if ( t0 === undefined ) { - // return a outputNode if exists - return null; + this._cachedIndex = 0; + return this.copySampleValue_( 0 ); - } + } - analyze( builder ) { + if ( t1 === undefined ) { - const usageCount = builder.increaseUsage( this ); + i1 = pp.length; + this._cachedIndex = i1; + return this.copySampleValue_( i1 - 1 ); - if ( usageCount === 1 ) { + } - // node flow children + } // seek - const nodeProperties = builder.getNodeProperties( this ); + this._cachedIndex = i1; - for ( const childNode of Object.values( nodeProperties ) ) { + this.intervalChanged_( i1, t0, t1 ); - if ( childNode && childNode.isNode === true ) { + } // validate_interval - childNode.build( builder ); + return this.interpolate_( i1, t0, t, t1 ); - } + } - } + getSettings_() { - } + return this.settings || this.DefaultSettings_; } - generate( builder, output ) { - - const { outputNode } = builder.getNodeProperties( this ); + copySampleValue_( index ) { - if ( outputNode && outputNode.isNode === true ) { + // copies a sample value to the result buffer - return outputNode.build( builder, output ); + const result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + offset = index * stride; - } + for ( let i = 0; i !== stride; ++ i ) { - } + result[ i ] = values[ offset + i ]; - updateBefore( /*frame*/ ) { + } - console.warn( 'Abstract function.' ); + return result; } - updateAfter( /*frame*/ ) { + // Template methods for derived classes: - console.warn( 'Abstract function.' ); + interpolate_( /* i1, t0, t, t1 */ ) { + + throw new Error( 'call to abstract method' ); + // implementations shall return this.resultBuffer } - update( /*frame*/ ) { + intervalChanged_( /* i1, t0, t1 */ ) { - console.warn( 'Abstract function.' ); + // empty } - build( builder, output = null ) { +} - const refNode = this.getShared( builder ); +/** + * Fast and simple cubic spline interpolant. + * + * It was derived from a Hermitian construction setting the first derivative + * at each sample position to the linear slope between neighboring positions + * over their parameter interval. + */ - if ( this !== refNode ) { +class CubicInterpolant extends Interpolant { - return refNode.build( builder, output ); + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - } + super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - builder.addNode( this ); - builder.addChain( this ); + this._weightPrev = - 0; + this._offsetPrev = - 0; + this._weightNext = - 0; + this._offsetNext = - 0; - /* Build stages expected results: - - "setup" -> Node - - "analyze" -> null - - "generate" -> String - */ - let result = null; + this.DefaultSettings_ = { - const buildStage = builder.getBuildStage(); + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding - if ( buildStage === 'setup' ) { + }; - this.updateReference( builder ); + } - const properties = builder.getNodeProperties( this ); + intervalChanged_( i1, t0, t1 ) { - if ( properties.initialized !== true ) { + const pp = this.parameterPositions; + let iPrev = i1 - 2, + iNext = i1 + 1, - const stackNodesBeforeSetup = builder.stack.nodes.length; + tPrev = pp[ iPrev ], + tNext = pp[ iNext ]; - properties.initialized = true; - properties.outputNode = this.setup( builder ); + if ( tPrev === undefined ) { - if ( properties.outputNode !== null && builder.stack.nodes.length !== stackNodesBeforeSetup ) ; + switch ( this.getSettings_().endingStart ) { - for ( const childNode of Object.values( properties ) ) { + case ZeroSlopeEnding: - if ( childNode && childNode.isNode === true ) { + // f'(t0) = 0 + iPrev = i1; + tPrev = 2 * t0 - t1; - childNode.build( builder ); + break; - } + case WrapAroundEnding: - } + // use the other end of the curve + iPrev = pp.length - 2; + tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; - } + break; - } else if ( buildStage === 'analyze' ) { + default: // ZeroCurvatureEnding - this.analyze( builder ); + // f''(t0) = 0 a.k.a. Natural Spline + iPrev = i1; + tPrev = t1; - } else if ( buildStage === 'generate' ) { + } - const isGenerateOnce = this.generate.length === 1; + } - if ( isGenerateOnce ) { + if ( tNext === undefined ) { - const type = this.getNodeType( builder ); - const nodeData = builder.getDataFromNode( this ); + switch ( this.getSettings_().endingEnd ) { - result = nodeData.snippet; + case ZeroSlopeEnding: - if ( result === undefined ) { + // f'(tN) = 0 + iNext = i1; + tNext = 2 * t1 - t0; - result = this.generate( builder ) || ''; + break; - nodeData.snippet = result; + case WrapAroundEnding: - } + // use the other end of the curve + iNext = 1; + tNext = t1 + pp[ 1 ] - pp[ 0 ]; - result = builder.format( result, type, output ); + break; - } else { + default: // ZeroCurvatureEnding - result = this.generate( builder, output ) || ''; + // f''(tN) = 0, a.k.a. Natural Spline + iNext = i1 - 1; + tNext = t0; } } - builder.removeChain( this ); + const halfDt = ( t1 - t0 ) * 0.5, + stride = this.valueSize; - return result; + this._weightPrev = halfDt / ( t0 - tPrev ); + this._weightNext = halfDt / ( tNext - t1 ); + this._offsetPrev = iPrev * stride; + this._offsetNext = iNext * stride; } - getSerializeChildren() { - - return getNodeChildren( this ); + interpolate_( i1, t0, t, t1 ) { - } + const result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, - serialize( json ) { + o1 = i1 * stride, o0 = o1 - stride, + oP = this._offsetPrev, oN = this._offsetNext, + wP = this._weightPrev, wN = this._weightNext, - const nodeChildren = this.getSerializeChildren(); + p = ( t - t0 ) / ( t1 - t0 ), + pp = p * p, + ppp = pp * p; - const inputNodes = {}; + // evaluate polynomials - for ( const { property, index, childNode } of nodeChildren ) { + const sP = - wP * ppp + 2 * wP * pp - wP * p; + const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; + const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; + const sN = wN * ppp - wN * pp; - if ( index !== undefined ) { + // combine data linearly - if ( inputNodes[ property ] === undefined ) { + for ( let i = 0; i !== stride; ++ i ) { - inputNodes[ property ] = Number.isInteger( index ) ? [] : {}; + result[ i ] = + sP * values[ oP + i ] + + s0 * values[ o0 + i ] + + s1 * values[ o1 + i ] + + sN * values[ oN + i ]; - } + } - inputNodes[ property ][ index ] = childNode.toJSON( json.meta ).uuid; + return result; - } else { + } - inputNodes[ property ] = childNode.toJSON( json.meta ).uuid; +} - } +class LinearInterpolant extends Interpolant { - } + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - if ( Object.keys( inputNodes ).length > 0 ) { + super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - json.inputNodes = inputNodes; + } - } + interpolate_( i1, t0, t, t1 ) { - } + const result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, - deserialize( json ) { + offset1 = i1 * stride, + offset0 = offset1 - stride, - if ( json.inputNodes !== undefined ) { + weight1 = ( t - t0 ) / ( t1 - t0 ), + weight0 = 1 - weight1; - const nodes = json.meta.nodes; + for ( let i = 0; i !== stride; ++ i ) { - for ( const property in json.inputNodes ) { + result[ i ] = + values[ offset0 + i ] * weight0 + + values[ offset1 + i ] * weight1; - if ( Array.isArray( json.inputNodes[ property ] ) ) { + } - const inputArray = []; + return result; - for ( const uuid of json.inputNodes[ property ] ) { + } - inputArray.push( nodes[ uuid ] ); +} - } +/** + * + * Interpolant that evaluates to the sample value at the position preceding + * the parameter. + */ - this[ property ] = inputArray; +class DiscreteInterpolant extends Interpolant { - } else if ( typeof json.inputNodes[ property ] === 'object' ) { + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - const inputObject = {}; + super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - for ( const subProperty in json.inputNodes[ property ] ) { + } - const uuid = json.inputNodes[ property ][ subProperty ]; + interpolate_( i1 /*, t0, t, t1 */ ) { - inputObject[ subProperty ] = nodes[ uuid ]; + return this.copySampleValue_( i1 - 1 ); - } + } - this[ property ] = inputObject; +} - } else { +class KeyframeTrack { - const uuid = json.inputNodes[ property ]; + constructor( name, times, values, interpolation ) { - this[ property ] = nodes[ uuid ]; + if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); + if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); - } + this.name = name; - } + this.times = convertArray( times, this.TimeBufferType ); + this.values = convertArray( values, this.ValueBufferType ); - } + this.setInterpolation( interpolation || this.DefaultInterpolation ); } - toJSON( meta ) { + // Serialization (in static context, because of constructor invocation + // and automatic invocation of .toJSON): - const { uuid, type } = this; - const isRoot = ( meta === undefined || typeof meta === 'string' ); + static toJSON( track ) { - if ( isRoot ) { + const trackType = track.constructor; - meta = { - textures: {}, - images: {}, - nodes: {} - }; + let json; - } + // derived classes can define a static toJSON method + if ( trackType.toJSON !== this.toJSON ) { - // serialize + json = trackType.toJSON( track ); - let data = meta.nodes[ uuid ]; + } else { - if ( data === undefined ) { + // by default, we assume the data can be serialized as-is + json = { - data = { - uuid, - type, - meta, - metadata: { - version: 4.6, - type: 'Node', - generator: 'Node.toJSON' - } - }; + 'name': track.name, + 'times': convertArray( track.times, Array ), + 'values': convertArray( track.values, Array ) - if ( isRoot !== true ) meta.nodes[ data.uuid ] = data; + }; - this.serialize( data ); + const interpolation = track.getInterpolation(); - delete data.meta; + if ( interpolation !== track.DefaultInterpolation ) { - } + json.interpolation = interpolation; - // TODO: Copied from Object3D.toJSON + } - function extractFromCache( cache ) { + } - const values = []; + json.type = track.ValueTypeName; // mandatory - for ( const key in cache ) { + return json; - const data = cache[ key ]; - delete data.metadata; - values.push( data ); + } - } + InterpolantFactoryMethodDiscrete( result ) { - return values; + return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); - } + } - if ( isRoot ) { + InterpolantFactoryMethodLinear( result ) { - const textures = extractFromCache( meta.textures ); - const images = extractFromCache( meta.images ); - const nodes = extractFromCache( meta.nodes ); + return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); - if ( textures.length > 0 ) data.textures = textures; - if ( images.length > 0 ) data.images = images; - if ( nodes.length > 0 ) data.nodes = nodes; + } - } + InterpolantFactoryMethodSmooth( result ) { - return data; + return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); } -} + setInterpolation( interpolation ) { -Node.type = /*@__PURE__*/ registerNode( '', Node ); + let factoryMethod; -function registerNode( type, nodeClass ) { + switch ( interpolation ) { - const suffix = 'Node'; - const nodeType = type + suffix; + case InterpolateDiscrete: - if ( typeof nodeClass !== 'function' ) throw new Error( `TSL.Node: Node class ${ type } is not a class` ); + factoryMethod = this.InterpolantFactoryMethodDiscrete; - if ( Nodes$1.has( nodeType ) ) { + break; - console.warn( `TSL.Node: Redefinition of node class ${ nodeType }` ); - return; + case InterpolateLinear: - } + factoryMethod = this.InterpolantFactoryMethodLinear; - if ( type.slice( - suffix.length ) === suffix ) { + break; - console.warn( `TSL.Node: Node class ${ nodeType } should not have '${ suffix }' suffix.` ); - return; + case InterpolateSmooth: - } + factoryMethod = this.InterpolantFactoryMethodSmooth; - Nodes$1.set( nodeType, nodeClass ); - nodeClass.type = nodeType; + break; - return nodeType; + } -} + if ( factoryMethod === undefined ) { -function createNodeFromType( type ) { + const message = 'unsupported interpolation for ' + + this.ValueTypeName + ' keyframe track named ' + this.name; - const Class = Nodes$1.get( type ); + if ( this.createInterpolant === undefined ) { - if ( Class !== undefined ) { + // fall back to default, unless the default itself is messed up + if ( interpolation !== this.DefaultInterpolation ) { - return new Class(); + this.setInterpolation( this.DefaultInterpolation ); - } + } else { -} + throw new Error( message ); // fatal, in this case -class ArrayElementNode extends Node { // @TODO: If extending from TempNode it breaks webgpu_compute + } - constructor( node, indexNode ) { + } - super(); + console.warn( 'THREE.KeyframeTrack:', message ); + return this; - this.node = node; - this.indexNode = indexNode; + } - this.isArrayElementNode = true; + this.createInterpolant = factoryMethod; - } + return this; - getNodeType( builder ) { + } - return this.node.getElementType( builder ); + getInterpolation() { - } + switch ( this.createInterpolant ) { - generate( builder ) { + case this.InterpolantFactoryMethodDiscrete: - const nodeSnippet = this.node.build( builder ); - const indexSnippet = this.indexNode.build( builder, 'uint' ); + return InterpolateDiscrete; - return `${nodeSnippet}[ ${indexSnippet} ]`; + case this.InterpolantFactoryMethodLinear: - } + return InterpolateLinear; -} + case this.InterpolantFactoryMethodSmooth: -ArrayElementNode.type = /*@__PURE__*/ registerNode( 'ArrayElement', ArrayElementNode ); + return InterpolateSmooth; -class ConvertNode extends Node { + } - constructor( node, convertTo ) { + } - super(); + getValueSize() { - this.node = node; - this.convertTo = convertTo; + return this.values.length / this.times.length; } - getNodeType( builder ) { - - const requestType = this.node.getNodeType( builder ); + // move all keyframes either forwards or backwards in time + shift( timeOffset ) { - let convertTo = null; + if ( timeOffset !== 0.0 ) { - for ( const overloadingType of this.convertTo.split( '|' ) ) { + const times = this.times; - if ( convertTo === null || builder.getTypeLength( requestType ) === builder.getTypeLength( overloadingType ) ) { + for ( let i = 0, n = times.length; i !== n; ++ i ) { - convertTo = overloadingType; + times[ i ] += timeOffset; } } - return convertTo; - - } - - serialize( data ) { - - super.serialize( data ); - - data.convertTo = this.convertTo; + return this; } - deserialize( data ) { + // scale all keyframe times by a factor (useful for frame <-> seconds conversions) + scale( timeScale ) { - super.deserialize( data ); + if ( timeScale !== 1.0 ) { - this.convertTo = data.convertTo; + const times = this.times; - } + for ( let i = 0, n = times.length; i !== n; ++ i ) { - generate( builder, output ) { + times[ i ] *= timeScale; - const node = this.node; - const type = this.getNodeType( builder ); + } - const snippet = node.build( builder, type ); + } - return builder.format( snippet, type, output ); + return this; } -} - -ConvertNode.type = /*@__PURE__*/ registerNode( 'Convert', ConvertNode ); + // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. + // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values + trim( startTime, endTime ) { -class TempNode extends Node { + const times = this.times, + nKeys = times.length; - constructor( type ) { + let from = 0, + to = nKeys - 1; - super( type ); + while ( from !== nKeys && times[ from ] < startTime ) { - this.isTempNode = true; + ++ from; - } + } - hasDependencies( builder ) { + while ( to !== - 1 && times[ to ] > endTime ) { - return builder.getDataFromNode( this ).usageCount > 1; + -- to; - } + } - build( builder, output ) { + ++ to; // inclusive -> exclusive bound - const buildStage = builder.getBuildStage(); + if ( from !== 0 || to !== nKeys ) { - if ( buildStage === 'generate' ) { + // empty tracks are forbidden, so keep at least one keyframe + if ( from >= to ) { - const type = builder.getVectorType( this.getNodeType( builder, output ) ); - const nodeData = builder.getDataFromNode( this ); + to = Math.max( to, 1 ); + from = to - 1; - if ( nodeData.propertyName !== undefined ) { + } - return builder.format( nodeData.propertyName, type, output ); + const stride = this.getValueSize(); + this.times = times.slice( from, to ); + this.values = this.values.slice( from * stride, to * stride ); - } else if ( type !== 'void' && output !== 'void' && this.hasDependencies( builder ) ) { + } - const snippet = super.build( builder, type ); + return this; - const nodeVar = builder.getVarFromNode( this, null, type ); - const propertyName = builder.getPropertyName( nodeVar ); + } - builder.addLineFlowCode( `${propertyName} = ${snippet}` ); + // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable + validate() { - nodeData.snippet = snippet; - nodeData.propertyName = propertyName; + let valid = true; - return builder.format( nodeData.propertyName, type, output ); + const valueSize = this.getValueSize(); + if ( valueSize - Math.floor( valueSize ) !== 0 ) { - } + console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); + valid = false; } - return super.build( builder, output ); + const times = this.times, + values = this.values, - } + nKeys = times.length; -} + if ( nKeys === 0 ) { -TempNode.type = /*@__PURE__*/ registerNode( 'Temp', TempNode ); + console.error( 'THREE.KeyframeTrack: Track is empty.', this ); + valid = false; -class JoinNode extends TempNode { + } - constructor( nodes = [], nodeType = null ) { + let prevTime = null; - super( nodeType ); + for ( let i = 0; i !== nKeys; i ++ ) { - this.nodes = nodes; + const currTime = times[ i ]; - } + if ( typeof currTime === 'number' && isNaN( currTime ) ) { - getNodeType( builder ) { + console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); + valid = false; + break; - if ( this.nodeType !== null ) { + } - return builder.getVectorType( this.nodeType ); + if ( prevTime !== null && prevTime > currTime ) { - } + console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); + valid = false; + break; - return builder.getTypeFromLength( this.nodes.reduce( ( count, cur ) => count + builder.getTypeLength( cur.getNodeType( builder ) ), 0 ) ); + } - } + prevTime = currTime; - generate( builder, output ) { + } - const type = this.getNodeType( builder ); - const nodes = this.nodes; + if ( values !== undefined ) { - const primitiveType = builder.getComponentType( type ); + if ( isTypedArray( values ) ) { - const snippetValues = []; + for ( let i = 0, n = values.length; i !== n; ++ i ) { - for ( const input of nodes ) { + const value = values[ i ]; - let inputSnippet = input.build( builder ); + if ( isNaN( value ) ) { - const inputPrimitiveType = builder.getComponentType( input.getNodeType( builder ) ); + console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); + valid = false; + break; - if ( inputPrimitiveType !== primitiveType ) { + } - inputSnippet = builder.format( inputSnippet, inputPrimitiveType, primitiveType ); + } } - snippetValues.push( inputSnippet ); - } - const snippet = `${ builder.getType( type ) }( ${ snippetValues.join( ', ' ) } )`; - - return builder.format( snippet, type, output ); + return valid; } -} + // removes equivalent sequential keys as common in morph target sequences + // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) + optimize() { -JoinNode.type = /*@__PURE__*/ registerNode( 'Join', JoinNode ); + // times or values may be shared with other tracks, so overwriting is unsafe + const times = this.times.slice(), + values = this.values.slice(), + stride = this.getValueSize(), -const stringVectorComponents = vectorComponents.join( '' ); + smoothInterpolation = this.getInterpolation() === InterpolateSmooth, -class SplitNode extends Node { + lastIndex = times.length - 1; - constructor( node, components = 'x' ) { + let writeIndex = 1; - super(); + for ( let i = 1; i < lastIndex; ++ i ) { - this.node = node; - this.components = components; + let keep = false; - this.isSplitNode = true; + const time = times[ i ]; + const timeNext = times[ i + 1 ]; - } + // remove adjacent keyframes scheduled at the same time - getVectorLength() { + if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) { - let vectorLength = this.components.length; + if ( ! smoothInterpolation ) { - for ( const c of this.components ) { + // remove unnecessary keyframes same as their neighbors - vectorLength = Math.max( vectorComponents.indexOf( c ) + 1, vectorLength ); + const offset = i * stride, + offsetP = offset - stride, + offsetN = offset + stride; - } + for ( let j = 0; j !== stride; ++ j ) { - return vectorLength; + const value = values[ offset + j ]; - } + if ( value !== values[ offsetP + j ] || + value !== values[ offsetN + j ] ) { - getComponentType( builder ) { + keep = true; + break; - return builder.getComponentType( this.node.getNodeType( builder ) ); + } - } + } - getNodeType( builder ) { + } else { - return builder.getTypeFromLength( this.components.length, this.getComponentType( builder ) ); + keep = true; - } + } - generate( builder, output ) { + } - const node = this.node; - const nodeTypeLength = builder.getTypeLength( node.getNodeType( builder ) ); + // in-place compaction - let snippet = null; + if ( keep ) { - if ( nodeTypeLength > 1 ) { + if ( i !== writeIndex ) { - let type = null; + times[ writeIndex ] = times[ i ]; - const componentsLength = this.getVectorLength(); + const readOffset = i * stride, + writeOffset = writeIndex * stride; - if ( componentsLength >= nodeTypeLength ) { + for ( let j = 0; j !== stride; ++ j ) { - // needed expand the input node + values[ writeOffset + j ] = values[ readOffset + j ]; - type = builder.getTypeFromLength( this.getVectorLength(), this.getComponentType( builder ) ); + } - } + } - const nodeSnippet = node.build( builder, type ); + ++ writeIndex; - if ( this.components.length === nodeTypeLength && this.components === stringVectorComponents.slice( 0, this.components.length ) ) { + } - // unnecessary swizzle + } - snippet = builder.format( nodeSnippet, type, output ); + // flush last keyframe (compaction looks ahead) - } else { + if ( lastIndex > 0 ) { - snippet = builder.format( `${nodeSnippet}.${this.components}`, this.getNodeType( builder ), output ); + times[ writeIndex ] = times[ lastIndex ]; - } + for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { - } else { + values[ writeOffset + j ] = values[ readOffset + j ]; - // ignore .components if .node returns float/integer + } - snippet = node.build( builder, output ); + ++ writeIndex; } - return snippet; + if ( writeIndex !== times.length ) { - } + this.times = times.slice( 0, writeIndex ); + this.values = values.slice( 0, writeIndex * stride ); - serialize( data ) { + } else { - super.serialize( data ); + this.times = times; + this.values = values; - data.components = this.components; + } + + return this; } - deserialize( data ) { + clone() { - super.deserialize( data ); + const times = this.times.slice(); + const values = this.values.slice(); - this.components = data.components; + const TypedKeyframeTrack = this.constructor; + const track = new TypedKeyframeTrack( this.name, times, values ); + + // Interpolant argument to constructor is not saved, so copy the factory method directly. + track.createInterpolant = this.createInterpolant; + + return track; } } -SplitNode.type = /*@__PURE__*/ registerNode( 'Split', SplitNode ); - -class SetNode extends TempNode { +KeyframeTrack.prototype.TimeBufferType = Float32Array; +KeyframeTrack.prototype.ValueBufferType = Float32Array; +KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; - constructor( sourceNode, components, targetNode ) { +/** + * A Track of Boolean keyframe values. + */ +class BooleanKeyframeTrack extends KeyframeTrack { - super(); + // No interpolation parameter because only InterpolateDiscrete is valid. + constructor( name, times, values ) { - this.sourceNode = sourceNode; - this.components = components; - this.targetNode = targetNode; + super( name, times, values ); } - getNodeType( builder ) { +} - return this.sourceNode.getNodeType( builder ); +BooleanKeyframeTrack.prototype.ValueTypeName = 'bool'; +BooleanKeyframeTrack.prototype.ValueBufferType = Array; +BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; +BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; +BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - } +/** + * A Track of keyframe values that represent color. + */ +class ColorKeyframeTrack extends KeyframeTrack {} - generate( builder ) { +ColorKeyframeTrack.prototype.ValueTypeName = 'color'; - const { sourceNode, components, targetNode } = this; +/** + * A Track of numeric keyframe values. + */ +class NumberKeyframeTrack extends KeyframeTrack {} - const sourceType = this.getNodeType( builder ); - const targetType = builder.getTypeFromLength( components.length ); +NumberKeyframeTrack.prototype.ValueTypeName = 'number'; - const targetSnippet = targetNode.build( builder, targetType ); - const sourceSnippet = sourceNode.build( builder, sourceType ); +/** + * Spherical linear unit quaternion interpolant. + */ - const length = builder.getTypeLength( sourceType ); - const snippetValues = []; +class QuaternionLinearInterpolant extends Interpolant { - for ( let i = 0; i < length; i ++ ) { + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - const component = vectorComponents[ i ]; + super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - if ( component === components[ 0 ] ) { + } - snippetValues.push( targetSnippet ); + interpolate_( i1, t0, t, t1 ) { - i += components.length - 1; + const result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, - } else { + alpha = ( t - t0 ) / ( t1 - t0 ); - snippetValues.push( sourceSnippet + '.' + component ); + let offset = i1 * stride; - } + for ( let end = offset + stride; offset !== end; offset += 4 ) { + + Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); } - return `${ builder.getType( sourceType ) }( ${ snippetValues.join( ', ' ) } )`; + return result; } } -SetNode.type = /*@__PURE__*/ registerNode( 'Set', SetNode ); - -class FlipNode extends TempNode { - - constructor( sourceNode, components ) { +/** + * A Track of quaternion keyframe values. + */ +class QuaternionKeyframeTrack extends KeyframeTrack { - super(); + InterpolantFactoryMethodLinear( result ) { - this.sourceNode = sourceNode; - this.components = components; + return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); } - getNodeType( builder ) { - - return this.sourceNode.getNodeType( builder ); - - } +} - generate( builder ) { +QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion'; +// ValueBufferType is inherited +// DefaultInterpolation is inherited; +QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - const { components, sourceNode } = this; +/** + * A Track that interpolates Strings + */ +class StringKeyframeTrack extends KeyframeTrack { - const sourceType = this.getNodeType( builder ); - const sourceSnippet = sourceNode.build( builder ); + // No interpolation parameter because only InterpolateDiscrete is valid. + constructor( name, times, values ) { - const sourceCache = builder.getVarFromNode( this ); - const sourceProperty = builder.getPropertyName( sourceCache ); + super( name, times, values ); - builder.addLineFlowCode( sourceProperty + ' = ' + sourceSnippet ); + } - const length = builder.getTypeLength( sourceType ); - const snippetValues = []; +} - let componentIndex = 0; +StringKeyframeTrack.prototype.ValueTypeName = 'string'; +StringKeyframeTrack.prototype.ValueBufferType = Array; +StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; +StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; +StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - for ( let i = 0; i < length; i ++ ) { +/** + * A Track of vectored keyframe values. + */ +class VectorKeyframeTrack extends KeyframeTrack {} - const component = vectorComponents[ i ]; +VectorKeyframeTrack.prototype.ValueTypeName = 'vector'; - if ( component === components[ componentIndex ] ) { +class AnimationClip { - snippetValues.push( '1.0 - ' + ( sourceProperty + '.' + component ) ); + constructor( name = '', duration = - 1, tracks = [], blendMode = NormalAnimationBlendMode ) { - componentIndex ++; + this.name = name; + this.tracks = tracks; + this.duration = duration; + this.blendMode = blendMode; - } else { + this.uuid = generateUUID(); - snippetValues.push( sourceProperty + '.' + component ); + // this means it should figure out its duration by scanning the tracks + if ( this.duration < 0 ) { - } + this.resetDuration(); } - return `${ builder.getType( sourceType ) }( ${ snippetValues.join( ', ' ) } )`; - } -} -FlipNode.type = /*@__PURE__*/ registerNode( 'Flip', FlipNode ); + static parse( json ) { -class InputNode extends Node { + const tracks = [], + jsonTracks = json.tracks, + frameTime = 1.0 / ( json.fps || 1.0 ); - constructor( value, nodeType = null ) { + for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) { - super( nodeType ); + tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) ); - this.isInputNode = true; + } - this.value = value; - this.precision = null; + const clip = new this( json.name, json.duration, tracks, json.blendMode ); + clip.uuid = json.uuid; - } + return clip; - getNodeType( /*builder*/ ) { + } - if ( this.nodeType === null ) { + static toJSON( clip ) { - return getValueType( this.value ); + const tracks = [], + clipTracks = clip.tracks; - } + const json = { - return this.nodeType; - - } - - getInputType( builder ) { + 'name': clip.name, + 'duration': clip.duration, + 'tracks': tracks, + 'uuid': clip.uuid, + 'blendMode': clip.blendMode - return this.getNodeType( builder ); + }; - } + for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) { - setPrecision( precision ) { + tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); - this.precision = precision; + } - return this; + return json; } - serialize( data ) { + static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) { - super.serialize( data ); + const numMorphTargets = morphTargetSequence.length; + const tracks = []; - data.value = this.value; + for ( let i = 0; i < numMorphTargets; i ++ ) { - if ( this.value && this.value.toArray ) data.value = this.value.toArray(); + let times = []; + let values = []; - data.valueType = getValueType( this.value ); - data.nodeType = this.nodeType; + times.push( + ( i + numMorphTargets - 1 ) % numMorphTargets, + i, + ( i + 1 ) % numMorphTargets ); - if ( data.valueType === 'ArrayBuffer' ) data.value = arrayBufferToBase64( data.value ); + values.push( 0, 1, 0 ); - data.precision = this.precision; + const order = getKeyframeOrder( times ); + times = sortedArray( times, 1, order ); + values = sortedArray( values, 1, order ); - } + // if there is a key at the first frame, duplicate it as the + // last frame as well for perfect loop. + if ( ! noLoop && times[ 0 ] === 0 ) { - deserialize( data ) { + times.push( numMorphTargets ); + values.push( values[ 0 ] ); - super.deserialize( data ); + } - this.nodeType = data.nodeType; - this.value = Array.isArray( data.value ) ? getValueFromType( data.valueType, ...data.value ) : data.value; + tracks.push( + new NumberKeyframeTrack( + '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', + times, values + ).scale( 1.0 / fps ) ); - this.precision = data.precision || null; + } - if ( this.value && this.value.fromArray ) this.value = this.value.fromArray( data.value ); + return new this( name, - 1, tracks ); } - generate( /*builder, output*/ ) { - - console.warn( 'Abstract function.' ); + static findByName( objectOrClipArray, name ) { - } + let clipArray = objectOrClipArray; -} + if ( ! Array.isArray( objectOrClipArray ) ) { -InputNode.type = /*@__PURE__*/ registerNode( 'Input', InputNode ); + const o = objectOrClipArray; + clipArray = o.geometry && o.geometry.animations || o.animations; -class ConstNode extends InputNode { + } - constructor( value, nodeType = null ) { + for ( let i = 0; i < clipArray.length; i ++ ) { - super( value, nodeType ); + if ( clipArray[ i ].name === name ) { - this.isConstNode = true; + return clipArray[ i ]; - } + } - generateConst( builder ) { + } - return builder.generateConst( this.getNodeType( builder ), this.value ); + return null; } - generate( builder, output ) { - - const type = this.getNodeType( builder ); + static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) { - return builder.format( this.generateConst( builder ), type, output ); + const animationToMorphTargets = {}; - } + // tested with https://regex101.com/ on trick sequences + // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 + const pattern = /^([\w-]*?)([\d]+)$/; -} + // sort morph target names into animation groups based + // patterns like Walk_001, Walk_002, Run_001, Run_002 + for ( let i = 0, il = morphTargets.length; i < il; i ++ ) { -ConstNode.type = /*@__PURE__*/ registerNode( 'Const', ConstNode ); + const morphTarget = morphTargets[ i ]; + const parts = morphTarget.name.match( pattern ); -// + if ( parts && parts.length > 1 ) { -let currentStack = null; + const name = parts[ 1 ]; -const NodeElements = new Map(); + let animationMorphTargets = animationToMorphTargets[ name ]; -function addMethodChaining( name, nodeElement ) { + if ( ! animationMorphTargets ) { - if ( NodeElements.has( name ) ) { + animationToMorphTargets[ name ] = animationMorphTargets = []; - console.warn( `Redefinition of method chaining ${ name }` ); - return; + } - } + animationMorphTargets.push( morphTarget ); - if ( typeof nodeElement !== 'function' ) throw new Error( `Node element ${ name } is not a function` ); + } - NodeElements.set( name, nodeElement ); + } -} + const clips = []; -const parseSwizzle = ( props ) => props.replace( /r|s/g, 'x' ).replace( /g|t/g, 'y' ).replace( /b|p/g, 'z' ).replace( /a|q/g, 'w' ); -const parseSwizzleAndSort = ( props ) => parseSwizzle( props ).split( '' ).sort().join( '' ); + for ( const name in animationToMorphTargets ) { -const shaderNodeHandler = { + clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); - setup( NodeClosure, params ) { + } - const inputs = params.shift(); + return clips; - return NodeClosure( nodeObjects( inputs ), ...params ); + } - }, + // parse the animation.hierarchy format + static parseAnimation( animation, bones ) { - get( node, prop, nodeObj ) { + if ( ! animation ) { - if ( typeof prop === 'string' && node[ prop ] === undefined ) { + console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); + return null; - if ( node.isStackNode !== true && prop === 'assign' ) { + } - return ( ...params ) => { + const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { - currentStack.assign( nodeObj, ...params ); + // only return track if there are actually keys. + if ( animationKeys.length !== 0 ) { - return nodeObj; + const times = []; + const values = []; - }; + flattenJSON( animationKeys, times, values, propertyName ); - } else if ( NodeElements.has( prop ) ) { + // empty keys are filtered out, so check again + if ( times.length !== 0 ) { - const nodeElement = NodeElements.get( prop ); + destTracks.push( new trackType( trackName, times, values ) ); - return node.isStackNode ? ( ...params ) => nodeObj.add( nodeElement( ...params ) ) : ( ...params ) => nodeElement( nodeObj, ...params ); + } - } else if ( prop === 'self' ) { + } - return node; + }; - } else if ( prop.endsWith( 'Assign' ) && NodeElements.has( prop.slice( 0, prop.length - 'Assign'.length ) ) ) { + const tracks = []; - const nodeElement = NodeElements.get( prop.slice( 0, prop.length - 'Assign'.length ) ); + const clipName = animation.name || 'default'; + const fps = animation.fps || 30; + const blendMode = animation.blendMode; - return node.isStackNode ? ( ...params ) => nodeObj.assign( params[ 0 ], nodeElement( ...params ) ) : ( ...params ) => nodeObj.assign( nodeElement( nodeObj, ...params ) ); + // automatic length determination in AnimationClip. + let duration = animation.length || - 1; - } else if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true ) { + const hierarchyTracks = animation.hierarchy || []; - // accessing properties ( swizzle ) + for ( let h = 0; h < hierarchyTracks.length; h ++ ) { - prop = parseSwizzle( prop ); + const animationKeys = hierarchyTracks[ h ].keys; - return nodeObject( new SplitNode( nodeObj, prop ) ); + // skip empty tracks + if ( ! animationKeys || animationKeys.length === 0 ) continue; - } else if ( /^set[XYZWRGBASTPQ]{1,4}$/.test( prop ) === true ) { + // process morph targets + if ( animationKeys[ 0 ].morphTargets ) { - // set properties ( swizzle ) and sort to xyzw sequence + // figure out all morph targets used in this track + const morphTargetNames = {}; - prop = parseSwizzleAndSort( prop.slice( 3 ).toLowerCase() ); + let k; - return ( value ) => nodeObject( new SetNode( node, prop, value ) ); + for ( k = 0; k < animationKeys.length; k ++ ) { - } else if ( /^flip[XYZWRGBASTPQ]{1,4}$/.test( prop ) === true ) { + if ( animationKeys[ k ].morphTargets ) { - // set properties ( swizzle ) and sort to xyzw sequence + for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { - prop = parseSwizzleAndSort( prop.slice( 4 ).toLowerCase() ); + morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; - return () => nodeObject( new FlipNode( nodeObject( node ), prop ) ); + } - } else if ( prop === 'width' || prop === 'height' || prop === 'depth' ) { + } - // accessing property + } - if ( prop === 'width' ) prop = 'x'; - else if ( prop === 'height' ) prop = 'y'; - else if ( prop === 'depth' ) prop = 'z'; + // create a track for each morph target with all zero + // morphTargetInfluences except for the keys in which + // the morphTarget is named. + for ( const morphTargetName in morphTargetNames ) { - return nodeObject( new SplitNode( node, prop ) ); + const times = []; + const values = []; - } else if ( /^\d+$/.test( prop ) === true ) { + for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { - // accessing array + const animationKey = animationKeys[ k ]; - return nodeObject( new ArrayElementNode( nodeObj, new ConstNode( Number( prop ), 'uint' ) ) ); + times.push( animationKey.time ); + values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); - } + } - } + tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); - return Reflect.get( node, prop, nodeObj ); + } - }, + duration = morphTargetNames.length * fps; - set( node, prop, value, nodeObj ) { + } else { - if ( typeof prop === 'string' && node[ prop ] === undefined ) { + // ...assume skeletal animation - // setting properties + const boneName = '.bones[' + bones[ h ].name + ']'; - if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true || prop === 'width' || prop === 'height' || prop === 'depth' || /^\d+$/.test( prop ) === true ) { + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.position', + animationKeys, 'pos', tracks ); - nodeObj[ prop ].assign( value ); + addNonemptyTrack( + QuaternionKeyframeTrack, boneName + '.quaternion', + animationKeys, 'rot', tracks ); - return true; + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.scale', + animationKeys, 'scl', tracks ); } } - return Reflect.set( node, prop, value, nodeObj ); + if ( tracks.length === 0 ) { - } + return null; -}; + } -const nodeObjectsCacheMap = new WeakMap(); -const nodeBuilderFunctionsCacheMap = new WeakMap(); + const clip = new this( clipName, duration, tracks, blendMode ); -const ShaderNodeObject = function ( obj, altType = null ) { + return clip; - const type = getValueType( obj ); + } - if ( type === 'node' ) { + resetDuration() { - let nodeObject = nodeObjectsCacheMap.get( obj ); + const tracks = this.tracks; + let duration = 0; - if ( nodeObject === undefined ) { + for ( let i = 0, n = tracks.length; i !== n; ++ i ) { - nodeObject = new Proxy( obj, shaderNodeHandler ); + const track = this.tracks[ i ]; - nodeObjectsCacheMap.set( obj, nodeObject ); - nodeObjectsCacheMap.set( nodeObject, nodeObject ); + duration = Math.max( duration, track.times[ track.times.length - 1 ] ); } - return nodeObject; - - } else if ( ( altType === null && ( type === 'float' || type === 'boolean' ) ) || ( type && type !== 'shader' && type !== 'string' ) ) { - - return nodeObject( getConstNode( obj, altType ) ); - - } else if ( type === 'shader' ) { + this.duration = duration; - return Fn( obj ); + return this; } - return obj; + trim() { -}; + for ( let i = 0; i < this.tracks.length; i ++ ) { -const ShaderNodeObjects = function ( objects, altType = null ) { + this.tracks[ i ].trim( 0, this.duration ); - for ( const name in objects ) { + } - objects[ name ] = nodeObject( objects[ name ], altType ); + return this; } - return objects; + validate() { -}; + let valid = true; -const ShaderNodeArray = function ( array, altType = null ) { + for ( let i = 0; i < this.tracks.length; i ++ ) { - const len = array.length; + valid = valid && this.tracks[ i ].validate(); - for ( let i = 0; i < len; i ++ ) { + } - array[ i ] = nodeObject( array[ i ], altType ); + return valid; } - return array; + optimize() { -}; + for ( let i = 0; i < this.tracks.length; i ++ ) { -const ShaderNodeProxy = function ( NodeClass, scope = null, factor = null, settings = null ) { + this.tracks[ i ].optimize(); - const assignNode = ( node ) => nodeObject( settings !== null ? Object.assign( node, settings ) : node ); + } - if ( scope === null ) { + return this; - return ( ...params ) => { + } - return assignNode( new NodeClass( ...nodeArray( params ) ) ); + clone() { - }; + const tracks = []; - } else if ( factor !== null ) { + for ( let i = 0; i < this.tracks.length; i ++ ) { - factor = nodeObject( factor ); + tracks.push( this.tracks[ i ].clone() ); - return ( ...params ) => { + } - return assignNode( new NodeClass( scope, ...nodeArray( params ), factor ) ); + return new this.constructor( this.name, this.duration, tracks, this.blendMode ); - }; + } - } else { + toJSON() { - return ( ...params ) => { + return this.constructor.toJSON( this ); - return assignNode( new NodeClass( scope, ...nodeArray( params ) ) ); + } - }; +} - } +function getTrackTypeForValueTypeName( typeName ) { -}; + switch ( typeName.toLowerCase() ) { -const ShaderNodeImmutable = function ( NodeClass, ...params ) { + case 'scalar': + case 'double': + case 'float': + case 'number': + case 'integer': - return nodeObject( new NodeClass( ...nodeArray( params ) ) ); + return NumberKeyframeTrack; -}; + case 'vector': + case 'vector2': + case 'vector3': + case 'vector4': -class ShaderCallNodeInternal extends Node { + return VectorKeyframeTrack; - constructor( shaderNode, inputNodes ) { + case 'color': - super(); + return ColorKeyframeTrack; - this.shaderNode = shaderNode; - this.inputNodes = inputNodes; + case 'quaternion': - } + return QuaternionKeyframeTrack; - getNodeType( builder ) { + case 'bool': + case 'boolean': - return this.shaderNode.nodeType || this.getOutputNode( builder ).getNodeType( builder ); + return BooleanKeyframeTrack; - } + case 'string': - call( builder ) { + return StringKeyframeTrack; - const { shaderNode, inputNodes } = this; + } - const properties = builder.getNodeProperties( shaderNode ); - if ( properties.onceOutput ) return properties.onceOutput; + throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); - // +} - let result = null; +function parseKeyframeTrack( json ) { - if ( shaderNode.layout ) { + if ( json.type === undefined ) { - let functionNodesCacheMap = nodeBuilderFunctionsCacheMap.get( builder.constructor ); + throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); - if ( functionNodesCacheMap === undefined ) { + } - functionNodesCacheMap = new WeakMap(); + const trackType = getTrackTypeForValueTypeName( json.type ); - nodeBuilderFunctionsCacheMap.set( builder.constructor, functionNodesCacheMap ); + if ( json.times === undefined ) { - } + const times = [], values = []; - let functionNode = functionNodesCacheMap.get( shaderNode ); + flattenJSON( json.keys, times, values, 'value' ); - if ( functionNode === undefined ) { + json.times = times; + json.values = values; - functionNode = nodeObject( builder.buildFunctionNode( shaderNode ) ); + } - functionNodesCacheMap.set( shaderNode, functionNode ); + // derived classes can define a static parse method + if ( trackType.parse !== undefined ) { - } + return trackType.parse( json ); - if ( builder.currentFunctionNode !== null ) { + } else { - builder.currentFunctionNode.includes.push( functionNode ); + // by default, we assume a constructor compatible with the base + return new trackType( json.name, json.times, json.values, json.interpolation ); - } + } - result = nodeObject( functionNode.call( inputNodes ) ); +} - } else { +const Cache = { - const jsFunc = shaderNode.jsFunc; - const outputNode = inputNodes !== null ? jsFunc( inputNodes, builder ) : jsFunc( builder ); + enabled: false, - result = nodeObject( outputNode ); + files: {}, - } + add: function ( key, file ) { - if ( shaderNode.once ) { + if ( this.enabled === false ) return; - properties.onceOutput = result; + // console.log( 'THREE.Cache', 'Adding key:', key ); - } + this.files[ key ] = file; - return result; + }, - } + get: function ( key ) { - getOutputNode( builder ) { + if ( this.enabled === false ) return; - const properties = builder.getNodeProperties( this ); + // console.log( 'THREE.Cache', 'Checking key:', key ); - if ( properties.outputNode === null ) { + return this.files[ key ]; - properties.outputNode = this.setupOutput( builder ); + }, - } + remove: function ( key ) { - return properties.outputNode; + delete this.files[ key ]; - } + }, - setup( builder ) { + clear: function () { - return this.getOutputNode( builder ); + this.files = {}; } - setupOutput( builder ) { +}; - builder.addStack(); +class LoadingManager { - builder.stack.outputNode = this.call( builder ); + constructor( onLoad, onProgress, onError ) { - return builder.removeStack(); + const scope = this; - } + let isLoading = false; + let itemsLoaded = 0; + let itemsTotal = 0; + let urlModifier = undefined; + const handlers = []; - generate( builder, output ) { + // Refer to #5689 for the reason why we don't set .onStart + // in the constructor - const outputNode = this.getOutputNode( builder ); + this.onStart = undefined; + this.onLoad = onLoad; + this.onProgress = onProgress; + this.onError = onError; - return outputNode.build( builder, output ); + this.itemStart = function ( url ) { - } + itemsTotal ++; -} + if ( isLoading === false ) { -class ShaderNodeInternal extends Node { + if ( scope.onStart !== undefined ) { - constructor( jsFunc, nodeType ) { + scope.onStart( url, itemsLoaded, itemsTotal ); - super( nodeType ); + } - this.jsFunc = jsFunc; - this.layout = null; + } - this.global = true; + isLoading = true; - this.once = false; + }; - } + this.itemEnd = function ( url ) { - setLayout( layout ) { + itemsLoaded ++; - this.layout = layout; + if ( scope.onProgress !== undefined ) { - return this; + scope.onProgress( url, itemsLoaded, itemsTotal ); - } + } - call( inputs = null ) { + if ( itemsLoaded === itemsTotal ) { - nodeObjects( inputs ); + isLoading = false; - return nodeObject( new ShaderCallNodeInternal( this, inputs ) ); + if ( scope.onLoad !== undefined ) { - } + scope.onLoad(); - setup() { + } - return this.call(); + } - } + }; -} + this.itemError = function ( url ) { -const bools = [ false, true ]; -const uints = [ 0, 1, 2, 3 ]; -const ints = [ - 1, - 2 ]; -const floats = [ 0.5, 1.5, 1 / 3, 1e-6, 1e6, Math.PI, Math.PI * 2, 1 / Math.PI, 2 / Math.PI, 1 / ( Math.PI * 2 ), Math.PI / 2 ]; + if ( scope.onError !== undefined ) { -const boolsCacheMap = new Map(); -for ( const bool of bools ) boolsCacheMap.set( bool, new ConstNode( bool ) ); + scope.onError( url ); -const uintsCacheMap = new Map(); -for ( const uint of uints ) uintsCacheMap.set( uint, new ConstNode( uint, 'uint' ) ); + } -const intsCacheMap = new Map( [ ...uintsCacheMap ].map( el => new ConstNode( el.value, 'int' ) ) ); -for ( const int of ints ) intsCacheMap.set( int, new ConstNode( int, 'int' ) ); + }; -const floatsCacheMap = new Map( [ ...intsCacheMap ].map( el => new ConstNode( el.value ) ) ); -for ( const float of floats ) floatsCacheMap.set( float, new ConstNode( float ) ); -for ( const float of floats ) floatsCacheMap.set( - float, new ConstNode( - float ) ); + this.resolveURL = function ( url ) { -const cacheMaps = { bool: boolsCacheMap, uint: uintsCacheMap, ints: intsCacheMap, float: floatsCacheMap }; + if ( urlModifier ) { -const constNodesCacheMap = new Map( [ ...boolsCacheMap, ...floatsCacheMap ] ); + return urlModifier( url ); -const getConstNode = ( value, type ) => { + } - if ( constNodesCacheMap.has( value ) ) { + return url; - return constNodesCacheMap.get( value ); + }; - } else if ( value.isNode === true ) { + this.setURLModifier = function ( transform ) { - return value; + urlModifier = transform; - } else { + return this; - return new ConstNode( value, type ); + }; - } + this.addHandler = function ( regex, loader ) { -}; + handlers.push( regex, loader ); -const safeGetNodeType = ( node ) => { + return this; - try { + }; - return node.getNodeType(); + this.removeHandler = function ( regex ) { - } catch ( _ ) { + const index = handlers.indexOf( regex ); - return undefined; + if ( index !== - 1 ) { - } + handlers.splice( index, 2 ); -}; + } -const ConvertType = function ( type, cacheMap = null ) { + return this; - return ( ...params ) => { + }; - if ( params.length === 0 || ( ! [ 'bool', 'float', 'int', 'uint' ].includes( type ) && params.every( param => typeof param !== 'object' ) ) ) { + this.getHandler = function ( file ) { - params = [ getValueFromType( type, ...params ) ]; + for ( let i = 0, l = handlers.length; i < l; i += 2 ) { - } + const regex = handlers[ i ]; + const loader = handlers[ i + 1 ]; - if ( params.length === 1 && cacheMap !== null && cacheMap.has( params[ 0 ] ) ) { + if ( regex.global ) regex.lastIndex = 0; // see #17920 - return nodeObject( cacheMap.get( params[ 0 ] ) ); + if ( regex.test( file ) ) { - } + return loader; - if ( params.length === 1 ) { + } - const node = getConstNode( params[ 0 ], type ); - if ( safeGetNodeType( node ) === type ) return nodeObject( node ); - return nodeObject( new ConvertNode( node, type ) ); + } - } + return null; - const nodes = params.map( param => getConstNode( param ) ); - return nodeObject( new JoinNode( nodes, type ) ); + }; - }; + } -}; +} -// exports +const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager(); -const defined = ( v ) => typeof v === 'object' && v !== null ? v.value : v; // TODO: remove boolean conversion and defined function +class Loader { -// utils + constructor( manager ) { -const getConstNodeType = ( value ) => ( value !== undefined && value !== null ) ? ( value.nodeType || value.convertTo || ( typeof value === 'string' ? value : null ) ) : null; + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; -// shader node base + this.crossOrigin = 'anonymous'; + this.withCredentials = false; + this.path = ''; + this.resourcePath = ''; + this.requestHeader = {}; -function ShaderNode( jsFunc, nodeType ) { + } - return new Proxy( new ShaderNodeInternal( jsFunc, nodeType ), shaderNodeHandler ); + load( /* url, onLoad, onProgress, onError */ ) {} -} + loadAsync( url, onProgress ) { -const nodeObject = ( val, altType = null ) => /* new */ ShaderNodeObject( val, altType ); -const nodeObjects = ( val, altType = null ) => new ShaderNodeObjects( val, altType ); -const nodeArray = ( val, altType = null ) => new ShaderNodeArray( val, altType ); -const nodeProxy = ( ...params ) => new ShaderNodeProxy( ...params ); -const nodeImmutable = ( ...params ) => new ShaderNodeImmutable( ...params ); + const scope = this; -const Fn = ( jsFunc, nodeType ) => { + return new Promise( function ( resolve, reject ) { - const shaderNode = new ShaderNode( jsFunc, nodeType ); + scope.load( url, resolve, onProgress, reject ); - const fn = ( ...params ) => { + } ); - let inputs; + } - nodeObjects( params ); + parse( /* data */ ) {} - if ( params[ 0 ] && params[ 0 ].isNode ) { + setCrossOrigin( crossOrigin ) { - inputs = [ ...params ]; + this.crossOrigin = crossOrigin; + return this; - } else { + } - inputs = params[ 0 ]; + setWithCredentials( value ) { - } + this.withCredentials = value; + return this; - return shaderNode.call( inputs ); + } - }; + setPath( path ) { - fn.shaderNode = shaderNode; + this.path = path; + return this; - fn.setLayout = ( layout ) => { + } - shaderNode.setLayout( layout ); + setResourcePath( resourcePath ) { - return fn; + this.resourcePath = resourcePath; + return this; - }; + } - fn.once = () => { + setRequestHeader( requestHeader ) { - shaderNode.once = true; + this.requestHeader = requestHeader; + return this; - return fn; + } - }; +} - return fn; +Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT'; -}; +const loading = {}; -const tslFn = ( ...params ) => { // @deprecated, r168 +class HttpError extends Error { - console.warn( 'TSL.ShaderNode: tslFn() has been renamed to Fn().' ); - return Fn( ...params ); + constructor( message, response ) { -}; + super( message ); + this.response = response; -// + } -addMethodChaining( 'toGlobal', ( node ) => { +} - node.global = true; +class FileLoader extends Loader { - return node; + constructor( manager ) { -} ); + super( manager ); -// + } -const setCurrentStack = ( stack ) => { + load( url, onLoad, onProgress, onError ) { - currentStack = stack; + if ( url === undefined ) url = ''; -}; + if ( this.path !== undefined ) url = this.path + url; -const getCurrentStack = () => currentStack; + url = this.manager.resolveURL( url ); -const If = ( ...params ) => currentStack.If( ...params ); + const cached = Cache.get( url ); -function append( node ) { + if ( cached !== undefined ) { - if ( currentStack ) currentStack.add( node ); + this.manager.itemStart( url ); - return node; + setTimeout( () => { -} + if ( onLoad ) onLoad( cached ); -addMethodChaining( 'append', append ); + this.manager.itemEnd( url ); -// types + }, 0 ); -const color = new ConvertType( 'color' ); + return cached; -const float = new ConvertType( 'float', cacheMaps.float ); -const int = new ConvertType( 'int', cacheMaps.ints ); -const uint = new ConvertType( 'uint', cacheMaps.uint ); -const bool = new ConvertType( 'bool', cacheMaps.bool ); + } -const vec2 = new ConvertType( 'vec2' ); -const ivec2 = new ConvertType( 'ivec2' ); -const uvec2 = new ConvertType( 'uvec2' ); -const bvec2 = new ConvertType( 'bvec2' ); + // Check if request is duplicate -const vec3 = new ConvertType( 'vec3' ); -const ivec3 = new ConvertType( 'ivec3' ); -const uvec3 = new ConvertType( 'uvec3' ); -const bvec3 = new ConvertType( 'bvec3' ); + if ( loading[ url ] !== undefined ) { -const vec4 = new ConvertType( 'vec4' ); -const ivec4 = new ConvertType( 'ivec4' ); -const uvec4 = new ConvertType( 'uvec4' ); -const bvec4 = new ConvertType( 'bvec4' ); + loading[ url ].push( { -const mat2 = new ConvertType( 'mat2' ); -const mat3 = new ConvertType( 'mat3' ); -const mat4 = new ConvertType( 'mat4' ); + onLoad: onLoad, + onProgress: onProgress, + onError: onError -const string = ( value = '' ) => nodeObject( new ConstNode( value, 'string' ) ); -const arrayBuffer = ( value ) => nodeObject( new ConstNode( value, 'ArrayBuffer' ) ); + } ); -addMethodChaining( 'toColor', color ); -addMethodChaining( 'toFloat', float ); -addMethodChaining( 'toInt', int ); -addMethodChaining( 'toUint', uint ); -addMethodChaining( 'toBool', bool ); -addMethodChaining( 'toVec2', vec2 ); -addMethodChaining( 'toIVec2', ivec2 ); -addMethodChaining( 'toUVec2', uvec2 ); -addMethodChaining( 'toBVec2', bvec2 ); -addMethodChaining( 'toVec3', vec3 ); -addMethodChaining( 'toIVec3', ivec3 ); -addMethodChaining( 'toUVec3', uvec3 ); -addMethodChaining( 'toBVec3', bvec3 ); -addMethodChaining( 'toVec4', vec4 ); -addMethodChaining( 'toIVec4', ivec4 ); -addMethodChaining( 'toUVec4', uvec4 ); -addMethodChaining( 'toBVec4', bvec4 ); -addMethodChaining( 'toMat2', mat2 ); -addMethodChaining( 'toMat3', mat3 ); -addMethodChaining( 'toMat4', mat4 ); + return; -// basic nodes + } -const element = /*@__PURE__*/ nodeProxy( ArrayElementNode ); -const convert = ( node, types ) => nodeObject( new ConvertNode( nodeObject( node ), types ) ); -const split = ( node, channels ) => nodeObject( new SplitNode( nodeObject( node ), channels ) ); + // Initialise array for duplicate requests + loading[ url ] = []; -addMethodChaining( 'element', element ); -addMethodChaining( 'convert', convert ); + loading[ url ].push( { + onLoad: onLoad, + onProgress: onProgress, + onError: onError, + } ); -class UniformGroupNode extends Node { + // create request + const req = new Request( url, { + headers: new Headers( this.requestHeader ), + credentials: this.withCredentials ? 'include' : 'same-origin', + // An abort controller could be added within a future PR + } ); - constructor( name, shared = false ) { + // record states ( avoid data race ) + const mimeType = this.mimeType; + const responseType = this.responseType; - super( 'string' ); + // start the fetch + fetch( req ) + .then( response => { - this.name = name; - this.version = 0; + if ( response.status === 200 || response.status === 0 ) { - this.shared = shared; + // Some browsers return HTTP Status 0 when using non-http protocol + // e.g. 'file://' or 'data://'. Handle as success. - this.isUniformGroup = true; + if ( response.status === 0 ) { - } + console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); - set needsUpdate( value ) { + } - if ( value === true ) this.version ++; + // Workaround: Checking if response.body === undefined for Alipay browser #23548 - } + if ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) { - serialize( data ) { + return response; - super.serialize( data ); + } - data.name = this.name; - data.version = this.version; - data.shared = this.shared; + const callbacks = loading[ url ]; + const reader = response.body.getReader(); - } + // Nginx needs X-File-Size check + // https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content + const contentLength = response.headers.get( 'X-File-Size' ) || response.headers.get( 'Content-Length' ); + const total = contentLength ? parseInt( contentLength ) : 0; + const lengthComputable = total !== 0; + let loaded = 0; - deserialize( data ) { + // periodically read data into the new stream tracking while download progress + const stream = new ReadableStream( { + start( controller ) { - super.deserialize( data ); + readData(); - this.name = data.name; - this.version = data.version; - this.shared = data.shared; + function readData() { - } + reader.read().then( ( { done, value } ) => { -} + if ( done ) { -UniformGroupNode.type = /*@__PURE__*/ registerNode( 'UniformGroup', UniformGroupNode ); + controller.close(); -const uniformGroup = ( name ) => new UniformGroupNode( name ); -const sharedUniformGroup = ( name ) => new UniformGroupNode( name, true ); + } else { -const frameGroup = /*@__PURE__*/ sharedUniformGroup( 'frame' ); -const renderGroup = /*@__PURE__*/ sharedUniformGroup( 'render' ); -const objectGroup = /*@__PURE__*/ uniformGroup( 'object' ); + loaded += value.byteLength; -class UniformNode extends InputNode { + const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } ); + for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - constructor( value, nodeType = null ) { + const callback = callbacks[ i ]; + if ( callback.onProgress ) callback.onProgress( event ); - super( value, nodeType ); + } - this.isUniformNode = true; + controller.enqueue( value ); + readData(); - this.name = ''; - this.groupNode = objectGroup; + } - } + }, ( e ) => { - label( name ) { + controller.error( e ); - this.name = name; + } ); - return this; + } - } + } - setGroup( group ) { + } ); - this.groupNode = group; + return new Response( stream ); - return this; + } else { - } + throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response ); - getGroup() { + } - return this.groupNode; + } ) + .then( response => { - } + switch ( responseType ) { - getUniformHash( builder ) { + case 'arraybuffer': - return this.getHash( builder ); + return response.arrayBuffer(); - } + case 'blob': - onUpdate( callback, updateType ) { + return response.blob(); - const self = this.getSelf(); + case 'document': - callback = callback.bind( self ); + return response.text() + .then( text => { - return super.onUpdate( ( frame ) => { + const parser = new DOMParser(); + return parser.parseFromString( text, mimeType ); - const value = callback( frame, self ); + } ); - if ( value !== undefined ) { + case 'json': - this.value = value; + return response.json(); - } + default: - }, updateType ); + if ( mimeType === undefined ) { - } + return response.text(); - generate( builder, output ) { + } else { - const type = this.getNodeType( builder ); + // sniff encoding + const re = /charset="?([^;"\s]*)"?/i; + const exec = re.exec( mimeType ); + const label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined; + const decoder = new TextDecoder( label ); + return response.arrayBuffer().then( ab => decoder.decode( ab ) ); - const hash = this.getUniformHash( builder ); + } - let sharedNode = builder.getNodeFromHash( hash ); + } - if ( sharedNode === undefined ) { + } ) + .then( data => { - builder.setHashNode( this, hash ); + // Add to cache only on HTTP success, so that we do not cache + // error response bodies as proper responses to requests. + Cache.add( url, data ); - sharedNode = this; + const callbacks = loading[ url ]; + delete loading[ url ]; - } + for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - const sharedNodeType = sharedNode.getInputType( builder ); + const callback = callbacks[ i ]; + if ( callback.onLoad ) callback.onLoad( data ); - const nodeUniform = builder.getUniformFromNode( sharedNode, sharedNodeType, builder.shaderStage, this.name || builder.context.label ); - const propertyName = builder.getPropertyName( nodeUniform ); + } - if ( builder.context.label !== undefined ) delete builder.context.label; + } ) + .catch( err => { - return builder.format( propertyName, type, output ); + // Abort errors and other errors are handled the same - } + const callbacks = loading[ url ]; -} + if ( callbacks === undefined ) { -UniformNode.type = /*@__PURE__*/ registerNode( 'Uniform', UniformNode ); + // When onLoad was called and url was deleted in `loading` + this.manager.itemError( url ); + throw err; -const uniform = ( arg1, arg2 ) => { + } - const nodeType = getConstNodeType( arg2 || arg1 ); + delete loading[ url ]; - // @TODO: get ConstNode from .traverse() in the future - const value = ( arg1 && arg1.isNode === true ) ? ( arg1.node && arg1.node.value ) || arg1.value : arg1; + for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - return nodeObject( new UniformNode( value, nodeType ) ); + const callback = callbacks[ i ]; + if ( callback.onError ) callback.onError( err ); -}; + } -class PropertyNode extends Node { + this.manager.itemError( url ); - constructor( nodeType, name = null, varying = false ) { + } ) + .finally( () => { - super( nodeType ); + this.manager.itemEnd( url ); - this.name = name; - this.varying = varying; + } ); - this.isPropertyNode = true; + this.manager.itemStart( url ); } - getHash( builder ) { + setResponseType( value ) { - return this.name || super.getHash( builder ); + this.responseType = value; + return this; } - isGlobal( /*builder*/ ) { + setMimeType( value ) { - return true; + this.mimeType = value; + return this; } - generate( builder ) { - - let nodeVar; - - if ( this.varying === true ) { - - nodeVar = builder.getVaryingFromNode( this, this.name ); - nodeVar.needsInterpolation = true; - - } else { +} - nodeVar = builder.getVarFromNode( this, this.name ); +class AnimationLoader extends Loader { - } + constructor( manager ) { - return builder.getPropertyName( nodeVar ); + super( manager ); } -} + load( url, onLoad, onProgress, onError ) { -PropertyNode.type = /*@__PURE__*/ registerNode( 'Property', PropertyNode ); + const scope = this; -const property = ( type, name ) => nodeObject( new PropertyNode( type, name ) ); -const varyingProperty = ( type, name ) => nodeObject( new PropertyNode( type, name, true ) ); + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( text ) { -const diffuseColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec4', 'DiffuseColor' ); -const emissive = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'EmissiveColor' ); -const roughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Roughness' ); -const metalness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Metalness' ); -const clearcoat = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Clearcoat' ); -const clearcoatRoughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'ClearcoatRoughness' ); -const sheen = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'Sheen' ); -const sheenRoughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'SheenRoughness' ); -const iridescence = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Iridescence' ); -const iridescenceIOR = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IridescenceIOR' ); -const iridescenceThickness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IridescenceThickness' ); -const alphaT = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'AlphaT' ); -const anisotropy = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Anisotropy' ); -const anisotropyT = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'AnisotropyT' ); -const anisotropyB = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'AnisotropyB' ); -const specularColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'color', 'SpecularColor' ); -const specularF90 = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'SpecularF90' ); -const shininess = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Shininess' ); -const output = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec4', 'Output' ); -const dashSize = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'dashSize' ); -const gapSize = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'gapSize' ); -const pointWidth = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'pointWidth' ); -const ior = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IOR' ); -const transmission = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Transmission' ); -const thickness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Thickness' ); -const attenuationDistance = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'AttenuationDistance' ); -const attenuationColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'color', 'AttenuationColor' ); -const dispersion = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Dispersion' ); + try { -class AssignNode extends TempNode { + onLoad( scope.parse( JSON.parse( text ) ) ); - constructor( targetNode, sourceNode ) { + } catch ( e ) { - super(); + if ( onError ) { - this.targetNode = targetNode; - this.sourceNode = sourceNode; + onError( e ); - } + } else { - hasDependencies() { + console.error( e ); - return false; + } - } + scope.manager.itemError( url ); - getNodeType( builder, output ) { + } - return output !== 'void' ? this.targetNode.getNodeType( builder ) : 'void'; + }, onProgress, onError ); } - needsSplitAssign( builder ) { + parse( json ) { - const { targetNode } = this; + const animations = []; - if ( builder.isAvailable( 'swizzleAssign' ) === false && targetNode.isSplitNode && targetNode.components.length > 1 ) { + for ( let i = 0; i < json.length; i ++ ) { - const targetLength = builder.getTypeLength( targetNode.node.getNodeType( builder ) ); - const assignDiferentVector = vectorComponents.join( '' ).slice( 0, targetLength ) !== targetNode.components; + const clip = AnimationClip.parse( json[ i ] ); - return assignDiferentVector; + animations.push( clip ); } - return false; + return animations; } - generate( builder, output ) { - - const { targetNode, sourceNode } = this; - - const needsSplitAssign = this.needsSplitAssign( builder ); +} - const targetType = targetNode.getNodeType( builder ); +/** + * Abstract Base class to block based textures loader (dds, pvr, ...) + * + * Sub classes have to implement the parse() method which will be used in load(). + */ - const target = targetNode.context( { assign: true } ).build( builder ); - const source = sourceNode.build( builder, targetType ); +class CompressedTextureLoader extends Loader { - const sourceType = sourceNode.getNodeType( builder ); + constructor( manager ) { - const nodeData = builder.getDataFromNode( this ); + super( manager ); - // + } - let snippet; + load( url, onLoad, onProgress, onError ) { - if ( nodeData.initialized === true ) { + const scope = this; - if ( output !== 'void' ) { + const images = []; - snippet = target; + const texture = new CompressedTexture(); - } + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setResponseType( 'arraybuffer' ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( scope.withCredentials ); - } else if ( needsSplitAssign ) { + let loaded = 0; - const sourceVar = builder.getVarFromNode( this, null, targetType ); - const sourceProperty = builder.getPropertyName( sourceVar ); + function loadTexture( i ) { - builder.addLineFlowCode( `${ sourceProperty } = ${ source }` ); + loader.load( url[ i ], function ( buffer ) { - const targetRoot = targetNode.node.context( { assign: true } ).build( builder ); + const texDatas = scope.parse( buffer, true ); - for ( let i = 0; i < targetNode.components.length; i ++ ) { + images[ i ] = { + width: texDatas.width, + height: texDatas.height, + format: texDatas.format, + mipmaps: texDatas.mipmaps + }; - const component = targetNode.components[ i ]; + loaded += 1; - builder.addLineFlowCode( `${ targetRoot }.${ component } = ${ sourceProperty }[ ${ i } ]` ); + if ( loaded === 6 ) { - } + if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter; - if ( output !== 'void' ) { + texture.image = images; + texture.format = texDatas.format; + texture.needsUpdate = true; - snippet = target; + if ( onLoad ) onLoad( texture ); - } + } - } else { + }, onProgress, onError ); - snippet = `${ target } = ${ source }`; + } - if ( output === 'void' || sourceType === 'void' ) { + if ( Array.isArray( url ) ) { - builder.addLineFlowCode( snippet ); + for ( let i = 0, il = url.length; i < il; ++ i ) { - if ( output !== 'void' ) { + loadTexture( i ); - snippet = target; + } - } + } else { - } + // compressed cubemap texture stored in a single DDS file - } + loader.load( url, function ( buffer ) { - nodeData.initialized = true; + const texDatas = scope.parse( buffer, true ); - return builder.format( snippet, targetType, output ); + if ( texDatas.isCubemap ) { - } + const faces = texDatas.mipmaps.length / texDatas.mipmapCount; -} + for ( let f = 0; f < faces; f ++ ) { -AssignNode.type = /*@__PURE__*/ registerNode( 'Assign', AssignNode ); + images[ f ] = { mipmaps: [] }; -const assign = /*@__PURE__*/ nodeProxy( AssignNode ); + for ( let i = 0; i < texDatas.mipmapCount; i ++ ) { -addMethodChaining( 'assign', assign ); + images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); + images[ f ].format = texDatas.format; + images[ f ].width = texDatas.width; + images[ f ].height = texDatas.height; -class FunctionCallNode extends TempNode { + } - constructor( functionNode = null, parameters = {} ) { + } - super(); + texture.image = images; - this.functionNode = functionNode; - this.parameters = parameters; + } else { - } + texture.image.width = texDatas.width; + texture.image.height = texDatas.height; + texture.mipmaps = texDatas.mipmaps; - setParameters( parameters ) { + } - this.parameters = parameters; + if ( texDatas.mipmapCount === 1 ) { - return this; + texture.minFilter = LinearFilter; - } + } - getParameters() { + texture.format = texDatas.format; + texture.needsUpdate = true; - return this.parameters; + if ( onLoad ) onLoad( texture ); - } + }, onProgress, onError ); - getNodeType( builder ) { + } - return this.functionNode.getNodeType( builder ); + return texture; } - generate( builder ) { - - const params = []; +} - const functionNode = this.functionNode; +class ImageLoader extends Loader { - const inputs = functionNode.getInputs( builder ); - const parameters = this.parameters; + constructor( manager ) { - if ( Array.isArray( parameters ) ) { + super( manager ); - for ( let i = 0; i < parameters.length; i ++ ) { + } - const inputNode = inputs[ i ]; - const node = parameters[ i ]; + load( url, onLoad, onProgress, onError ) { - params.push( node.build( builder, inputNode.type ) ); + if ( this.path !== undefined ) url = this.path + url; - } + url = this.manager.resolveURL( url ); - } else { + const scope = this; - for ( const inputNode of inputs ) { + const cached = Cache.get( url ); - const node = parameters[ inputNode.name ]; + if ( cached !== undefined ) { - if ( node !== undefined ) { + scope.manager.itemStart( url ); - params.push( node.build( builder, inputNode.type ) ); + setTimeout( function () { - } else { + if ( onLoad ) onLoad( cached ); - throw new Error( `FunctionCallNode: Input '${inputNode.name}' not found in FunctionNode.` ); + scope.manager.itemEnd( url ); - } + }, 0 ); - } + return cached; } - const functionName = functionNode.build( builder, 'property' ); - - return `${functionName}( ${params.join( ', ' )} )`; + const image = createElementNS( 'img' ); - } + function onImageLoad() { -} + removeEventListeners(); -FunctionCallNode.type = /*@__PURE__*/ registerNode( 'FunctionCall', FunctionCallNode ); + Cache.add( url, this ); -const call = ( func, ...params ) => { + if ( onLoad ) onLoad( this ); - params = params.length > 1 || ( params[ 0 ] && params[ 0 ].isNode === true ) ? nodeArray( params ) : nodeObjects( params[ 0 ] ); + scope.manager.itemEnd( url ); - return nodeObject( new FunctionCallNode( nodeObject( func ), params ) ); + } -}; + function onImageError( event ) { -addMethodChaining( 'call', call ); + removeEventListeners(); -class OperatorNode extends TempNode { + if ( onError ) onError( event ); - constructor( op, aNode, bNode, ...params ) { + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - super(); + } - if ( params.length > 0 ) { + function removeEventListeners() { - let finalOp = new OperatorNode( op, aNode, bNode ); + image.removeEventListener( 'load', onImageLoad, false ); + image.removeEventListener( 'error', onImageError, false ); - for ( let i = 0; i < params.length - 1; i ++ ) { + } - finalOp = new OperatorNode( op, finalOp, params[ i ] ); + image.addEventListener( 'load', onImageLoad, false ); + image.addEventListener( 'error', onImageError, false ); - } + if ( url.slice( 0, 5 ) !== 'data:' ) { - aNode = finalOp; - bNode = params[ params.length - 1 ]; + if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; } - this.op = op; - this.aNode = aNode; - this.bNode = bNode; + scope.manager.itemStart( url ); - } + image.src = url; - getNodeType( builder, output ) { + return image; - const op = this.op; + } - const aNode = this.aNode; - const bNode = this.bNode; +} - const typeA = aNode.getNodeType( builder ); - const typeB = typeof bNode !== 'undefined' ? bNode.getNodeType( builder ) : null; +class CubeTextureLoader extends Loader { - if ( typeA === 'void' || typeB === 'void' ) { + constructor( manager ) { - return 'void'; + super( manager ); - } else if ( op === '%' ) { + } - return typeA; + load( urls, onLoad, onProgress, onError ) { - } else if ( op === '~' || op === '&' || op === '|' || op === '^' || op === '>>' || op === '<<' ) { + const texture = new CubeTexture(); + texture.colorSpace = SRGBColorSpace; - return builder.getIntegerType( typeA ); + const loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setPath( this.path ); - } else if ( op === '!' || op === '==' || op === '&&' || op === '||' || op === '^^' ) { + let loaded = 0; - return 'bool'; + function loadTexture( i ) { - } else if ( op === '<' || op === '>' || op === '<=' || op === '>=' ) { + loader.load( urls[ i ], function ( image ) { - const typeLength = output ? builder.getTypeLength( output ) : Math.max( builder.getTypeLength( typeA ), builder.getTypeLength( typeB ) ); + texture.images[ i ] = image; - return typeLength > 1 ? `bvec${ typeLength }` : 'bool'; + loaded ++; - } else { + if ( loaded === 6 ) { - if ( typeA === 'float' && builder.isMatrix( typeB ) ) { + texture.needsUpdate = true; - return typeB; + if ( onLoad ) onLoad( texture ); - } else if ( builder.isMatrix( typeA ) && builder.isVector( typeB ) ) { + } - // matrix x vector + }, undefined, onError ); - return builder.getVectorFromMatrix( typeA ); + } - } else if ( builder.isVector( typeA ) && builder.isMatrix( typeB ) ) { + for ( let i = 0; i < urls.length; ++ i ) { - // vector x matrix + loadTexture( i ); - return builder.getVectorFromMatrix( typeB ); + } - } else if ( builder.getTypeLength( typeB ) > builder.getTypeLength( typeA ) ) { + return texture; - // anytype x anytype: use the greater length vector + } - return typeB; +} - } +/** + * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) + * + * Sub classes have to implement the parse() method which will be used in load(). + */ - return typeA; +class DataTextureLoader extends Loader { - } + constructor( manager ) { + + super( manager ); } - generate( builder, output ) { + load( url, onLoad, onProgress, onError ) { - const op = this.op; + const scope = this; - const aNode = this.aNode; - const bNode = this.bNode; + const texture = new DataTexture(); - const type = this.getNodeType( builder, output ); + const loader = new FileLoader( this.manager ); + loader.setResponseType( 'arraybuffer' ); + loader.setRequestHeader( this.requestHeader ); + loader.setPath( this.path ); + loader.setWithCredentials( scope.withCredentials ); + loader.load( url, function ( buffer ) { - let typeA = null; - let typeB = null; + let texData; - if ( type !== 'void' ) { + try { - typeA = aNode.getNodeType( builder ); - typeB = typeof bNode !== 'undefined' ? bNode.getNodeType( builder ) : null; + texData = scope.parse( buffer ); - if ( op === '<' || op === '>' || op === '<=' || op === '>=' || op === '==' ) { + } catch ( error ) { - if ( builder.isVector( typeA ) ) { + if ( onError !== undefined ) { - typeB = typeA; + onError( error ); - } else if ( typeA !== typeB ) { + } else { - typeA = typeB = 'float'; + console.error( error ); + return; } - } else if ( op === '>>' || op === '<<' ) { + } - typeA = type; - typeB = builder.changeComponentType( typeB, 'uint' ); + if ( texData.image !== undefined ) { - } else if ( builder.isMatrix( typeA ) && builder.isVector( typeB ) ) { + texture.image = texData.image; - // matrix x vector + } else if ( texData.data !== undefined ) { - typeB = builder.getVectorFromMatrix( typeA ); + texture.image.width = texData.width; + texture.image.height = texData.height; + texture.image.data = texData.data; - } else if ( builder.isVector( typeA ) && builder.isMatrix( typeB ) ) { + } - // vector x matrix + texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; + texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; - typeA = builder.getVectorFromMatrix( typeB ); + texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; + texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter; - } else { + texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; - // anytype x anytype + if ( texData.colorSpace !== undefined ) { - typeA = typeB = type; + texture.colorSpace = texData.colorSpace; } - } else { + if ( texData.flipY !== undefined ) { - typeA = typeB = type; + texture.flipY = texData.flipY; - } + } - const a = aNode.build( builder, typeA ); - const b = typeof bNode !== 'undefined' ? bNode.build( builder, typeB ) : null; + if ( texData.format !== undefined ) { - const outputLength = builder.getTypeLength( output ); - const fnOpSnippet = builder.getFunctionOperator( op ); + texture.format = texData.format; - if ( output !== 'void' ) { + } - if ( op === '<' && outputLength > 1 ) { + if ( texData.type !== undefined ) { - if ( builder.useComparisonMethod ) { + texture.type = texData.type; - return builder.format( `${ builder.getMethod( 'lessThan', output ) }( ${ a }, ${ b } )`, type, output ); + } - } else { + if ( texData.mipmaps !== undefined ) { - return builder.format( `( ${ a } < ${ b } )`, type, output ); + texture.mipmaps = texData.mipmaps; + texture.minFilter = LinearMipmapLinearFilter; // presumably... - } + } - } else if ( op === '<=' && outputLength > 1 ) { + if ( texData.mipmapCount === 1 ) { - if ( builder.useComparisonMethod ) { + texture.minFilter = LinearFilter; - return builder.format( `${ builder.getMethod( 'lessThanEqual', output ) }( ${ a }, ${ b } )`, type, output ); + } - } else { + if ( texData.generateMipmaps !== undefined ) { - return builder.format( `( ${ a } <= ${ b } )`, type, output ); + texture.generateMipmaps = texData.generateMipmaps; - } + } - } else if ( op === '>' && outputLength > 1 ) { + texture.needsUpdate = true; - if ( builder.useComparisonMethod ) { + if ( onLoad ) onLoad( texture, texData ); - return builder.format( `${ builder.getMethod( 'greaterThan', output ) }( ${ a }, ${ b } )`, type, output ); + }, onProgress, onError ); - } else { - return builder.format( `( ${ a } > ${ b } )`, type, output ); + return texture; - } + } - } else if ( op === '>=' && outputLength > 1 ) { +} - if ( builder.useComparisonMethod ) { +class TextureLoader extends Loader { - return builder.format( `${ builder.getMethod( 'greaterThanEqual', output ) }( ${ a }, ${ b } )`, type, output ); + constructor( manager ) { - } else { + super( manager ); - return builder.format( `( ${ a } >= ${ b } )`, type, output ); + } - } + load( url, onLoad, onProgress, onError ) { - } else if ( op === '!' || op === '~' ) { + const texture = new Texture(); - return builder.format( `(${op}${a})`, typeA, output ); + const loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setPath( this.path ); - } else if ( fnOpSnippet ) { + loader.load( url, function ( image ) { - return builder.format( `${ fnOpSnippet }( ${ a }, ${ b } )`, type, output ); + texture.image = image; + texture.needsUpdate = true; - } else { + if ( onLoad !== undefined ) { - return builder.format( `( ${ a } ${ op } ${ b } )`, type, output ); + onLoad( texture ); } - } else if ( typeA !== 'void' ) { + }, onProgress, onError ); - if ( fnOpSnippet ) { + return texture; - return builder.format( `${ fnOpSnippet }( ${ a }, ${ b } )`, type, output ); + } - } else { +} - return builder.format( `${ a } ${ op } ${ b }`, type, output ); +class Light extends Object3D { - } + constructor( color, intensity = 1 ) { - } + super(); - } + this.isLight = true; - serialize( data ) { + this.type = 'Light'; - super.serialize( data ); - - data.op = this.op; + this.color = new Color( color ); + this.intensity = intensity; } - deserialize( data ) { - - super.deserialize( data ); + dispose() { - this.op = data.op; + // Empty here in base class; some subclasses override. } -} + copy( source, recursive ) { -OperatorNode.type = /*@__PURE__*/ registerNode( 'Operator', OperatorNode ); + super.copy( source, recursive ); -const add = /*@__PURE__*/ nodeProxy( OperatorNode, '+' ); -const sub = /*@__PURE__*/ nodeProxy( OperatorNode, '-' ); -const mul = /*@__PURE__*/ nodeProxy( OperatorNode, '*' ); -const div = /*@__PURE__*/ nodeProxy( OperatorNode, '/' ); -const modInt = /*@__PURE__*/ nodeProxy( OperatorNode, '%' ); -const equal = /*@__PURE__*/ nodeProxy( OperatorNode, '==' ); -const notEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '!=' ); -const lessThan = /*@__PURE__*/ nodeProxy( OperatorNode, '<' ); -const greaterThan = /*@__PURE__*/ nodeProxy( OperatorNode, '>' ); -const lessThanEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '<=' ); -const greaterThanEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '>=' ); -const and = /*@__PURE__*/ nodeProxy( OperatorNode, '&&' ); -const or = /*@__PURE__*/ nodeProxy( OperatorNode, '||' ); -const not = /*@__PURE__*/ nodeProxy( OperatorNode, '!' ); -const xor = /*@__PURE__*/ nodeProxy( OperatorNode, '^^' ); -const bitAnd = /*@__PURE__*/ nodeProxy( OperatorNode, '&' ); -const bitNot = /*@__PURE__*/ nodeProxy( OperatorNode, '~' ); -const bitOr = /*@__PURE__*/ nodeProxy( OperatorNode, '|' ); -const bitXor = /*@__PURE__*/ nodeProxy( OperatorNode, '^' ); -const shiftLeft = /*@__PURE__*/ nodeProxy( OperatorNode, '<<' ); -const shiftRight = /*@__PURE__*/ nodeProxy( OperatorNode, '>>' ); + this.color.copy( source.color ); + this.intensity = source.intensity; -addMethodChaining( 'add', add ); -addMethodChaining( 'sub', sub ); -addMethodChaining( 'mul', mul ); -addMethodChaining( 'div', div ); -addMethodChaining( 'modInt', modInt ); -addMethodChaining( 'equal', equal ); -addMethodChaining( 'notEqual', notEqual ); -addMethodChaining( 'lessThan', lessThan ); -addMethodChaining( 'greaterThan', greaterThan ); -addMethodChaining( 'lessThanEqual', lessThanEqual ); -addMethodChaining( 'greaterThanEqual', greaterThanEqual ); -addMethodChaining( 'and', and ); -addMethodChaining( 'or', or ); -addMethodChaining( 'not', not ); -addMethodChaining( 'xor', xor ); -addMethodChaining( 'bitAnd', bitAnd ); -addMethodChaining( 'bitNot', bitNot ); -addMethodChaining( 'bitOr', bitOr ); -addMethodChaining( 'bitXor', bitXor ); -addMethodChaining( 'shiftLeft', shiftLeft ); -addMethodChaining( 'shiftRight', shiftRight ); + return this; + } -const remainder = ( ...params ) => { // @deprecated, r168 + toJSON( meta ) { - console.warn( 'TSL.OperatorNode: .remainder() has been renamed to .modInt().' ); - return modInt( ...params ); + const data = super.toJSON( meta ); -}; + data.object.color = this.color.getHex(); + data.object.intensity = this.intensity; -addMethodChaining( 'remainder', remainder ); + if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); -class MathNode extends TempNode { + if ( this.distance !== undefined ) data.object.distance = this.distance; + if ( this.angle !== undefined ) data.object.angle = this.angle; + if ( this.decay !== undefined ) data.object.decay = this.decay; + if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; - constructor( method, aNode, bNode = null, cNode = null ) { + if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); + if ( this.target !== undefined ) data.object.target = this.target.uuid; - super(); + return data; - this.method = method; + } - this.aNode = aNode; - this.bNode = bNode; - this.cNode = cNode; +} - } +class HemisphereLight extends Light { - getInputType( builder ) { + constructor( skyColor, groundColor, intensity ) { - const aType = this.aNode.getNodeType( builder ); - const bType = this.bNode ? this.bNode.getNodeType( builder ) : null; - const cType = this.cNode ? this.cNode.getNodeType( builder ) : null; + super( skyColor, intensity ); - const aLen = builder.isMatrix( aType ) ? 0 : builder.getTypeLength( aType ); - const bLen = builder.isMatrix( bType ) ? 0 : builder.getTypeLength( bType ); - const cLen = builder.isMatrix( cType ) ? 0 : builder.getTypeLength( cType ); + this.isHemisphereLight = true; - if ( aLen > bLen && aLen > cLen ) { + this.type = 'HemisphereLight'; - return aType; + this.position.copy( Object3D.DEFAULT_UP ); + this.updateMatrix(); - } else if ( bLen > cLen ) { + this.groundColor = new Color( groundColor ); - return bType; + } - } else if ( cLen > aLen ) { + copy( source, recursive ) { - return cType; + super.copy( source, recursive ); - } + this.groundColor.copy( source.groundColor ); - return aType; + return this; } - getNodeType( builder ) { +} - const method = this.method; +const _projScreenMatrix$2 = /*@__PURE__*/ new Matrix4(); +const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3(); +const _lookTarget$1 = /*@__PURE__*/ new Vector3(); - if ( method === MathNode.LENGTH || method === MathNode.DISTANCE || method === MathNode.DOT ) { +class LightShadow { - return 'float'; + constructor( camera ) { - } else if ( method === MathNode.CROSS ) { + this.camera = camera; - return 'vec3'; + this.intensity = 1; - } else if ( method === MathNode.ALL ) { + this.bias = 0; + this.normalBias = 0; + this.radius = 1; + this.blurSamples = 8; - return 'bool'; + this.mapSize = new Vector2( 512, 512 ); - } else if ( method === MathNode.EQUALS ) { + this.map = null; + this.mapPass = null; + this.matrix = new Matrix4(); - return builder.changeComponentType( this.aNode.getNodeType( builder ), 'bool' ); + this.autoUpdate = true; + this.needsUpdate = false; - } else if ( method === MathNode.MOD ) { + this._frustum = new Frustum(); + this._frameExtents = new Vector2( 1, 1 ); - return this.aNode.getNodeType( builder ); + this._viewportCount = 1; - } else { + this._viewports = [ - return this.getInputType( builder ); + new Vector4( 0, 0, 1, 1 ) - } + ]; } - generate( builder, output ) { - - const method = this.method; + getViewportCount() { - const type = this.getNodeType( builder ); - const inputType = this.getInputType( builder ); + return this._viewportCount; - const a = this.aNode; - const b = this.bNode; - const c = this.cNode; + } - const isWebGL = builder.renderer.isWebGLRenderer === true; + getFrustum() { - if ( method === MathNode.TRANSFORM_DIRECTION ) { + return this._frustum; - // dir can be either a direction vector or a normal vector - // upper-left 3x3 of matrix is assumed to be orthogonal + } - let tA = a; - let tB = b; + updateMatrices( light ) { - if ( builder.isMatrix( tA.getNodeType( builder ) ) ) { + const shadowCamera = this.camera; + const shadowMatrix = this.matrix; - tB = vec4( vec3( tB ), 0.0 ); + _lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld ); + shadowCamera.position.copy( _lightPositionWorld$1 ); - } else { + _lookTarget$1.setFromMatrixPosition( light.target.matrixWorld ); + shadowCamera.lookAt( _lookTarget$1 ); + shadowCamera.updateMatrixWorld(); - tA = vec4( vec3( tA ), 0.0 ); + _projScreenMatrix$2.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); + this._frustum.setFromProjectionMatrix( _projScreenMatrix$2 ); - } + shadowMatrix.set( + 0.5, 0.0, 0.0, 0.5, + 0.0, 0.5, 0.0, 0.5, + 0.0, 0.0, 0.5, 0.5, + 0.0, 0.0, 0.0, 1.0 + ); - const mulNode = mul( tA, tB ).xyz; + shadowMatrix.multiply( _projScreenMatrix$2 ); - return normalize( mulNode ).build( builder, output ); + } - } else if ( method === MathNode.NEGATE ) { + getViewport( viewportIndex ) { - return builder.format( '( - ' + a.build( builder, inputType ) + ' )', type, output ); + return this._viewports[ viewportIndex ]; - } else if ( method === MathNode.ONE_MINUS ) { + } - return sub( 1.0, a ).build( builder, output ); + getFrameExtents() { - } else if ( method === MathNode.RECIPROCAL ) { + return this._frameExtents; - return div( 1.0, a ).build( builder, output ); + } - } else if ( method === MathNode.DIFFERENCE ) { + dispose() { - return abs( sub( a, b ) ).build( builder, output ); + if ( this.map ) { - } else { + this.map.dispose(); - const params = []; + } - if ( method === MathNode.CROSS || method === MathNode.MOD ) { + if ( this.mapPass ) { - params.push( - a.build( builder, type ), - b.build( builder, type ) - ); + this.mapPass.dispose(); - } else if ( isWebGL && method === MathNode.STEP ) { + } - params.push( - a.build( builder, builder.getTypeLength( a.getNodeType( builder ) ) === 1 ? 'float' : inputType ), - b.build( builder, inputType ) - ); + } - } else if ( ( isWebGL && ( method === MathNode.MIN || method === MathNode.MAX ) ) || method === MathNode.MOD ) { + copy( source ) { - params.push( - a.build( builder, inputType ), - b.build( builder, builder.getTypeLength( b.getNodeType( builder ) ) === 1 ? 'float' : inputType ) - ); + this.camera = source.camera.clone(); - } else if ( method === MathNode.REFRACT ) { + this.intensity = source.intensity; - params.push( - a.build( builder, inputType ), - b.build( builder, inputType ), - c.build( builder, 'float' ) - ); + this.bias = source.bias; + this.radius = source.radius; - } else if ( method === MathNode.MIX ) { + this.mapSize.copy( source.mapSize ); - params.push( - a.build( builder, inputType ), - b.build( builder, inputType ), - c.build( builder, builder.getTypeLength( c.getNodeType( builder ) ) === 1 ? 'float' : inputType ) - ); + return this; - } else { + } - params.push( a.build( builder, inputType ) ); - if ( b !== null ) params.push( b.build( builder, inputType ) ); - if ( c !== null ) params.push( c.build( builder, inputType ) ); + clone() { - } + return new this.constructor().copy( this ); - return builder.format( `${ builder.getMethod( method, type ) }( ${params.join( ', ' )} )`, type, output ); + } - } + toJSON() { - } + const object = {}; - serialize( data ) { + if ( this.intensity !== 1 ) object.intensity = this.intensity; + if ( this.bias !== 0 ) object.bias = this.bias; + if ( this.normalBias !== 0 ) object.normalBias = this.normalBias; + if ( this.radius !== 1 ) object.radius = this.radius; + if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); - super.serialize( data ); + object.camera = this.camera.toJSON( false ).object; + delete object.camera.matrix; - data.method = this.method; + return object; } - deserialize( data ) { +} - super.deserialize( data ); +class SpotLightShadow extends LightShadow { - this.method = data.method; + constructor() { - } + super( new PerspectiveCamera( 50, 1, 0.5, 500 ) ); -} + this.isSpotLightShadow = true; -// 1 input + this.focus = 1; -MathNode.ALL = 'all'; -MathNode.ANY = 'any'; -MathNode.EQUALS = 'equals'; + } -MathNode.RADIANS = 'radians'; -MathNode.DEGREES = 'degrees'; -MathNode.EXP = 'exp'; -MathNode.EXP2 = 'exp2'; -MathNode.LOG = 'log'; -MathNode.LOG2 = 'log2'; -MathNode.SQRT = 'sqrt'; -MathNode.INVERSE_SQRT = 'inversesqrt'; -MathNode.FLOOR = 'floor'; -MathNode.CEIL = 'ceil'; -MathNode.NORMALIZE = 'normalize'; -MathNode.FRACT = 'fract'; -MathNode.SIN = 'sin'; -MathNode.COS = 'cos'; -MathNode.TAN = 'tan'; -MathNode.ASIN = 'asin'; -MathNode.ACOS = 'acos'; -MathNode.ATAN = 'atan'; -MathNode.ABS = 'abs'; -MathNode.SIGN = 'sign'; -MathNode.LENGTH = 'length'; -MathNode.NEGATE = 'negate'; -MathNode.ONE_MINUS = 'oneMinus'; -MathNode.DFDX = 'dFdx'; -MathNode.DFDY = 'dFdy'; -MathNode.ROUND = 'round'; -MathNode.RECIPROCAL = 'reciprocal'; -MathNode.TRUNC = 'trunc'; -MathNode.FWIDTH = 'fwidth'; -MathNode.BITCAST = 'bitcast'; -MathNode.TRANSPOSE = 'transpose'; + updateMatrices( light ) { -// 2 inputs + const camera = this.camera; -MathNode.ATAN2 = 'atan2'; -MathNode.MIN = 'min'; -MathNode.MAX = 'max'; -MathNode.MOD = 'mod'; -MathNode.STEP = 'step'; -MathNode.REFLECT = 'reflect'; -MathNode.DISTANCE = 'distance'; -MathNode.DIFFERENCE = 'difference'; -MathNode.DOT = 'dot'; -MathNode.CROSS = 'cross'; -MathNode.POW = 'pow'; -MathNode.TRANSFORM_DIRECTION = 'transformDirection'; + const fov = RAD2DEG * 2 * light.angle * this.focus; + const aspect = this.mapSize.width / this.mapSize.height; + const far = light.distance || camera.far; -// 3 inputs + if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { -MathNode.MIX = 'mix'; -MathNode.CLAMP = 'clamp'; -MathNode.REFRACT = 'refract'; -MathNode.SMOOTHSTEP = 'smoothstep'; -MathNode.FACEFORWARD = 'faceforward'; + camera.fov = fov; + camera.aspect = aspect; + camera.far = far; + camera.updateProjectionMatrix(); -MathNode.type = /*@__PURE__*/ registerNode( 'Math', MathNode ); + } -const EPSILON = /*@__PURE__*/ float( 1e-6 ); -const INFINITY = /*@__PURE__*/ float( 1e6 ); -const PI = /*@__PURE__*/ float( Math.PI ); -const PI2 = /*@__PURE__*/ float( Math.PI * 2 ); + super.updateMatrices( light ); -const all = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ALL ); -const any = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ANY ); -const equals = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EQUALS ); + } -const radians = /*@__PURE__*/ nodeProxy( MathNode, MathNode.RADIANS ); -const degrees = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DEGREES ); -const exp = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EXP ); -const exp2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EXP2 ); -const log = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LOG ); -const log2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LOG2 ); -const sqrt = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SQRT ); -const inverseSqrt = /*@__PURE__*/ nodeProxy( MathNode, MathNode.INVERSE_SQRT ); -const floor = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FLOOR ); -const ceil = /*@__PURE__*/ nodeProxy( MathNode, MathNode.CEIL ); -const normalize = /*@__PURE__*/ nodeProxy( MathNode, MathNode.NORMALIZE ); -const fract = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FRACT ); -const sin = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SIN ); -const cos = /*@__PURE__*/ nodeProxy( MathNode, MathNode.COS ); -const tan = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TAN ); -const asin = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ASIN ); -const acos = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ACOS ); -const atan = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ATAN ); -const abs = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ABS ); -const sign = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SIGN ); -const length = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LENGTH ); -const negate = /*@__PURE__*/ nodeProxy( MathNode, MathNode.NEGATE ); -const oneMinus = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ONE_MINUS ); -const dFdx = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DFDX ); -const dFdy = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DFDY ); -const round = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ROUND ); -const reciprocal = /*@__PURE__*/ nodeProxy( MathNode, MathNode.RECIPROCAL ); -const trunc = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRUNC ); -const fwidth = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FWIDTH ); -const bitcast = /*@__PURE__*/ nodeProxy( MathNode, MathNode.BITCAST ); -const transpose = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRANSPOSE ); + copy( source ) { -const atan2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ATAN2 ); -const min$1 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MIN ); -const max$1 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MAX ); -const mod = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MOD ); -const step = /*@__PURE__*/ nodeProxy( MathNode, MathNode.STEP ); -const reflect = /*@__PURE__*/ nodeProxy( MathNode, MathNode.REFLECT ); -const distance = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DISTANCE ); -const difference = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DIFFERENCE ); -const dot = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DOT ); -const cross = /*@__PURE__*/ nodeProxy( MathNode, MathNode.CROSS ); -const pow = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW ); -const pow2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 2 ); -const pow3 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 3 ); -const pow4 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 4 ); -const transformDirection = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRANSFORM_DIRECTION ); + super.copy( source ); -const cbrt = ( a ) => mul( sign( a ), pow( abs( a ), 1.0 / 3.0 ) ); -const lengthSq = ( a ) => dot( a, a ); -const mix = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MIX ); -const clamp = ( value, low = 0, high = 1 ) => nodeObject( new MathNode( MathNode.CLAMP, nodeObject( value ), nodeObject( low ), nodeObject( high ) ) ); -const saturate = ( value ) => clamp( value ); -const refract = /*@__PURE__*/ nodeProxy( MathNode, MathNode.REFRACT ); -const smoothstep = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SMOOTHSTEP ); -const faceForward = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FACEFORWARD ); + this.focus = source.focus; -const rand = /*@__PURE__*/ Fn( ( [ uv ] ) => { + return this; - const a = 12.9898, b = 78.233, c = 43758.5453; - const dt = dot( uv.xy, vec2( a, b ) ), sn = mod( dt, PI ); + } - return fract( sin( sn ).mul( c ) ); +} -} ); +class SpotLight extends Light { -const mixElement = ( t, e1, e2 ) => mix( e1, e2, t ); -const smoothstepElement = ( x, low, high ) => smoothstep( low, high, x ); + constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2 ) { -addMethodChaining( 'all', all ); -addMethodChaining( 'any', any ); -addMethodChaining( 'equals', equals ); + super( color, intensity ); -addMethodChaining( 'radians', radians ); -addMethodChaining( 'degrees', degrees ); -addMethodChaining( 'exp', exp ); -addMethodChaining( 'exp2', exp2 ); -addMethodChaining( 'log', log ); -addMethodChaining( 'log2', log2 ); -addMethodChaining( 'sqrt', sqrt ); -addMethodChaining( 'inverseSqrt', inverseSqrt ); -addMethodChaining( 'floor', floor ); -addMethodChaining( 'ceil', ceil ); -addMethodChaining( 'normalize', normalize ); -addMethodChaining( 'fract', fract ); -addMethodChaining( 'sin', sin ); -addMethodChaining( 'cos', cos ); -addMethodChaining( 'tan', tan ); -addMethodChaining( 'asin', asin ); -addMethodChaining( 'acos', acos ); -addMethodChaining( 'atan', atan ); -addMethodChaining( 'abs', abs ); -addMethodChaining( 'sign', sign ); -addMethodChaining( 'length', length ); -addMethodChaining( 'lengthSq', lengthSq ); -addMethodChaining( 'negate', negate ); -addMethodChaining( 'oneMinus', oneMinus ); -addMethodChaining( 'dFdx', dFdx ); -addMethodChaining( 'dFdy', dFdy ); -addMethodChaining( 'round', round ); -addMethodChaining( 'reciprocal', reciprocal ); -addMethodChaining( 'trunc', trunc ); -addMethodChaining( 'fwidth', fwidth ); -addMethodChaining( 'atan2', atan2 ); -addMethodChaining( 'min', min$1 ); -addMethodChaining( 'max', max$1 ); -addMethodChaining( 'mod', mod ); -addMethodChaining( 'step', step ); -addMethodChaining( 'reflect', reflect ); -addMethodChaining( 'distance', distance ); -addMethodChaining( 'dot', dot ); -addMethodChaining( 'cross', cross ); -addMethodChaining( 'pow', pow ); -addMethodChaining( 'pow2', pow2 ); -addMethodChaining( 'pow3', pow3 ); -addMethodChaining( 'pow4', pow4 ); -addMethodChaining( 'transformDirection', transformDirection ); -addMethodChaining( 'mix', mixElement ); -addMethodChaining( 'clamp', clamp ); -addMethodChaining( 'refract', refract ); -addMethodChaining( 'smoothstep', smoothstepElement ); -addMethodChaining( 'faceForward', faceForward ); -addMethodChaining( 'difference', difference ); -addMethodChaining( 'saturate', saturate ); -addMethodChaining( 'cbrt', cbrt ); -addMethodChaining( 'transpose', transpose ); -addMethodChaining( 'rand', rand ); + this.isSpotLight = true; -class ConditionalNode extends Node { + this.type = 'SpotLight'; - constructor( condNode, ifNode, elseNode = null ) { + this.position.copy( Object3D.DEFAULT_UP ); + this.updateMatrix(); - super(); + this.target = new Object3D(); - this.condNode = condNode; + this.distance = distance; + this.angle = angle; + this.penumbra = penumbra; + this.decay = decay; - this.ifNode = ifNode; - this.elseNode = elseNode; + this.map = null; + + this.shadow = new SpotLightShadow(); } - getNodeType( builder ) { + get power() { - const ifType = this.ifNode.getNodeType( builder ); - - if ( this.elseNode !== null ) { - - const elseType = this.elseNode.getNodeType( builder ); - - if ( builder.getTypeLength( elseType ) > builder.getTypeLength( ifType ) ) { - - return elseType; - - } - - } - - return ifType; + // compute the light's luminous power (in lumens) from its intensity (in candela) + // by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd) + return this.intensity * Math.PI; } - setup( builder ) { + set power( power ) { - const properties = builder.getNodeProperties( this ); - properties.condNode = this.condNode.cache(); - properties.ifNode = this.ifNode.cache(); - properties.elseNode = this.elseNode ? this.elseNode.cache() : null; + // set the light's intensity (in candela) from the desired luminous power (in lumens) + this.intensity = power / Math.PI; } - generate( builder, output ) { - - const type = this.getNodeType( builder ); - - const nodeData = builder.getDataFromNode( this ); + dispose() { - if ( nodeData.nodeProperty !== undefined ) { + this.shadow.dispose(); - return nodeData.nodeProperty; + } - } + copy( source, recursive ) { - const { condNode, ifNode, elseNode } = builder.getNodeProperties( this ); + super.copy( source, recursive ); - const needsOutput = output !== 'void'; - const nodeProperty = needsOutput ? property( type ).build( builder ) : ''; + this.distance = source.distance; + this.angle = source.angle; + this.penumbra = source.penumbra; + this.decay = source.decay; - nodeData.nodeProperty = nodeProperty; + this.target = source.target.clone(); - const nodeSnippet = condNode.build( builder, 'bool' ); + this.shadow = source.shadow.clone(); - builder.addFlowCode( `\n${ builder.tab }if ( ${ nodeSnippet } ) {\n\n` ).addFlowTab(); + return this; - let ifSnippet = ifNode.build( builder, type ); + } - if ( ifSnippet ) { +} - if ( needsOutput ) { +const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4(); +const _lightPositionWorld = /*@__PURE__*/ new Vector3(); +const _lookTarget = /*@__PURE__*/ new Vector3(); - ifSnippet = nodeProperty + ' = ' + ifSnippet + ';'; +class PointLightShadow extends LightShadow { - } else { + constructor() { - ifSnippet = 'return ' + ifSnippet + ';'; + super( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); - } + this.isPointLightShadow = true; - } + this._frameExtents = new Vector2( 4, 2 ); - builder.removeFlowTab().addFlowCode( builder.tab + '\t' + ifSnippet + '\n\n' + builder.tab + '}' ); + this._viewportCount = 6; - if ( elseNode !== null ) { + this._viewports = [ + // These viewports map a cube-map onto a 2D texture with the + // following orientation: + // + // xzXZ + // y Y + // + // X - Positive x direction + // x - Negative x direction + // Y - Positive y direction + // y - Negative y direction + // Z - Positive z direction + // z - Negative z direction - builder.addFlowCode( ' else {\n\n' ).addFlowTab(); + // positive X + new Vector4( 2, 1, 1, 1 ), + // negative X + new Vector4( 0, 1, 1, 1 ), + // positive Z + new Vector4( 3, 1, 1, 1 ), + // negative Z + new Vector4( 1, 1, 1, 1 ), + // positive Y + new Vector4( 3, 0, 1, 1 ), + // negative Y + new Vector4( 1, 0, 1, 1 ) + ]; - let elseSnippet = elseNode.build( builder, type ); + this._cubeDirections = [ + new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ), + new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 ) + ]; - if ( elseSnippet ) { + this._cubeUps = [ + new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), + new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 ) + ]; - if ( needsOutput ) { + } - elseSnippet = nodeProperty + ' = ' + elseSnippet + ';'; + updateMatrices( light, viewportIndex = 0 ) { - } else { + const camera = this.camera; + const shadowMatrix = this.matrix; - elseSnippet = 'return ' + elseSnippet + ';'; + const far = light.distance || camera.far; - } + if ( far !== camera.far ) { - } + camera.far = far; + camera.updateProjectionMatrix(); - builder.removeFlowTab().addFlowCode( builder.tab + '\t' + elseSnippet + '\n\n' + builder.tab + '}\n\n' ); + } - } else { + _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); + camera.position.copy( _lightPositionWorld ); - builder.addFlowCode( '\n\n' ); + _lookTarget.copy( camera.position ); + _lookTarget.add( this._cubeDirections[ viewportIndex ] ); + camera.up.copy( this._cubeUps[ viewportIndex ] ); + camera.lookAt( _lookTarget ); + camera.updateMatrixWorld(); - } + shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); - return builder.format( nodeProperty, type, output ); + _projScreenMatrix$1.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 ); } } -ConditionalNode.type = /*@__PURE__*/ registerNode( 'Conditional', ConditionalNode ); - -const select = /*@__PURE__*/ nodeProxy( ConditionalNode ); - -addMethodChaining( 'select', select ); - -// - -const cond = ( ...params ) => { // @deprecated, r168 - - console.warn( 'TSL.ConditionalNode: cond() has been renamed to select().' ); - return select( ...params ); - -}; +class PointLight extends Light { -addMethodChaining( 'cond', cond ); + constructor( color, intensity, distance = 0, decay = 2 ) { -class ContextNode extends Node { + super( color, intensity ); - constructor( node, value = {} ) { + this.isPointLight = true; - super(); + this.type = 'PointLight'; - this.isContextNode = true; + this.distance = distance; + this.decay = decay; - this.node = node; - this.value = value; + this.shadow = new PointLightShadow(); } - getScope() { + get power() { - return this.node.getScope(); + // compute the light's luminous power (in lumens) from its intensity (in candela) + // for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd) + return this.intensity * 4 * Math.PI; } - getNodeType( builder ) { + set power( power ) { - return this.node.getNodeType( builder ); + // set the light's intensity (in candela) from the desired luminous power (in lumens) + this.intensity = power / ( 4 * Math.PI ); } - analyze( builder ) { + dispose() { - this.node.build( builder ); + this.shadow.dispose(); } - setup( builder ) { - - const previousContext = builder.getContext(); + copy( source, recursive ) { - builder.setContext( { ...builder.context, ...this.value } ); + super.copy( source, recursive ); - const node = this.node.build( builder ); + this.distance = source.distance; + this.decay = source.decay; - builder.setContext( previousContext ); + this.shadow = source.shadow.clone(); - return node; + return this; } - generate( builder, output ) { - - const previousContext = builder.getContext(); +} - builder.setContext( { ...builder.context, ...this.value } ); +class OrthographicCamera extends Camera { - const snippet = this.node.build( builder, output ); + constructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) { - builder.setContext( previousContext ); + super(); - return snippet; + this.isOrthographicCamera = true; - } + this.type = 'OrthographicCamera'; -} + this.zoom = 1; + this.view = null; -ContextNode.type = /*@__PURE__*/ registerNode( 'Context', ContextNode ); + this.left = left; + this.right = right; + this.top = top; + this.bottom = bottom; -const context = /*@__PURE__*/ nodeProxy( ContextNode ); -const label = ( node, name ) => context( node, { label: name } ); + this.near = near; + this.far = far; -addMethodChaining( 'context', context ); -addMethodChaining( 'label', label ); + this.updateProjectionMatrix(); -class VarNode extends Node { + } - constructor( node, name = null ) { + copy( source, recursive ) { - super(); + super.copy( source, recursive ); - this.node = node; - this.name = name; + this.left = source.left; + this.right = source.right; + this.top = source.top; + this.bottom = source.bottom; + this.near = source.near; + this.far = source.far; - this.global = true; + this.zoom = source.zoom; + this.view = source.view === null ? null : Object.assign( {}, source.view ); - this.isVarNode = true; + return this; } - getHash( builder ) { - - return this.name || super.getHash( builder ); + setViewOffset( fullWidth, fullHeight, x, y, width, height ) { - } + if ( this.view === null ) { - getNodeType( builder ) { + this.view = { + enabled: true, + fullWidth: 1, + fullHeight: 1, + offsetX: 0, + offsetY: 0, + width: 1, + height: 1 + }; - return this.node.getNodeType( builder ); + } - } + this.view.enabled = true; + this.view.fullWidth = fullWidth; + this.view.fullHeight = fullHeight; + this.view.offsetX = x; + this.view.offsetY = y; + this.view.width = width; + this.view.height = height; - generate( builder ) { + this.updateProjectionMatrix(); - const { node, name } = this; + } - const nodeVar = builder.getVarFromNode( this, name, builder.getVectorType( this.getNodeType( builder ) ) ); + clearViewOffset() { - const propertyName = builder.getPropertyName( nodeVar ); + if ( this.view !== null ) { - const snippet = node.build( builder, nodeVar.type ); + this.view.enabled = false; - builder.addLineFlowCode( `${propertyName} = ${snippet}` ); + } - return propertyName; + this.updateProjectionMatrix(); } -} + updateProjectionMatrix() { -VarNode.type = /*@__PURE__*/ registerNode( 'Var', VarNode ); + const dx = ( this.right - this.left ) / ( 2 * this.zoom ); + const dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); + const cx = ( this.right + this.left ) / 2; + const cy = ( this.top + this.bottom ) / 2; -const temp = /*@__PURE__*/ nodeProxy( VarNode ); + let left = cx - dx; + let right = cx + dx; + let top = cy + dy; + let bottom = cy - dy; -addMethodChaining( 'temp', temp ); // @TODO: Will be removed in the future -addMethodChaining( 'toVar', ( ...params ) => temp( ...params ).append() ); + if ( this.view !== null && this.view.enabled ) { -class VaryingNode extends Node { + const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom; + const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom; - constructor( node, name = null ) { + left += scaleW * this.view.offsetX; + right = left + scaleW * this.view.width; + top -= scaleH * this.view.offsetY; + bottom = top - scaleH * this.view.height; - super(); + } - this.node = node; - this.name = name; + this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem ); - this.isVaryingNode = true; + this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); } - isGlobal() { + toJSON( meta ) { - return true; + const data = super.toJSON( meta ); - } + data.object.zoom = this.zoom; + data.object.left = this.left; + data.object.right = this.right; + data.object.top = this.top; + data.object.bottom = this.bottom; + data.object.near = this.near; + data.object.far = this.far; - getHash( builder ) { + if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - return this.name || super.getHash( builder ); + return data; } - getNodeType( builder ) { +} - // VaryingNode is auto type +class DirectionalLightShadow extends LightShadow { - return this.node.getNodeType( builder ); + constructor() { + + super( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); + + this.isDirectionalLightShadow = true; } - setupVarying( builder ) { +} - const properties = builder.getNodeProperties( this ); +class DirectionalLight extends Light { - let varying = properties.varying; + constructor( color, intensity ) { - if ( varying === undefined ) { + super( color, intensity ); - const name = this.name; - const type = this.getNodeType( builder ); + this.isDirectionalLight = true; - properties.varying = varying = builder.getVaryingFromNode( this, name, type ); - properties.node = this.node; + this.type = 'DirectionalLight'; - } + this.position.copy( Object3D.DEFAULT_UP ); + this.updateMatrix(); - // this property can be used to check if the varying can be optimized for a variable - varying.needsInterpolation || ( varying.needsInterpolation = ( builder.shaderStage === 'fragment' ) ); + this.target = new Object3D(); - return varying; + this.shadow = new DirectionalLightShadow(); } - setup( builder ) { + dispose() { - this.setupVarying( builder ); + this.shadow.dispose(); } - analyze( builder ) { - - this.setupVarying( builder ); + copy( source ) { - return this.node.analyze( builder ); + super.copy( source ); - } + this.target = source.target.clone(); + this.shadow = source.shadow.clone(); - generate( builder ) { + return this; - const properties = builder.getNodeProperties( this ); - const varying = this.setupVarying( builder ); + } - if ( properties.propertyName === undefined ) { +} - const type = this.getNodeType( builder ); - const propertyName = builder.getPropertyName( varying, NodeShaderStage.VERTEX ); +class AmbientLight extends Light { - // force node run in vertex stage - builder.flowNodeFromShaderStage( NodeShaderStage.VERTEX, this.node, type, propertyName ); + constructor( color, intensity ) { - properties.propertyName = propertyName; + super( color, intensity ); - } + this.isAmbientLight = true; - return builder.getPropertyName( varying ); + this.type = 'AmbientLight'; } } -VaryingNode.type = /*@__PURE__*/ registerNode( 'Varying', VaryingNode ); +class RectAreaLight extends Light { -const varying = /*@__PURE__*/ nodeProxy( VaryingNode ); + constructor( color, intensity, width = 10, height = 10 ) { -addMethodChaining( 'varying', varying ); + super( color, intensity ); -const getColorSpaceName = ( colorSpace ) => { + this.isRectAreaLight = true; - let method = null; + this.type = 'RectAreaLight'; - if ( colorSpace === LinearSRGBColorSpace ) { + this.width = width; + this.height = height; - method = 'Linear'; + } - } else if ( colorSpace === SRGBColorSpace ) { + get power() { - method = 'sRGB'; + // compute the light's luminous power (in lumens) from its intensity (in nits) + return this.intensity * this.width * this.height * Math.PI; } - return method; + set power( power ) { -}; + // set the light's intensity (in nits) from the desired luminous power (in lumens) + this.intensity = power / ( this.width * this.height * Math.PI ); -const getColorSpaceMethod = ( source, target ) => { + } - return getColorSpaceName( source ) + 'To' + getColorSpaceName( target ); + copy( source ) { -}; + super.copy( source ); -class ColorSpaceNode extends TempNode { + this.width = source.width; + this.height = source.height; - constructor( colorNode, target = null, source = null ) { + return this; - super( 'vec4' ); + } - this.colorNode = colorNode; - this.target = target; - this.source = source; + toJSON( meta ) { - } + const data = super.toJSON( meta ); - setup( builder ) { + data.object.width = this.width; + data.object.height = this.height; - const { renderer, context } = builder; + return data; - const source = this.source || context.outputColorSpace || renderer.outputColorSpace; - const target = this.target || context.outputColorSpace || renderer.outputColorSpace; - const colorNode = this.colorNode; + } - if ( source === target ) return colorNode; +} - const colorSpace = getColorSpaceMethod( source, target ); +/** + * Primary reference: + * https://graphics.stanford.edu/papers/envmap/envmap.pdf + * + * Secondary reference: + * https://www.ppsloan.org/publications/StupidSH36.pdf + */ - let outputNode = null; +// 3-band SH defined by 9 coefficients - const colorSpaceFn = renderer.nodes.library.getColorSpaceFunction( colorSpace ); +class SphericalHarmonics3 { - if ( colorSpaceFn !== null ) { + constructor() { - outputNode = vec4( colorSpaceFn( colorNode.rgb ), colorNode.a ); + this.isSphericalHarmonics3 = true; - } else { + this.coefficients = []; - console.error( 'ColorSpaceNode: Unsupported Color Space configuration.', colorSpace ); + for ( let i = 0; i < 9; i ++ ) { - outputNode = colorNode; + this.coefficients.push( new Vector3() ); } - return outputNode; - } -} - -ColorSpaceNode.type = /*@__PURE__*/ registerNode( 'ColorSpace', ColorSpaceNode ); + set( coefficients ) { -const toOutputColorSpace = ( node, colorSpace = null ) => nodeObject( new ColorSpaceNode( nodeObject( node ), colorSpace, LinearSRGBColorSpace ) ); -const toWorkingColorSpace = ( node, colorSpace = null ) => nodeObject( new ColorSpaceNode( nodeObject( node ), LinearSRGBColorSpace, colorSpace ) ); + for ( let i = 0; i < 9; i ++ ) { -addMethodChaining( 'toOutputColorSpace', toOutputColorSpace ); -addMethodChaining( 'toWorkingColorSpace', toWorkingColorSpace ); + this.coefficients[ i ].copy( coefficients[ i ] ); -let ReferenceElementNode$1 = class ReferenceElementNode extends ArrayElementNode { + } - constructor( referenceNode, indexNode ) { + return this; - super( referenceNode, indexNode ); + } - this.referenceNode = referenceNode; + zero() { - this.isReferenceElementNode = true; + for ( let i = 0; i < 9; i ++ ) { - } + this.coefficients[ i ].set( 0, 0, 0 ); - getNodeType() { + } - return this.referenceNode.uniformType; + return this; } - generate( builder ) { + // get the radiance in the direction of the normal + // target is a Vector3 + getAt( normal, target ) { - const snippet = super.generate( builder ); - const arrayType = this.referenceNode.getNodeType(); - const elementType = this.getNodeType(); + // normal is assumed to be unit length - return builder.format( snippet, arrayType, elementType ); + const x = normal.x, y = normal.y, z = normal.z; - } + const coeff = this.coefficients; -}; + // band 0 + target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 ); -class ReferenceBaseNode extends Node { + // band 1 + target.addScaledVector( coeff[ 1 ], 0.488603 * y ); + target.addScaledVector( coeff[ 2 ], 0.488603 * z ); + target.addScaledVector( coeff[ 3 ], 0.488603 * x ); - constructor( property, uniformType, object = null, count = null ) { + // band 2 + target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) ); + target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) ); + target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) ); + target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) ); + target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) ); - super(); + return target; - this.property = property; - this.uniformType = uniformType; - this.object = object; - this.count = count; + } - this.properties = property.split( '.' ); - this.reference = object; - this.node = null; + // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal + // target is a Vector3 + // https://graphics.stanford.edu/papers/envmap/envmap.pdf + getIrradianceAt( normal, target ) { - this.updateType = NodeUpdateType.OBJECT; + // normal is assumed to be unit length - } + const x = normal.x, y = normal.y, z = normal.z; - element( indexNode ) { + const coeff = this.coefficients; - return nodeObject( new ReferenceElementNode$1( this, nodeObject( indexNode ) ) ); + // band 0 + target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095 - } + // band 1 + target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603 + target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z ); + target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x ); - setNodeType( uniformType ) { + // band 2 + target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548 + target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z ); + target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3 + target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z ); + target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274 - this.node = uniform( null, uniformType ).getSelf(); + return target; } - getNodeType( builder ) { + add( sh ) { - if ( this.node === null ) { + for ( let i = 0; i < 9; i ++ ) { - this.updateValue(); + this.coefficients[ i ].add( sh.coefficients[ i ] ); } - return this.node.getNodeType( builder ); + return this; } - getValueFromReference( object = this.reference ) { + addScaledSH( sh, s ) { - const { properties } = this; + for ( let i = 0; i < 9; i ++ ) { - let value = object[ properties[ 0 ] ]; + this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s ); - for ( let i = 1; i < properties.length; i ++ ) { + } - value = value[ properties[ i ] ]; + return this; + + } + + scale( s ) { + + for ( let i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].multiplyScalar( s ); } - return value; + return this; } - updateReference( state ) { + lerp( sh, alpha ) { - this.reference = this.object !== null ? this.object : state.object; + for ( let i = 0; i < 9; i ++ ) { - return this.reference; + this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha ); + + } + + return this; } - setup() { + equals( sh ) { - this.updateValue(); + for ( let i = 0; i < 9; i ++ ) { - return this.node; + if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) { + + return false; + + } + + } + + return true; } - update( /*frame*/ ) { + copy( sh ) { - this.updateValue(); + return this.set( sh.coefficients ); } - updateValue() { + clone() { - if ( this.node === null ) this.setNodeType( this.uniformType ); + return new this.constructor().copy( this ); - const value = this.getValueFromReference(); + } - if ( Array.isArray( value ) ) { + fromArray( array, offset = 0 ) { - this.node.array = value; + const coefficients = this.coefficients; - } else { + for ( let i = 0; i < 9; i ++ ) { - this.node.value = value; + coefficients[ i ].fromArray( array, offset + ( i * 3 ) ); } + return this; + } -} + toArray( array = [], offset = 0 ) { -ReferenceBaseNode.type = /*@__PURE__*/ registerNode( 'ReferenceBase', ReferenceBaseNode ); + const coefficients = this.coefficients; -class RendererReferenceNode extends ReferenceBaseNode { + for ( let i = 0; i < 9; i ++ ) { - constructor( property, inputType, renderer = null ) { + coefficients[ i ].toArray( array, offset + ( i * 3 ) ); - super( property, inputType, renderer ); + } - this.renderer = renderer; + return array; } - updateReference( state ) { + // evaluate the basis functions + // shBasis is an Array[ 9 ] + static getBasisAt( normal, shBasis ) { - this.reference = this.renderer !== null ? this.renderer : state.renderer; + // normal is assumed to be unit length - return this.reference; + const x = normal.x, y = normal.y, z = normal.z; - } + // band 0 + shBasis[ 0 ] = 0.282095; -} + // band 1 + shBasis[ 1 ] = 0.488603 * y; + shBasis[ 2 ] = 0.488603 * z; + shBasis[ 3 ] = 0.488603 * x; -RendererReferenceNode.type = /*@__PURE__*/ registerNode( 'RendererReference', RendererReferenceNode ); + // band 2 + shBasis[ 4 ] = 1.092548 * x * y; + shBasis[ 5 ] = 1.092548 * y * z; + shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 ); + shBasis[ 7 ] = 1.092548 * x * z; + shBasis[ 8 ] = 0.546274 * ( x * x - y * y ); -const rendererReference = ( name, type, renderer ) => nodeObject( new RendererReferenceNode( name, type, renderer ) ); + } -class ToneMappingNode extends TempNode { +} - constructor( toneMapping, exposureNode = toneMappingExposure, colorNode = null ) { +class LightProbe extends Light { - super( 'vec3' ); + constructor( sh = new SphericalHarmonics3(), intensity = 1 ) { - this.toneMapping = toneMapping; + super( undefined, intensity ); - this.exposureNode = exposureNode; - this.colorNode = colorNode; + this.isLightProbe = true; + + this.sh = sh; } - getCacheKey() { + copy( source ) { + + super.copy( source ); - let cacheKey = super.getCacheKey(); - cacheKey = '{toneMapping:' + this.toneMapping + ',nodes:' + cacheKey + '}'; + this.sh.copy( source.sh ); - return cacheKey; + return this; } - setup( builder ) { + fromJSON( json ) { - const colorNode = this.colorNode || builder.context.color; - const toneMapping = this.toneMapping; + this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON(); + this.sh.fromArray( json.sh ); - if ( toneMapping === NoToneMapping ) return colorNode; + return this; - let outputNode = null; + } - const toneMappingFn = builder.renderer.nodes.library.getToneMappingFunction( toneMapping ); + toJSON( meta ) { - if ( toneMappingFn !== null ) { + const data = super.toJSON( meta ); - outputNode = vec4( toneMappingFn( colorNode.rgb, this.exposureNode ), colorNode.a ); + data.object.sh = this.sh.toArray(); - } else { + return data; - console.error( 'ToneMappingNode: Unsupported Tone Mapping configuration.', toneMapping ); + } - outputNode = colorNode; +} - } +class MaterialLoader extends Loader { - return outputNode; + constructor( manager ) { - } + super( manager ); + this.textures = {}; -} + } -ToneMappingNode.type = /*@__PURE__*/ registerNode( 'ToneMapping', ToneMappingNode ); + load( url, onLoad, onProgress, onError ) { -const toneMapping = ( mapping, exposure, color ) => nodeObject( new ToneMappingNode( mapping, nodeObject( exposure ), nodeObject( color ) ) ); -const toneMappingExposure = /*@__PURE__*/ rendererReference( 'toneMappingExposure', 'float' ); + const scope = this; -addMethodChaining( 'toneMapping', ( color, mapping, exposure ) => toneMapping( mapping, exposure, color ) ); + const loader = new FileLoader( scope.manager ); + loader.setPath( scope.path ); + loader.setRequestHeader( scope.requestHeader ); + loader.setWithCredentials( scope.withCredentials ); + loader.load( url, function ( text ) { -class BufferAttributeNode extends InputNode { + try { - constructor( value, bufferType = null, bufferStride = 0, bufferOffset = 0 ) { + onLoad( scope.parse( JSON.parse( text ) ) ); - super( value, bufferType ); + } catch ( e ) { - this.isBufferNode = true; + if ( onError ) { - this.bufferType = bufferType; - this.bufferStride = bufferStride; - this.bufferOffset = bufferOffset; + onError( e ); - this.usage = StaticDrawUsage; - this.instanced = false; + } else { - this.attribute = null; + console.error( e ); - this.global = true; + } - if ( value && value.isBufferAttribute === true ) { + scope.manager.itemError( url ); - this.attribute = value; - this.usage = value.usage; - this.instanced = value.isInstancedBufferAttribute; + } - } + }, onProgress, onError ); } - getHash( builder ) { - - if ( this.bufferStride === 0 && this.bufferOffset === 0 ) { + parse( json ) { - let bufferData = builder.globalCache.getData( this.value ); + const textures = this.textures; - if ( bufferData === undefined ) { + function getTexture( name ) { - bufferData = { - node: this - }; + if ( textures[ name ] === undefined ) { - builder.globalCache.setData( this.value, bufferData ); + console.warn( 'THREE.MaterialLoader: Undefined texture', name ); } - return bufferData.node.uuid; + return textures[ name ]; } - return this.uuid; - - } + const material = this.createMaterialFromType( json.type ); - getNodeType( builder ) { + if ( json.uuid !== undefined ) material.uuid = json.uuid; + if ( json.name !== undefined ) material.name = json.name; + if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color ); + if ( json.roughness !== undefined ) material.roughness = json.roughness; + if ( json.metalness !== undefined ) material.metalness = json.metalness; + if ( json.sheen !== undefined ) material.sheen = json.sheen; + if ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor ); + if ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness; + if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive ); + if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular ); + if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity; + if ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor ); + if ( json.shininess !== undefined ) material.shininess = json.shininess; + if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat; + if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness; + if ( json.dispersion !== undefined ) material.dispersion = json.dispersion; + if ( json.iridescence !== undefined ) material.iridescence = json.iridescence; + if ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR; + if ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange; + if ( json.transmission !== undefined ) material.transmission = json.transmission; + if ( json.thickness !== undefined ) material.thickness = json.thickness; + if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance; + if ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor ); + if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy; + if ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation; + if ( json.fog !== undefined ) material.fog = json.fog; + if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; + if ( json.blending !== undefined ) material.blending = json.blending; + if ( json.combine !== undefined ) material.combine = json.combine; + if ( json.side !== undefined ) material.side = json.side; + if ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide; + if ( json.opacity !== undefined ) material.opacity = json.opacity; + if ( json.transparent !== undefined ) material.transparent = json.transparent; + if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; + if ( json.alphaHash !== undefined ) material.alphaHash = json.alphaHash; + if ( json.depthFunc !== undefined ) material.depthFunc = json.depthFunc; + if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; + if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; + if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; + if ( json.blendSrc !== undefined ) material.blendSrc = json.blendSrc; + if ( json.blendDst !== undefined ) material.blendDst = json.blendDst; + if ( json.blendEquation !== undefined ) material.blendEquation = json.blendEquation; + if ( json.blendSrcAlpha !== undefined ) material.blendSrcAlpha = json.blendSrcAlpha; + if ( json.blendDstAlpha !== undefined ) material.blendDstAlpha = json.blendDstAlpha; + if ( json.blendEquationAlpha !== undefined ) material.blendEquationAlpha = json.blendEquationAlpha; + if ( json.blendColor !== undefined && material.blendColor !== undefined ) material.blendColor.setHex( json.blendColor ); + if ( json.blendAlpha !== undefined ) material.blendAlpha = json.blendAlpha; + if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask; + if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc; + if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef; + if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask; + if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail; + if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail; + if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass; + if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite; - if ( this.bufferType === null ) { + if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; + if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; + if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; + if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; - this.bufferType = builder.getTypeFromAttribute( this.attribute ); + if ( json.rotation !== undefined ) material.rotation = json.rotation; - } + if ( json.linewidth !== undefined ) material.linewidth = json.linewidth; + if ( json.dashSize !== undefined ) material.dashSize = json.dashSize; + if ( json.gapSize !== undefined ) material.gapSize = json.gapSize; + if ( json.scale !== undefined ) material.scale = json.scale; - return this.bufferType; + if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset; + if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor; + if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits; - } + if ( json.dithering !== undefined ) material.dithering = json.dithering; - setup( builder ) { + if ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage; + if ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha; + if ( json.forceSinglePass !== undefined ) material.forceSinglePass = json.forceSinglePass; - if ( this.attribute !== null ) return; + if ( json.visible !== undefined ) material.visible = json.visible; - const type = this.getNodeType( builder ); - const array = this.value; - const itemSize = builder.getTypeLength( type ); - const stride = this.bufferStride || itemSize; - const offset = this.bufferOffset; + if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped; - const buffer = array.isInterleavedBuffer === true ? array : new InterleavedBuffer( array, stride ); - const bufferAttribute = new InterleavedBufferAttribute( buffer, itemSize, offset ); + if ( json.userData !== undefined ) material.userData = json.userData; - buffer.setUsage( this.usage ); + if ( json.vertexColors !== undefined ) { - this.attribute = bufferAttribute; - this.attribute.isInstancedBufferAttribute = this.instanced; // @TODO: Add a possible: InstancedInterleavedBufferAttribute + if ( typeof json.vertexColors === 'number' ) { - } + material.vertexColors = ( json.vertexColors > 0 ) ? true : false; - generate( builder ) { + } else { - const nodeType = this.getNodeType( builder ); + material.vertexColors = json.vertexColors; - const nodeAttribute = builder.getBufferAttributeFromNode( this, nodeType ); - const propertyName = builder.getPropertyName( nodeAttribute ); + } - let output = null; + } - if ( builder.shaderStage === 'vertex' || builder.shaderStage === 'compute' ) { + // Shader Material - this.name = propertyName; + if ( json.uniforms !== undefined ) { - output = propertyName; + for ( const name in json.uniforms ) { - } else { + const uniform = json.uniforms[ name ]; - const nodeVarying = varying( this ); + material.uniforms[ name ] = {}; - output = nodeVarying.build( builder, nodeType ); + switch ( uniform.type ) { - } + case 't': + material.uniforms[ name ].value = getTexture( uniform.value ); + break; - return output; + case 'c': + material.uniforms[ name ].value = new Color().setHex( uniform.value ); + break; - } + case 'v2': + material.uniforms[ name ].value = new Vector2().fromArray( uniform.value ); + break; - getInputType( /*builder*/ ) { + case 'v3': + material.uniforms[ name ].value = new Vector3().fromArray( uniform.value ); + break; - return 'bufferAttribute'; + case 'v4': + material.uniforms[ name ].value = new Vector4().fromArray( uniform.value ); + break; - } + case 'm3': + material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value ); + break; - setUsage( value ) { + case 'm4': + material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value ); + break; - this.usage = value; + default: + material.uniforms[ name ].value = uniform.value; - if ( this.attribute && this.attribute.isBufferAttribute === true ) { + } - this.attribute.usage = value; + } } - return this; + if ( json.defines !== undefined ) material.defines = json.defines; + if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; + if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; + if ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion; - } + if ( json.extensions !== undefined ) { - setInstanced( value ) { + for ( const key in json.extensions ) { - this.instanced = value; + material.extensions[ key ] = json.extensions[ key ]; - return this; + } - } + } -} + if ( json.lights !== undefined ) material.lights = json.lights; + if ( json.clipping !== undefined ) material.clipping = json.clipping; -BufferAttributeNode.type = /*@__PURE__*/ registerNode( 'BufferAttribute', BufferAttributeNode ); + // for PointsMaterial -const bufferAttribute = ( array, type, stride, offset ) => nodeObject( new BufferAttributeNode( array, type, stride, offset ) ); -const dynamicBufferAttribute = ( array, type, stride, offset ) => bufferAttribute( array, type, stride, offset ).setUsage( DynamicDrawUsage ); + if ( json.size !== undefined ) material.size = json.size; + if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; -const instancedBufferAttribute = ( array, type, stride, offset ) => bufferAttribute( array, type, stride, offset ).setInstanced( true ); -const instancedDynamicBufferAttribute = ( array, type, stride, offset ) => dynamicBufferAttribute( array, type, stride, offset ).setInstanced( true ); + // maps -addMethodChaining( 'toAttribute', ( bufferNode ) => bufferAttribute( bufferNode.value ) ); + if ( json.map !== undefined ) material.map = getTexture( json.map ); + if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap ); -class ComputeNode extends Node { + if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap ); - constructor( computeNode, count, workgroupSize = [ 64 ] ) { + if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); + if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; - super( 'void' ); + if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); + if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType; + if ( json.normalScale !== undefined ) { - this.isComputeNode = true; + let normalScale = json.normalScale; - this.computeNode = computeNode; + if ( Array.isArray( normalScale ) === false ) { - this.count = count; - this.workgroupSize = workgroupSize; - this.dispatchCount = 0; + // Blender exporter used to export a scalar. See #7459 - this.version = 1; - this.updateBeforeType = NodeUpdateType.OBJECT; + normalScale = [ normalScale, normalScale ]; - this.updateDispatchCount(); + } - } + material.normalScale = new Vector2().fromArray( normalScale ); - dispose() { + } - this.dispatchEvent( { type: 'dispose' } ); + if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); + if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; + if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; - } + if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); + if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); - set needsUpdate( value ) { + if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); + if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; - if ( value === true ) this.version ++; + if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); + if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap ); + if ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap ); - } + if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); + if ( json.envMapRotation !== undefined ) material.envMapRotation.fromArray( json.envMapRotation ); + if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity; - updateDispatchCount() { + if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; + if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio; - const { count, workgroupSize } = this; + if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); + if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; - let size = workgroupSize[ 0 ]; + if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); + if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; - for ( let i = 1; i < workgroupSize.length; i ++ ) - size *= workgroupSize[ i ]; + if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); - this.dispatchCount = Math.ceil( count / size ); + if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap ); + if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap ); + if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap ); + if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale ); - } + if ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap ); + if ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap ); - onInit() { } + if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap ); + if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap ); - updateBefore( { renderer } ) { + if ( json.anisotropyMap !== undefined ) material.anisotropyMap = getTexture( json.anisotropyMap ); - renderer.compute( this ); + if ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap ); + if ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap ); + + return material; } - generate( builder ) { + setTextures( value ) { - const { shaderStage } = builder; + this.textures = value; + return this; - if ( shaderStage === 'compute' ) { + } - const snippet = this.computeNode.build( builder, 'void' ); + createMaterialFromType( type ) { - if ( snippet !== '' ) { + return MaterialLoader.createMaterialFromType( type ); - builder.addLineFlowCode( snippet ); + } - } + static createMaterialFromType( type ) { - } + const materialLib = { + ShadowMaterial, + SpriteMaterial, + RawShaderMaterial, + ShaderMaterial, + PointsMaterial, + MeshPhysicalMaterial, + MeshStandardMaterial, + MeshPhongMaterial, + MeshToonMaterial, + MeshNormalMaterial, + MeshLambertMaterial, + MeshDepthMaterial, + MeshDistanceMaterial, + MeshBasicMaterial, + MeshMatcapMaterial, + LineDashedMaterial, + LineBasicMaterial, + Material + }; + + return new materialLib[ type ](); } } -ComputeNode.type = /*@__PURE__*/ registerNode( 'Compute', ComputeNode ); - -const compute = ( node, count, workgroupSize ) => nodeObject( new ComputeNode( nodeObject( node ), count, workgroupSize ) ); +class LoaderUtils { -addMethodChaining( 'compute', compute ); + static decodeText( array ) { // @deprecated, r165 -class CacheNode extends Node { + console.warn( 'THREE.LoaderUtils: decodeText() has been deprecated with r165 and will be removed with r175. Use TextDecoder instead.' ); - constructor( node, parent = true ) { + if ( typeof TextDecoder !== 'undefined' ) { - super(); + return new TextDecoder().decode( array ); - this.node = node; - this.parent = parent; + } - this.isCacheNode = true; + // Avoid the String.fromCharCode.apply(null, array) shortcut, which + // throws a "maximum call stack size exceeded" error for large arrays. - } + let s = ''; - getNodeType( builder ) { + for ( let i = 0, il = array.length; i < il; i ++ ) { - return this.node.getNodeType( builder ); + // Implicitly assumes little-endian. + s += String.fromCharCode( array[ i ] ); - } + } - build( builder, ...params ) { + try { - const previousCache = builder.getCache(); - const cache = builder.getCacheFromNode( this, parent ); + // merges multi-byte utf-8 characters. - builder.setCache( cache ); + return decodeURIComponent( escape( s ) ); - const data = this.node.build( builder, ...params ); + } catch ( e ) { // see #16358 - builder.setCache( previousCache ); + return s; - return data; + } } -} - -CacheNode.type = /*@__PURE__*/ registerNode( 'Cache', CacheNode ); - -const cache = ( node, ...params ) => nodeObject( new CacheNode( nodeObject( node ), ...params ) ); - -addMethodChaining( 'cache', cache ); - -class BypassNode extends Node { - - constructor( returnNode, callNode ) { + static extractUrlBase( url ) { - super(); + const index = url.lastIndexOf( '/' ); - this.isBypassNode = true; + if ( index === - 1 ) return './'; - this.outputNode = returnNode; - this.callNode = callNode; + return url.slice( 0, index + 1 ); } - getNodeType( builder ) { + static resolveURL( url, path ) { - return this.outputNode.getNodeType( builder ); + // Invalid URL + if ( typeof url !== 'string' || url === '' ) return ''; - } + // Host Relative URL + if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) { - generate( builder ) { + path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' ); - const snippet = this.callNode.build( builder, 'void' ); + } - if ( snippet !== '' ) { + // Absolute URL http://,https://,// + if ( /^(https?:)?\/\//i.test( url ) ) return url; - builder.addLineFlowCode( snippet ); + // Data URI + if ( /^data:.*,.*$/i.test( url ) ) return url; - } + // Blob URL + if ( /^blob:.*$/i.test( url ) ) return url; - return this.outputNode.build( builder ); + // Relative URL + return path + url; } } -BypassNode.type = /*@__PURE__*/ registerNode( 'Bypass', BypassNode ); +class InstancedBufferGeometry extends BufferGeometry { -const bypass = /*@__PURE__*/ nodeProxy( BypassNode ); + constructor() { -addMethodChaining( 'bypass', bypass ); + super(); -class RemapNode extends Node { + this.isInstancedBufferGeometry = true; - constructor( node, inLowNode, inHighNode, outLowNode = float( 0 ), outHighNode = float( 1 ) ) { + this.type = 'InstancedBufferGeometry'; + this.instanceCount = Infinity; - super(); + } - this.node = node; - this.inLowNode = inLowNode; - this.inHighNode = inHighNode; - this.outLowNode = outLowNode; - this.outHighNode = outHighNode; + copy( source ) { - this.doClamp = true; + super.copy( source ); + + this.instanceCount = source.instanceCount; + + return this; } - setup() { + toJSON() { - const { node, inLowNode, inHighNode, outLowNode, outHighNode, doClamp } = this; + const data = super.toJSON(); - let t = node.sub( inLowNode ).div( inHighNode.sub( inLowNode ) ); + data.instanceCount = this.instanceCount; - if ( doClamp === true ) t = t.clamp(); + data.isInstancedBufferGeometry = true; - return t.mul( outHighNode.sub( outLowNode ) ).add( outLowNode ); + return data; } } -RemapNode.type = /*@__PURE__*/ registerNode( 'Remap', RemapNode ); +class BufferGeometryLoader extends Loader { -const remap = /*@__PURE__*/ nodeProxy( RemapNode, null, null, { doClamp: false } ); -const remapClamp = /*@__PURE__*/ nodeProxy( RemapNode ); + constructor( manager ) { -addMethodChaining( 'remap', remap ); -addMethodChaining( 'remapClamp', remapClamp ); + super( manager ); -class ExpressionNode extends Node { + } - constructor( snippet = '', nodeType = 'void' ) { + load( url, onLoad, onProgress, onError ) { - super( nodeType ); + const scope = this; - this.snippet = snippet; + const loader = new FileLoader( scope.manager ); + loader.setPath( scope.path ); + loader.setRequestHeader( scope.requestHeader ); + loader.setWithCredentials( scope.withCredentials ); + loader.load( url, function ( text ) { - } + try { - generate( builder, output ) { + onLoad( scope.parse( JSON.parse( text ) ) ); - const type = this.getNodeType( builder ); - const snippet = this.snippet; + } catch ( e ) { - if ( type === 'void' ) { + if ( onError ) { - builder.addLineFlowCode( snippet ); + onError( e ); - } else { + } else { - return builder.format( `( ${ snippet } )`, type, output ); + console.error( e ); - } + } - } + scope.manager.itemError( url ); -} + } -ExpressionNode.type = /*@__PURE__*/ registerNode( 'Expression', ExpressionNode ); + }, onProgress, onError ); -const expression = /*@__PURE__*/ nodeProxy( ExpressionNode ); + } -const Discard = ( conditional ) => ( conditional ? select( conditional, expression( 'discard' ) ) : expression( 'discard' ) ).append(); -const Return = () => expression( 'return' ).append(); + parse( json ) { -addMethodChaining( 'discard', Discard ); + const interleavedBufferMap = {}; + const arrayBufferMap = {}; -class RenderOutputNode extends TempNode { + function getInterleavedBuffer( json, uuid ) { - constructor( colorNode, toneMapping, outputColorSpace ) { + if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ]; - super( 'vec4' ); + const interleavedBuffers = json.interleavedBuffers; + const interleavedBuffer = interleavedBuffers[ uuid ]; - this.colorNode = colorNode; - this.toneMapping = toneMapping; - this.outputColorSpace = outputColorSpace; + const buffer = getArrayBuffer( json, interleavedBuffer.buffer ); - this.isRenderOutput = true; + const array = getTypedArray( interleavedBuffer.type, buffer ); + const ib = new InterleavedBuffer( array, interleavedBuffer.stride ); + ib.uuid = interleavedBuffer.uuid; - } + interleavedBufferMap[ uuid ] = ib; - setup( { context } ) { + return ib; - let outputNode = this.colorNode || context.color; + } - // tone mapping + function getArrayBuffer( json, uuid ) { - const toneMapping = ( this.toneMapping !== null ? this.toneMapping : context.toneMapping ) || NoToneMapping; - const outputColorSpace = ( this.outputColorSpace !== null ? this.outputColorSpace : context.outputColorSpace ) || LinearSRGBColorSpace; + if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ]; - if ( toneMapping !== NoToneMapping ) { + const arrayBuffers = json.arrayBuffers; + const arrayBuffer = arrayBuffers[ uuid ]; - outputNode = outputNode.toneMapping( toneMapping ); + const ab = new Uint32Array( arrayBuffer ).buffer; - } + arrayBufferMap[ uuid ] = ab; - // output color space + return ab; - if ( outputColorSpace === SRGBColorSpace ) { + } - outputNode = outputNode.toOutputColorSpace( outputColorSpace ); + const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry(); - } + const index = json.data.index; - return outputNode; + if ( index !== undefined ) { - } + const typedArray = getTypedArray( index.type, index.array ); + geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); -} + } -RenderOutputNode.type = /*@__PURE__*/ registerNode( 'RenderOutput', RenderOutputNode ); + const attributes = json.data.attributes; -const renderOutput = ( color, toneMapping = null, outputColorSpace = null ) => nodeObject( new RenderOutputNode( nodeObject( color ), toneMapping, outputColorSpace ) ); + for ( const key in attributes ) { -addMethodChaining( 'renderOutput', renderOutput ); + const attribute = attributes[ key ]; + let bufferAttribute; -// Non-PURE exports list, side-effects are required here. -// TSL Base Syntax + if ( attribute.isInterleavedBufferAttribute ) { + const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); + bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); -function addNodeElement( name/*, nodeElement*/ ) { + } else { - console.warn( 'THREE.TSLBase: AddNodeElement has been removed in favor of tree-shaking. Trying add', name ); + const typedArray = getTypedArray( attribute.type, attribute.array ); + const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute; + bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized ); -} + } -class AttributeNode extends Node { + if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; + if ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage ); - constructor( attributeName, nodeType = null ) { + geometry.setAttribute( key, bufferAttribute ); - super( nodeType ); + } - this.global = true; + const morphAttributes = json.data.morphAttributes; - this._attributeName = attributeName; + if ( morphAttributes ) { - } + for ( const key in morphAttributes ) { - getHash( builder ) { + const attributeArray = morphAttributes[ key ]; - return this.getAttributeName( builder ); + const array = []; - } + for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { - getNodeType( builder ) { + const attribute = attributeArray[ i ]; + let bufferAttribute; - let nodeType = this.nodeType; + if ( attribute.isInterleavedBufferAttribute ) { - if ( nodeType === null ) { + const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); + bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); - const attributeName = this.getAttributeName( builder ); + } else { - if ( builder.hasGeometryAttribute( attributeName ) ) { + const typedArray = getTypedArray( attribute.type, attribute.array ); + bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ); - const attribute = builder.geometry.getAttribute( attributeName ); + } - nodeType = builder.getTypeFromAttribute( attribute ); + if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; + array.push( bufferAttribute ); - } else { + } - nodeType = 'float'; + geometry.morphAttributes[ key ] = array; } } - return nodeType; - - } - - setAttributeName( attributeName ) { - - this._attributeName = attributeName; + const morphTargetsRelative = json.data.morphTargetsRelative; - return this; + if ( morphTargetsRelative ) { - } + geometry.morphTargetsRelative = true; - getAttributeName( /*builder*/ ) { + } - return this._attributeName; + const groups = json.data.groups || json.data.drawcalls || json.data.offsets; - } + if ( groups !== undefined ) { - generate( builder ) { + for ( let i = 0, n = groups.length; i !== n; ++ i ) { - const attributeName = this.getAttributeName( builder ); - const nodeType = this.getNodeType( builder ); - const geometryAttribute = builder.hasGeometryAttribute( attributeName ); + const group = groups[ i ]; - if ( geometryAttribute === true ) { + geometry.addGroup( group.start, group.count, group.materialIndex ); - const attribute = builder.geometry.getAttribute( attributeName ); - const attributeType = builder.getTypeFromAttribute( attribute ); + } - const nodeAttribute = builder.getAttribute( attributeName, attributeType ); + } - if ( builder.shaderStage === 'vertex' ) { + const boundingSphere = json.data.boundingSphere; - return builder.format( nodeAttribute.name, attributeType, nodeType ); + if ( boundingSphere !== undefined ) { - } else { + const center = new Vector3(); - const nodeVarying = varying( this ); + if ( boundingSphere.center !== undefined ) { - return nodeVarying.build( builder, nodeType ); + center.fromArray( boundingSphere.center ); } - } else { + geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); - console.warn( `AttributeNode: Vertex attribute "${ attributeName }" not found on geometry.` ); + } - return builder.generateConst( nodeType ); + if ( json.name ) geometry.name = json.name; + if ( json.userData ) geometry.userData = json.userData; - } + return geometry; } - serialize( data ) { +} - super.serialize( data ); +class ObjectLoader extends Loader { - data.global = this.global; - data._attributeName = this._attributeName; + constructor( manager ) { - } + super( manager ); - deserialize( data ) { + } - super.deserialize( data ); + load( url, onLoad, onProgress, onError ) { - this.global = data.global; - this._attributeName = data._attributeName; + const scope = this; - } + const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; + this.resourcePath = this.resourcePath || path; -} + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( text ) { -AttributeNode.type = /*@__PURE__*/ registerNode( 'Attribute', AttributeNode ); + let json = null; -const attribute = ( name, nodeType ) => nodeObject( new AttributeNode( name, nodeType ) ); + try { -const uv = ( index ) => attribute( 'uv' + ( index > 0 ? index : '' ), 'vec2' ); + json = JSON.parse( text ); -class TextureSizeNode extends Node { + } catch ( error ) { - constructor( textureNode, levelNode = null ) { + if ( onError !== undefined ) onError( error ); - super( 'uvec2' ); + console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); - this.isTextureSizeNode = true; + return; - this.textureNode = textureNode; - this.levelNode = levelNode; + } - } + const metadata = json.metadata; - generate( builder, output ) { + if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - const textureProperty = this.textureNode.build( builder, 'property' ); - const levelNode = this.levelNode.build( builder, 'int' ); + if ( onError !== undefined ) onError( new Error( 'THREE.ObjectLoader: Can\'t load ' + url ) ); - return builder.format( `${ builder.getMethod( 'textureDimensions' ) }( ${ textureProperty }, ${ levelNode } )`, this.getNodeType( builder ), output ); + console.error( 'THREE.ObjectLoader: Can\'t load ' + url ); + return; - } + } -} + scope.parse( json, onLoad ); -TextureSizeNode.type = /*@__PURE__*/ registerNode( 'TextureSize', TextureSizeNode ); + }, onProgress, onError ); -const textureSize = /*@__PURE__*/ nodeProxy( TextureSizeNode ); + } -class MaxMipLevelNode extends UniformNode { + async loadAsync( url, onProgress ) { - constructor( textureNode ) { + const scope = this; - super( 0 ); + const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; + this.resourcePath = this.resourcePath || path; - this._textureNode = textureNode; + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); - this.updateType = NodeUpdateType.FRAME; + const text = await loader.loadAsync( url, onProgress ); - } + const json = JSON.parse( text ); - get textureNode() { + const metadata = json.metadata; - return this._textureNode; + if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - } + throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url ); - get texture() { + } - return this._textureNode.value; + return await scope.parseAsync( json ); } - update() { + parse( json, onLoad ) { - const texture = this.texture; - const images = texture.images; - const image = ( images && images.length > 0 ) ? ( ( images[ 0 ] && images[ 0 ].image ) || images[ 0 ] ) : texture.image; + const animations = this.parseAnimations( json.animations ); + const shapes = this.parseShapes( json.shapes ); + const geometries = this.parseGeometries( json.geometries, shapes ); - if ( image && image.width !== undefined ) { + const images = this.parseImages( json.images, function () { - const { width, height } = image; + if ( onLoad !== undefined ) onLoad( object ); - this.value = Math.log2( Math.max( width, height ) ); + } ); - } + const textures = this.parseTextures( json.textures, images ); + const materials = this.parseMaterials( json.materials, textures ); - } + const object = this.parseObject( json.object, geometries, materials, textures, animations ); + const skeletons = this.parseSkeletons( json.skeletons, object ); -} + this.bindSkeletons( object, skeletons ); + this.bindLightTargets( object ); -MaxMipLevelNode.type = /*@__PURE__*/ registerNode( 'MaxMipLevel', MaxMipLevelNode ); + // -const maxMipLevel = /*@__PURE__*/ nodeProxy( MaxMipLevelNode ); + if ( onLoad !== undefined ) { -class TextureNode extends UniformNode { + let hasImages = false; - constructor( value, uvNode = null, levelNode = null, biasNode = null ) { + for ( const uuid in images ) { - super( value ); + if ( images[ uuid ].data instanceof HTMLImageElement ) { - this.isTextureNode = true; + hasImages = true; + break; - this.uvNode = uvNode; - this.levelNode = levelNode; - this.biasNode = biasNode; - this.compareNode = null; - this.depthNode = null; - this.gradNode = null; + } - this.sampler = true; - this.updateMatrix = false; - this.updateType = NodeUpdateType.NONE; + } - this.referenceNode = null; + if ( hasImages === false ) onLoad( object ); - this._value = value; - this._matrixUniform = null; + } - this.setUpdateMatrix( uvNode === null ); + return object; } - set value( value ) { + async parseAsync( json ) { - if ( this.referenceNode ) { + const animations = this.parseAnimations( json.animations ); + const shapes = this.parseShapes( json.shapes ); + const geometries = this.parseGeometries( json.geometries, shapes ); - this.referenceNode.value = value; + const images = await this.parseImagesAsync( json.images ); - } else { + const textures = this.parseTextures( json.textures, images ); + const materials = this.parseMaterials( json.materials, textures ); - this._value = value; + const object = this.parseObject( json.object, geometries, materials, textures, animations ); + const skeletons = this.parseSkeletons( json.skeletons, object ); - } + this.bindSkeletons( object, skeletons ); + this.bindLightTargets( object ); + + return object; } - get value() { + parseShapes( json ) { - return this.referenceNode ? this.referenceNode.value : this._value; + const shapes = {}; - } + if ( json !== undefined ) { - getUniformHash( /*builder*/ ) { + for ( let i = 0, l = json.length; i < l; i ++ ) { - return this.value.uuid; + const shape = new Shape().fromJSON( json[ i ] ); - } + shapes[ shape.uuid ] = shape; - getNodeType( /*builder*/ ) { + } - if ( this.value.isDepthTexture === true ) return 'float'; + } - if ( this.value.type === UnsignedIntType ) { + return shapes; - return 'uvec4'; + } - } else if ( this.value.type === IntType ) { + parseSkeletons( json, object ) { - return 'ivec4'; + const skeletons = {}; + const bones = {}; - } + // generate bone lookup table - return 'vec4'; + object.traverse( function ( child ) { - } + if ( child.isBone ) bones[ child.uuid ] = child; - getInputType( /*builder*/ ) { + } ); - return 'texture'; + // create skeletons - } + if ( json !== undefined ) { - getDefaultUV() { + for ( let i = 0, l = json.length; i < l; i ++ ) { - return uv( this.value.channel ); + const skeleton = new Skeleton().fromJSON( json[ i ], bones ); - } + skeletons[ skeleton.uuid ] = skeleton; - updateReference( /*state*/ ) { + } - return this.value; + } - } + return skeletons; - getTransformedUV( uvNode ) { + } - if ( this._matrixUniform === null ) this._matrixUniform = uniform( this.value.matrix ); + parseGeometries( json, shapes ) { - return this._matrixUniform.mul( vec3( uvNode, 1 ) ).xy; + const geometries = {}; - } + if ( json !== undefined ) { - setUpdateMatrix( value ) { + const bufferGeometryLoader = new BufferGeometryLoader(); - this.updateMatrix = value; - this.updateType = value ? NodeUpdateType.FRAME : NodeUpdateType.NONE; + for ( let i = 0, l = json.length; i < l; i ++ ) { - return this; + let geometry; + const data = json[ i ]; - } + switch ( data.type ) { - setupUV( builder, uvNode ) { + case 'BufferGeometry': + case 'InstancedBufferGeometry': - const texture = this.value; + geometry = bufferGeometryLoader.parse( data ); + break; - if ( builder.isFlipY() && ( texture.isRenderTargetTexture === true || texture.isFramebufferTexture === true || texture.isDepthTexture === true ) ) { + default: - uvNode = uvNode.setY( uvNode.y.oneMinus() ); + if ( data.type in Geometries$1 ) { - } + geometry = Geometries$1[ data.type ].fromJSON( data, shapes ); - return uvNode; + } else { - } + console.warn( `THREE.ObjectLoader: Unsupported geometry type "${ data.type }"` ); - setup( builder ) { + } - const properties = builder.getNodeProperties( this ); - properties.referenceNode = this.referenceNode; + } - // + geometry.uuid = data.uuid; - let uvNode = this.uvNode; + if ( data.name !== undefined ) geometry.name = data.name; + if ( data.userData !== undefined ) geometry.userData = data.userData; - if ( ( uvNode === null || builder.context.forceUVContext === true ) && builder.context.getUV ) { + geometries[ data.uuid ] = geometry; - uvNode = builder.context.getUV( this ); + } } - if ( ! uvNode ) uvNode = this.getDefaultUV(); + return geometries; - if ( this.updateMatrix === true ) { + } - uvNode = this.getTransformedUV( uvNode ); + parseMaterials( json, textures ) { - } + const cache = {}; // MultiMaterial + const materials = {}; - uvNode = this.setupUV( builder, uvNode ); + if ( json !== undefined ) { - // + const loader = new MaterialLoader(); + loader.setTextures( textures ); - let levelNode = this.levelNode; + for ( let i = 0, l = json.length; i < l; i ++ ) { - if ( levelNode === null && builder.context.getTextureLevel ) { + const data = json[ i ]; - levelNode = builder.context.getTextureLevel( this ); + if ( cache[ data.uuid ] === undefined ) { - } + cache[ data.uuid ] = loader.parse( data ); - // + } - properties.uvNode = uvNode; - properties.levelNode = levelNode; - properties.biasNode = this.biasNode; - properties.compareNode = this.compareNode; - properties.gradNode = this.gradNode; - properties.depthNode = this.depthNode; + materials[ data.uuid ] = cache[ data.uuid ]; - } + } - generateUV( builder, uvNode ) { + } - return uvNode.build( builder, this.sampler === true ? 'vec2' : 'ivec2' ); + return materials; } - generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet ) { - - const texture = this.value; - - let snippet; + parseAnimations( json ) { - if ( levelSnippet ) { + const animations = {}; - snippet = builder.generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet ); + if ( json !== undefined ) { - } else if ( biasSnippet ) { + for ( let i = 0; i < json.length; i ++ ) { - snippet = builder.generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet ); + const data = json[ i ]; - } else if ( gradSnippet ) { + const clip = AnimationClip.parse( data ); - snippet = builder.generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet ); + animations[ clip.uuid ] = clip; - } else if ( compareSnippet ) { + } - snippet = builder.generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet ); + } - } else if ( this.sampler === false ) { + return animations; - snippet = builder.generateTextureLoad( texture, textureProperty, uvSnippet, depthSnippet ); + } - } else { + parseImages( json, onLoad ) { - snippet = builder.generateTexture( texture, textureProperty, uvSnippet, depthSnippet ); + const scope = this; + const images = {}; - } + let loader; - return snippet; + function loadImage( url ) { - } + scope.manager.itemStart( url ); - generate( builder, output ) { + return loader.load( url, function () { - const properties = builder.getNodeProperties( this ); + scope.manager.itemEnd( url ); - const texture = this.value; + }, undefined, function () { - if ( ! texture || texture.isTexture !== true ) { + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - throw new Error( 'TextureNode: Need a three.js texture.' ); + } ); } - const textureProperty = super.generate( builder, 'property' ); - - if ( output === 'sampler' ) { + function deserializeImage( image ) { - return textureProperty + '_sampler'; + if ( typeof image === 'string' ) { - } else if ( builder.isReference( output ) ) { + const url = image; - return textureProperty; + const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; - } else { + return loadImage( path ); - const nodeData = builder.getDataFromNode( this ); + } else { - let propertyName = nodeData.propertyName; + if ( image.data ) { - if ( propertyName === undefined ) { + return { + data: getTypedArray( image.type, image.data ), + width: image.width, + height: image.height + }; - const { uvNode, levelNode, biasNode, compareNode, depthNode, gradNode } = properties; + } else { - const uvSnippet = this.generateUV( builder, uvNode ); - const levelSnippet = levelNode ? levelNode.build( builder, 'float' ) : null; - const biasSnippet = biasNode ? biasNode.build( builder, 'float' ) : null; - const depthSnippet = depthNode ? depthNode.build( builder, 'int' ) : null; - const compareSnippet = compareNode ? compareNode.build( builder, 'float' ) : null; - const gradSnippet = gradNode ? [ gradNode[ 0 ].build( builder, 'vec2' ), gradNode[ 1 ].build( builder, 'vec2' ) ] : null; + return null; - const nodeVar = builder.getVarFromNode( this ); + } - propertyName = builder.getPropertyName( nodeVar ); + } - const snippet = this.generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet ); + } - builder.addLineFlowCode( `${propertyName} = ${snippet}` ); + if ( json !== undefined && json.length > 0 ) { - nodeData.snippet = snippet; - nodeData.propertyName = propertyName; + const manager = new LoadingManager( onLoad ); - } + loader = new ImageLoader( manager ); + loader.setCrossOrigin( this.crossOrigin ); - let snippet = propertyName; - const nodeType = this.getNodeType( builder ); + for ( let i = 0, il = json.length; i < il; i ++ ) { - if ( builder.needsToWorkingColorSpace( texture ) ) { + const image = json[ i ]; + const url = image.url; - snippet = toWorkingColorSpace( expression( snippet, nodeType ), texture.colorSpace ).setup( builder ).build( builder, nodeType ); + if ( Array.isArray( url ) ) { - } + // load array of images e.g CubeTexture - return builder.format( snippet, nodeType, output ); + const imageArray = []; - } + for ( let j = 0, jl = url.length; j < jl; j ++ ) { - } + const currentUrl = url[ j ]; - setSampler( value ) { + const deserializedImage = deserializeImage( currentUrl ); - this.sampler = value; + if ( deserializedImage !== null ) { - return this; + if ( deserializedImage instanceof HTMLImageElement ) { - } + imageArray.push( deserializedImage ); - getSampler() { + } else { - return this.sampler; + // special case: handle array of data textures for cube textures - } + imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); - // @TODO: Move to TSL + } - uv( uvNode ) { + } - const textureNode = this.clone(); - textureNode.uvNode = nodeObject( uvNode ); - textureNode.referenceNode = this.getSelf(); + } - return nodeObject( textureNode ); + images[ image.uuid ] = new Source( imageArray ); - } + } else { - blur( amountNode ) { + // load single image - const textureNode = this.clone(); - textureNode.biasNode = nodeObject( amountNode ).mul( maxMipLevel( textureNode ) ); - textureNode.referenceNode = this.getSelf(); + const deserializedImage = deserializeImage( image.url ); + images[ image.uuid ] = new Source( deserializedImage ); - return nodeObject( textureNode ); - } + } - level( levelNode ) { + } - const textureNode = this.clone(); - textureNode.levelNode = nodeObject( levelNode ); - textureNode.referenceNode = this.getSelf(); + } - return nodeObject( textureNode ); + return images; } - size( levelNode ) { + async parseImagesAsync( json ) { - return textureSize( this, levelNode ); + const scope = this; + const images = {}; - } + let loader; - bias( biasNode ) { + async function deserializeImage( image ) { - const textureNode = this.clone(); - textureNode.biasNode = nodeObject( biasNode ); - textureNode.referenceNode = this.getSelf(); + if ( typeof image === 'string' ) { - return nodeObject( textureNode ); + const url = image; - } + const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; - compare( compareNode ) { + return await loader.loadAsync( path ); - const textureNode = this.clone(); - textureNode.compareNode = nodeObject( compareNode ); - textureNode.referenceNode = this.getSelf(); + } else { - return nodeObject( textureNode ); + if ( image.data ) { - } + return { + data: getTypedArray( image.type, image.data ), + width: image.width, + height: image.height + }; - grad( gradNodeX, gradNodeY ) { + } else { - const textureNode = this.clone(); - textureNode.gradNode = [ nodeObject( gradNodeX ), nodeObject( gradNodeY ) ]; - textureNode.referenceNode = this.getSelf(); + return null; - return nodeObject( textureNode ); + } - } + } - depth( depthNode ) { + } - const textureNode = this.clone(); - textureNode.depthNode = nodeObject( depthNode ); - textureNode.referenceNode = this.getSelf(); + if ( json !== undefined && json.length > 0 ) { - return nodeObject( textureNode ); + loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); - } + for ( let i = 0, il = json.length; i < il; i ++ ) { - // -- + const image = json[ i ]; + const url = image.url; - serialize( data ) { + if ( Array.isArray( url ) ) { - super.serialize( data ); + // load array of images e.g CubeTexture - data.value = this.value.toJSON( data.meta ).uuid; - data.sampler = this.sampler; - data.updateMatrix = this.updateMatrix; - data.updateType = this.updateType; + const imageArray = []; - } + for ( let j = 0, jl = url.length; j < jl; j ++ ) { - deserialize( data ) { + const currentUrl = url[ j ]; - super.deserialize( data ); + const deserializedImage = await deserializeImage( currentUrl ); - this.value = data.meta.textures[ data.value ]; - this.sampler = data.sampler; - this.updateMatrix = data.updateMatrix; - this.updateType = data.updateType; + if ( deserializedImage !== null ) { - } + if ( deserializedImage instanceof HTMLImageElement ) { - update() { + imageArray.push( deserializedImage ); - const texture = this.value; - const matrixUniform = this._matrixUniform; + } else { - if ( matrixUniform !== null ) matrixUniform.value = texture.matrix; + // special case: handle array of data textures for cube textures - if ( texture.matrixAutoUpdate === true ) { + imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); - texture.updateMatrix(); + } - } + } - } + } - clone() { + images[ image.uuid ] = new Source( imageArray ); - const newNode = new this.constructor( this.value, this.uvNode, this.levelNode, this.biasNode ); - newNode.sampler = this.sampler; + } else { - return newNode; + // load single image - } + const deserializedImage = await deserializeImage( image.url ); + images[ image.uuid ] = new Source( deserializedImage ); -} + } -TextureNode.type = /*@__PURE__*/ registerNode( 'Texture', TextureNode ); + } -const texture = /*@__PURE__*/ nodeProxy( TextureNode ); -const textureLoad = ( ...params ) => texture( ...params ).setSampler( false ); + } -//export const textureLevel = ( value, uv, level ) => texture( value, uv ).level( level ); + return images; -const sampler = ( aTexture ) => ( aTexture.isNode === true ? aTexture : texture( aTexture ) ).convert( 'sampler' ); + } -const cameraGroup = /*@__PURE__*/ sharedUniformGroup( 'camera' ).onRenderUpdate( () => { + parseTextures( json, images ) { - cameraGroup.needsUpdate = true; + function parseConstant( value, type ) { -} ); + if ( typeof value === 'number' ) return value; -const cameraNear = /*@__PURE__*/ uniform( 'float' ).label( 'cameraNear' ).setGroup( cameraGroup ).onRenderUpdate( ( { camera } ) => camera.near ); -const cameraFar = /*@__PURE__*/ uniform( 'float' ).label( 'cameraFar' ).setGroup( cameraGroup ).onRenderUpdate( ( { camera } ) => camera.far ); -const cameraLogDepth = /*@__PURE__*/ uniform( 'float' ).label( 'cameraLogDepth' ).setGroup( cameraGroup ).onRenderUpdate( ( { camera } ) => 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); -const cameraProjectionMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraProjectionMatrix' ).setGroup( cameraGroup ).onRenderUpdate( ( { camera } ) => camera.projectionMatrix ); -const cameraProjectionMatrixInverse = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraProjectionMatrixInverse' ).setGroup( cameraGroup ).onRenderUpdate( ( { camera } ) => camera.projectionMatrixInverse ); -const cameraViewMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraViewMatrix' ).setGroup( cameraGroup ).onRenderUpdate( ( { camera } ) => camera.matrixWorldInverse ); -const cameraWorldMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraWorldMatrix' ).setGroup( cameraGroup ).onRenderUpdate( ( { camera } ) => camera.matrixWorld ); -const cameraNormalMatrix = /*@__PURE__*/ uniform( 'mat3' ).label( 'cameraNormalMatrix' ).setGroup( cameraGroup ).onRenderUpdate( ( { camera } ) => camera.normalMatrix ); -const cameraPosition = /*@__PURE__*/ uniform( new Vector3() ).label( 'cameraPosition' ).setGroup( cameraGroup ).onRenderUpdate( ( { camera }, self ) => self.value.setFromMatrixPosition( camera.matrixWorld ) ); + console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); -class Object3DNode extends Node { + return type[ value ]; - constructor( scope = Object3DNode.VIEW_MATRIX, object3d = null ) { + } - super(); + const textures = {}; - this.scope = scope; - this.object3d = object3d; + if ( json !== undefined ) { - this.updateType = NodeUpdateType.OBJECT; + for ( let i = 0, l = json.length; i < l; i ++ ) { - this._uniformNode = new UniformNode( null ); + const data = json[ i ]; - } + if ( data.image === undefined ) { - getNodeType() { + console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); - const scope = this.scope; + } - if ( scope === Object3DNode.WORLD_MATRIX || scope === Object3DNode.VIEW_MATRIX ) { + if ( images[ data.image ] === undefined ) { - return 'mat4'; + console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); - } else if ( scope === Object3DNode.NORMAL_MATRIX ) { + } - return 'mat3'; + const source = images[ data.image ]; + const image = source.data; - } else if ( scope === Object3DNode.POSITION || scope === Object3DNode.VIEW_POSITION || scope === Object3DNode.DIRECTION || scope === Object3DNode.SCALE ) { + let texture; - return 'vec3'; + if ( Array.isArray( image ) ) { - } + texture = new CubeTexture(); - } + if ( image.length === 6 ) texture.needsUpdate = true; - update( frame ) { + } else { - const object = this.object3d; - const uniformNode = this._uniformNode; - const scope = this.scope; + if ( image && image.data ) { - if ( scope === Object3DNode.VIEW_MATRIX ) { + texture = new DataTexture(); - uniformNode.value = object.modelViewMatrix; + } else { - } else if ( scope === Object3DNode.NORMAL_MATRIX ) { + texture = new Texture(); - uniformNode.value = object.normalMatrix; + } - } else if ( scope === Object3DNode.WORLD_MATRIX ) { + if ( image ) texture.needsUpdate = true; // textures can have undefined image data - uniformNode.value = object.matrixWorld; + } - } else if ( scope === Object3DNode.POSITION ) { + texture.source = source; - uniformNode.value = uniformNode.value || new Vector3(); + texture.uuid = data.uuid; - uniformNode.value.setFromMatrixPosition( object.matrixWorld ); + if ( data.name !== undefined ) texture.name = data.name; - } else if ( scope === Object3DNode.SCALE ) { + if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); + if ( data.channel !== undefined ) texture.channel = data.channel; - uniformNode.value = uniformNode.value || new Vector3(); + if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); + if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); + if ( data.center !== undefined ) texture.center.fromArray( data.center ); + if ( data.rotation !== undefined ) texture.rotation = data.rotation; - uniformNode.value.setFromMatrixScale( object.matrixWorld ); + if ( data.wrap !== undefined ) { - } else if ( scope === Object3DNode.DIRECTION ) { + texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); + texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); - uniformNode.value = uniformNode.value || new Vector3(); + } - object.getWorldDirection( uniformNode.value ); + if ( data.format !== undefined ) texture.format = data.format; + if ( data.internalFormat !== undefined ) texture.internalFormat = data.internalFormat; + if ( data.type !== undefined ) texture.type = data.type; + if ( data.colorSpace !== undefined ) texture.colorSpace = data.colorSpace; - } else if ( scope === Object3DNode.VIEW_POSITION ) { + if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); + if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); + if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; - const camera = frame.camera; + if ( data.flipY !== undefined ) texture.flipY = data.flipY; - uniformNode.value = uniformNode.value || new Vector3(); - uniformNode.value.setFromMatrixPosition( object.matrixWorld ); + if ( data.generateMipmaps !== undefined ) texture.generateMipmaps = data.generateMipmaps; + if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha; + if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment; + if ( data.compareFunction !== undefined ) texture.compareFunction = data.compareFunction; - uniformNode.value.applyMatrix4( camera.matrixWorldInverse ); + if ( data.userData !== undefined ) texture.userData = data.userData; + + textures[ data.uuid ] = texture; + + } } - } + return textures; - generate( builder ) { + } - const scope = this.scope; + parseObject( data, geometries, materials, textures, animations ) { - if ( scope === Object3DNode.WORLD_MATRIX || scope === Object3DNode.VIEW_MATRIX ) { + let object; - this._uniformNode.nodeType = 'mat4'; + function getGeometry( name ) { - } else if ( scope === Object3DNode.NORMAL_MATRIX ) { + if ( geometries[ name ] === undefined ) { - this._uniformNode.nodeType = 'mat3'; + console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); - } else if ( scope === Object3DNode.POSITION || scope === Object3DNode.VIEW_POSITION || scope === Object3DNode.DIRECTION || scope === Object3DNode.SCALE ) { + } - this._uniformNode.nodeType = 'vec3'; + return geometries[ name ]; } - return this._uniformNode.build( builder ); + function getMaterial( name ) { - } + if ( name === undefined ) return undefined; - serialize( data ) { + if ( Array.isArray( name ) ) { - super.serialize( data ); + const array = []; - data.scope = this.scope; + for ( let i = 0, l = name.length; i < l; i ++ ) { - } + const uuid = name[ i ]; - deserialize( data ) { + if ( materials[ uuid ] === undefined ) { - super.deserialize( data ); + console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); - this.scope = data.scope; + } - } + array.push( materials[ uuid ] ); -} + } -Object3DNode.VIEW_MATRIX = 'viewMatrix'; -Object3DNode.NORMAL_MATRIX = 'normalMatrix'; -Object3DNode.WORLD_MATRIX = 'worldMatrix'; -Object3DNode.POSITION = 'position'; -Object3DNode.SCALE = 'scale'; -Object3DNode.VIEW_POSITION = 'viewPosition'; -Object3DNode.DIRECTION = 'direction'; + return array; -Object3DNode.type = /*@__PURE__*/ registerNode( 'Object3D', Object3DNode ); + } -const objectDirection = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.DIRECTION ); -const objectViewMatrix = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.VIEW_MATRIX ); -const objectNormalMatrix = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.NORMAL_MATRIX ); -const objectWorldMatrix = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.WORLD_MATRIX ); -const objectPosition = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.POSITION ); -const objectScale = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.SCALE ); -const objectViewPosition = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.VIEW_POSITION ); + if ( materials[ name ] === undefined ) { -class ModelNode extends Object3DNode { + console.warn( 'THREE.ObjectLoader: Undefined material', name ); - constructor( scope = ModelNode.VIEW_MATRIX ) { + } - super( scope ); + return materials[ name ]; - } + } - update( frame ) { + function getTexture( uuid ) { - this.object3d = frame.object; + if ( textures[ uuid ] === undefined ) { - super.update( frame ); + console.warn( 'THREE.ObjectLoader: Undefined texture', uuid ); - } + } -} + return textures[ uuid ]; -ModelNode.type = /*@__PURE__*/ registerNode( 'Model', ModelNode ); + } -const modelDirection = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.DIRECTION ); -const modelViewMatrix = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.VIEW_MATRIX ).label( 'modelViewMatrix' ).toVar( 'ModelViewMatrix' ); -const modelNormalMatrix = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.NORMAL_MATRIX ); -const modelWorldMatrix = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.WORLD_MATRIX ); -const modelPosition = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.POSITION ); -const modelScale = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.SCALE ); -const modelViewPosition = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.VIEW_POSITION ); -const modelWorldMatrixInverse = /*@__PURE__*/ uniform( new Matrix4() ).onObjectUpdate( ( { object }, self ) => self.value.copy( object.matrixWorld ).invert() ); + let geometry, material; -const positionGeometry = /*@__PURE__*/ attribute( 'position', 'vec3' ); -const positionLocal = /*@__PURE__*/ positionGeometry.varying( 'positionLocal' ); -const positionPrevious = /*@__PURE__*/ positionGeometry.varying( 'positionPrevious' ); -const positionWorld = /*@__PURE__*/ modelWorldMatrix.mul( positionLocal ).xyz.varying( 'v_positionWorld' ); -const positionWorldDirection = /*@__PURE__*/ positionLocal.transformDirection( modelWorldMatrix ).varying( 'v_positionWorldDirection' ).normalize().toVar( 'positionWorldDirection' ); -const positionView = /*@__PURE__*/ modelViewMatrix.mul( positionLocal ).xyz.varying( 'v_positionView' ); -const positionViewDirection = /*@__PURE__*/ positionView.negate().varying( 'v_positionViewDirection' ).normalize().toVar( 'positionViewDirection' ); + switch ( data.type ) { -class FrontFacingNode extends Node { + case 'Scene': - constructor() { + object = new Scene(); - super( 'bool' ); + if ( data.background !== undefined ) { - this.isFrontFacingNode = true; + if ( Number.isInteger( data.background ) ) { - } + object.background = new Color( data.background ); - generate( builder ) { + } else { - const { renderer, material } = builder; + object.background = getTexture( data.background ); - if ( renderer.coordinateSystem === WebGLCoordinateSystem ) { + } - if ( material.side === BackSide ) { + } - return 'false'; + if ( data.environment !== undefined ) { - } + object.environment = getTexture( data.environment ); - } + } - return builder.getFrontFacing(); + if ( data.fog !== undefined ) { - } + if ( data.fog.type === 'Fog' ) { -} + object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); -FrontFacingNode.type = /*@__PURE__*/ registerNode( 'FrontFacing', FrontFacingNode ); + } else if ( data.fog.type === 'FogExp2' ) { -const frontFacing = /*@__PURE__*/ nodeImmutable( FrontFacingNode ); -const faceDirection = /*@__PURE__*/ float( frontFacing ).mul( 2.0 ).sub( 1.0 ); + object.fog = new FogExp2( data.fog.color, data.fog.density ); -const normalGeometry = /*@__PURE__*/ attribute( 'normal', 'vec3' ); + } -const normalLocal = /*@__PURE__*/ ( Fn( ( builder ) => { + if ( data.fog.name !== '' ) { - if ( builder.geometry.hasAttribute( 'normal' ) === false ) { + object.fog.name = data.fog.name; - console.warn( 'TSL.NormalNode: Vertex attribute "normal" not found on geometry.' ); + } - return vec3( 0, 1, 0 ); + } - } + if ( data.backgroundBlurriness !== undefined ) object.backgroundBlurriness = data.backgroundBlurriness; + if ( data.backgroundIntensity !== undefined ) object.backgroundIntensity = data.backgroundIntensity; + if ( data.backgroundRotation !== undefined ) object.backgroundRotation.fromArray( data.backgroundRotation ); - return normalGeometry; + if ( data.environmentIntensity !== undefined ) object.environmentIntensity = data.environmentIntensity; + if ( data.environmentRotation !== undefined ) object.environmentRotation.fromArray( data.environmentRotation ); -}, 'vec3' ).once() )().toVar( 'normalLocal' ); + break; -const normalFlat = /*@__PURE__*/ positionView.dFdx().cross( positionView.dFdy() ).normalize().toVar( 'normalFlat' ); + case 'PerspectiveCamera': -let normalViewVarying = null; + object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); -const normalView = /*@__PURE__*/ ( Fn( ( builder ) => { + if ( data.focus !== undefined ) object.focus = data.focus; + if ( data.zoom !== undefined ) object.zoom = data.zoom; + if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; + if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; + if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); - let node; + break; - if ( builder.material.flatShading === true ) { + case 'OrthographicCamera': - node = normalFlat; + object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); - } else { + if ( data.zoom !== undefined ) object.zoom = data.zoom; + if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); - node = normalViewVarying || ( normalViewVarying = varying( modelNormalMatrix.mul( normalLocal ), 'v_normalView' ).normalize() ); + break; - } + case 'AmbientLight': - return node; + object = new AmbientLight( data.color, data.intensity ); -}, 'vec3' ).once() )().toVar( 'normalView' ); + break; -const normalWorld = /*@__PURE__*/ varying( normalView.transformDirection( cameraViewMatrix ), 'v_normalWorld' ).normalize().toVar( 'normalWorld' ); + case 'DirectionalLight': -const transformedNormalView = /*@__PURE__*/ ( Fn( ( builder ) => { + object = new DirectionalLight( data.color, data.intensity ); + object.target = data.target || ''; - return builder.context.setupNormal(); + break; -}, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedNormalView' ); + case 'PointLight': + object = new PointLight( data.color, data.intensity, data.distance, data.decay ); -const transformedNormalWorld = /*@__PURE__*/ transformedNormalView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedNormalWorld' ); + break; -const transformedClearcoatNormalView = /*@__PURE__*/ ( Fn( ( builder ) => { + case 'RectAreaLight': - return builder.context.setupClearcoatNormal(); + object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); -}, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedClearcoatNormalView' ); + break; -const materialRefractionRatio = /*@__PURE__*/ uniform( 0 ).onReference( ( { material } ) => material ).onRenderUpdate( ( { material } ) => material.refractionRatio ); + case 'SpotLight': -const reflectView = /*@__PURE__*/ positionViewDirection.negate().reflect( transformedNormalView ); -const refractView = /*@__PURE__*/ positionViewDirection.negate().refract( transformedNormalView, materialRefractionRatio ); + object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); + object.target = data.target || ''; -const reflectVector = /*@__PURE__*/ reflectView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' ); -const refractVector = /*@__PURE__*/ refractView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' ); + break; -class CubeTextureNode extends TextureNode { + case 'HemisphereLight': - constructor( value, uvNode = null, levelNode = null, biasNode = null ) { + object = new HemisphereLight( data.color, data.groundColor, data.intensity ); - super( value, uvNode, levelNode, biasNode ); + break; - this.isCubeTextureNode = true; + case 'LightProbe': - } + object = new LightProbe().fromJSON( data ); - getInputType( /*builder*/ ) { + break; - return 'cubeTexture'; + case 'SkinnedMesh': - } + geometry = getGeometry( data.geometry ); + material = getMaterial( data.material ); - getDefaultUV() { + object = new SkinnedMesh( geometry, material ); - const texture = this.value; + if ( data.bindMode !== undefined ) object.bindMode = data.bindMode; + if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix ); + if ( data.skeleton !== undefined ) object.skeleton = data.skeleton; - if ( texture.mapping === CubeReflectionMapping ) { + break; - return reflectVector; + case 'Mesh': - } else if ( texture.mapping === CubeRefractionMapping ) { + geometry = getGeometry( data.geometry ); + material = getMaterial( data.material ); - return refractVector; + object = new Mesh( geometry, material ); - } else { + break; - console.error( 'THREE.CubeTextureNode: Mapping "%s" not supported.', texture.mapping ); + case 'InstancedMesh': - return vec3( 0, 0, 0 ); + geometry = getGeometry( data.geometry ); + material = getMaterial( data.material ); + const count = data.count; + const instanceMatrix = data.instanceMatrix; + const instanceColor = data.instanceColor; - } + object = new InstancedMesh( geometry, material, count ); + object.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 ); + if ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize ); - } + break; - setUpdateMatrix( /*updateMatrix*/ ) { } // Ignore .updateMatrix for CubeTextureNode + case 'BatchedMesh': - setupUV( builder, uvNode ) { + geometry = getGeometry( data.geometry ); + material = getMaterial( data.material ); - const texture = this.value; + object = new BatchedMesh( data.maxInstanceCount, data.maxVertexCount, data.maxIndexCount, material ); + object.geometry = geometry; + object.perObjectFrustumCulled = data.perObjectFrustumCulled; + object.sortObjects = data.sortObjects; - if ( builder.renderer.coordinateSystem === WebGPUCoordinateSystem || ! texture.isRenderTargetTexture ) { + object._drawRanges = data.drawRanges; + object._reservedRanges = data.reservedRanges; - return vec3( uvNode.x.negate(), uvNode.yz ); + object._visibility = data.visibility; + object._active = data.active; + object._bounds = data.bounds.map( bound => { - } else { + const box = new Box3(); + box.min.fromArray( bound.boxMin ); + box.max.fromArray( bound.boxMax ); - return uvNode; + const sphere = new Sphere(); + sphere.radius = bound.sphereRadius; + sphere.center.fromArray( bound.sphereCenter ); - } + return { + boxInitialized: bound.boxInitialized, + box: box, - } + sphereInitialized: bound.sphereInitialized, + sphere: sphere + }; - generateUV( builder, cubeUV ) { + } ); - return cubeUV.build( builder, 'vec3' ); + object._maxInstanceCount = data.maxInstanceCount; + object._maxVertexCount = data.maxVertexCount; + object._maxIndexCount = data.maxIndexCount; - } + object._geometryInitialized = data.geometryInitialized; + object._geometryCount = data.geometryCount; -} + object._matricesTexture = getTexture( data.matricesTexture.uuid ); + if ( data.colorsTexture !== undefined ) object._colorsTexture = getTexture( data.colorsTexture.uuid ); -CubeTextureNode.type = /*@__PURE__*/ registerNode( 'CubeTexture', CubeTextureNode ); + break; -const cubeTexture = /*@__PURE__*/ nodeProxy( CubeTextureNode ); + case 'LOD': -class BufferNode extends UniformNode { + object = new LOD(); - constructor( value, bufferType, bufferCount = 0 ) { + break; - super( value, bufferType ); + case 'Line': - this.isBufferNode = true; + object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) ); - this.bufferType = bufferType; - this.bufferCount = bufferCount; + break; - } + case 'LineLoop': - getElementType( builder ) { + object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); - return this.getNodeType( builder ); + break; - } + case 'LineSegments': - getInputType( /*builder*/ ) { + object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); - return 'buffer'; + break; - } + case 'PointCloud': + case 'Points': -} + object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); -BufferNode.type = /*@__PURE__*/ registerNode( 'Buffer', BufferNode ); + break; -const buffer = ( value, type, count ) => nodeObject( new BufferNode( value, type, count ) ); + case 'Sprite': -class UniformArrayElementNode extends ArrayElementNode { + object = new Sprite( getMaterial( data.material ) ); - constructor( arrayBuffer, indexNode ) { + break; - super( arrayBuffer, indexNode ); + case 'Group': - this.isArrayBufferElementNode = true; + object = new Group(); - } + break; - getNodeType( builder ) { + case 'Bone': - return this.node.getElementType( builder ); + object = new Bone(); - } + break; - generate( builder ) { + default: - const snippet = super.generate( builder ); - const type = this.getNodeType(); + object = new Object3D(); - return builder.format( snippet, 'vec4', type ); + } - } + object.uuid = data.uuid; -} + if ( data.name !== undefined ) object.name = data.name; -class UniformArrayNode extends BufferNode { + if ( data.matrix !== undefined ) { - constructor( value, elementType = null ) { + object.matrix.fromArray( data.matrix ); - super( null, 'vec4' ); + if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate; + if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale ); - this.array = value; - this.elementType = elementType; + } else { - this._elementType = null; - this._elementLength = 0; + if ( data.position !== undefined ) object.position.fromArray( data.position ); + if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); + if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); + if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); - this.updateType = NodeUpdateType.RENDER; + } - this.isArrayBufferNode = true; + if ( data.up !== undefined ) object.up.fromArray( data.up ); - } + if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; + if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; - getElementType() { + if ( data.shadow ) { - return this.elementType || this._elementType; + if ( data.shadow.intensity !== undefined ) object.shadow.intensity = data.shadow.intensity; + if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; + if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias; + if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; + if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); + if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); - } + } - getElementLength() { + if ( data.visible !== undefined ) object.visible = data.visible; + if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled; + if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder; + if ( data.userData !== undefined ) object.userData = data.userData; + if ( data.layers !== undefined ) object.layers.mask = data.layers; - return this._elementLength; + if ( data.children !== undefined ) { - } + const children = data.children; - update( /*frame*/ ) { + for ( let i = 0; i < children.length; i ++ ) { - const { array, value } = this; + object.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) ); - const elementLength = this.getElementLength(); - const elementType = this.getElementType(); + } - if ( elementLength === 1 ) { + } - for ( let i = 0; i < array.length; i ++ ) { + if ( data.animations !== undefined ) { - const index = i * 4; + const objectAnimations = data.animations; - value[ index ] = array[ i ]; + for ( let i = 0; i < objectAnimations.length; i ++ ) { + + const uuid = objectAnimations[ i ]; + + object.animations.push( animations[ uuid ] ); } - } else if ( elementType === 'color' ) { + } - for ( let i = 0; i < array.length; i ++ ) { + if ( data.type === 'LOD' ) { - const index = i * 4; - const vector = array[ i ]; + if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate; - value[ index ] = vector.r; - value[ index + 1 ] = vector.g; - value[ index + 2 ] = vector.b || 0; - //value[ index + 3 ] = vector.a || 0; + const levels = data.levels; - } + for ( let l = 0; l < levels.length; l ++ ) { - } else { + const level = levels[ l ]; + const child = object.getObjectByProperty( 'uuid', level.object ); - for ( let i = 0; i < array.length; i ++ ) { + if ( child !== undefined ) { - const index = i * 4; - const vector = array[ i ]; + object.addLevel( child, level.distance, level.hysteresis ); - value[ index ] = vector.x; - value[ index + 1 ] = vector.y; - value[ index + 2 ] = vector.z || 0; - value[ index + 3 ] = vector.w || 0; + } } } - } + return object; - setup( builder ) { + } - const length = this.array.length; + bindSkeletons( object, skeletons ) { - this._elementType = this.elementType === null ? getValueType( this.array[ 0 ] ) : this.elementType; - this._elementLength = builder.getTypeLength( this._elementType ); + if ( Object.keys( skeletons ).length === 0 ) return; - let arrayType = Float32Array; + object.traverse( function ( child ) { - if ( this._elementType.charAt( 0 ) === 'i' ) arrayType = Int32Array; - else if ( this._elementType.charAt( 0 ) === 'u' ) arrayType = Uint32Array; + if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) { - this.value = new arrayType( length * 4 ); - this.bufferCount = length; - this.bufferType = builder.changeComponentType( 'vec4', builder.getComponentType( this._elementType ) ); + const skeleton = skeletons[ child.skeleton ]; - return super.setup( builder ); + if ( skeleton === undefined ) { - } + console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton ); - element( indexNode ) { + } else { - return nodeObject( new UniformArrayElementNode( this, nodeObject( indexNode ) ) ); + child.bind( skeleton, child.bindMatrix ); - } + } -} + } -UniformArrayNode.type = /*@__PURE__*/ registerNode( 'UniformArray', UniformArrayNode ); + } ); -const uniformArray = ( values, nodeType ) => nodeObject( new UniformArrayNode( values, nodeType ) ); + } -class ReferenceElementNode extends ArrayElementNode { + bindLightTargets( object ) { - constructor( referenceNode, indexNode ) { + object.traverse( function ( child ) { - super( referenceNode, indexNode ); + if ( child.isDirectionalLight || child.isSpotLight ) { - this.referenceNode = referenceNode; + const uuid = child.target; - this.isReferenceElementNode = true; + const target = object.getObjectByProperty( 'uuid', uuid ); - } + if ( target !== undefined ) { - getNodeType() { + child.target = target; - return this.referenceNode.uniformType; + } else { - } + child.target = new Object3D(); - generate( builder ) { + } - const snippet = super.generate( builder ); - const arrayType = this.referenceNode.getNodeType(); - const elementType = this.getNodeType(); + } - return builder.format( snippet, arrayType, elementType ); + } ); } } -// TODO: Extends this from ReferenceBaseNode -class ReferenceNode extends Node { +const TEXTURE_MAPPING = { + UVMapping: UVMapping, + CubeReflectionMapping: CubeReflectionMapping, + CubeRefractionMapping: CubeRefractionMapping, + EquirectangularReflectionMapping: EquirectangularReflectionMapping, + EquirectangularRefractionMapping: EquirectangularRefractionMapping, + CubeUVReflectionMapping: CubeUVReflectionMapping +}; - constructor( property, uniformType, object = null, count = null ) { +const TEXTURE_WRAPPING = { + RepeatWrapping: RepeatWrapping, + ClampToEdgeWrapping: ClampToEdgeWrapping, + MirroredRepeatWrapping: MirroredRepeatWrapping +}; - super(); +const TEXTURE_FILTER = { + NearestFilter: NearestFilter, + NearestMipmapNearestFilter: NearestMipmapNearestFilter, + NearestMipmapLinearFilter: NearestMipmapLinearFilter, + LinearFilter: LinearFilter, + LinearMipmapNearestFilter: LinearMipmapNearestFilter, + LinearMipmapLinearFilter: LinearMipmapLinearFilter +}; - this.property = property; - this.uniformType = uniformType; - this.object = object; - this.count = count; +class ImageBitmapLoader extends Loader { - this.properties = property.split( '.' ); - this.reference = object; - this.node = null; + constructor( manager ) { - this.updateType = NodeUpdateType.OBJECT; + super( manager ); - } + this.isImageBitmapLoader = true; - element( indexNode ) { + if ( typeof createImageBitmap === 'undefined' ) { - return nodeObject( new ReferenceElementNode( this, nodeObject( indexNode ) ) ); + console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); - } + } - setNodeType( uniformType ) { + if ( typeof fetch === 'undefined' ) { - let node = null; + console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); - if ( this.count !== null ) { + } - node = buffer( null, uniformType, this.count ); + this.options = { premultiplyAlpha: 'none' }; - } else if ( Array.isArray( this.getValueFromReference() ) ) { + } - node = uniformArray( null, uniformType ); + setOptions( options ) { - } else if ( uniformType === 'texture' ) { + this.options = options; - node = texture( null ); + return this; - } else if ( uniformType === 'cubeTexture' ) { + } - node = cubeTexture( null ); - - } else { + load( url, onLoad, onProgress, onError ) { - node = uniform( null, uniformType ); + if ( url === undefined ) url = ''; - } + if ( this.path !== undefined ) url = this.path + url; - this.node = node.getSelf(); + url = this.manager.resolveURL( url ); - } + const scope = this; - getNodeType( builder ) { + const cached = Cache.get( url ); - if ( this.node === null ) { + if ( cached !== undefined ) { - this.updateValue(); + scope.manager.itemStart( url ); - } + // If cached is a promise, wait for it to resolve + if ( cached.then ) { - return this.node.getNodeType( builder ); + cached.then( imageBitmap => { - } + if ( onLoad ) onLoad( imageBitmap ); - getValueFromReference( object = this.reference ) { + scope.manager.itemEnd( url ); - const { properties } = this; + } ).catch( e => { - let value = object[ properties[ 0 ] ]; + if ( onError ) onError( e ); - for ( let i = 1; i < properties.length; i ++ ) { + } ); + return; - value = value[ properties[ i ] ]; + } - } + // If cached is not a promise (i.e., it's already an imageBitmap) + setTimeout( function () { - return value; + if ( onLoad ) onLoad( cached ); - } + scope.manager.itemEnd( url ); - updateReference( state ) { + }, 0 ); - this.reference = this.object !== null ? this.object : state.object; + return cached; - return this.reference; + } - } + const fetchOptions = {}; + fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include'; + fetchOptions.headers = this.requestHeader; - setup() { + const promise = fetch( url, fetchOptions ).then( function ( res ) { - this.updateValue(); + return res.blob(); - return this.node; + } ).then( function ( blob ) { - } + return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) ); - update( /*frame*/ ) { + } ).then( function ( imageBitmap ) { - this.updateValue(); + Cache.add( url, imageBitmap ); - } + if ( onLoad ) onLoad( imageBitmap ); - updateValue() { + scope.manager.itemEnd( url ); - if ( this.node === null ) this.setNodeType( this.uniformType ); + return imageBitmap; - const value = this.getValueFromReference(); + } ).catch( function ( e ) { - if ( Array.isArray( value ) ) { + if ( onError ) onError( e ); - this.node.array = value; + Cache.remove( url ); - } else { + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - this.node.value = value; + } ); - } + Cache.add( url, promise ); + scope.manager.itemStart( url ); } } -ReferenceNode.type = /*@__PURE__*/ registerNode( 'Reference', ReferenceNode ); - -const reference = ( name, type, object ) => nodeObject( new ReferenceNode( name, type, object ) ); -const referenceBuffer = ( name, type, count, object ) => nodeObject( new ReferenceNode( name, type, object, count ) ); +let _context; -class MaterialReferenceNode extends ReferenceNode { +class AudioContext { - constructor( property, inputType, material = null ) { + static getContext() { - super( property, inputType, material ); + if ( _context === undefined ) { - this.material = material; + _context = new ( window.AudioContext || window.webkitAudioContext )(); - //this.updateType = NodeUpdateType.RENDER; + } - this.isMaterialReferenceNode = true; + return _context; } - /*setNodeType( node ) { - - super.setNodeType( node ); - - this.node.groupNode = renderGroup; - - }*/ - - updateReference( state ) { - - this.reference = this.material !== null ? this.material : state.material; + static setContext( value ) { - return this.reference; + _context = value; } } -MaterialReferenceNode.type = /*@__PURE__*/ registerNode( 'MaterialReference', MaterialReferenceNode ); +class AudioLoader extends Loader { -const materialReference = ( name, type, material ) => nodeObject( new MaterialReferenceNode( name, type, material ) ); + constructor( manager ) { -const tangentGeometry = /*@__PURE__*/ Fn( ( builder ) => { + super( manager ); - if ( builder.geometry.hasAttribute( 'tangent' ) === false ) { + } - builder.geometry.computeTangents(); + load( url, onLoad, onProgress, onError ) { - } + const scope = this; - return attribute( 'tangent', 'vec4' ); + const loader = new FileLoader( this.manager ); + loader.setResponseType( 'arraybuffer' ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( buffer ) { -} )(); + try { -const tangentLocal = /*@__PURE__*/ tangentGeometry.xyz.toVar( 'tangentLocal' ); -const tangentView = /*@__PURE__*/ modelViewMatrix.mul( vec4( tangentLocal, 0 ) ).xyz.varying( 'v_tangentView' ).normalize().toVar( 'tangentView' ); -const tangentWorld = /*@__PURE__*/ tangentView.transformDirection( cameraViewMatrix ).varying( 'v_tangentWorld' ).normalize().toVar( 'tangentWorld' ); -const transformedTangentView = /*@__PURE__*/ tangentView.toVar( 'transformedTangentView' ); -const transformedTangentWorld = /*@__PURE__*/ transformedTangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedTangentWorld' ); + // Create a copy of the buffer. The `decodeAudioData` method + // detaches the buffer when complete, preventing reuse. + const bufferCopy = buffer.slice( 0 ); -const getBitangent = ( crossNormalTangent ) => crossNormalTangent.mul( tangentGeometry.w ).xyz; + const context = AudioContext.getContext(); + context.decodeAudioData( bufferCopy, function ( audioBuffer ) { -const bitangentGeometry = /*@__PURE__*/ varying( getBitangent( normalGeometry.cross( tangentGeometry ) ), 'v_bitangentGeometry' ).normalize().toVar( 'bitangentGeometry' ); -const bitangentLocal = /*@__PURE__*/ varying( getBitangent( normalLocal.cross( tangentLocal ) ), 'v_bitangentLocal' ).normalize().toVar( 'bitangentLocal' ); -const bitangentView = /*@__PURE__*/ varying( getBitangent( normalView.cross( tangentView ) ), 'v_bitangentView' ).normalize().toVar( 'bitangentView' ); -const bitangentWorld = /*@__PURE__*/ varying( getBitangent( normalWorld.cross( tangentWorld ) ), 'v_bitangentWorld' ).normalize().toVar( 'bitangentWorld' ); -const transformedBitangentView = /*@__PURE__*/ getBitangent( transformedNormalView.cross( transformedTangentView ) ).normalize().toVar( 'transformedBitangentView' ); -const transformedBitangentWorld = /*@__PURE__*/ transformedBitangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedBitangentWorld' ); + onLoad( audioBuffer ); -const TBNViewMatrix = /*@__PURE__*/ mat3( tangentView, bitangentView, normalView ); + } ).catch( handleError ); -const parallaxDirection = /*@__PURE__*/ positionViewDirection.mul( TBNViewMatrix )/*.normalize()*/; -const parallaxUV = ( uv, scale ) => uv.sub( parallaxDirection.mul( scale ) ); + } catch ( e ) { -const transformedBentNormalView = /*@__PURE__*/ ( () => { + handleError( e ); - // https://google.github.io/filament/Filament.md.html#lighting/imagebasedlights/anisotropy + } - let bentNormal = anisotropyB.cross( positionViewDirection ); - bentNormal = bentNormal.cross( anisotropyB ).normalize(); - bentNormal = mix( bentNormal, transformedNormalView, anisotropy.mul( roughness.oneMinus() ).oneMinus().pow2().pow2() ).normalize(); + }, onProgress, onError ); - return bentNormal; + function handleError( e ) { + if ( onError ) { -} )(); + onError( e ); -// Normal Mapping Without Precomputed Tangents -// http://www.thetenthplanet.de/archives/1180 + } else { -const perturbNormal2Arb = /*@__PURE__*/ Fn( ( inputs ) => { + console.error( e ); - const { eye_pos, surf_norm, mapN, uv } = inputs; + } - const q0 = eye_pos.dFdx(); - const q1 = eye_pos.dFdy(); - const st0 = uv.dFdx(); - const st1 = uv.dFdy(); + scope.manager.itemError( url ); - const N = surf_norm; // normalized + } - const q1perp = q1.cross( N ); - const q0perp = N.cross( q0 ); + } - const T = q1perp.mul( st0.x ).add( q0perp.mul( st1.x ) ); - const B = q1perp.mul( st0.y ).add( q0perp.mul( st1.y ) ); +} - const det = T.dot( T ).max( B.dot( B ) ); - const scale = faceDirection.mul( det.inverseSqrt() ); +const _eyeRight = /*@__PURE__*/ new Matrix4(); +const _eyeLeft = /*@__PURE__*/ new Matrix4(); +const _projectionMatrix = /*@__PURE__*/ new Matrix4(); - return add( T.mul( mapN.x, scale ), B.mul( mapN.y, scale ), N.mul( mapN.z ) ).normalize(); +class StereoCamera { -} ); + constructor() { -class NormalMapNode extends TempNode { + this.type = 'StereoCamera'; - constructor( node, scaleNode = null ) { + this.aspect = 1; - super( 'vec3' ); + this.eyeSep = 0.064; - this.node = node; - this.scaleNode = scaleNode; + this.cameraL = new PerspectiveCamera(); + this.cameraL.layers.enable( 1 ); + this.cameraL.matrixAutoUpdate = false; - this.normalMapType = TangentSpaceNormalMap; + this.cameraR = new PerspectiveCamera(); + this.cameraR.layers.enable( 2 ); + this.cameraR.matrixAutoUpdate = false; + + this._cache = { + focus: null, + fov: null, + aspect: null, + near: null, + far: null, + zoom: null, + eyeSep: null + }; } - setup( builder ) { + update( camera ) { - const { normalMapType, scaleNode } = this; + const cache = this._cache; - let normalMap = this.node.mul( 2.0 ).sub( 1.0 ); + const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov || + cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near || + cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep; - if ( scaleNode !== null ) { + if ( needsUpdate ) { - normalMap = vec3( normalMap.xy.mul( scaleNode ), normalMap.z ); + cache.focus = camera.focus; + cache.fov = camera.fov; + cache.aspect = camera.aspect * this.aspect; + cache.near = camera.near; + cache.far = camera.far; + cache.zoom = camera.zoom; + cache.eyeSep = this.eyeSep; - } + // Off-axis stereoscopic effect based on + // http://paulbourke.net/stereographics/stereorender/ - let outputNode = null; + _projectionMatrix.copy( camera.projectionMatrix ); + const eyeSepHalf = cache.eyeSep / 2; + const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus; + const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom; + let xmin, xmax; - if ( normalMapType === ObjectSpaceNormalMap ) { + // translate xOffset + + _eyeLeft.elements[ 12 ] = - eyeSepHalf; + _eyeRight.elements[ 12 ] = eyeSepHalf; - outputNode = modelNormalMatrix.mul( normalMap ).normalize(); + // for left eye - } else if ( normalMapType === TangentSpaceNormalMap ) { + xmin = - ymax * cache.aspect + eyeSepOnProjection; + xmax = ymax * cache.aspect + eyeSepOnProjection; - const tangent = builder.hasGeometryAttribute( 'tangent' ); + _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); + _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - if ( tangent === true ) { + this.cameraL.projectionMatrix.copy( _projectionMatrix ); - outputNode = TBNViewMatrix.mul( normalMap ).normalize(); + // for right eye - } else { + xmin = - ymax * cache.aspect - eyeSepOnProjection; + xmax = ymax * cache.aspect - eyeSepOnProjection; - outputNode = perturbNormal2Arb( { - eye_pos: positionView, - surf_norm: normalView, - mapN: normalMap, - uv: uv() - } ); + _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); + _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - } + this.cameraR.projectionMatrix.copy( _projectionMatrix ); } - return outputNode; + this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft ); + this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight ); } } -NormalMapNode.type = /*@__PURE__*/ registerNode( 'NormalMap', NormalMapNode ); +class ArrayCamera extends PerspectiveCamera { -const normalMap = /*@__PURE__*/ nodeProxy( NormalMapNode ); + constructor( array = [] ) { -// Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen -// https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf + super(); -const dHdxy_fwd = Fn( ( { textureNode, bumpScale } ) => { + this.isArrayCamera = true; - // It's used to preserve the same TextureNode instance - const sampleTexture = ( callback ) => textureNode.cache().context( { getUV: ( texNode ) => callback( texNode.uvNode || uv() ), forceUVContext: true } ); + this.cameras = array; - const Hll = float( sampleTexture( ( uvNode ) => uvNode ) ); + } - return vec2( - float( sampleTexture( ( uvNode ) => uvNode.add( uvNode.dFdx() ) ) ).sub( Hll ), - float( sampleTexture( ( uvNode ) => uvNode.add( uvNode.dFdy() ) ) ).sub( Hll ) - ).mul( bumpScale ); +} -} ); +class Clock { -// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2) + constructor( autoStart = true ) { -const perturbNormalArb = Fn( ( inputs ) => { + this.autoStart = autoStart; - const { surf_pos, surf_norm, dHdxy } = inputs; + this.startTime = 0; + this.oldTime = 0; + this.elapsedTime = 0; - // normalize is done to ensure that the bump map looks the same regardless of the texture's scale - const vSigmaX = surf_pos.dFdx().normalize(); - const vSigmaY = surf_pos.dFdy().normalize(); - const vN = surf_norm; // normalized + this.running = false; - const R1 = vSigmaY.cross( vN ); - const R2 = vN.cross( vSigmaX ); + } - const fDet = vSigmaX.dot( R1 ).mul( faceDirection ); + start() { - const vGrad = fDet.sign().mul( dHdxy.x.mul( R1 ).add( dHdxy.y.mul( R2 ) ) ); + this.startTime = now(); - return fDet.abs().mul( surf_norm ).sub( vGrad ).normalize(); + this.oldTime = this.startTime; + this.elapsedTime = 0; + this.running = true; -} ); + } -class BumpMapNode extends TempNode { + stop() { - constructor( textureNode, scaleNode = null ) { + this.getElapsedTime(); + this.running = false; + this.autoStart = false; - super( 'vec3' ); + } - this.textureNode = textureNode; - this.scaleNode = scaleNode; + getElapsedTime() { + + this.getDelta(); + return this.elapsedTime; } - setup() { + getDelta() { - const bumpScale = this.scaleNode !== null ? this.scaleNode : 1; - const dHdxy = dHdxy_fwd( { textureNode: this.textureNode, bumpScale } ); + let diff = 0; - return perturbNormalArb( { - surf_pos: positionView, - surf_norm: normalView, - dHdxy - } ); + if ( this.autoStart && ! this.running ) { - } + this.start(); + return 0; -} + } -const bumpMap = /*@__PURE__*/ nodeProxy( BumpMapNode ); + if ( this.running ) { -const _propertyCache = new Map(); + const newTime = now(); -class MaterialNode extends Node { + diff = ( newTime - this.oldTime ) / 1000; + this.oldTime = newTime; - constructor( scope ) { + this.elapsedTime += diff; - super(); + } - this.scope = scope; + return diff; } - getCache( property, type ) { +} - let node = _propertyCache.get( property ); +function now() { - if ( node === undefined ) { + return performance.now(); - node = materialReference( property, type ); +} - _propertyCache.set( property, node ); +const _position$1 = /*@__PURE__*/ new Vector3(); +const _quaternion$1 = /*@__PURE__*/ new Quaternion(); +const _scale$1 = /*@__PURE__*/ new Vector3(); +const _orientation$1 = /*@__PURE__*/ new Vector3(); - } +class AudioListener extends Object3D { - return node; + constructor() { - } + super(); - getFloat( property ) { + this.type = 'AudioListener'; - return this.getCache( property, 'float' ); + this.context = AudioContext.getContext(); - } + this.gain = this.context.createGain(); + this.gain.connect( this.context.destination ); - getColor( property ) { + this.filter = null; - return this.getCache( property, 'color' ); + this.timeDelta = 0; + + // private + + this._clock = new Clock(); } - getTexture( property ) { + getInput() { - return this.getCache( property === 'map' ? 'map' : property + 'Map', 'texture' ); + return this.gain; } - setup( builder ) { + removeFilter() { - const material = builder.context.material; - const scope = this.scope; + if ( this.filter !== null ) { - let node = null; + this.gain.disconnect( this.filter ); + this.filter.disconnect( this.context.destination ); + this.gain.connect( this.context.destination ); + this.filter = null; - if ( scope === MaterialNode.COLOR ) { + } - const colorNode = material.color !== undefined ? this.getColor( scope ) : vec3(); + return this; - if ( material.map && material.map.isTexture === true ) { + } - node = colorNode.mul( this.getTexture( 'map' ) ); + getFilter() { - } else { + return this.filter; - node = colorNode; + } - } + setFilter( value ) { - } else if ( scope === MaterialNode.OPACITY ) { + if ( this.filter !== null ) { - const opacityNode = this.getFloat( scope ); + this.gain.disconnect( this.filter ); + this.filter.disconnect( this.context.destination ); - if ( material.alphaMap && material.alphaMap.isTexture === true ) { + } else { - node = opacityNode.mul( this.getTexture( 'alpha' ) ); + this.gain.disconnect( this.context.destination ); - } else { + } - node = opacityNode; + this.filter = value; + this.gain.connect( this.filter ); + this.filter.connect( this.context.destination ); - } + return this; - } else if ( scope === MaterialNode.SPECULAR_STRENGTH ) { + } - if ( material.specularMap && material.specularMap.isTexture === true ) { + getMasterVolume() { - node = this.getTexture( 'specular' ).r; + return this.gain.gain.value; - } else { + } - node = float( 1 ); + setMasterVolume( value ) { - } + this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); - } else if ( scope === MaterialNode.SPECULAR_INTENSITY ) { + return this; - const specularIntensity = this.getFloat( scope ); + } - if ( material.specularMap ) { + updateMatrixWorld( force ) { - node = specularIntensity.mul( this.getTexture( scope ).a ); + super.updateMatrixWorld( force ); - } else { + const listener = this.context.listener; + const up = this.up; - node = specularIntensity; + this.timeDelta = this._clock.getDelta(); - } + this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 ); - } else if ( scope === MaterialNode.SPECULAR_COLOR ) { + _orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 ); - const specularColorNode = this.getColor( scope ); + if ( listener.positionX ) { - if ( material.specularColorMap && material.specularColorMap.isTexture === true ) { + // code path for Chrome (see #14393) - node = specularColorNode.mul( this.getTexture( scope ).rgb ); + const endTime = this.context.currentTime + this.timeDelta; - } else { + listener.positionX.linearRampToValueAtTime( _position$1.x, endTime ); + listener.positionY.linearRampToValueAtTime( _position$1.y, endTime ); + listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime ); + listener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime ); + listener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime ); + listener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime ); + listener.upX.linearRampToValueAtTime( up.x, endTime ); + listener.upY.linearRampToValueAtTime( up.y, endTime ); + listener.upZ.linearRampToValueAtTime( up.z, endTime ); - node = specularColorNode; + } else { - } + listener.setPosition( _position$1.x, _position$1.y, _position$1.z ); + listener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z ); - } else if ( scope === MaterialNode.ROUGHNESS ) { // TODO: cleanup similar branches + } - const roughnessNode = this.getFloat( scope ); + } - if ( material.roughnessMap && material.roughnessMap.isTexture === true ) { +} - node = roughnessNode.mul( this.getTexture( scope ).g ); +class Audio extends Object3D { - } else { + constructor( listener ) { - node = roughnessNode; - - } + super(); - } else if ( scope === MaterialNode.METALNESS ) { + this.type = 'Audio'; - const metalnessNode = this.getFloat( scope ); + this.listener = listener; + this.context = listener.context; - if ( material.metalnessMap && material.metalnessMap.isTexture === true ) { + this.gain = this.context.createGain(); + this.gain.connect( listener.getInput() ); - node = metalnessNode.mul( this.getTexture( scope ).b ); + this.autoplay = false; - } else { + this.buffer = null; + this.detune = 0; + this.loop = false; + this.loopStart = 0; + this.loopEnd = 0; + this.offset = 0; + this.duration = undefined; + this.playbackRate = 1; + this.isPlaying = false; + this.hasPlaybackControl = true; + this.source = null; + this.sourceType = 'empty'; - node = metalnessNode; + this._startedAt = 0; + this._progress = 0; + this._connected = false; - } + this.filters = []; - } else if ( scope === MaterialNode.EMISSIVE ) { + } - const emissiveIntensityNode = this.getFloat( 'emissiveIntensity' ); - const emissiveNode = this.getColor( scope ).mul( emissiveIntensityNode ); + getOutput() { - if ( material.emissiveMap && material.emissiveMap.isTexture === true ) { + return this.gain; - node = emissiveNode.mul( this.getTexture( scope ) ); + } - } else { + setNodeSource( audioNode ) { - node = emissiveNode; + this.hasPlaybackControl = false; + this.sourceType = 'audioNode'; + this.source = audioNode; + this.connect(); - } + return this; - } else if ( scope === MaterialNode.NORMAL ) { + } - if ( material.normalMap ) { + setMediaElementSource( mediaElement ) { - node = normalMap( this.getTexture( 'normal' ), this.getCache( 'normalScale', 'vec2' ) ); + this.hasPlaybackControl = false; + this.sourceType = 'mediaNode'; + this.source = this.context.createMediaElementSource( mediaElement ); + this.connect(); - } else if ( material.bumpMap ) { + return this; - node = bumpMap( this.getTexture( 'bump' ).r, this.getFloat( 'bumpScale' ) ); + } - } else { + setMediaStreamSource( mediaStream ) { - node = normalView; + this.hasPlaybackControl = false; + this.sourceType = 'mediaStreamNode'; + this.source = this.context.createMediaStreamSource( mediaStream ); + this.connect(); - } + return this; - } else if ( scope === MaterialNode.CLEARCOAT ) { + } - const clearcoatNode = this.getFloat( scope ); + setBuffer( audioBuffer ) { - if ( material.clearcoatMap && material.clearcoatMap.isTexture === true ) { + this.buffer = audioBuffer; + this.sourceType = 'buffer'; - node = clearcoatNode.mul( this.getTexture( scope ).r ); + if ( this.autoplay ) this.play(); - } else { + return this; - node = clearcoatNode; + } - } + play( delay = 0 ) { - } else if ( scope === MaterialNode.CLEARCOAT_ROUGHNESS ) { + if ( this.isPlaying === true ) { - const clearcoatRoughnessNode = this.getFloat( scope ); + console.warn( 'THREE.Audio: Audio is already playing.' ); + return; - if ( material.clearcoatRoughnessMap && material.clearcoatRoughnessMap.isTexture === true ) { + } - node = clearcoatRoughnessNode.mul( this.getTexture( scope ).r ); + if ( this.hasPlaybackControl === false ) { - } else { + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - node = clearcoatRoughnessNode; + } - } + this._startedAt = this.context.currentTime + delay; - } else if ( scope === MaterialNode.CLEARCOAT_NORMAL ) { + const source = this.context.createBufferSource(); + source.buffer = this.buffer; + source.loop = this.loop; + source.loopStart = this.loopStart; + source.loopEnd = this.loopEnd; + source.onended = this.onEnded.bind( this ); + source.start( this._startedAt, this._progress + this.offset, this.duration ); - if ( material.clearcoatNormalMap ) { + this.isPlaying = true; - node = normalMap( this.getTexture( scope ), this.getCache( scope + 'Scale', 'vec2' ) ); + this.source = source; - } else { + this.setDetune( this.detune ); + this.setPlaybackRate( this.playbackRate ); - node = normalView; + return this.connect(); - } + } - } else if ( scope === MaterialNode.SHEEN ) { + pause() { - const sheenNode = this.getColor( 'sheenColor' ).mul( this.getFloat( 'sheen' ) ); // Move this mul() to CPU + if ( this.hasPlaybackControl === false ) { - if ( material.sheenColorMap && material.sheenColorMap.isTexture === true ) { + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - node = sheenNode.mul( this.getTexture( 'sheenColor' ).rgb ); + } - } else { + if ( this.isPlaying === true ) { - node = sheenNode; + // update current progress - } + this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate; - } else if ( scope === MaterialNode.SHEEN_ROUGHNESS ) { + if ( this.loop === true ) { - const sheenRoughnessNode = this.getFloat( scope ); + // ensure _progress does not exceed duration with looped audios - if ( material.sheenRoughnessMap && material.sheenRoughnessMap.isTexture === true ) { + this._progress = this._progress % ( this.duration || this.buffer.duration ); - node = sheenRoughnessNode.mul( this.getTexture( scope ).a ); + } - } else { + this.source.stop(); + this.source.onended = null; - node = sheenRoughnessNode; + this.isPlaying = false; - } + } - node = node.clamp( 0.07, 1.0 ); + return this; - } else if ( scope === MaterialNode.ANISOTROPY ) { + } - if ( material.anisotropyMap && material.anisotropyMap.isTexture === true ) { + stop( delay = 0 ) { - const anisotropyPolar = this.getTexture( scope ); - const anisotropyMat = mat2( materialAnisotropyVector.x, materialAnisotropyVector.y, materialAnisotropyVector.y.negate(), materialAnisotropyVector.x ); + if ( this.hasPlaybackControl === false ) { - node = anisotropyMat.mul( anisotropyPolar.rg.mul( 2.0 ).sub( vec2( 1.0 ) ).normalize().mul( anisotropyPolar.b ) ); + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - } else { + } - node = materialAnisotropyVector; + this._progress = 0; - } + if ( this.source !== null ) { - } else if ( scope === MaterialNode.IRIDESCENCE_THICKNESS ) { + this.source.stop( this.context.currentTime + delay ); + this.source.onended = null; - const iridescenceThicknessMaximum = reference( '1', 'float', material.iridescenceThicknessRange ); + } - if ( material.iridescenceThicknessMap ) { + this.isPlaying = false; - const iridescenceThicknessMinimum = reference( '0', 'float', material.iridescenceThicknessRange ); + return this; - node = iridescenceThicknessMaximum.sub( iridescenceThicknessMinimum ).mul( this.getTexture( scope ).g ).add( iridescenceThicknessMinimum ); + } - } else { + connect() { - node = iridescenceThicknessMaximum; + if ( this.filters.length > 0 ) { - } + this.source.connect( this.filters[ 0 ] ); - } else if ( scope === MaterialNode.TRANSMISSION ) { + for ( let i = 1, l = this.filters.length; i < l; i ++ ) { - const transmissionNode = this.getFloat( scope ); + this.filters[ i - 1 ].connect( this.filters[ i ] ); - if ( material.transmissionMap ) { + } - node = transmissionNode.mul( this.getTexture( scope ).r ); + this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); - } else { + } else { - node = transmissionNode; + this.source.connect( this.getOutput() ); - } + } - } else if ( scope === MaterialNode.THICKNESS ) { + this._connected = true; - const thicknessNode = this.getFloat( scope ); + return this; - if ( material.thicknessMap ) { + } - node = thicknessNode.mul( this.getTexture( scope ).g ); + disconnect() { - } else { + if ( this._connected === false ) { - node = thicknessNode; + return; - } + } - } else if ( scope === MaterialNode.IOR ) { + if ( this.filters.length > 0 ) { - node = this.getFloat( scope ); + this.source.disconnect( this.filters[ 0 ] ); - } else if ( scope === MaterialNode.LIGHT_MAP ) { + for ( let i = 1, l = this.filters.length; i < l; i ++ ) { - node = this.getTexture( scope ).rgb.mul( this.getFloat( 'lightMapIntensity' ) ); + this.filters[ i - 1 ].disconnect( this.filters[ i ] ); - } else if ( scope === MaterialNode.AO_MAP ) { + } - node = this.getTexture( scope ).r.sub( 1.0 ).mul( this.getFloat( 'aoMapIntensity' ) ).add( 1.0 ); + this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); } else { - const outputType = this.getNodeType( builder ); - - node = this.getCache( scope, outputType ); + this.source.disconnect( this.getOutput() ); } - return node; - - } - -} + this._connected = false; -MaterialNode.ALPHA_TEST = 'alphaTest'; -MaterialNode.COLOR = 'color'; -MaterialNode.OPACITY = 'opacity'; -MaterialNode.SHININESS = 'shininess'; -MaterialNode.SPECULAR = 'specular'; -MaterialNode.SPECULAR_STRENGTH = 'specularStrength'; -MaterialNode.SPECULAR_INTENSITY = 'specularIntensity'; -MaterialNode.SPECULAR_COLOR = 'specularColor'; -MaterialNode.REFLECTIVITY = 'reflectivity'; -MaterialNode.ROUGHNESS = 'roughness'; -MaterialNode.METALNESS = 'metalness'; -MaterialNode.NORMAL = 'normal'; -MaterialNode.CLEARCOAT = 'clearcoat'; -MaterialNode.CLEARCOAT_ROUGHNESS = 'clearcoatRoughness'; -MaterialNode.CLEARCOAT_NORMAL = 'clearcoatNormal'; -MaterialNode.EMISSIVE = 'emissive'; -MaterialNode.ROTATION = 'rotation'; -MaterialNode.SHEEN = 'sheen'; -MaterialNode.SHEEN_ROUGHNESS = 'sheenRoughness'; -MaterialNode.ANISOTROPY = 'anisotropy'; -MaterialNode.IRIDESCENCE = 'iridescence'; -MaterialNode.IRIDESCENCE_IOR = 'iridescenceIOR'; -MaterialNode.IRIDESCENCE_THICKNESS = 'iridescenceThickness'; -MaterialNode.IOR = 'ior'; -MaterialNode.TRANSMISSION = 'transmission'; -MaterialNode.THICKNESS = 'thickness'; -MaterialNode.ATTENUATION_DISTANCE = 'attenuationDistance'; -MaterialNode.ATTENUATION_COLOR = 'attenuationColor'; -MaterialNode.LINE_SCALE = 'scale'; -MaterialNode.LINE_DASH_SIZE = 'dashSize'; -MaterialNode.LINE_GAP_SIZE = 'gapSize'; -MaterialNode.LINE_WIDTH = 'linewidth'; -MaterialNode.LINE_DASH_OFFSET = 'dashOffset'; -MaterialNode.POINT_WIDTH = 'pointWidth'; -MaterialNode.DISPERSION = 'dispersion'; -MaterialNode.LIGHT_MAP = 'light'; -MaterialNode.AO_MAP = 'ao'; + return this; -MaterialNode.type = /*@__PURE__*/ registerNode( 'Material', MaterialNode ); + } -const materialAlphaTest = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ALPHA_TEST ); -const materialColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.COLOR ); -const materialShininess = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHININESS ); -const materialEmissive = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.EMISSIVE ); -const materialOpacity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.OPACITY ); -const materialSpecular = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR ); + getFilters() { -const materialSpecularIntensity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_INTENSITY ); -const materialSpecularColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_COLOR ); + return this.filters; -const materialSpecularStrength = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_STRENGTH ); -const materialReflectivity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.REFLECTIVITY ); -const materialRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ROUGHNESS ); -const materialMetalness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.METALNESS ); -const materialNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.NORMAL ).context( { getUV: null } ); -const materialClearcoat = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT ); -const materialClearcoatRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_ROUGHNESS ); -const materialClearcoatNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_NORMAL ).context( { getUV: null } ); -const materialRotation = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ROTATION ); -const materialSheen = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHEEN ); -const materialSheenRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHEEN_ROUGHNESS ); -const materialAnisotropy = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ANISOTROPY ); -const materialIridescence = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE ); -const materialIridescenceIOR = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_IOR ); -const materialIridescenceThickness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_THICKNESS ); -const materialTransmission = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.TRANSMISSION ); -const materialThickness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.THICKNESS ); -const materialIOR = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IOR ); -const materialAttenuationDistance = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_DISTANCE ); -const materialAttenuationColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_COLOR ); -const materialLineScale = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_SCALE ); -const materialLineDashSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_SIZE ); -const materialLineGapSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_GAP_SIZE ); -const materialLineWidth = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_WIDTH ); -const materialLineDashOffset = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_OFFSET ); -const materialPointWidth = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.POINT_WIDTH ); -const materialDispersion = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.DISPERSION ); -const materialLightMap = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LIGHT_MAP ); -const materialAOMap = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.AO_MAP ); -/*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.REFRACTION_RATIO ); -const materialAnisotropyVector = /*@__PURE__*/ uniform( new Vector2() ).onReference( function ( frame ) { + } - return frame.material; + setFilters( value ) { -} ).onRenderUpdate( function ( { material } ) { + if ( ! value ) value = []; - this.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) ); + if ( this._connected === true ) { -} ); + this.disconnect(); + this.filters = value.slice(); + this.connect(); -class ModelViewProjectionNode extends TempNode { + } else { - constructor( positionNode = null ) { + this.filters = value.slice(); - super( 'vec4' ); + } - this.positionNode = positionNode; + return this; } - setup( builder ) { + setDetune( value ) { - if ( builder.shaderStage === 'fragment' ) { + this.detune = value; - return varying( builder.context.mvp ); + if ( this.isPlaying === true && this.source.detune !== undefined ) { - } + this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 ); - const position = this.positionNode || positionLocal; + } - return cameraProjectionMatrix.mul( modelViewMatrix ).mul( position ); + return this; } -} + getDetune() { -ModelViewProjectionNode.type = /*@__PURE__*/ registerNode( 'ModelViewProjection', ModelViewProjectionNode ); + return this.detune; -const modelViewProjection = /*@__PURE__*/ nodeProxy( ModelViewProjectionNode ); + } -class IndexNode extends Node { + getFilter() { - constructor( scope ) { + return this.getFilters()[ 0 ]; - super( 'uint' ); + } - this.scope = scope; + setFilter( filter ) { - this.isInstanceIndexNode = true; + return this.setFilters( filter ? [ filter ] : [] ); } - generate( builder ) { - - const nodeType = this.getNodeType( builder ); - const scope = this.scope; + setPlaybackRate( value ) { - let propertyName; + if ( this.hasPlaybackControl === false ) { - if ( scope === IndexNode.VERTEX ) { + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - propertyName = builder.getVertexIndex(); + } - } else if ( scope === IndexNode.INSTANCE ) { + this.playbackRate = value; - propertyName = builder.getInstanceIndex(); + if ( this.isPlaying === true ) { - } else if ( scope === IndexNode.DRAW ) { + this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 ); - propertyName = builder.getDrawIndex(); + } - } else if ( scope === IndexNode.INVOCATION_LOCAL ) { + return this; - propertyName = builder.getInvocationLocalIndex(); + } - } else { + getPlaybackRate() { - throw new Error( 'THREE.IndexNode: Unknown scope: ' + scope ); + return this.playbackRate; - } + } - let output; + onEnded() { - if ( builder.shaderStage === 'vertex' || builder.shaderStage === 'compute' ) { + this.isPlaying = false; - output = propertyName; + } - } else { + getLoop() { - const nodeVarying = varying( this ); + if ( this.hasPlaybackControl === false ) { - output = nodeVarying.build( builder, nodeType ); + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return false; } - return output; + return this.loop; } -} + setLoop( value ) { -IndexNode.VERTEX = 'vertex'; -IndexNode.INSTANCE = 'instance'; -IndexNode.INVOCATION_LOCAL = 'invocationLocal'; -IndexNode.DRAW = 'draw'; + if ( this.hasPlaybackControl === false ) { -IndexNode.type = /*@__PURE__*/ registerNode( 'Index', IndexNode ); + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; -const vertexIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.VERTEX ); -const instanceIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INSTANCE ); -const invocationLocalIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INVOCATION_LOCAL ); -const drawIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.DRAW ); + } -class InstancedInterleavedBuffer extends InterleavedBuffer { + this.loop = value; - constructor( array, stride, meshPerAttribute = 1 ) { + if ( this.isPlaying === true ) { - super( array, stride ); + this.source.loop = this.loop; - this.isInstancedInterleavedBuffer = true; + } - this.meshPerAttribute = meshPerAttribute; + return this; } - copy( source ) { - - super.copy( source ); + setLoopStart( value ) { - this.meshPerAttribute = source.meshPerAttribute; + this.loopStart = value; return this; } - clone( data ) { - - const ib = super.clone( data ); + setLoopEnd( value ) { - ib.meshPerAttribute = this.meshPerAttribute; + this.loopEnd = value; - return ib; + return this; } - toJSON( data ) { + getVolume() { - const json = super.toJSON( data ); + return this.gain.gain.value; - json.isInstancedInterleavedBuffer = true; - json.meshPerAttribute = this.meshPerAttribute; + } - return json; + setVolume( value ) { + + this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); + + return this; } } -class InstanceNode extends Node { +const _position = /*@__PURE__*/ new Vector3(); +const _quaternion = /*@__PURE__*/ new Quaternion(); +const _scale = /*@__PURE__*/ new Vector3(); +const _orientation = /*@__PURE__*/ new Vector3(); - constructor( instanceMesh ) { +class PositionalAudio extends Audio { - super( 'void' ); + constructor( listener ) { - this.instanceMesh = instanceMesh; + super( listener ); - this.instanceMatrixNode = null; + this.panner = this.context.createPanner(); + this.panner.panningModel = 'HRTF'; + this.panner.connect( this.gain ); - this.instanceColorNode = null; + } - this.updateType = NodeUpdateType.FRAME; + connect() { - this.buffer = null; - this.bufferColor = null; + super.connect(); + + this.panner.connect( this.gain ); } - setup( builder ) { + disconnect() { - let instanceMatrixNode = this.instanceMatrixNode; - let instanceColorNode = this.instanceColorNode; + super.disconnect(); - const instanceMesh = this.instanceMesh; + this.panner.disconnect( this.gain ); - if ( instanceMatrixNode === null ) { + } - const instanceAttribute = instanceMesh.instanceMatrix; + getOutput() { - // Both WebGPU and WebGL backends have UBO max limited to 64kb. Matrix count number bigger than 1000 ( 16 * 4 * 1000 = 64kb ) will fallback to attribute. + return this.panner; - if ( instanceMesh.count <= 1000 ) { + } - instanceMatrixNode = buffer( instanceAttribute.array, 'mat4', instanceMesh.count ).element( instanceIndex ); + getRefDistance() { - } else { + return this.panner.refDistance; - const buffer = new InstancedInterleavedBuffer( instanceAttribute.array, 16, 1 ); + } - this.buffer = buffer; + setRefDistance( value ) { - const bufferFn = instanceAttribute.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute; + this.panner.refDistance = value; - const instanceBuffers = [ - // F.Signature -> bufferAttribute( array, type, stride, offset ) - bufferFn( buffer, 'vec4', 16, 0 ), - bufferFn( buffer, 'vec4', 16, 4 ), - bufferFn( buffer, 'vec4', 16, 8 ), - bufferFn( buffer, 'vec4', 16, 12 ) - ]; + return this; - instanceMatrixNode = mat4( ...instanceBuffers ); - - } + } - this.instanceMatrixNode = instanceMatrixNode; + getRolloffFactor() { - } + return this.panner.rolloffFactor; - const instanceColorAttribute = instanceMesh.instanceColor; + } - if ( instanceColorAttribute && instanceColorNode === null ) { + setRolloffFactor( value ) { - const buffer = new InstancedBufferAttribute( instanceColorAttribute.array, 3 ); + this.panner.rolloffFactor = value; - const bufferFn = instanceColorAttribute.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute; + return this; - this.bufferColor = buffer; + } - instanceColorNode = vec3( bufferFn( buffer, 'vec3', 3, 0 ) ); + getDistanceModel() { - this.instanceColorNode = instanceColorNode; + return this.panner.distanceModel; - } + } - // POSITION + setDistanceModel( value ) { - const instancePosition = instanceMatrixNode.mul( positionLocal ).xyz; - positionLocal.assign( instancePosition ); + this.panner.distanceModel = value; - // NORMAL + return this; - if ( builder.hasGeometryAttribute( 'normal' ) ) { + } - const m = mat3( instanceMatrixNode ); + getMaxDistance() { - const transformedNormal = normalLocal.div( vec3( m[ 0 ].dot( m[ 0 ] ), m[ 1 ].dot( m[ 1 ] ), m[ 2 ].dot( m[ 2 ] ) ) ); + return this.panner.maxDistance; - const instanceNormal = m.mul( transformedNormal ).xyz; + } - // ASSIGNS + setMaxDistance( value ) { - normalLocal.assign( instanceNormal ); + this.panner.maxDistance = value; - } + return this; - // COLOR + } - if ( this.instanceColorNode !== null ) { + setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) { - varyingProperty( 'vec3', 'vInstanceColor' ).assign( this.instanceColorNode ); + this.panner.coneInnerAngle = coneInnerAngle; + this.panner.coneOuterAngle = coneOuterAngle; + this.panner.coneOuterGain = coneOuterGain; - } + return this; } - update( /*frame*/ ) { - - if ( this.instanceMesh.instanceMatrix.usage !== DynamicDrawUsage && this.buffer != null && this.instanceMesh.instanceMatrix.version !== this.buffer.version ) { - - this.buffer.version = this.instanceMesh.instanceMatrix.version; + updateMatrixWorld( force ) { - } + super.updateMatrixWorld( force ); - if ( this.instanceMesh.instanceColor && this.instanceMesh.instanceColor.usage !== DynamicDrawUsage && this.bufferColor != null && this.instanceMesh.instanceColor.version !== this.bufferColor.version ) { + if ( this.hasPlaybackControl === true && this.isPlaying === false ) return; - this.bufferColor.version = this.instanceMesh.instanceColor.version; + this.matrixWorld.decompose( _position, _quaternion, _scale ); - } + _orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion ); - } + const panner = this.panner; -} + if ( panner.positionX ) { -InstanceNode.type = /*@__PURE__*/ registerNode( 'Instance', InstanceNode ); + // code path for Chrome and Firefox (see #14393) -const instance = /*@__PURE__*/ nodeProxy( InstanceNode ); + const endTime = this.context.currentTime + this.listener.timeDelta; -class BatchNode extends Node { + panner.positionX.linearRampToValueAtTime( _position.x, endTime ); + panner.positionY.linearRampToValueAtTime( _position.y, endTime ); + panner.positionZ.linearRampToValueAtTime( _position.z, endTime ); + panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime ); + panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime ); + panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime ); - constructor( batchMesh ) { + } else { - super( 'void' ); + panner.setPosition( _position.x, _position.y, _position.z ); + panner.setOrientation( _orientation.x, _orientation.y, _orientation.z ); - this.batchMesh = batchMesh; + } + } - this.batchingIdNode = null; +} - } +class AudioAnalyser { - setup( builder ) { + constructor( audio, fftSize = 2048 ) { - // POSITION + this.analyser = audio.context.createAnalyser(); + this.analyser.fftSize = fftSize; - if ( this.batchingIdNode === null ) { + this.data = new Uint8Array( this.analyser.frequencyBinCount ); - if ( builder.getDrawIndex() === null ) { + audio.getOutput().connect( this.analyser ); - this.batchingIdNode = instanceIndex; + } - } else { - this.batchingIdNode = drawIndex; + getFrequencyData() { - } + this.analyser.getByteFrequencyData( this.data ); - } + return this.data; - const getIndirectIndex = Fn( ( [ id ] ) => { + } - const size = textureSize( textureLoad( this.batchMesh._indirectTexture ), 0 ); - const x = int( id ).modInt( int( size ) ); - const y = int( id ).div( int( size ) ); - return textureLoad( this.batchMesh._indirectTexture, ivec2( x, y ) ).x; + getAverageFrequency() { - } ).setLayout( { - name: 'getIndirectIndex', - type: 'uint', - inputs: [ - { name: 'id', type: 'int' } - ] - } ); + let value = 0; + const data = this.getFrequencyData(); - const indirectId = getIndirectIndex( int( this.batchingIdNode ) ); + for ( let i = 0; i < data.length; i ++ ) { - const matricesTexture = this.batchMesh._matricesTexture; + value += data[ i ]; - const size = textureSize( textureLoad( matricesTexture ), 0 ); - const j = float( indirectId ).mul( 4 ).toInt().toVar(); + } - const x = j.modInt( size ); - const y = j.div( int( size ) ); - const batchingMatrix = mat4( - textureLoad( matricesTexture, ivec2( x, y ) ), - textureLoad( matricesTexture, ivec2( x.add( 1 ), y ) ), - textureLoad( matricesTexture, ivec2( x.add( 2 ), y ) ), - textureLoad( matricesTexture, ivec2( x.add( 3 ), y ) ) - ); + return value / data.length; + } - const colorsTexture = this.batchMesh._colorsTexture; +} - if ( colorsTexture !== null ) { +class PropertyMixer { - const getBatchingColor = Fn( ( [ id ] ) => { + constructor( binding, typeName, valueSize ) { - const size = textureSize( textureLoad( colorsTexture ), 0 ).x; - const j = id; - const x = j.modInt( size ); - const y = j.div( size ); - return textureLoad( colorsTexture, ivec2( x, y ) ).rgb; + this.binding = binding; + this.valueSize = valueSize; - } ).setLayout( { - name: 'getBatchingColor', - type: 'vec3', - inputs: [ - { name: 'id', type: 'int' } - ] - } ); + let mixFunction, + mixFunctionAdditive, + setIdentity; - const color = getBatchingColor( indirectId ); + // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ] + // + // interpolators can use .buffer as their .result + // the data then goes to 'incoming' + // + // 'accu0' and 'accu1' are used frame-interleaved for + // the cumulative result and are compared to detect + // changes + // + // 'orig' stores the original state of the property + // + // 'add' is used for additive cumulative results + // + // 'work' is optional and is only present for quaternion types. It is used + // to store intermediate quaternion multiplication results - varyingProperty( 'vec3', 'vBatchColor' ).assign( color ); + switch ( typeName ) { - } + case 'quaternion': + mixFunction = this._slerp; + mixFunctionAdditive = this._slerpAdditive; + setIdentity = this._setAdditiveIdentityQuaternion; - const bm = mat3( batchingMatrix ); + this.buffer = new Float64Array( valueSize * 6 ); + this._workIndex = 5; + break; - positionLocal.assign( batchingMatrix.mul( positionLocal ) ); + case 'string': + case 'bool': + mixFunction = this._select; - const transformedNormal = normalLocal.div( vec3( bm[ 0 ].dot( bm[ 0 ] ), bm[ 1 ].dot( bm[ 1 ] ), bm[ 2 ].dot( bm[ 2 ] ) ) ); + // Use the regular mix function and for additive on these types, + // additive is not relevant for non-numeric types + mixFunctionAdditive = this._select; - const batchingNormal = bm.mul( transformedNormal ).xyz; + setIdentity = this._setAdditiveIdentityOther; - normalLocal.assign( batchingNormal ); + this.buffer = new Array( valueSize * 5 ); + break; - if ( builder.hasGeometryAttribute( 'tangent' ) ) { + default: + mixFunction = this._lerp; + mixFunctionAdditive = this._lerpAdditive; + setIdentity = this._setAdditiveIdentityNumeric; - tangentLocal.mulAssign( bm ); + this.buffer = new Float64Array( valueSize * 5 ); } - } - -} + this._mixBufferRegion = mixFunction; + this._mixBufferRegionAdditive = mixFunctionAdditive; + this._setIdentity = setIdentity; + this._origIndex = 3; + this._addIndex = 4; -BatchNode.type = /*@__PURE__*/ registerNode( 'Batch', BatchNode ); + this.cumulativeWeight = 0; + this.cumulativeWeightAdditive = 0; -const batch = /*@__PURE__*/ nodeProxy( BatchNode ); + this.useCount = 0; + this.referenceCount = 0; -const _frameId = new WeakMap(); + } -class SkinningNode extends Node { + // accumulate data in the 'incoming' region into 'accu' + accumulate( accuIndex, weight ) { - constructor( skinnedMesh, useReference = false ) { + // note: happily accumulating nothing when weight = 0, the caller knows + // the weight and shouldn't have made the call in the first place - super( 'void' ); + const buffer = this.buffer, + stride = this.valueSize, + offset = accuIndex * stride + stride; - this.skinnedMesh = skinnedMesh; - this.useReference = useReference; + let currentWeight = this.cumulativeWeight; - this.updateType = NodeUpdateType.OBJECT; + if ( currentWeight === 0 ) { - // + // accuN := incoming * weight - this.skinIndexNode = attribute( 'skinIndex', 'uvec4' ); - this.skinWeightNode = attribute( 'skinWeight', 'vec4' ); + for ( let i = 0; i !== stride; ++ i ) { - let bindMatrixNode, bindMatrixInverseNode, boneMatricesNode; + buffer[ offset + i ] = buffer[ i ]; - if ( useReference ) { + } - bindMatrixNode = reference( 'bindMatrix', 'mat4' ); - bindMatrixInverseNode = reference( 'bindMatrixInverse', 'mat4' ); - boneMatricesNode = referenceBuffer( 'skeleton.boneMatrices', 'mat4', skinnedMesh.skeleton.bones.length ); + currentWeight = weight; } else { - bindMatrixNode = uniform( skinnedMesh.bindMatrix, 'mat4' ); - bindMatrixInverseNode = uniform( skinnedMesh.bindMatrixInverse, 'mat4' ); - boneMatricesNode = buffer( skinnedMesh.skeleton.boneMatrices, 'mat4', skinnedMesh.skeleton.bones.length ); + // accuN := accuN + incoming * weight + + currentWeight += weight; + const mix = weight / currentWeight; + this._mixBufferRegion( buffer, offset, 0, mix, stride ); } - this.bindMatrixNode = bindMatrixNode; - this.bindMatrixInverseNode = bindMatrixInverseNode; - this.boneMatricesNode = boneMatricesNode; - this.previousBoneMatricesNode = null; + this.cumulativeWeight = currentWeight; } - getSkinnedPosition( boneMatrices = this.boneMatricesNode, position = positionLocal ) { + // accumulate data in the 'incoming' region into 'add' + accumulateAdditive( weight ) { - const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; + const buffer = this.buffer, + stride = this.valueSize, + offset = stride * this._addIndex; - const boneMatX = boneMatrices.element( skinIndexNode.x ); - const boneMatY = boneMatrices.element( skinIndexNode.y ); - const boneMatZ = boneMatrices.element( skinIndexNode.z ); - const boneMatW = boneMatrices.element( skinIndexNode.w ); + if ( this.cumulativeWeightAdditive === 0 ) { - // POSITION + // add = identity - const skinVertex = bindMatrixNode.mul( position ); + this._setIdentity(); - const skinned = add( - boneMatX.mul( skinWeightNode.x ).mul( skinVertex ), - boneMatY.mul( skinWeightNode.y ).mul( skinVertex ), - boneMatZ.mul( skinWeightNode.z ).mul( skinVertex ), - boneMatW.mul( skinWeightNode.w ).mul( skinVertex ) - ); + } - return bindMatrixInverseNode.mul( skinned ).xyz; + // add := add + incoming * weight + + this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride ); + this.cumulativeWeightAdditive += weight; } - getSkinnedNormal( boneMatrices = this.boneMatricesNode, normal = normalLocal ) { + // apply the state of 'accu' to the binding when accus differ + apply( accuIndex ) { - const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; + const stride = this.valueSize, + buffer = this.buffer, + offset = accuIndex * stride + stride, - const boneMatX = boneMatrices.element( skinIndexNode.x ); - const boneMatY = boneMatrices.element( skinIndexNode.y ); - const boneMatZ = boneMatrices.element( skinIndexNode.z ); - const boneMatW = boneMatrices.element( skinIndexNode.w ); + weight = this.cumulativeWeight, + weightAdditive = this.cumulativeWeightAdditive, - // NORMAL + binding = this.binding; - let skinMatrix = add( - skinWeightNode.x.mul( boneMatX ), - skinWeightNode.y.mul( boneMatY ), - skinWeightNode.z.mul( boneMatZ ), - skinWeightNode.w.mul( boneMatW ) - ); + this.cumulativeWeight = 0; + this.cumulativeWeightAdditive = 0; - skinMatrix = bindMatrixInverseNode.mul( skinMatrix ).mul( bindMatrixNode ); + if ( weight < 1 ) { - return skinMatrix.transformDirection( normal ).xyz; + // accuN := accuN + original * ( 1 - cumulativeWeight ) - } + const originalValueOffset = stride * this._origIndex; - getPreviousSkinnedPosition( builder ) { + this._mixBufferRegion( + buffer, offset, originalValueOffset, 1 - weight, stride ); - const skinnedMesh = builder.object; + } - if ( this.previousBoneMatricesNode === null ) { + if ( weightAdditive > 0 ) { - skinnedMesh.skeleton.previousBoneMatrices = new Float32Array( skinnedMesh.skeleton.boneMatrices ); + // accuN := accuN + additive accuN - this.previousBoneMatricesNode = referenceBuffer( 'skeleton.previousBoneMatrices', 'mat4', skinnedMesh.skeleton.bones.length ); + this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride ); } - return this.getSkinnedPosition( this.previousBoneMatricesNode, positionPrevious ); + for ( let i = stride, e = stride + stride; i !== e; ++ i ) { - } + if ( buffer[ i ] !== buffer[ i + stride ] ) { - needsPreviousBoneMatrices( builder ) { + // value has changed -> update scene graph - const mrt = builder.renderer.getMRT(); + binding.setValue( buffer, offset ); + break; - return mrt && mrt.has( 'velocity' ); + } - } + } - setup( builder ) { + } - if ( this.needsPreviousBoneMatrices( builder ) ) { + // remember the state of the bound property and copy it to both accus + saveOriginalState() { - positionPrevious.assign( this.getPreviousSkinnedPosition( builder ) ); + const binding = this.binding; - } + const buffer = this.buffer, + stride = this.valueSize, - const skinPosition = this.getSkinnedPosition(); + originalValueOffset = stride * this._origIndex; + binding.getValue( buffer, originalValueOffset ); - positionLocal.assign( skinPosition ); + // accu[0..1] := orig -- initially detect changes against the original + for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) { - if ( builder.hasGeometryAttribute( 'normal' ) ) { + buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; - const skinNormal = this.getSkinnedNormal(); + } - normalLocal.assign( skinNormal ); + // Add to identity for additive + this._setIdentity(); - if ( builder.hasGeometryAttribute( 'tangent' ) ) { + this.cumulativeWeight = 0; + this.cumulativeWeightAdditive = 0; - tangentLocal.assign( skinNormal ); + } - } + // apply the state previously taken via 'saveOriginalState' to the binding + restoreOriginalState() { - } + const originalValueOffset = this.valueSize * 3; + this.binding.setValue( this.buffer, originalValueOffset ); } - generate( builder, output ) { + _setAdditiveIdentityNumeric() { - if ( output !== 'void' ) { + const startIndex = this._addIndex * this.valueSize; + const endIndex = startIndex + this.valueSize; - return positionLocal.build( builder, output ); + for ( let i = startIndex; i < endIndex; i ++ ) { + + this.buffer[ i ] = 0; } } - update( frame ) { + _setAdditiveIdentityQuaternion() { - const object = this.useReference ? frame.object : this.skinnedMesh; - const skeleton = object.skeleton; + this._setAdditiveIdentityNumeric(); + this.buffer[ this._addIndex * this.valueSize + 3 ] = 1; - if ( _frameId.get( skeleton ) === frame.frameId ) return; + } - _frameId.set( skeleton, frame.frameId ); + _setAdditiveIdentityOther() { - if ( this.previousBoneMatricesNode !== null ) skeleton.previousBoneMatrices.set( skeleton.boneMatrices ); + const startIndex = this._origIndex * this.valueSize; + const targetIndex = this._addIndex * this.valueSize; - skeleton.update(); + for ( let i = 0; i < this.valueSize; i ++ ) { - } + this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ]; -} + } -SkinningNode.type = /*@__PURE__*/ registerNode( 'Skinning', SkinningNode ); + } -const skinning = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh ) ); -const skinningReference = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh, true ) ); -class LoopNode extends Node { + // mix functions - constructor( params = [] ) { + _select( buffer, dstOffset, srcOffset, t, stride ) { - super(); + if ( t >= 0.5 ) { - this.params = params; + for ( let i = 0; i !== stride; ++ i ) { - } + buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; - getVarName( index ) { + } - return String.fromCharCode( 'i'.charCodeAt() + index ); + } } - getProperties( builder ) { + _slerp( buffer, dstOffset, srcOffset, t ) { - const properties = builder.getNodeProperties( this ); + Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); - if ( properties.stackNode !== undefined ) return properties; + } - // + _slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { - const inputs = {}; + const workOffset = this._workIndex * stride; - for ( let i = 0, l = this.params.length - 1; i < l; i ++ ) { + // Store result in intermediate buffer offset + Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset ); - const param = this.params[ i ]; + // Slerp to the intermediate result + Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t ); - const name = ( param.isNode !== true && param.name ) || this.getVarName( i ); - const type = ( param.isNode !== true && param.type ) || 'int'; + } - inputs[ name ] = expression( name, type ); + _lerp( buffer, dstOffset, srcOffset, t, stride ) { - } + const s = 1 - t; - const stack = builder.addStack(); // TODO: cache() it + for ( let i = 0; i !== stride; ++ i ) { - properties.returnsNode = this.params[ this.params.length - 1 ]( inputs, stack, builder ); - properties.stackNode = stack; + const j = dstOffset + i; - builder.removeStack(); + buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; - return properties; + } } - getNodeType( builder ) { + _lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { - const { returnsNode } = this.getProperties( builder ); + for ( let i = 0; i !== stride; ++ i ) { - return returnsNode ? returnsNode.getNodeType( builder ) : 'void'; + const j = dstOffset + i; - } + buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t; - setup( builder ) { + } - // setup properties + } - this.getProperties( builder ); +} - } +// Characters [].:/ are reserved for track binding syntax. +const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; +const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' ); - generate( builder ) { +// Attempts to allow node names from any language. ES5's `\w` regexp matches +// only latin characters, and the unicode \p{L} is not yet supported. So +// instead, we exclude reserved characters and match everything else. +const _wordChar = '[^' + _RESERVED_CHARS_RE + ']'; +const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; - const properties = this.getProperties( builder ); +// Parent directories, delimited by '/' or ':'. Currently unused, but must +// be matched to parse the rest of the track name. +const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar ); - const params = this.params; - const stackNode = properties.stackNode; +// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. +const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot ); - for ( let i = 0, l = params.length - 1; i < l; i ++ ) { +// Object on target node, and accessor. May not contain reserved +// characters. Accessor may contain any character except closing bracket. +const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar ); - const param = params[ i ]; +// Property and accessor. May not contain reserved characters. Accessor may +// contain any non-bracket characters. +const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar ); - let start = null, end = null, name = null, type = null, condition = null, update = null; +const _trackRe = new RegExp( '' + + '^' + + _directoryRe + + _nodeRe + + _objectRe + + _propertyRe + + '$' +); - if ( param.isNode ) { +const _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ]; - type = 'int'; - name = this.getVarName( i ); - start = '0'; - end = param.build( builder, type ); - condition = '<'; +class Composite { - } else { + constructor( targetGroup, path, optionalParsedPath ) { - type = param.type || 'int'; - name = param.name || this.getVarName( i ); - start = param.start; - end = param.end; - condition = param.condition; - update = param.update; + const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); - if ( typeof start === 'number' ) start = start.toString(); - else if ( start && start.isNode ) start = start.build( builder, type ); + this._targetGroup = targetGroup; + this._bindings = targetGroup.subscribe_( path, parsedPath ); - if ( typeof end === 'number' ) end = end.toString(); - else if ( end && end.isNode ) end = end.build( builder, type ); + } - if ( start !== undefined && end === undefined ) { + getValue( array, offset ) { - start = start + ' - 1'; - end = '0'; - condition = '>='; + this.bind(); // bind all binding - } else if ( end !== undefined && start === undefined ) { + const firstValidIndex = this._targetGroup.nCachedObjects_, + binding = this._bindings[ firstValidIndex ]; - start = '0'; - condition = '<'; + // and only call .getValue on the first + if ( binding !== undefined ) binding.getValue( array, offset ); - } + } - if ( condition === undefined ) { + setValue( array, offset ) { - if ( Number( start ) > Number( end ) ) { + const bindings = this._bindings; - condition = '>='; + for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - } else { + bindings[ i ].setValue( array, offset ); - condition = '<'; + } - } + } - } + bind() { - } + const bindings = this._bindings; - const internalParam = { start, end, condition }; + for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - // + bindings[ i ].bind(); - const startSnippet = internalParam.start; - const endSnippet = internalParam.end; + } - let declarationSnippet = ''; - let conditionalSnippet = ''; - let updateSnippet = ''; + } - if ( ! update ) { + unbind() { - if ( type === 'int' || type === 'uint' ) { + const bindings = this._bindings; - if ( condition.includes( '<' ) ) update = '++'; - else update = '--'; + for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - } else { + bindings[ i ].unbind(); - if ( condition.includes( '<' ) ) update = '+= 1.'; - else update = '-= 1.'; + } - } + } - } +} - declarationSnippet += builder.getVar( type, name ) + ' = ' + startSnippet; +// Note: This class uses a State pattern on a per-method basis: +// 'bind' sets 'this.getValue' / 'setValue' and shadows the +// prototype version of these methods with one that represents +// the bound state. When the property is not found, the methods +// become no-ops. +class PropertyBinding { - conditionalSnippet += name + ' ' + condition + ' ' + endSnippet; - updateSnippet += name + ' ' + update; + constructor( rootNode, path, parsedPath ) { - const forSnippet = `for ( ${ declarationSnippet }; ${ conditionalSnippet }; ${ updateSnippet } )`; + this.path = path; + this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); - builder.addFlowCode( ( i === 0 ? '\n' : '' ) + builder.tab + forSnippet + ' {\n\n' ).addFlowTab(); + this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ); - } + this.rootNode = rootNode; - const stackSnippet = stackNode.build( builder, 'void' ); + // initial state of these methods that calls 'bind' + this.getValue = this._getValue_unbound; + this.setValue = this._setValue_unbound; - const returnsSnippet = properties.returnsNode ? properties.returnsNode.build( builder ) : ''; + } - builder.removeFlowTab().addFlowCode( '\n' + builder.tab + stackSnippet ); - for ( let i = 0, l = this.params.length - 1; i < l; i ++ ) { + static create( root, path, parsedPath ) { - builder.addFlowCode( ( i === 0 ? '' : builder.tab ) + '}\n\n' ).removeFlowTab(); + if ( ! ( root && root.isAnimationObjectGroup ) ) { - } + return new PropertyBinding( root, path, parsedPath ); - builder.addFlowTab(); + } else { - return returnsSnippet; + return new PropertyBinding.Composite( root, path, parsedPath ); + + } } -} + /** + * Replaces spaces with underscores and removes unsupported characters from + * node names, to ensure compatibility with parseTrackName(). + * + * @param {string} name Node name to be sanitized. + * @return {string} + */ + static sanitizeNodeName( name ) { -LoopNode.type = /*@__PURE__*/ registerNode( 'Loop', LoopNode ); + return name.replace( /\s/g, '_' ).replace( _reservedRe, '' ); -const Loop = ( ...params ) => nodeObject( new LoopNode( nodeArray( params, 'int' ) ) ).append(); -const Continue = () => expression( 'continue' ).append(); -const Break = () => expression( 'break' ).append(); + } -const _morphTextures = /*@__PURE__*/ new WeakMap(); -const _morphVec4 = /*@__PURE__*/ new Vector4(); + static parseTrackName( trackName ) { -const getMorph = /*@__PURE__*/ Fn( ( { bufferMap, influence, stride, width, depth, offset } ) => { + const matches = _trackRe.exec( trackName ); - const texelIndex = int( vertexIndex ).mul( stride ).add( offset ); + if ( matches === null ) { - const y = texelIndex.div( width ); - const x = texelIndex.sub( y.mul( width ) ); + throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); - const bufferAttrib = textureLoad( bufferMap, ivec2( x, y ) ).depth( depth ); + } - return bufferAttrib.mul( influence ); + const results = { + // directoryName: matches[ 1 ], // (tschw) currently unused + nodeName: matches[ 2 ], + objectName: matches[ 3 ], + objectIndex: matches[ 4 ], + propertyName: matches[ 5 ], // required + propertyIndex: matches[ 6 ] + }; -} ); + const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); -function getEntry( geometry ) { + if ( lastDot !== undefined && lastDot !== - 1 ) { - const hasMorphPosition = geometry.morphAttributes.position !== undefined; - const hasMorphNormals = geometry.morphAttributes.normal !== undefined; - const hasMorphColors = geometry.morphAttributes.color !== undefined; + const objectName = results.nodeName.substring( lastDot + 1 ); - // instead of using attributes, the WebGL 2 code path encodes morph targets - // into an array of data textures. Each layer represents a single morph target. + // Object names must be checked against an allowlist. Otherwise, there + // is no way to parse 'foo.bar.baz': 'baz' must be a property, but + // 'bar' could be the objectName, or part of a nodeName (which can + // include '.' characters). + if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) { - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; + results.nodeName = results.nodeName.substring( 0, lastDot ); + results.objectName = objectName; - let entry = _morphTextures.get( geometry ); + } - if ( entry === undefined || entry.count !== morphTargetsCount ) { + } - if ( entry !== undefined ) entry.texture.dispose(); + if ( results.propertyName === null || results.propertyName.length === 0 ) { - const morphTargets = geometry.morphAttributes.position || []; - const morphNormals = geometry.morphAttributes.normal || []; - const morphColors = geometry.morphAttributes.color || []; + throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); - let vertexDataCount = 0; + } - if ( hasMorphPosition === true ) vertexDataCount = 1; - if ( hasMorphNormals === true ) vertexDataCount = 2; - if ( hasMorphColors === true ) vertexDataCount = 3; + return results; - let width = geometry.attributes.position.count * vertexDataCount; - let height = 1; + } - const maxTextureSize = 4096; // @TODO: Use 'capabilities.maxTextureSize' + static findNode( root, nodeName ) { - if ( width > maxTextureSize ) { + if ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { - height = Math.ceil( width / maxTextureSize ); - width = maxTextureSize; + return root; } - const buffer = new Float32Array( width * height * 4 * morphTargetsCount ); - - const bufferTexture = new DataArrayTexture( buffer, width, height, morphTargetsCount ); - bufferTexture.type = FloatType; - bufferTexture.needsUpdate = true; + // search into skeleton bones. + if ( root.skeleton ) { - // fill buffer + const bone = root.skeleton.getBoneByName( nodeName ); - const vertexDataStride = vertexDataCount * 4; + if ( bone !== undefined ) { - for ( let i = 0; i < morphTargetsCount; i ++ ) { + return bone; - const morphTarget = morphTargets[ i ]; - const morphNormal = morphNormals[ i ]; - const morphColor = morphColors[ i ]; + } - const offset = width * height * 4 * i; + } - for ( let j = 0; j < morphTarget.count; j ++ ) { + // search into node subtree. + if ( root.children ) { - const stride = j * vertexDataStride; + const searchNodeSubtree = function ( children ) { - if ( hasMorphPosition === true ) { + for ( let i = 0; i < children.length; i ++ ) { - _morphVec4.fromBufferAttribute( morphTarget, j ); + const childNode = children[ i ]; - buffer[ offset + stride + 0 ] = _morphVec4.x; - buffer[ offset + stride + 1 ] = _morphVec4.y; - buffer[ offset + stride + 2 ] = _morphVec4.z; - buffer[ offset + stride + 3 ] = 0; + if ( childNode.name === nodeName || childNode.uuid === nodeName ) { - } + return childNode; - if ( hasMorphNormals === true ) { + } - _morphVec4.fromBufferAttribute( morphNormal, j ); + const result = searchNodeSubtree( childNode.children ); - buffer[ offset + stride + 4 ] = _morphVec4.x; - buffer[ offset + stride + 5 ] = _morphVec4.y; - buffer[ offset + stride + 6 ] = _morphVec4.z; - buffer[ offset + stride + 7 ] = 0; + if ( result ) return result; } - if ( hasMorphColors === true ) { + return null; - _morphVec4.fromBufferAttribute( morphColor, j ); + }; - buffer[ offset + stride + 8 ] = _morphVec4.x; - buffer[ offset + stride + 9 ] = _morphVec4.y; - buffer[ offset + stride + 10 ] = _morphVec4.z; - buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? _morphVec4.w : 1; + const subTreeNode = searchNodeSubtree( root.children ); - } + if ( subTreeNode ) { + + return subTreeNode; } } - entry = { - count: morphTargetsCount, - texture: bufferTexture, - stride: vertexDataCount, - size: new Vector2( width, height ) - }; - - _morphTextures.set( geometry, entry ); - - function disposeTexture() { + return null; - bufferTexture.dispose(); + } - _morphTextures.delete( geometry ); + // these are used to "bind" a nonexistent property + _getValue_unavailable() {} + _setValue_unavailable() {} - geometry.removeEventListener( 'dispose', disposeTexture ); + // Getters - } + _getValue_direct( buffer, offset ) { - geometry.addEventListener( 'dispose', disposeTexture ); + buffer[ offset ] = this.targetObject[ this.propertyName ]; } - return entry; - -} - - -class MorphNode extends Node { + _getValue_array( buffer, offset ) { - constructor( mesh ) { + const source = this.resolvedProperty; - super( 'void' ); + for ( let i = 0, n = source.length; i !== n; ++ i ) { - this.mesh = mesh; - this.morphBaseInfluence = uniform( 1 ); + buffer[ offset ++ ] = source[ i ]; - this.updateType = NodeUpdateType.OBJECT; + } } - setup( builder ) { + _getValue_arrayElement( buffer, offset ) { - const { geometry } = builder; + buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; - const hasMorphPosition = geometry.morphAttributes.position !== undefined; - const hasMorphNormals = geometry.hasAttribute( 'normal' ) && geometry.morphAttributes.normal !== undefined; + } - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; + _getValue_toArray( buffer, offset ) { - // nodes + this.resolvedProperty.toArray( buffer, offset ); - const { texture: bufferMap, stride, size } = getEntry( geometry ); + } - if ( hasMorphPosition === true ) positionLocal.mulAssign( this.morphBaseInfluence ); - if ( hasMorphNormals === true ) normalLocal.mulAssign( this.morphBaseInfluence ); + // Direct - const width = int( size.width ); + _setValue_direct( buffer, offset ) { - Loop( morphTargetsCount, ( { i } ) => { + this.targetObject[ this.propertyName ] = buffer[ offset ]; - const influence = float( 0 ).toVar(); + } - if ( this.mesh.count > 1 && ( this.mesh.morphTexture !== null && this.mesh.morphTexture !== undefined ) ) { + _setValue_direct_setNeedsUpdate( buffer, offset ) { - influence.assign( textureLoad( this.mesh.morphTexture, ivec2( int( i ).add( 1 ), int( instanceIndex ) ) ).r ); + this.targetObject[ this.propertyName ] = buffer[ offset ]; + this.targetObject.needsUpdate = true; - } else { + } - influence.assign( reference( 'morphTargetInfluences', 'float' ).element( i ).toVar() ); + _setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { - } + this.targetObject[ this.propertyName ] = buffer[ offset ]; + this.targetObject.matrixWorldNeedsUpdate = true; - if ( hasMorphPosition === true ) { + } - positionLocal.addAssign( getMorph( { - bufferMap, - influence, - stride, - width, - depth: i, - offset: int( 0 ) - } ) ); + // EntireArray - } + _setValue_array( buffer, offset ) { - if ( hasMorphNormals === true ) { + const dest = this.resolvedProperty; - normalLocal.addAssign( getMorph( { - bufferMap, - influence, - stride, - width, - depth: i, - offset: int( 1 ) - } ) ); + for ( let i = 0, n = dest.length; i !== n; ++ i ) { - } + dest[ i ] = buffer[ offset ++ ]; - } ); + } } - update() { - - const morphBaseInfluence = this.morphBaseInfluence; - - if ( this.mesh.geometry.morphTargetsRelative ) { + _setValue_array_setNeedsUpdate( buffer, offset ) { - morphBaseInfluence.value = 1; + const dest = this.resolvedProperty; - } else { + for ( let i = 0, n = dest.length; i !== n; ++ i ) { - morphBaseInfluence.value = 1 - this.mesh.morphTargetInfluences.reduce( ( a, b ) => a + b, 0 ); + dest[ i ] = buffer[ offset ++ ]; } - } + this.targetObject.needsUpdate = true; -} + } -MorphNode.type = /*@__PURE__*/ registerNode( 'Morph', MorphNode ); + _setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { -const morphReference = /*@__PURE__*/ nodeProxy( MorphNode ); + const dest = this.resolvedProperty; -const sortLights = ( lights ) => { + for ( let i = 0, n = dest.length; i !== n; ++ i ) { - return lights.sort( ( a, b ) => a.id - b.id ); + dest[ i ] = buffer[ offset ++ ]; -}; + } -const getLightNodeById = ( id, lightNodes ) => { + this.targetObject.matrixWorldNeedsUpdate = true; - for ( const lightNode of lightNodes ) { + } - if ( lightNode.isAnalyticLightNode && lightNode.light.id === id ) { + // ArrayElement - return lightNode; + _setValue_arrayElement( buffer, offset ) { - } + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; } - return null; - -}; + _setValue_arrayElement_setNeedsUpdate( buffer, offset ) { -class LightsNode extends Node { + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + this.targetObject.needsUpdate = true; - constructor( lights = [] ) { + } - super( 'vec3' ); + _setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { - this.totalDiffuseNode = vec3().toVar( 'totalDiffuse' ); - this.totalSpecularNode = vec3().toVar( 'totalSpecular' ); + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + this.targetObject.matrixWorldNeedsUpdate = true; - this.outgoingLightNode = vec3().toVar( 'outgoingLight' ); + } - this._lights = lights; + // HasToFromArray - this._lightNodes = null; - this._lightNodesHash = null; + _setValue_fromArray( buffer, offset ) { - this.global = true; + this.resolvedProperty.fromArray( buffer, offset ); } - getHash( builder ) { - - if ( this._lightNodesHash === null ) { - - if ( this._lightNodes === null ) this.setupLightsNode( builder ); + _setValue_fromArray_setNeedsUpdate( buffer, offset ) { - const hash = []; + this.resolvedProperty.fromArray( buffer, offset ); + this.targetObject.needsUpdate = true; - for ( const lightNode of this._lightNodes ) { + } - hash.push( lightNode.getHash() ); + _setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { - } + this.resolvedProperty.fromArray( buffer, offset ); + this.targetObject.matrixWorldNeedsUpdate = true; - this._lightNodesHash = 'lights-' + hash.join( ',' ); + } - } + _getValue_unbound( targetArray, offset ) { - return this._lightNodesHash; + this.bind(); + this.getValue( targetArray, offset ); } - analyze( builder ) { + _setValue_unbound( sourceArray, offset ) { - const properties = builder.getDataFromNode( this ); + this.bind(); + this.setValue( sourceArray, offset ); - for ( const node of properties.nodes ) { + } - node.build( builder ); + // create getter / setter pair for a property in the scene graph + bind() { - } + let targetObject = this.node; + const parsedPath = this.parsedPath; - } + const objectName = parsedPath.objectName; + const propertyName = parsedPath.propertyName; + let propertyIndex = parsedPath.propertyIndex; - setupLightsNode( builder ) { + if ( ! targetObject ) { - const lightNodes = []; + targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ); - const previousLightNodes = this._lightNodes; + this.node = targetObject; - const lights = sortLights( this._lights ); - const nodeLibrary = builder.renderer.nodes.library; + } - for ( const light of lights ) { + // set fail state so we can just 'return' on error + this.getValue = this._getValue_unavailable; + this.setValue = this._setValue_unavailable; - if ( light.isNode ) { + // ensure there is a value node + if ( ! targetObject ) { - lightNodes.push( nodeObject( light ) ); + console.warn( 'THREE.PropertyBinding: No target node found for track: ' + this.path + '.' ); + return; - } else { + } - let lightNode = null; + if ( objectName ) { - if ( previousLightNodes !== null ) { + let objectIndex = parsedPath.objectIndex; - lightNode = getLightNodeById( light.id, previousLightNodes ); // resuse existing light node + // special cases were we need to reach deeper into the hierarchy to get the face materials.... + switch ( objectName ) { - } + case 'materials': - if ( lightNode === null ) { + if ( ! targetObject.material ) { - const lightNodeClass = nodeLibrary.getLightNodeClass( light.constructor ); + console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); + return; - if ( lightNodeClass === undefined ) { + } - console.warn( `LightsNode.setupNodeLights: Light node not found for ${ light.constructor.name }` ); - continue; + if ( ! targetObject.material.materials ) { + + console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); + return; } - lightNodes.push( nodeObject( new lightNodeClass( light ) ) ); + targetObject = targetObject.material.materials; - } + break; - } + case 'bones': - } + if ( ! targetObject.skeleton ) { - this._lightNodes = lightNodes; + console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); + return; - } + } - setup( builder ) { + // potential future optimization: skip this if propertyIndex is already an integer + // and convert the integer string to a true integer. - if ( this._lightNodes === null ) this.setupLightsNode( builder ); + targetObject = targetObject.skeleton.bones; - const context = builder.context; - const lightingModel = context.lightingModel; + // support resolving morphTarget names into indices. + for ( let i = 0; i < targetObject.length; i ++ ) { - let outgoingLightNode = this.outgoingLightNode; + if ( targetObject[ i ].name === objectIndex ) { - if ( lightingModel ) { + objectIndex = i; + break; - const { _lightNodes, totalDiffuseNode, totalSpecularNode } = this; + } - context.outgoingLight = outgoingLightNode; + } - const stack = builder.addStack(); + break; - // + case 'map': - const properties = builder.getDataFromNode( this ); - properties.nodes = stack.nodes; + if ( 'map' in targetObject ) { - // + targetObject = targetObject.map; + break; - lightingModel.start( context, stack, builder ); + } - // lights + if ( ! targetObject.material ) { - for ( const lightNode of _lightNodes ) { + console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); + return; - lightNode.build( builder ); + } - } + if ( ! targetObject.material.map ) { - // + console.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this ); + return; - lightingModel.indirect( context, stack, builder ); + } - // + targetObject = targetObject.material.map; + break; - const { backdrop, backdropAlpha } = context; - const { directDiffuse, directSpecular, indirectDiffuse, indirectSpecular } = context.reflectedLight; + default: - let totalDiffuse = directDiffuse.add( indirectDiffuse ); + if ( targetObject[ objectName ] === undefined ) { - if ( backdrop !== null ) { + console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); + return; - if ( backdropAlpha !== null ) { + } - totalDiffuse = vec3( backdropAlpha.mix( totalDiffuse, backdrop ) ); + targetObject = targetObject[ objectName ]; - } else { + } - totalDiffuse = vec3( backdrop ); + + if ( objectIndex !== undefined ) { + + if ( targetObject[ objectIndex ] === undefined ) { + + console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); + return; } - context.material.transparent = true; + targetObject = targetObject[ objectIndex ]; } - totalDiffuseNode.assign( totalDiffuse ); - totalSpecularNode.assign( directSpecular.add( indirectSpecular ) ); - - outgoingLightNode.assign( totalDiffuseNode.add( totalSpecularNode ) ); + } - // + // resolve property + const nodeProperty = targetObject[ propertyName ]; - lightingModel.finish( context, stack, builder ); + if ( nodeProperty === undefined ) { - // + const nodeName = parsedPath.nodeName; - outgoingLightNode = outgoingLightNode.bypass( builder.removeStack() ); + console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + + '.' + propertyName + ' but it wasn\'t found.', targetObject ); + return; } - return outgoingLightNode; + // determine versioning scheme + let versioning = this.Versioning.None; - } + this.targetObject = targetObject; - setLights( lights ) { + if ( targetObject.needsUpdate !== undefined ) { // material - this._lights = lights; + versioning = this.Versioning.NeedsUpdate; - this._lightNodes = null; - this._lightNodesHash = null; + } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform - return this; + versioning = this.Versioning.MatrixWorldNeedsUpdate; - } + } - getLights() { + // determine how the property gets bound + let bindingType = this.BindingType.Direct; - return this._lights; + if ( propertyIndex !== undefined ) { - } + // access a sub element of the property array (only primitives are supported right now) -} + if ( propertyName === 'morphTargetInfluences' ) { -LightsNode.type = /*@__PURE__*/ registerNode( 'Lights', LightsNode ); + // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. -const lights = /*@__PURE__*/ nodeProxy( LightsNode ); + // support resolving morphTarget names into indices. + if ( ! targetObject.geometry ) { -class LightingNode extends Node { + console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); + return; - constructor() { + } - super( 'vec3' ); + if ( ! targetObject.geometry.morphAttributes ) { - this.isLightingNode = true; + console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); + return; - } + } - generate( /*builder*/ ) { + if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) { - console.warn( 'Abstract function.' ); + propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ]; - } + } -} + } -LightingNode.type = /*@__PURE__*/ registerNode( 'Lighting', LightingNode ); + bindingType = this.BindingType.ArrayElement; -class AONode extends LightingNode { + this.resolvedProperty = nodeProperty; + this.propertyIndex = propertyIndex; - constructor( aoNode = null ) { + } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { - super(); + // must use copy for Object3D.Euler/Quaternion - this.aoNode = aoNode; + bindingType = this.BindingType.HasFromToArray; - } + this.resolvedProperty = nodeProperty; - setup( builder ) { + } else if ( Array.isArray( nodeProperty ) ) { - builder.context.ambientOcclusion.mulAssign( this.aoNode ); + bindingType = this.BindingType.EntireArray; - } + this.resolvedProperty = nodeProperty; -} + } else { -AONode.type = /*@__PURE__*/ registerNode( 'AO', AONode ); + this.propertyName = propertyName; -class LightingContextNode extends ContextNode { + } - constructor( node, lightingModel = null, backdropNode = null, backdropAlphaNode = null ) { + // select getter / setter + this.getValue = this.GetterByBindingType[ bindingType ]; + this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; - super( node ); + } - this.lightingModel = lightingModel; - this.backdropNode = backdropNode; - this.backdropAlphaNode = backdropAlphaNode; + unbind() { - this._value = null; + this.node = null; - } + // back to the prototype version of getValue / setValue + // note: avoiding to mutate the shape of 'this' via 'delete' + this.getValue = this._getValue_unbound; + this.setValue = this._setValue_unbound; - getContext() { + } - const { backdropNode, backdropAlphaNode } = this; +} - const directDiffuse = vec3().toVar( 'directDiffuse' ), - directSpecular = vec3().toVar( 'directSpecular' ), - indirectDiffuse = vec3().toVar( 'indirectDiffuse' ), - indirectSpecular = vec3().toVar( 'indirectSpecular' ); +PropertyBinding.Composite = Composite; - const reflectedLight = { - directDiffuse, - directSpecular, - indirectDiffuse, - indirectSpecular - }; +PropertyBinding.prototype.BindingType = { + Direct: 0, + EntireArray: 1, + ArrayElement: 2, + HasFromToArray: 3 +}; - const context = { - radiance: vec3().toVar( 'radiance' ), - irradiance: vec3().toVar( 'irradiance' ), - iblIrradiance: vec3().toVar( 'iblIrradiance' ), - ambientOcclusion: float( 1 ).toVar( 'ambientOcclusion' ), - reflectedLight, - backdrop: backdropNode, - backdropAlpha: backdropAlphaNode - }; +PropertyBinding.prototype.Versioning = { + None: 0, + NeedsUpdate: 1, + MatrixWorldNeedsUpdate: 2 +}; - return context; +PropertyBinding.prototype.GetterByBindingType = [ - } + PropertyBinding.prototype._getValue_direct, + PropertyBinding.prototype._getValue_array, + PropertyBinding.prototype._getValue_arrayElement, + PropertyBinding.prototype._getValue_toArray, - setup( builder ) { +]; - this.value = this._value || ( this._value = this.getContext() ); - this.value.lightingModel = this.lightingModel || builder.context.lightingModel; +PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [ - return super.setup( builder ); + [ + // Direct + PropertyBinding.prototype._setValue_direct, + PropertyBinding.prototype._setValue_direct_setNeedsUpdate, + PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate, - } + ], [ -} + // EntireArray -LightingContextNode.type = /*@__PURE__*/ registerNode( 'LightingContext', LightingContextNode ); + PropertyBinding.prototype._setValue_array, + PropertyBinding.prototype._setValue_array_setNeedsUpdate, + PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate, -const lightingContext = /*@__PURE__*/ nodeProxy( LightingContextNode ); + ], [ -class IrradianceNode extends LightingNode { + // ArrayElement + PropertyBinding.prototype._setValue_arrayElement, + PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate, + PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate, - constructor( node ) { + ], [ - super(); + // HasToFromArray + PropertyBinding.prototype._setValue_fromArray, + PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate, + PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate, - this.node = node; + ] - } +]; - setup( builder ) { +/** + * + * A group of objects that receives a shared animation state. + * + * Usage: + * + * - Add objects you would otherwise pass as 'root' to the + * constructor or the .clipAction method of AnimationMixer. + * + * - Instead pass this object as 'root'. + * + * - You can also add and remove objects later when the mixer + * is running. + * + * Note: + * + * Objects of this class appear as one object to the mixer, + * so cache control of the individual objects must be done + * on the group. + * + * Limitation: + * + * - The animated properties must be compatible among the + * all objects in the group. + * + * - A single property can either be controlled through a + * target group or directly, but not both. + */ - builder.context.irradiance.addAssign( this.node ); +class AnimationObjectGroup { - } + constructor() { -} + this.isAnimationObjectGroup = true; -IrradianceNode.type = /*@__PURE__*/ registerNode( 'Irradiance', IrradianceNode ); + this.uuid = generateUUID(); -let resolution, viewportResult; + // cached objects followed by the active ones + this._objects = Array.prototype.slice.call( arguments ); -class ViewportNode extends Node { + this.nCachedObjects_ = 0; // threshold + // note: read by PropertyBinding.Composite - constructor( scope ) { + const indices = {}; + this._indicesByUUID = indices; // for bookkeeping - super(); + for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - this.scope = scope; + indices[ arguments[ i ].uuid ] = i; - this.isViewportNode = true; + } - } + this._paths = []; // inside: string + this._parsedPaths = []; // inside: { we don't care, here } + this._bindings = []; // inside: Array< PropertyBinding > + this._bindingsIndicesByPath = {}; // inside: indices in these arrays - getNodeType() { + const scope = this; - if ( this.scope === ViewportNode.VIEWPORT ) return 'vec4'; - else return 'vec2'; + this.stats = { - } + objects: { + get total() { - getUpdateType() { + return scope._objects.length; - let updateType = NodeUpdateType.NONE; + }, + get inUse() { - if ( this.scope === ViewportNode.RESOLUTION || this.scope === ViewportNode.VIEWPORT ) { + return this.total - scope.nCachedObjects_; - updateType = NodeUpdateType.RENDER; + } + }, + get bindingsPerObject() { - } + return scope._bindings.length; - this.updateType = updateType; + } - return updateType; + }; } - update( { renderer } ) { + add() { - if ( this.scope === ViewportNode.VIEWPORT ) { + const objects = this._objects, + indicesByUUID = this._indicesByUUID, + paths = this._paths, + parsedPaths = this._parsedPaths, + bindings = this._bindings, + nBindings = bindings.length; - renderer.getViewport( viewportResult ); + let knownObject = undefined, + nObjects = objects.length, + nCachedObjects = this.nCachedObjects_; - } else { + for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - renderer.getDrawingBufferSize( resolution ); + const object = arguments[ i ], + uuid = object.uuid; + let index = indicesByUUID[ uuid ]; - } + if ( index === undefined ) { - } + // unknown object -> add it to the ACTIVE region - setup( /*builder*/ ) { + index = nObjects ++; + indicesByUUID[ uuid ] = index; + objects.push( object ); - const scope = this.scope; + // accounting is done, now do the same for all bindings - let output = null; + for ( let j = 0, m = nBindings; j !== m; ++ j ) { - if ( scope === ViewportNode.RESOLUTION ) { + bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); - output = uniform( resolution || ( resolution = new Vector2() ) ); + } - } else if ( scope === ViewportNode.VIEWPORT ) { + } else if ( index < nCachedObjects ) { - output = uniform( viewportResult || ( viewportResult = new Vector4() ) ); + knownObject = objects[ index ]; - } else { + // move existing object to the ACTIVE region - output = vec2( viewportCoordinate.div( viewportResolution ) ); + const firstActiveIndex = -- nCachedObjects, + lastCachedObject = objects[ firstActiveIndex ]; - } + indicesByUUID[ lastCachedObject.uuid ] = index; + objects[ index ] = lastCachedObject; - return output; + indicesByUUID[ uuid ] = firstActiveIndex; + objects[ firstActiveIndex ] = object; - } + // accounting is done, now do the same for all bindings - generate( builder ) { + for ( let j = 0, m = nBindings; j !== m; ++ j ) { - if ( this.scope === ViewportNode.COORDINATE ) { + const bindingsForPath = bindings[ j ], + lastCached = bindingsForPath[ firstActiveIndex ]; - let coord = builder.getFragCoord(); + let binding = bindingsForPath[ index ]; - if ( builder.isFlipY() ) { + bindingsForPath[ index ] = lastCached; - // follow webgpu standards + if ( binding === undefined ) { - const resolution = builder.getNodeProperties( viewportResolution ).outputNode.build( builder ); + // since we do not bother to create new bindings + // for objects that are cached, the binding may + // or may not exist - coord = `${ builder.getType( 'vec2' ) }( ${ coord }.x, ${ resolution }.y - ${ coord }.y )`; + binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ); - } + } - return coord; + bindingsForPath[ firstActiveIndex ] = binding; - } + } - return super.generate( builder ); + } else if ( objects[ index ] !== knownObject ) { - } + console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' + + 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); -} + } // else the object is already where we want it to be -ViewportNode.COORDINATE = 'coordinate'; -ViewportNode.RESOLUTION = 'resolution'; -ViewportNode.VIEWPORT = 'viewport'; -ViewportNode.UV = 'uv'; + } // for arguments -ViewportNode.type = /*@__PURE__*/ registerNode( 'Viewport', ViewportNode ); + this.nCachedObjects_ = nCachedObjects; -const viewportCoordinate = /*@__PURE__*/ nodeImmutable( ViewportNode, ViewportNode.COORDINATE ); -const viewportResolution = /*@__PURE__*/ nodeImmutable( ViewportNode, ViewportNode.RESOLUTION ); -const viewport = /*@__PURE__*/ nodeImmutable( ViewportNode, ViewportNode.VIEWPORT ); -const viewportUV = /*@__PURE__*/ nodeImmutable( ViewportNode, ViewportNode.UV ); + } -const viewportTopLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 + remove() { - console.warn( 'TSL.ViewportNode: "viewportTopLeft" is deprecated. Use "viewportUV" instead.' ); + const objects = this._objects, + indicesByUUID = this._indicesByUUID, + bindings = this._bindings, + nBindings = bindings.length; - return viewportUV; + let nCachedObjects = this.nCachedObjects_; -}, 'vec2' ).once() )(); + for ( let i = 0, n = arguments.length; i !== n; ++ i ) { -const viewportBottomLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 + const object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ]; - console.warn( 'TSL.ViewportNode: "viewportBottomLeft" is deprecated. Use "viewportUV.flipY()" instead.' ); + if ( index !== undefined && index >= nCachedObjects ) { - return viewportUV.flipY(); + // move existing object into the CACHED region -}, 'vec2' ).once() )(); + const lastCachedIndex = nCachedObjects ++, + firstActiveObject = objects[ lastCachedIndex ]; -const _size$a = /*@__PURE__*/ new Vector2(); + indicesByUUID[ firstActiveObject.uuid ] = index; + objects[ index ] = firstActiveObject; -class ViewportTextureNode extends TextureNode { + indicesByUUID[ uuid ] = lastCachedIndex; + objects[ lastCachedIndex ] = object; - constructor( uvNode = viewportUV, levelNode = null, framebufferTexture = null ) { + // accounting is done, now do the same for all bindings - if ( framebufferTexture === null ) { + for ( let j = 0, m = nBindings; j !== m; ++ j ) { - framebufferTexture = new FramebufferTexture(); - framebufferTexture.minFilter = LinearMipmapLinearFilter; + const bindingsForPath = bindings[ j ], + firstActive = bindingsForPath[ lastCachedIndex ], + binding = bindingsForPath[ index ]; - } + bindingsForPath[ index ] = firstActive; + bindingsForPath[ lastCachedIndex ] = binding; - super( framebufferTexture, uvNode, levelNode ); + } - this.generateMipmaps = false; + } - this.isOutputTextureNode = true; + } // for arguments - this.updateBeforeType = NodeUpdateType.FRAME; + this.nCachedObjects_ = nCachedObjects; } - updateBefore( frame ) { + // remove & forget + uncache() { - const renderer = frame.renderer; - renderer.getDrawingBufferSize( _size$a ); + const objects = this._objects, + indicesByUUID = this._indicesByUUID, + bindings = this._bindings, + nBindings = bindings.length; - // + let nCachedObjects = this.nCachedObjects_, + nObjects = objects.length; - const framebufferTexture = this.value; + for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - if ( framebufferTexture.image.width !== _size$a.width || framebufferTexture.image.height !== _size$a.height ) { + const object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ]; - framebufferTexture.image.width = _size$a.width; - framebufferTexture.image.height = _size$a.height; - framebufferTexture.needsUpdate = true; + if ( index !== undefined ) { - } + delete indicesByUUID[ uuid ]; - // + if ( index < nCachedObjects ) { - const currentGenerateMipmaps = framebufferTexture.generateMipmaps; - framebufferTexture.generateMipmaps = this.generateMipmaps; + // object is cached, shrink the CACHED region - renderer.copyFramebufferToTexture( framebufferTexture ); + const firstActiveIndex = -- nCachedObjects, + lastCachedObject = objects[ firstActiveIndex ], + lastIndex = -- nObjects, + lastObject = objects[ lastIndex ]; - framebufferTexture.generateMipmaps = currentGenerateMipmaps; + // last cached object takes this object's place + indicesByUUID[ lastCachedObject.uuid ] = index; + objects[ index ] = lastCachedObject; - } + // last object goes to the activated slot and pop + indicesByUUID[ lastObject.uuid ] = firstActiveIndex; + objects[ firstActiveIndex ] = lastObject; + objects.pop(); - clone() { + // accounting is done, now do the same for all bindings - const viewportTextureNode = new this.constructor( this.uvNode, this.levelNode, this.value ); - viewportTextureNode.generateMipmaps = this.generateMipmaps; + for ( let j = 0, m = nBindings; j !== m; ++ j ) { - return viewportTextureNode; + const bindingsForPath = bindings[ j ], + lastCached = bindingsForPath[ firstActiveIndex ], + last = bindingsForPath[ lastIndex ]; - } + bindingsForPath[ index ] = lastCached; + bindingsForPath[ firstActiveIndex ] = last; + bindingsForPath.pop(); -} + } -ViewportTextureNode.type = /*@__PURE__*/ registerNode( 'ViewportTexture', ViewportTextureNode ); + } else { -const viewportTexture = /*@__PURE__*/ nodeProxy( ViewportTextureNode ); -const viewportMipTexture = /*@__PURE__*/ nodeProxy( ViewportTextureNode, null, null, { generateMipmaps: true } ); + // object is active, just swap with the last and pop -let sharedDepthbuffer = null; + const lastIndex = -- nObjects, + lastObject = objects[ lastIndex ]; -class ViewportDepthTextureNode extends ViewportTextureNode { + if ( lastIndex > 0 ) { - constructor( uvNode = viewportUV, levelNode = null ) { + indicesByUUID[ lastObject.uuid ] = index; - if ( sharedDepthbuffer === null ) { + } - sharedDepthbuffer = new DepthTexture(); + objects[ index ] = lastObject; + objects.pop(); - } + // accounting is done, now do the same for all bindings - super( uvNode, levelNode, sharedDepthbuffer ); + for ( let j = 0, m = nBindings; j !== m; ++ j ) { - } + const bindingsForPath = bindings[ j ]; -} + bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; + bindingsForPath.pop(); -ViewportDepthTextureNode.type = /*@__PURE__*/ registerNode( 'ViewportDepthTexture', ViewportDepthTextureNode ); + } -const viewportDepthTexture = /*@__PURE__*/ nodeProxy( ViewportDepthTextureNode ); + } // cached or active -class ViewportDepthNode extends Node { + } // if object is known - constructor( scope, valueNode = null ) { + } // for arguments - super( 'float' ); + this.nCachedObjects_ = nCachedObjects; - this.scope = scope; - this.valueNode = valueNode; + } - this.isViewportDepthNode = true; + // Internal interface used by befriended PropertyBinding.Composite: - } + subscribe_( path, parsedPath ) { - generate( builder ) { + // returns an array of bindings for the given path that is changed + // according to the contained objects in the group - const { scope } = this; + const indicesByPath = this._bindingsIndicesByPath; + let index = indicesByPath[ path ]; + const bindings = this._bindings; - if ( scope === ViewportDepthNode.DEPTH_BASE ) { + if ( index !== undefined ) return bindings[ index ]; - return builder.getFragDepth(); + const paths = this._paths, + parsedPaths = this._parsedPaths, + objects = this._objects, + nObjects = objects.length, + nCachedObjects = this.nCachedObjects_, + bindingsForPath = new Array( nObjects ); - } + index = bindings.length; - return super.generate( builder ); + indicesByPath[ path ] = index; - } + paths.push( path ); + parsedPaths.push( parsedPath ); + bindings.push( bindingsForPath ); - setup( { camera } ) { + for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) { - const { scope } = this; - const value = this.valueNode; + const object = objects[ i ]; + bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); - let node = null; + } - if ( scope === ViewportDepthNode.DEPTH_BASE ) { + return bindingsForPath; - if ( value !== null ) { + } - node = depthBase().assign( value ); + unsubscribe_( path ) { - } + // tells the group to forget about a property path and no longer + // update the array previously obtained with 'subscribe_' - } else if ( scope === ViewportDepthNode.DEPTH ) { + const indicesByPath = this._bindingsIndicesByPath, + index = indicesByPath[ path ]; - if ( camera.isPerspectiveCamera ) { + if ( index !== undefined ) { - node = viewZToPerspectiveDepth( positionView.z, cameraNear, cameraFar ); + const paths = this._paths, + parsedPaths = this._parsedPaths, + bindings = this._bindings, + lastBindingsIndex = bindings.length - 1, + lastBindings = bindings[ lastBindingsIndex ], + lastBindingsPath = path[ lastBindingsIndex ]; - } else { + indicesByPath[ lastBindingsPath ] = index; - node = viewZToOrthographicDepth( positionView.z, cameraNear, cameraFar ); + bindings[ index ] = lastBindings; + bindings.pop(); - } + parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; + parsedPaths.pop(); - } else if ( scope === ViewportDepthNode.LINEAR_DEPTH ) { + paths[ index ] = paths[ lastBindingsIndex ]; + paths.pop(); - if ( value !== null ) { + } - if ( camera.isPerspectiveCamera ) { + } - const viewZ = perspectiveDepthToViewZ( value, cameraNear, cameraFar ); +} - node = viewZToOrthographicDepth( viewZ, cameraNear, cameraFar ); +class AnimationAction { - } else { + constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) { - node = value; + this._mixer = mixer; + this._clip = clip; + this._localRoot = localRoot; + this.blendMode = blendMode; - } + const tracks = clip.tracks, + nTracks = tracks.length, + interpolants = new Array( nTracks ); - } else { + const interpolantSettings = { + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding + }; - node = viewZToOrthographicDepth( positionView.z, cameraNear, cameraFar ); + for ( let i = 0; i !== nTracks; ++ i ) { - } + const interpolant = tracks[ i ].createInterpolant( null ); + interpolants[ i ] = interpolant; + interpolant.settings = interpolantSettings; } - return node; + this._interpolantSettings = interpolantSettings; - } + this._interpolants = interpolants; // bound by the mixer -} + // inside: PropertyMixer (managed by the mixer) + this._propertyBindings = new Array( nTracks ); -ViewportDepthNode.DEPTH_BASE = 'depthBase'; -ViewportDepthNode.DEPTH = 'depth'; -ViewportDepthNode.LINEAR_DEPTH = 'linearDepth'; + this._cacheIndex = null; // for the memory manager + this._byClipCacheIndex = null; // for the memory manager -ViewportDepthNode.type = /*@__PURE__*/ registerNode( 'ViewportDepth', ViewportDepthNode ); + this._timeScaleInterpolant = null; + this._weightInterpolant = null; -// NOTE: viewZ, the z-coordinate in camera space, is negative for points in front of the camera + this.loop = LoopRepeat; + this._loopCount = - 1; -// -near maps to 0; -far maps to 1 -const viewZToOrthographicDepth = ( viewZ, near, far ) => viewZ.add( near ).div( near.sub( far ) ); + // global mixer time when the action is to be started + // it's set back to 'null' upon start of the action + this._startTime = null; -// maps orthographic depth in [ 0, 1 ] to viewZ -const orthographicDepthToViewZ = ( depth, near, far ) => near.sub( far ).mul( depth ).sub( near ); + // scaled local time of the action + // gets clamped or wrapped to 0..clip.duration according to loop + this.time = 0; -// NOTE: https://twitter.com/gonnavis/status/1377183786949959682 + this.timeScale = 1; + this._effectiveTimeScale = 1; -// -near maps to 0; -far maps to 1 -const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ ).mul( far ).div( far.sub( near ).mul( viewZ ) ); + this.weight = 1; + this._effectiveWeight = 1; -// maps perspective depth in [ 0, 1 ] to viewZ -const perspectiveDepthToViewZ = ( depth, near, far ) => near.mul( far ).div( far.sub( near ).mul( depth ).sub( far ) ); + this.repetitions = Infinity; // no. of repetitions when looping -const depthBase = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.DEPTH_BASE ); + this.paused = false; // true -> zero effective time scale + this.enabled = true; // false -> zero effective weight -const depth = /*@__PURE__*/ nodeImmutable( ViewportDepthNode, ViewportDepthNode.DEPTH ); -const linearDepth = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.LINEAR_DEPTH ); -const viewportLinearDepth = /*@__PURE__*/ linearDepth( viewportDepthTexture() ); + this.clampWhenFinished = false;// keep feeding the last frame? -depth.assign = ( value ) => depthBase( value ); + this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate + this.zeroSlopeAtEnd = true;// clips for start, loop and end -class ClippingNode extends Node { + } - constructor( scope = ClippingNode.DEFAULT ) { + // State & Scheduling - super(); + play() { - this.scope = scope; + this._mixer._activateAction( this ); - } + return this; - setup( builder ) { + } - super.setup( builder ); + stop() { - const clippingContext = builder.clippingContext; - const { localClipIntersection, localClippingCount, globalClippingCount } = clippingContext; + this._mixer._deactivateAction( this ); - const numClippingPlanes = globalClippingCount + localClippingCount; - const numUnionClippingPlanes = localClipIntersection ? numClippingPlanes - localClippingCount : numClippingPlanes; + return this.reset(); - if ( this.scope === ClippingNode.ALPHA_TO_COVERAGE ) { + } - return this.setupAlphaToCoverage( clippingContext.planes, numClippingPlanes, numUnionClippingPlanes ); + reset() { - } else { + this.paused = false; + this.enabled = true; - return this.setupDefault( clippingContext.planes, numClippingPlanes, numUnionClippingPlanes ); + this.time = 0; // restart clip + this._loopCount = - 1;// forget previous loops + this._startTime = null;// forget scheduling - } + return this.stopFading().stopWarping(); } - setupAlphaToCoverage( planes, numClippingPlanes, numUnionClippingPlanes ) { - - return Fn( () => { + isRunning() { - const clippingPlanes = uniformArray( planes ); + return this.enabled && ! this.paused && this.timeScale !== 0 && + this._startTime === null && this._mixer._isActiveAction( this ); - const distanceToPlane = property( 'float', 'distanceToPlane' ); - const distanceGradient = property( 'float', 'distanceToGradient' ); + } - const clipOpacity = property( 'float', 'clipOpacity' ); + // return true when play has been called + isScheduled() { - clipOpacity.assign( 1 ); + return this._mixer._isActiveAction( this ); - let plane; + } - Loop( numUnionClippingPlanes, ( { i } ) => { + startAt( time ) { - plane = clippingPlanes.element( i ); + this._startTime = time; - distanceToPlane.assign( positionView.dot( plane.xyz ).negate().add( plane.w ) ); - distanceGradient.assign( distanceToPlane.fwidth().div( 2.0 ) ); + return this; - clipOpacity.mulAssign( smoothstep( distanceGradient.negate(), distanceGradient, distanceToPlane ) ); + } - clipOpacity.equal( 0.0 ).discard(); + setLoop( mode, repetitions ) { - } ); + this.loop = mode; + this.repetitions = repetitions; - if ( numUnionClippingPlanes < numClippingPlanes ) { + return this; - const unionClipOpacity = property( 'float', 'unionclipOpacity' ); + } - unionClipOpacity.assign( 1 ); + // Weight - Loop( { start: numUnionClippingPlanes, end: numClippingPlanes }, ( { i } ) => { + // set the weight stopping any scheduled fading + // although .enabled = false yields an effective weight of zero, this + // method does *not* change .enabled, because it would be confusing + setEffectiveWeight( weight ) { - plane = clippingPlanes.element( i ); + this.weight = weight; - distanceToPlane.assign( positionView.dot( plane.xyz ).negate().add( plane.w ) ); - distanceGradient.assign( distanceToPlane.fwidth().div( 2.0 ) ); + // note: same logic as when updated at runtime + this._effectiveWeight = this.enabled ? weight : 0; - unionClipOpacity.mulAssign( smoothstep( distanceGradient.negate(), distanceGradient, distanceToPlane ).oneMinus() ); + return this.stopFading(); - } ); + } - clipOpacity.mulAssign( unionClipOpacity.oneMinus() ); + // return the weight considering fading and .enabled + getEffectiveWeight() { - } + return this._effectiveWeight; - diffuseColor.a.mulAssign( clipOpacity ); + } - diffuseColor.a.equal( 0.0 ).discard(); + fadeIn( duration ) { - } )(); + return this._scheduleFading( duration, 0, 1 ); } - setupDefault( planes, numClippingPlanes, numUnionClippingPlanes ) { + fadeOut( duration ) { - return Fn( () => { + return this._scheduleFading( duration, 1, 0 ); - const clippingPlanes = uniformArray( planes ); + } - let plane; + crossFadeFrom( fadeOutAction, duration, warp ) { - Loop( numUnionClippingPlanes, ( { i } ) => { + fadeOutAction.fadeOut( duration ); + this.fadeIn( duration ); - plane = clippingPlanes.element( i ); - positionView.dot( plane.xyz ).greaterThan( plane.w ).discard(); + if ( warp ) { - } ); + const fadeInDuration = this._clip.duration, + fadeOutDuration = fadeOutAction._clip.duration, - if ( numUnionClippingPlanes < numClippingPlanes ) { + startEndRatio = fadeOutDuration / fadeInDuration, + endStartRatio = fadeInDuration / fadeOutDuration; - const clipped = property( 'bool', 'clipped' ); + fadeOutAction.warp( 1.0, startEndRatio, duration ); + this.warp( endStartRatio, 1.0, duration ); - clipped.assign( true ); + } - Loop( { start: numUnionClippingPlanes, end: numClippingPlanes }, ( { i } ) => { + return this; - plane = clippingPlanes.element( i ); - clipped.assign( positionView.dot( plane.xyz ).greaterThan( plane.w ).and( clipped ) ); + } - } ); + crossFadeTo( fadeInAction, duration, warp ) { - clipped.discard(); + return fadeInAction.crossFadeFrom( this, duration, warp ); - } + } - } )(); + stopFading() { - } + const weightInterpolant = this._weightInterpolant; -} + if ( weightInterpolant !== null ) { -ClippingNode.ALPHA_TO_COVERAGE = 'alphaToCoverage'; -ClippingNode.DEFAULT = 'default'; + this._weightInterpolant = null; + this._mixer._takeBackControlInterpolant( weightInterpolant ); -ClippingNode.type = /*@__PURE__*/ registerNode( 'Clipping', ClippingNode ); + } -const clipping = () => nodeObject( new ClippingNode() ); + return this; -const clippingAlpha = () => nodeObject( new ClippingNode( ClippingNode.ALPHA_TO_COVERAGE ) ); + } -const NodeMaterials = new Map(); + // Time Scale Control -class NodeMaterial extends Material { + // set the time scale stopping any scheduled warping + // although .paused = true yields an effective time scale of zero, this + // method does *not* change .paused, because it would be confusing + setEffectiveTimeScale( timeScale ) { - constructor() { + this.timeScale = timeScale; + this._effectiveTimeScale = this.paused ? 0 : timeScale; - super(); + return this.stopWarping(); - this.isNodeMaterial = true; + } - this.type = this.constructor.type; + // return the time scale considering warping and .paused + getEffectiveTimeScale() { - this.forceSinglePass = false; + return this._effectiveTimeScale; - this.fog = true; - this.lights = false; + } - this.lightsNode = null; - this.envNode = null; - this.aoNode = null; + setDuration( duration ) { - this.colorNode = null; - this.normalNode = null; - this.opacityNode = null; - this.backdropNode = null; - this.backdropAlphaNode = null; - this.alphaTestNode = null; + this.timeScale = this._clip.duration / duration; - this.positionNode = null; + return this.stopWarping(); - this.depthNode = null; - this.shadowNode = null; - this.shadowPositionNode = null; + } - this.outputNode = null; - this.mrtNode = null; + syncWith( action ) { - this.fragmentNode = null; - this.vertexNode = null; + this.time = action.time; + this.timeScale = action.timeScale; + + return this.stopWarping(); } - customProgramCacheKey() { + halt( duration ) { - return this.type + getCacheKey$1( this ); + return this.warp( this._effectiveTimeScale, 0, duration ); } - build( builder ) { + warp( startTimeScale, endTimeScale, duration ) { - this.setup( builder ); + const mixer = this._mixer, + now = mixer.time, + timeScale = this.timeScale; - } + let interpolant = this._timeScaleInterpolant; - setup( builder ) { + if ( interpolant === null ) { - builder.context.setupNormal = () => this.setupNormal( builder ); + interpolant = mixer._lendControlInterpolant(); + this._timeScaleInterpolant = interpolant; - // < VERTEX STAGE > + } - builder.addStack(); + const times = interpolant.parameterPositions, + values = interpolant.sampleValues; - builder.stack.outputNode = this.vertexNode || this.setupPosition( builder ); + times[ 0 ] = now; + times[ 1 ] = now + duration; - builder.addFlow( 'vertex', builder.removeStack() ); + values[ 0 ] = startTimeScale / timeScale; + values[ 1 ] = endTimeScale / timeScale; - // < FRAGMENT STAGE > + return this; - builder.addStack(); + } - let resultNode; + stopWarping() { - const clippingNode = this.setupClipping( builder ); + const timeScaleInterpolant = this._timeScaleInterpolant; - if ( this.depthWrite === true ) this.setupDepth( builder ); + if ( timeScaleInterpolant !== null ) { - if ( this.fragmentNode === null ) { + this._timeScaleInterpolant = null; + this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); - this.setupDiffuseColor( builder ); - this.setupVariants( builder ); + } - const outgoingLightNode = this.setupLighting( builder ); + return this; - if ( clippingNode !== null ) builder.stack.add( clippingNode ); + } - // force unsigned floats - useful for RenderTargets + // Object Accessors - const basicOutput = vec4( outgoingLightNode, diffuseColor.a ).max( 0 ); + getMixer() { - resultNode = this.setupOutput( builder, basicOutput ); + return this._mixer; - // OUTPUT NODE + } - output.assign( resultNode ); + getClip() { - // + return this._clip; - if ( this.outputNode !== null ) resultNode = this.outputNode; + } - // MRT + getRoot() { - const renderTarget = builder.renderer.getRenderTarget(); + return this._localRoot || this._mixer._root; - if ( renderTarget !== null ) { + } - const mrt = builder.renderer.getMRT(); - const materialMRT = this.mrtNode; + // Interna - if ( mrt !== null ) { + _update( time, deltaTime, timeDirection, accuIndex ) { - resultNode = mrt; + // called by the mixer - if ( materialMRT !== null ) { + if ( ! this.enabled ) { - resultNode = mrt.merge( materialMRT ); + // call ._updateWeight() to update ._effectiveWeight - } + this._updateWeight( time ); + return; - } else if ( materialMRT !== null ) { + } - resultNode = materialMRT; + const startTime = this._startTime; - } + if ( startTime !== null ) { - } + // check for scheduled start of action - } else { + const timeRunning = ( time - startTime ) * timeDirection; + if ( timeRunning < 0 || timeDirection === 0 ) { - let fragmentNode = this.fragmentNode; + deltaTime = 0; - if ( fragmentNode.isOutputStructNode !== true ) { + } else { - fragmentNode = vec4( fragmentNode ); - } + this._startTime = null; // unschedule + deltaTime = timeDirection * timeRunning; - resultNode = this.setupOutput( builder, fragmentNode ); + } } - builder.stack.outputNode = resultNode; + // apply time scale and advance time - builder.addFlow( 'fragment', builder.removeStack() ); + deltaTime *= this._updateTimeScale( time ); + const clipTime = this._updateTime( deltaTime ); - } + // note: _updateTime may disable the action resulting in + // an effective weight of 0 - setupClipping( builder ) { + const weight = this._updateWeight( time ); - if ( builder.clippingContext === null ) return null; + if ( weight > 0 ) { - const { globalClippingCount, localClippingCount } = builder.clippingContext; + const interpolants = this._interpolants; + const propertyMixers = this._propertyBindings; - let result = null; + switch ( this.blendMode ) { - if ( globalClippingCount || localClippingCount ) { + case AdditiveAnimationBlendMode: - if ( this.alphaToCoverage ) { + for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { - // to be added to flow when the color/alpha value has been determined - result = clippingAlpha(); + interpolants[ j ].evaluate( clipTime ); + propertyMixers[ j ].accumulateAdditive( weight ); - } else { + } - builder.stack.add( clipping() ); + break; + + case NormalAnimationBlendMode: + default: + + for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { + + interpolants[ j ].evaluate( clipTime ); + propertyMixers[ j ].accumulate( accuIndex, weight ); + + } } } - return result; - } - setupDepth( builder ) { + _updateWeight( time ) { - const { renderer } = builder; + let weight = 0; - // Depth - - let depthNode = this.depthNode; + if ( this.enabled ) { - if ( depthNode === null ) { + weight = this.weight; + const interpolant = this._weightInterpolant; - const mrt = renderer.getMRT(); + if ( interpolant !== null ) { - if ( mrt && mrt.has( 'depth' ) ) { + const interpolantValue = interpolant.evaluate( time )[ 0 ]; - depthNode = mrt.get( 'depth' ); + weight *= interpolantValue; - } else if ( renderer.logarithmicDepthBuffer === true ) { + if ( time > interpolant.parameterPositions[ 1 ] ) { - const fragDepth = modelViewProjection().w.add( 1 ); + this.stopFading(); - depthNode = fragDepth.log2().mul( cameraLogDepth ).mul( 0.5 ); + if ( interpolantValue === 0 ) { - } + // faded out, disable + this.enabled = false; - } + } - if ( depthNode !== null ) { + } - depth.assign( depthNode ).append(); + } } + this._effectiveWeight = weight; + return weight; + } - setupPosition( builder ) { + _updateTimeScale( time ) { - const { object } = builder; - const geometry = object.geometry; + let timeScale = 0; - builder.addStack(); + if ( ! this.paused ) { - // Vertex + timeScale = this.timeScale; - if ( geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color ) { + const interpolant = this._timeScaleInterpolant; - morphReference( object ).append(); + if ( interpolant !== null ) { - } + const interpolantValue = interpolant.evaluate( time )[ 0 ]; - if ( object.isSkinnedMesh === true ) { + timeScale *= interpolantValue; - skinningReference( object ).append(); + if ( time > interpolant.parameterPositions[ 1 ] ) { - } + this.stopWarping(); - if ( this.displacementMap ) { + if ( timeScale === 0 ) { - const displacementMap = materialReference( 'displacementMap', 'texture' ); - const displacementScale = materialReference( 'displacementScale', 'float' ); - const displacementBias = materialReference( 'displacementBias', 'float' ); + // motion has halted, pause + this.paused = true; - positionLocal.addAssign( normalLocal.normalize().mul( ( displacementMap.x.mul( displacementScale ).add( displacementBias ) ) ) ); + } else { - } + // warp done - apply final time scale + this.timeScale = timeScale; - if ( object.isBatchedMesh ) { + } - batch( object ).append(); + } - } + } - if ( ( object.instanceMatrix && object.instanceMatrix.isInstancedBufferAttribute === true ) ) { + } - instance( object ).append(); + this._effectiveTimeScale = timeScale; + return timeScale; - } + } - if ( this.positionNode !== null ) { + _updateTime( deltaTime ) { - positionLocal.assign( this.positionNode ); + const duration = this._clip.duration; + const loop = this.loop; - } + let time = this.time + deltaTime; + let loopCount = this._loopCount; - const mvp = modelViewProjection(); + const pingPong = ( loop === LoopPingPong ); - builder.context.vertex = builder.removeStack(); - builder.context.mvp = mvp; + if ( deltaTime === 0 ) { - return mvp; + if ( loopCount === - 1 ) return time; - } + return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time; - setupDiffuseColor( { object, geometry } ) { + } - let colorNode = this.colorNode ? vec4( this.colorNode ) : materialColor; + if ( loop === LoopOnce ) { - // VERTEX COLORS + if ( loopCount === - 1 ) { - if ( this.vertexColors === true && geometry.hasAttribute( 'color' ) ) { + // just started - colorNode = vec4( colorNode.xyz.mul( attribute( 'color', 'vec3' ) ), colorNode.a ); + this._loopCount = 0; + this._setEndings( true, true, false ); - } + } - // Instanced colors + handle_stop: { - if ( object.instanceColor ) { + if ( time >= duration ) { - const instanceColor = varyingProperty( 'vec3', 'vInstanceColor' ); + time = duration; - colorNode = instanceColor.mul( colorNode ); + } else if ( time < 0 ) { - } + time = 0; - if ( object.isBatchedMesh && object._colorsTexture ) { + } else { - const batchColor = varyingProperty( 'vec3', 'vBatchColor' ); + this.time = time; - colorNode = batchColor.mul( colorNode ); + break handle_stop; - } + } + if ( this.clampWhenFinished ) this.paused = true; + else this.enabled = false; - // COLOR + this.time = time; - diffuseColor.assign( colorNode ); + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime < 0 ? - 1 : 1 + } ); - // OPACITY + } - const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity; - diffuseColor.a.assign( diffuseColor.a.mul( opacityNode ) ); + } else { // repetitive Repeat or PingPong - // ALPHA TEST + if ( loopCount === - 1 ) { - if ( this.alphaTestNode !== null || this.alphaTest > 0 ) { + // just started - const alphaTestNode = this.alphaTestNode !== null ? float( this.alphaTestNode ) : materialAlphaTest; + if ( deltaTime >= 0 ) { - diffuseColor.a.lessThanEqual( alphaTestNode ).discard(); + loopCount = 0; - } + this._setEndings( true, this.repetitions === 0, pingPong ); - if ( this.transparent === false && this.blending === NormalBlending && this.alphaToCoverage === false ) { + } else { - diffuseColor.a.assign( 1.0 ); + // when looping in reverse direction, the initial + // transition through zero counts as a repetition, + // so leave loopCount at -1 - } + this._setEndings( this.repetitions === 0, true, pingPong ); - } + } - setupVariants( /*builder*/ ) { + } - // Interface function. + if ( time >= duration || time < 0 ) { - } + // wrap around - setupOutgoingLight() { + const loopDelta = Math.floor( time / duration ); // signed + time -= duration * loopDelta; - return ( this.lights === true ) ? vec3( 0 ) : diffuseColor.rgb; + loopCount += Math.abs( loopDelta ); - } + const pending = this.repetitions - loopCount; - setupNormal() { + if ( pending <= 0 ) { - return this.normalNode ? vec3( this.normalNode ) : materialNormal; + // have to stop (switch state, clamp time, fire event) - } + if ( this.clampWhenFinished ) this.paused = true; + else this.enabled = false; - setupEnvironment( /*builder*/ ) { + time = deltaTime > 0 ? duration : 0; - let node = null; + this.time = time; - if ( this.envNode ) { + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime > 0 ? 1 : - 1 + } ); - node = this.envNode; + } else { - } else if ( this.envMap ) { + // keep running - node = this.envMap.isCubeTexture ? materialReference( 'envMap', 'cubeTexture' ) : materialReference( 'envMap', 'texture' ); + if ( pending === 1 ) { - } + // entering the last round - return node; + const atStart = deltaTime < 0; + this._setEndings( atStart, ! atStart, pingPong ); - } + } else { - setupLightMap( builder ) { + this._setEndings( false, false, pingPong ); - let node = null; + } - if ( builder.material.lightMap ) { + this._loopCount = loopCount; - node = new IrradianceNode( materialLightMap ); + this.time = time; - } + this._mixer.dispatchEvent( { + type: 'loop', action: this, loopDelta: loopDelta + } ); - return node; + } - } + } else { - setupLights( builder ) { + this.time = time; - const materialLightsNode = []; + } - // + if ( pingPong && ( loopCount & 1 ) === 1 ) { - const envNode = this.setupEnvironment( builder ); + // invert time for the "pong round" - if ( envNode && envNode.isLightingNode ) { + return duration - time; - materialLightsNode.push( envNode ); + } } - const lightMapNode = this.setupLightMap( builder ); + return time; - if ( lightMapNode && lightMapNode.isLightingNode ) { + } - materialLightsNode.push( lightMapNode ); + _setEndings( atStart, atEnd, pingPong ) { - } + const settings = this._interpolantSettings; - if ( this.aoNode !== null || builder.material.aoMap ) { + if ( pingPong ) { - const aoNode = this.aoNode !== null ? this.aoNode : materialAOMap; + settings.endingStart = ZeroSlopeEnding; + settings.endingEnd = ZeroSlopeEnding; - materialLightsNode.push( new AONode( aoNode ) ); + } else { - } + // assuming for LoopOnce atStart == atEnd == true - let lightsN = this.lightsNode || builder.lightsNode; + if ( atStart ) { - if ( materialLightsNode.length > 0 ) { + settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; - lightsN = lights( [ ...lightsN.getLights(), ...materialLightsNode ] ); + } else { - } + settings.endingStart = WrapAroundEnding; - return lightsN; + } - } + if ( atEnd ) { - setupLightingModel( /*builder*/ ) { + settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; - // Interface function. + } else { - } + settings.endingEnd = WrapAroundEnding; - setupLighting( builder ) { + } - const { material } = builder; - const { backdropNode, backdropAlphaNode, emissiveNode } = this; + } - // OUTGOING LIGHT + } - const lights = this.lights === true || this.lightsNode !== null; + _scheduleFading( duration, weightNow, weightThen ) { - const lightsNode = lights ? this.setupLights( builder ) : null; + const mixer = this._mixer, now = mixer.time; + let interpolant = this._weightInterpolant; - let outgoingLightNode = this.setupOutgoingLight( builder ); + if ( interpolant === null ) { - if ( lightsNode && lightsNode.getScope().getLights().length > 0 ) { + interpolant = mixer._lendControlInterpolant(); + this._weightInterpolant = interpolant; - const lightingModel = this.setupLightingModel( builder ); + } - outgoingLightNode = lightingContext( lightsNode, lightingModel, backdropNode, backdropAlphaNode ); + const times = interpolant.parameterPositions, + values = interpolant.sampleValues; - } else if ( backdropNode !== null ) { + times[ 0 ] = now; + values[ 0 ] = weightNow; + times[ 1 ] = now + duration; + values[ 1 ] = weightThen; - outgoingLightNode = vec3( backdropAlphaNode !== null ? mix( outgoingLightNode, backdropNode, backdropAlphaNode ) : backdropNode ); + return this; - } + } - // EMISSIVE +} - if ( ( emissiveNode && emissiveNode.isNode === true ) || ( material.emissive && material.emissive.isColor === true ) ) { +const _controlInterpolantsResultBuffer = new Float32Array( 1 ); - emissive.assign( vec3( emissiveNode ? emissiveNode : materialEmissive ) ); - outgoingLightNode = outgoingLightNode.add( emissive ); +class AnimationMixer extends EventDispatcher { - } + constructor( root ) { - return outgoingLightNode; + super(); + + this._root = root; + this._initMemoryManager(); + this._accuIndex = 0; + this.time = 0; + this.timeScale = 1.0; } - setupOutput( builder, outputNode ) { + _bindAction( action, prototypeAction ) { - // FOG + const root = action._localRoot || this._root, + tracks = action._clip.tracks, + nTracks = tracks.length, + bindings = action._propertyBindings, + interpolants = action._interpolants, + rootUuid = root.uuid, + bindingsByRoot = this._bindingsByRootAndName; - if ( this.fog === true ) { + let bindingsByName = bindingsByRoot[ rootUuid ]; - const fogNode = builder.fogNode; + if ( bindingsByName === undefined ) { - if ( fogNode ) outputNode = vec4( fogNode.mix( outputNode.rgb, fogNode.colorNode ), outputNode.a ); + bindingsByName = {}; + bindingsByRoot[ rootUuid ] = bindingsByName; } - return outputNode; + for ( let i = 0; i !== nTracks; ++ i ) { - } + const track = tracks[ i ], + trackName = track.name; - setDefaultValues( material ) { + let binding = bindingsByName[ trackName ]; - // This approach is to reuse the native refreshUniforms* - // and turn available the use of features like transmission and environment in core + if ( binding !== undefined ) { - for ( const property in material ) { + ++ binding.referenceCount; + bindings[ i ] = binding; - const value = material[ property ]; + } else { - if ( this[ property ] === undefined ) { + binding = bindings[ i ]; - this[ property ] = value; + if ( binding !== undefined ) { - if ( value && value.clone ) this[ property ] = value.clone(); + // existing binding, make sure the cache knows - } + if ( binding._cacheIndex === null ) { - } + ++ binding.referenceCount; + this._addInactiveBinding( binding, rootUuid, trackName ); - const descriptors = Object.getOwnPropertyDescriptors( material.constructor.prototype ); + } - for ( const key in descriptors ) { + continue; - if ( Object.getOwnPropertyDescriptor( this.constructor.prototype, key ) === undefined && - descriptors[ key ].get !== undefined ) { + } - Object.defineProperty( this.constructor.prototype, key, descriptors[ key ] ); + const path = prototypeAction && prototypeAction. + _propertyBindings[ i ].binding.parsedPath; + + binding = new PropertyMixer( + PropertyBinding.create( root, trackName, path ), + track.ValueTypeName, track.getValueSize() ); + + ++ binding.referenceCount; + this._addInactiveBinding( binding, rootUuid, trackName ); + + bindings[ i ] = binding; } + interpolants[ i ].resultBuffer = binding.buffer; + } } - toJSON( meta ) { - - const isRoot = ( meta === undefined || typeof meta === 'string' ); + _activateAction( action ) { - if ( isRoot ) { + if ( ! this._isActiveAction( action ) ) { - meta = { - textures: {}, - images: {}, - nodes: {} - }; + if ( action._cacheIndex === null ) { - } + // this action has been forgotten by the cache, but the user + // appears to be still using it -> rebind - const data = Material.prototype.toJSON.call( this, meta ); - const nodeChildren = getNodeChildren( this ); + const rootUuid = ( action._localRoot || this._root ).uuid, + clipUuid = action._clip.uuid, + actionsForClip = this._actionsByClip[ clipUuid ]; - data.inputNodes = {}; + this._bindAction( action, + actionsForClip && actionsForClip.knownActions[ 0 ] ); - for ( const { property, childNode } of nodeChildren ) { + this._addInactiveAction( action, clipUuid, rootUuid ); - data.inputNodes[ property ] = childNode.toJSON( meta ).uuid; + } - } + const bindings = action._propertyBindings; - // TODO: Copied from Object3D.toJSON + // increment reference counts / sort out state + for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - function extractFromCache( cache ) { + const binding = bindings[ i ]; - const values = []; + if ( binding.useCount ++ === 0 ) { - for ( const key in cache ) { + this._lendBinding( binding ); + binding.saveOriginalState(); - const data = cache[ key ]; - delete data.metadata; - values.push( data ); + } } - return values; + this._lendAction( action ); } - if ( isRoot ) { - - const textures = extractFromCache( meta.textures ); - const images = extractFromCache( meta.images ); - const nodes = extractFromCache( meta.nodes ); - - if ( textures.length > 0 ) data.textures = textures; - if ( images.length > 0 ) data.images = images; - if ( nodes.length > 0 ) data.nodes = nodes; + } - } + _deactivateAction( action ) { - return data; + if ( this._isActiveAction( action ) ) { - } + const bindings = action._propertyBindings; - copy( source ) { + // decrement reference counts / sort out state + for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - this.lightsNode = source.lightsNode; - this.envNode = source.envNode; + const binding = bindings[ i ]; - this.colorNode = source.colorNode; - this.normalNode = source.normalNode; - this.opacityNode = source.opacityNode; - this.backdropNode = source.backdropNode; - this.backdropAlphaNode = source.backdropAlphaNode; - this.alphaTestNode = source.alphaTestNode; + if ( -- binding.useCount === 0 ) { - this.positionNode = source.positionNode; + binding.restoreOriginalState(); + this._takeBackBinding( binding ); - this.depthNode = source.depthNode; - this.shadowNode = source.shadowNode; - this.shadowPositionNode = source.shadowPositionNode; + } - this.outputNode = source.outputNode; - this.mrtNode = source.mrtNode; + } - this.fragmentNode = source.fragmentNode; - this.vertexNode = source.vertexNode; + this._takeBackAction( action ); - return super.copy( source ); + } } -} + // Memory manager -NodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( '', NodeMaterial ); + _initMemoryManager() { -function registerNodeMaterial( type, nodeMaterialClass ) { + this._actions = []; // 'nActiveActions' followed by inactive ones + this._nActiveActions = 0; - const suffix = 'NodeMaterial'; - const nodeMaterialType = type + suffix; + this._actionsByClip = {}; + // inside: + // { + // knownActions: Array< AnimationAction > - used as prototypes + // actionByRoot: AnimationAction - lookup + // } - if ( typeof nodeMaterialClass !== 'function' ) throw new Error( `THREE.Node: NodeMaterial class "${ type }" is not a class.` ); - if ( NodeMaterials.has( nodeMaterialType ) ) { + this._bindings = []; // 'nActiveBindings' followed by inactive ones + this._nActiveBindings = 0; - console.warn( `THREE.Node: Redefinition of NodeMaterial class "${ nodeMaterialType }".` ); - return; + this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > - } - if ( type.slice( - suffix.length ) === suffix ) { + this._controlInterpolants = []; // same game as above + this._nActiveControlInterpolants = 0; - console.warn( `THREE.NodeMaterial: NodeMaterial class ${ nodeMaterialType } should not have '${ suffix }' suffix.` ); - return; + const scope = this; - } + this.stats = { - NodeMaterials.set( nodeMaterialType, nodeMaterialClass ); - nodeMaterialClass.type = nodeMaterialType; + actions: { + get total() { - return nodeMaterialType; + return scope._actions.length; -} + }, + get inUse() { -function createNodeMaterialFromType( type ) { + return scope._nActiveActions; - const Material = NodeMaterials.get( type ); + } + }, + bindings: { + get total() { - if ( Material !== undefined ) { + return scope._bindings.length; - return new Material(); + }, + get inUse() { - } + return scope._nActiveBindings; -} + } + }, + controlInterpolants: { + get total() { -const _defaultValues$e = /*@__PURE__*/ new PointsMaterial(); + return scope._controlInterpolants.length; -class InstancedPointsNodeMaterial extends NodeMaterial { + }, + get inUse() { - constructor( params = {} ) { + return scope._nActiveControlInterpolants; - super(); + } + } - this.lights = false; + }; - this.useAlphaToCoverage = true; + } - this.useColor = params.vertexColors; + // Memory management for AnimationAction objects - this.pointWidth = 1; + _isActiveAction( action ) { - this.pointColorNode = null; + const index = action._cacheIndex; + return index !== null && index < this._nActiveActions; - this.pointWidthNode = null; + } - this.setDefaultValues( _defaultValues$e ); + _addInactiveAction( action, clipUuid, rootUuid ) { - this.setupShaders(); + const actions = this._actions, + actionsByClip = this._actionsByClip; - this.setValues( params ); + let actionsForClip = actionsByClip[ clipUuid ]; - } + if ( actionsForClip === undefined ) { - setup( builder ) { + actionsForClip = { - this.setupShaders(); + knownActions: [ action ], + actionByRoot: {} - super.setup( builder ); + }; - } + action._byClipCacheIndex = 0; - setupShaders() { + actionsByClip[ clipUuid ] = actionsForClip; - const useAlphaToCoverage = this.alphaToCoverage; - const useColor = this.useColor; + } else { - this.vertexNode = Fn( () => { + const knownActions = actionsForClip.knownActions; - //vUv = uv; - varying( vec2(), 'vUv' ).assign( uv() ); // @TODO: Analyze other way to do this + action._byClipCacheIndex = knownActions.length; + knownActions.push( action ); - const instancePosition = attribute( 'instancePosition' ).xyz; + } - // camera space - const mvPos = property( 'vec4', 'mvPos' ); - mvPos.assign( modelViewMatrix.mul( vec4( instancePosition, 1.0 ) ) ); + action._cacheIndex = actions.length; + actions.push( action ); - const aspect = viewport.z.div( viewport.w ); + actionsForClip.actionByRoot[ rootUuid ] = action; - // clip space - const clipPos = cameraProjectionMatrix.mul( mvPos ); + } - // offset in ndc space - const offset = property( 'vec2', 'offset' ); - offset.assign( positionGeometry.xy ); + _removeInactiveAction( action ) { - offset.mulAssign( this.pointWidthNode ? this.pointWidthNode : materialPointWidth ); + const actions = this._actions, + lastInactiveAction = actions[ actions.length - 1 ], + cacheIndex = action._cacheIndex; - offset.assign( offset.div( viewport.z ) ); - offset.y.assign( offset.y.mul( aspect ) ); + lastInactiveAction._cacheIndex = cacheIndex; + actions[ cacheIndex ] = lastInactiveAction; + actions.pop(); - // back to clip space - offset.assign( offset.mul( clipPos.w ) ); + action._cacheIndex = null; - //clipPos.xy += offset; - clipPos.assign( clipPos.add( vec4( offset, 0, 0 ) ) ); - return clipPos; + const clipUuid = action._clip.uuid, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ], + knownActionsForClip = actionsForClip.knownActions, - //vec4 mvPosition = mvPos; // this was used for somethihng... + lastKnownAction = + knownActionsForClip[ knownActionsForClip.length - 1 ], - } )(); + byClipCacheIndex = action._byClipCacheIndex; - this.fragmentNode = Fn( () => { + lastKnownAction._byClipCacheIndex = byClipCacheIndex; + knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; + knownActionsForClip.pop(); - const vUv = varying( vec2(), 'vUv' ); + action._byClipCacheIndex = null; - // force assignment into correct place in flow - const alpha = property( 'float', 'alpha' ); - alpha.assign( 1 ); - const a = vUv.x; - const b = vUv.y; + const actionByRoot = actionsForClip.actionByRoot, + rootUuid = ( action._localRoot || this._root ).uuid; - const len2 = a.mul( a ).add( b.mul( b ) ); + delete actionByRoot[ rootUuid ]; - if ( useAlphaToCoverage ) { + if ( knownActionsForClip.length === 0 ) { - // force assignment out of following 'if' statement - to avoid uniform control flow errors - const dlen = property( 'float', 'dlen' ); - dlen.assign( len2.fwidth() ); + delete actionsByClip[ clipUuid ]; - alpha.assign( smoothstep( dlen.oneMinus(), dlen.add( 1 ), len2 ).oneMinus() ); + } - } else { + this._removeInactiveBindingsForAction( action ); - len2.greaterThan( 1.0 ).discard(); + } - } + _removeInactiveBindingsForAction( action ) { - let pointColorNode; + const bindings = action._propertyBindings; - if ( this.pointColorNode ) { + for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - pointColorNode = this.pointColorNode; + const binding = bindings[ i ]; - } else { + if ( -- binding.referenceCount === 0 ) { - if ( useColor ) { + this._removeInactiveBinding( binding ); - const instanceColor = attribute( 'instanceColor' ); + } - pointColorNode = instanceColor.mul( materialColor ); + } - } else { + } - pointColorNode = materialColor; + _lendAction( action ) { - } + // [ active actions | inactive actions ] + // [ active actions >| inactive actions ] + // s a + // <-swap-> + // a s - } + const actions = this._actions, + prevIndex = action._cacheIndex, - alpha.mulAssign( materialOpacity ); + lastActiveIndex = this._nActiveActions ++, - return vec4( pointColorNode, alpha ); + firstInactiveAction = actions[ lastActiveIndex ]; - } )(); + action._cacheIndex = lastActiveIndex; + actions[ lastActiveIndex ] = action; + + firstInactiveAction._cacheIndex = prevIndex; + actions[ prevIndex ] = firstInactiveAction; } - get alphaToCoverage() { + _takeBackAction( action ) { - return this.useAlphaToCoverage; + // [ active actions | inactive actions ] + // [ active actions |< inactive actions ] + // a s + // <-swap-> + // s a - } + const actions = this._actions, + prevIndex = action._cacheIndex, - set alphaToCoverage( value ) { + firstInactiveIndex = -- this._nActiveActions, - if ( this.useAlphaToCoverage !== value ) { + lastActiveAction = actions[ firstInactiveIndex ]; - this.useAlphaToCoverage = value; - this.needsUpdate = true; + action._cacheIndex = firstInactiveIndex; + actions[ firstInactiveIndex ] = action; - } + lastActiveAction._cacheIndex = prevIndex; + actions[ prevIndex ] = lastActiveAction; } -} - -InstancedPointsNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'InstancedPoints', InstancedPointsNodeMaterial ); + // Memory management for PropertyMixer objects -const _defaultValues$d = /*@__PURE__*/ new LineBasicMaterial(); + _addInactiveBinding( binding, rootUuid, trackName ) { -class LineBasicNodeMaterial extends NodeMaterial { + const bindingsByRoot = this._bindingsByRootAndName, + bindings = this._bindings; - constructor( parameters ) { + let bindingByName = bindingsByRoot[ rootUuid ]; - super(); + if ( bindingByName === undefined ) { - this.isLineBasicNodeMaterial = true; + bindingByName = {}; + bindingsByRoot[ rootUuid ] = bindingByName; - this.lights = false; + } - this.setDefaultValues( _defaultValues$d ); + bindingByName[ trackName ] = binding; - this.setValues( parameters ); + binding._cacheIndex = bindings.length; + bindings.push( binding ); } -} - -LineBasicNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'LineBasic', LineBasicNodeMaterial ); - -const _defaultValues$c = /*@__PURE__*/ new LineDashedMaterial(); - -class LineDashedNodeMaterial extends NodeMaterial { + _removeInactiveBinding( binding ) { - constructor( parameters ) { + const bindings = this._bindings, + propBinding = binding.binding, + rootUuid = propBinding.rootNode.uuid, + trackName = propBinding.path, + bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ], - super(); + lastInactiveBinding = bindings[ bindings.length - 1 ], + cacheIndex = binding._cacheIndex; - this.isLineDashedNodeMaterial = true; + lastInactiveBinding._cacheIndex = cacheIndex; + bindings[ cacheIndex ] = lastInactiveBinding; + bindings.pop(); - this.lights = false; + delete bindingByName[ trackName ]; - this.setDefaultValues( _defaultValues$c ); + if ( Object.keys( bindingByName ).length === 0 ) { - this.offsetNode = null; - this.dashScaleNode = null; - this.dashSizeNode = null; - this.gapSizeNode = null; + delete bindingsByRoot[ rootUuid ]; - this.setValues( parameters ); + } } - setupVariants() { + _lendBinding( binding ) { - const offsetNode = this.offsetNode; - const dashScaleNode = this.dashScaleNode ? float( this.dashScaleNode ) : materialLineScale; - const dashSizeNode = this.dashSizeNode ? float( this.dashSizeNode ) : materialLineDashSize; - const gapSizeNode = this.dashSizeNode ? float( this.dashGapNode ) : materialLineGapSize; + const bindings = this._bindings, + prevIndex = binding._cacheIndex, - dashSize.assign( dashSizeNode ); - gapSize.assign( gapSizeNode ); + lastActiveIndex = this._nActiveBindings ++, - const vLineDistance = varying( attribute( 'lineDistance' ).mul( dashScaleNode ) ); - const vLineDistanceOffset = offsetNode ? vLineDistance.add( offsetNode ) : vLineDistance; + firstInactiveBinding = bindings[ lastActiveIndex ]; - vLineDistanceOffset.mod( dashSize.add( gapSize ) ).greaterThan( dashSize ).discard(); + binding._cacheIndex = lastActiveIndex; + bindings[ lastActiveIndex ] = binding; + + firstInactiveBinding._cacheIndex = prevIndex; + bindings[ prevIndex ] = firstInactiveBinding; } -} + _takeBackBinding( binding ) { -LineDashedNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'LineDashed', LineDashedNodeMaterial ); + const bindings = this._bindings, + prevIndex = binding._cacheIndex, -const _defaultValues$b = /*@__PURE__*/ new LineDashedMaterial(); + firstInactiveIndex = -- this._nActiveBindings, -class Line2NodeMaterial extends NodeMaterial { + lastActiveBinding = bindings[ firstInactiveIndex ]; - constructor( params = {} ) { + binding._cacheIndex = firstInactiveIndex; + bindings[ firstInactiveIndex ] = binding; - super(); + lastActiveBinding._cacheIndex = prevIndex; + bindings[ prevIndex ] = lastActiveBinding; - this.lights = false; + } - this.setDefaultValues( _defaultValues$b ); - this.useAlphaToCoverage = true; - this.useColor = params.vertexColors; - this.useDash = params.dashed; - this.useWorldUnits = false; + // Memory management of Interpolants for weight and time scale - this.dashOffset = 0; - this.lineWidth = 1; + _lendControlInterpolant() { - this.lineColorNode = null; + const interpolants = this._controlInterpolants, + lastActiveIndex = this._nActiveControlInterpolants ++; - this.offsetNode = null; - this.dashScaleNode = null; - this.dashSizeNode = null; - this.gapSizeNode = null; + let interpolant = interpolants[ lastActiveIndex ]; - this.setValues( params ); + if ( interpolant === undefined ) { - } + interpolant = new LinearInterpolant( + new Float32Array( 2 ), new Float32Array( 2 ), + 1, _controlInterpolantsResultBuffer ); - setup( builder ) { + interpolant.__cacheIndex = lastActiveIndex; + interpolants[ lastActiveIndex ] = interpolant; - this.setupShaders(); + } - super.setup( builder ); + return interpolant; } - setupShaders() { + _takeBackControlInterpolant( interpolant ) { - const useAlphaToCoverage = this.alphaToCoverage; - const useColor = this.useColor; - const useDash = this.dashed; - const useWorldUnits = this.worldUnits; + const interpolants = this._controlInterpolants, + prevIndex = interpolant.__cacheIndex, - const trimSegment = Fn( ( { start, end } ) => { + firstInactiveIndex = -- this._nActiveControlInterpolants, - const a = cameraProjectionMatrix.element( 2 ).element( 2 ); // 3nd entry in 3th column - const b = cameraProjectionMatrix.element( 3 ).element( 2 ); // 3nd entry in 4th column - const nearEstimate = b.mul( - 0.5 ).div( a ); + lastActiveInterpolant = interpolants[ firstInactiveIndex ]; - const alpha = nearEstimate.sub( start.z ).div( end.z.sub( start.z ) ); + interpolant.__cacheIndex = firstInactiveIndex; + interpolants[ firstInactiveIndex ] = interpolant; - return vec4( mix( start.xyz, end.xyz, alpha ), end.w ); + lastActiveInterpolant.__cacheIndex = prevIndex; + interpolants[ prevIndex ] = lastActiveInterpolant; - } ); + } - this.vertexNode = Fn( () => { + // return an action for a clip optionally using a custom root target + // object (this method allocates a lot of dynamic memory in case a + // previously unknown clip/root combination is specified) + clipAction( clip, optionalRoot, blendMode ) { - varyingProperty( 'vec2', 'vUv' ).assign( uv() ); + const root = optionalRoot || this._root, + rootUuid = root.uuid; - const instanceStart = attribute( 'instanceStart' ); - const instanceEnd = attribute( 'instanceEnd' ); + let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip; - // camera space + const clipUuid = clipObject !== null ? clipObject.uuid : clip; - const start = property( 'vec4', 'start' ); - const end = property( 'vec4', 'end' ); + const actionsForClip = this._actionsByClip[ clipUuid ]; + let prototypeAction = null; - start.assign( modelViewMatrix.mul( vec4( instanceStart, 1.0 ) ) ); // force assignment into correct place in flow - end.assign( modelViewMatrix.mul( vec4( instanceEnd, 1.0 ) ) ); + if ( blendMode === undefined ) { - if ( useWorldUnits ) { + if ( clipObject !== null ) { - varyingProperty( 'vec3', 'worldStart' ).assign( start.xyz ); - varyingProperty( 'vec3', 'worldEnd' ).assign( end.xyz ); + blendMode = clipObject.blendMode; - } + } else { - const aspect = viewport.z.div( viewport.w ); + blendMode = NormalAnimationBlendMode; - // special case for perspective projection, and segments that terminate either in, or behind, the camera plane - // clearly the gpu firmware has a way of addressing this issue when projecting into ndc space - // but we need to perform ndc-space calculations in the shader, so we must address this issue directly - // perhaps there is a more elegant solution -- WestLangley + } - const perspective = cameraProjectionMatrix.element( 2 ).element( 3 ).equal( - 1.0 ); // 4th entry in the 3rd column + } - If( perspective, () => { + if ( actionsForClip !== undefined ) { - If( start.z.lessThan( 0.0 ).and( end.z.greaterThan( 0.0 ) ), () => { + const existingAction = actionsForClip.actionByRoot[ rootUuid ]; - end.assign( trimSegment( { start: start, end: end } ) ); + if ( existingAction !== undefined && existingAction.blendMode === blendMode ) { - } ).ElseIf( end.z.lessThan( 0.0 ).and( start.z.greaterThanEqual( 0.0 ) ), () => { + return existingAction; - start.assign( trimSegment( { start: end, end: start } ) ); + } - } ); + // we know the clip, so we don't have to parse all + // the bindings again but can just copy + prototypeAction = actionsForClip.knownActions[ 0 ]; - } ); + // also, take the clip from the prototype action + if ( clipObject === null ) + clipObject = prototypeAction._clip; - // clip space - const clipStart = cameraProjectionMatrix.mul( start ); - const clipEnd = cameraProjectionMatrix.mul( end ); + } - // ndc space - const ndcStart = clipStart.xyz.div( clipStart.w ); - const ndcEnd = clipEnd.xyz.div( clipEnd.w ); + // clip must be known when specified via string + if ( clipObject === null ) return null; - // direction - const dir = ndcEnd.xy.sub( ndcStart.xy ).toVar(); + // allocate all resources required to run it + const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode ); - // account for clip-space aspect ratio - dir.x.assign( dir.x.mul( aspect ) ); - dir.assign( dir.normalize() ); + this._bindAction( newAction, prototypeAction ); - const clip = vec4().toVar(); + // and make the action known to the memory manager + this._addInactiveAction( newAction, clipUuid, rootUuid ); - if ( useWorldUnits ) { + return newAction; - // get the offset direction as perpendicular to the view vector + } - const worldDir = end.xyz.sub( start.xyz ).normalize(); - const tmpFwd = mix( start.xyz, end.xyz, 0.5 ).normalize(); - const worldUp = worldDir.cross( tmpFwd ).normalize(); - const worldFwd = worldDir.cross( worldUp ); + // get an existing action + existingAction( clip, optionalRoot ) { - const worldPos = varyingProperty( 'vec4', 'worldPos' ); + const root = optionalRoot || this._root, + rootUuid = root.uuid, - worldPos.assign( positionGeometry.y.lessThan( 0.5 ).select( start, end ) ); + clipObject = typeof clip === 'string' ? + AnimationClip.findByName( root, clip ) : clip, - // height offset - const hw = materialLineWidth.mul( 0.5 ); - worldPos.addAssign( vec4( positionGeometry.x.lessThan( 0.0 ).select( worldUp.mul( hw ), worldUp.mul( hw ).negate() ), 0 ) ); + clipUuid = clipObject ? clipObject.uuid : clip, - // don't extend the line if we're rendering dashes because we - // won't be rendering the endcaps - if ( ! useDash ) { + actionsForClip = this._actionsByClip[ clipUuid ]; - // cap extension - worldPos.addAssign( vec4( positionGeometry.y.lessThan( 0.5 ).select( worldDir.mul( hw ).negate(), worldDir.mul( hw ) ), 0 ) ); + if ( actionsForClip !== undefined ) { - // add width to the box - worldPos.addAssign( vec4( worldFwd.mul( hw ), 0 ) ); + return actionsForClip.actionByRoot[ rootUuid ] || null; - // endcaps - If( positionGeometry.y.greaterThan( 1.0 ).or( positionGeometry.y.lessThan( 0.0 ) ), () => { + } - worldPos.subAssign( vec4( worldFwd.mul( 2.0 ).mul( hw ), 0 ) ); + return null; - } ); + } - } + // deactivates all previously scheduled actions + stopAllAction() { - // project the worldpos - clip.assign( cameraProjectionMatrix.mul( worldPos ) ); + const actions = this._actions, + nActions = this._nActiveActions; - // shift the depth of the projected points so the line - // segments overlap neatly - const clipPose = vec3().toVar(); + for ( let i = nActions - 1; i >= 0; -- i ) { - clipPose.assign( positionGeometry.y.lessThan( 0.5 ).select( ndcStart, ndcEnd ) ); - clip.z.assign( clipPose.z.mul( clip.w ) ); + actions[ i ].stop(); - } else { + } - const offset = property( 'vec2', 'offset' ); + return this; - offset.assign( vec2( dir.y, dir.x.negate() ) ); + } - // undo aspect ratio adjustment - dir.x.assign( dir.x.div( aspect ) ); - offset.x.assign( offset.x.div( aspect ) ); + // advance the time and update apply the animation + update( deltaTime ) { - // sign flip - offset.assign( positionGeometry.x.lessThan( 0.0 ).select( offset.negate(), offset ) ); + deltaTime *= this.timeScale; - // endcaps - If( positionGeometry.y.lessThan( 0.0 ), () => { + const actions = this._actions, + nActions = this._nActiveActions, - offset.assign( offset.sub( dir ) ); + time = this.time += deltaTime, + timeDirection = Math.sign( deltaTime ), - } ).ElseIf( positionGeometry.y.greaterThan( 1.0 ), () => { + accuIndex = this._accuIndex ^= 1; - offset.assign( offset.add( dir ) ); + // run active actions - } ); + for ( let i = 0; i !== nActions; ++ i ) { - // adjust for linewidth - offset.assign( offset.mul( materialLineWidth ) ); + const action = actions[ i ]; - // adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ... - offset.assign( offset.div( viewport.w ) ); + action._update( time, deltaTime, timeDirection, accuIndex ); - // select end - clip.assign( positionGeometry.y.lessThan( 0.5 ).select( clipStart, clipEnd ) ); + } - // back to clip space - offset.assign( offset.mul( clip.w ) ); + // update scene graph - clip.assign( clip.add( vec4( offset, 0, 0 ) ) ); + const bindings = this._bindings, + nBindings = this._nActiveBindings; - } + for ( let i = 0; i !== nBindings; ++ i ) { - return clip; + bindings[ i ].apply( accuIndex ); - } )(); + } - const closestLineToLine = Fn( ( { p1, p2, p3, p4 } ) => { + return this; - const p13 = p1.sub( p3 ); - const p43 = p4.sub( p3 ); + } - const p21 = p2.sub( p1 ); + // Allows you to seek to a specific time in an animation. + setTime( timeInSeconds ) { - const d1343 = p13.dot( p43 ); - const d4321 = p43.dot( p21 ); - const d1321 = p13.dot( p21 ); - const d4343 = p43.dot( p43 ); - const d2121 = p21.dot( p21 ); + this.time = 0; // Zero out time attribute for AnimationMixer object; + for ( let i = 0; i < this._actions.length; i ++ ) { - const denom = d2121.mul( d4343 ).sub( d4321.mul( d4321 ) ); - const numer = d1343.mul( d4321 ).sub( d1321.mul( d4343 ) ); + this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects. - const mua = numer.div( denom ).clamp(); - const mub = d1343.add( d4321.mul( mua ) ).div( d4343 ).clamp(); + } - return vec2( mua, mub ); + return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object. - } ); + } - this.fragmentNode = Fn( () => { + // return this mixer's root target object + getRoot() { - const vUv = varyingProperty( 'vec2', 'vUv' ); + return this._root; - if ( useDash ) { + } - const offsetNode = this.offsetNode ? float( this.offsetNodeNode ) : materialLineDashOffset; - const dashScaleNode = this.dashScaleNode ? float( this.dashScaleNode ) : materialLineScale; - const dashSizeNode = this.dashSizeNode ? float( this.dashSizeNode ) : materialLineDashSize; - const gapSizeNode = this.dashSizeNode ? float( this.dashGapNode ) : materialLineGapSize; + // free all resources specific to a particular clip + uncacheClip( clip ) { - dashSize.assign( dashSizeNode ); - gapSize.assign( gapSizeNode ); + const actions = this._actions, + clipUuid = clip.uuid, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ]; - const instanceDistanceStart = attribute( 'instanceDistanceStart' ); - const instanceDistanceEnd = attribute( 'instanceDistanceEnd' ); + if ( actionsForClip !== undefined ) { - const lineDistance = positionGeometry.y.lessThan( 0.5 ).select( dashScaleNode.mul( instanceDistanceStart ), materialLineScale.mul( instanceDistanceEnd ) ); + // note: just calling _removeInactiveAction would mess up the + // iteration state and also require updating the state we can + // just throw away - const vLineDistance = varying( lineDistance.add( materialLineDashOffset ) ); - const vLineDistanceOffset = offsetNode ? vLineDistance.add( offsetNode ) : vLineDistance; + const actionsToRemove = actionsForClip.knownActions; - vUv.y.lessThan( - 1.0 ).or( vUv.y.greaterThan( 1.0 ) ).discard(); // discard endcaps - vLineDistanceOffset.mod( dashSize.add( gapSize ) ).greaterThan( dashSize ).discard(); // todo - FIX + for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) { - } + const action = actionsToRemove[ i ]; - // force assignment into correct place in flow - const alpha = property( 'float', 'alpha' ); - alpha.assign( 1 ); + this._deactivateAction( action ); - if ( useWorldUnits ) { + const cacheIndex = action._cacheIndex, + lastInactiveAction = actions[ actions.length - 1 ]; - const worldStart = varyingProperty( 'vec3', 'worldStart' ); - const worldEnd = varyingProperty( 'vec3', 'worldEnd' ); + action._cacheIndex = null; + action._byClipCacheIndex = null; - // Find the closest points on the view ray and the line segment - const rayEnd = varyingProperty( 'vec4', 'worldPos' ).xyz.normalize().mul( 1e5 ); - const lineDir = worldEnd.sub( worldStart ); - const params = closestLineToLine( { p1: worldStart, p2: worldEnd, p3: vec3( 0.0, 0.0, 0.0 ), p4: rayEnd } ); + lastInactiveAction._cacheIndex = cacheIndex; + actions[ cacheIndex ] = lastInactiveAction; + actions.pop(); - const p1 = worldStart.add( lineDir.mul( params.x ) ); - const p2 = rayEnd.mul( params.y ); - const delta = p1.sub( p2 ); - const len = delta.length(); - const norm = len.div( materialLineWidth ); + this._removeInactiveBindingsForAction( action ); - if ( ! useDash ) { + } - if ( useAlphaToCoverage ) { + delete actionsByClip[ clipUuid ]; - const dnorm = norm.fwidth(); - alpha.assign( smoothstep( dnorm.negate().add( 0.5 ), dnorm.add( 0.5 ), norm ).oneMinus() ); + } - } else { + } - norm.greaterThan( 0.5 ).discard(); + // free all resources specific to a particular root target object + uncacheRoot( root ) { - } + const rootUuid = root.uuid, + actionsByClip = this._actionsByClip; - } + for ( const clipUuid in actionsByClip ) { - } else { + const actionByRoot = actionsByClip[ clipUuid ].actionByRoot, + action = actionByRoot[ rootUuid ]; - // round endcaps + if ( action !== undefined ) { - if ( useAlphaToCoverage ) { + this._deactivateAction( action ); + this._removeInactiveAction( action ); - const a = vUv.x; - const b = vUv.y.greaterThan( 0.0 ).select( vUv.y.sub( 1.0 ), vUv.y.add( 1.0 ) ); + } - const len2 = a.mul( a ).add( b.mul( b ) ); + } - // force assignment out of following 'if' statement - to avoid uniform control flow errors - const dlen = property( 'float', 'dlen' ); - dlen.assign( len2.fwidth() ); + const bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ]; - If( vUv.y.abs().greaterThan( 1.0 ), () => { + if ( bindingByName !== undefined ) { - alpha.assign( smoothstep( dlen.oneMinus(), dlen.add( 1 ), len2 ).oneMinus() ); + for ( const trackName in bindingByName ) { - } ); + const binding = bindingByName[ trackName ]; + binding.restoreOriginalState(); + this._removeInactiveBinding( binding ); - } else { + } - If( vUv.y.abs().greaterThan( 1.0 ), () => { + } - const a = vUv.x; - const b = vUv.y.greaterThan( 0.0 ).select( vUv.y.sub( 1.0 ), vUv.y.add( 1.0 ) ); - const len2 = a.mul( a ).add( b.mul( b ) ); + } - len2.greaterThan( 1.0 ).discard(); + // remove a targeted clip from the cache + uncacheAction( clip, optionalRoot ) { - } ); + const action = this.existingAction( clip, optionalRoot ); - } + if ( action !== null ) { - } + this._deactivateAction( action ); + this._removeInactiveAction( action ); - let lineColorNode; + } - if ( this.lineColorNode ) { + } - lineColorNode = this.lineColorNode; +} - } else { +let Uniform$1 = class Uniform { - if ( useColor ) { + constructor( value ) { - const instanceColorStart = attribute( 'instanceColorStart' ); - const instanceColorEnd = attribute( 'instanceColorEnd' ); + this.value = value; - const instanceColor = positionGeometry.y.lessThan( 0.5 ).select( instanceColorStart, instanceColorEnd ); + } - lineColorNode = instanceColor.mul( materialColor ); + clone() { - } else { + return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); - lineColorNode = materialColor; + } - } +}; - } +let _id$8 = 0; - return vec4( lineColorNode, alpha ); +let UniformsGroup$1 = class UniformsGroup extends EventDispatcher { - } )(); + constructor() { - } + super(); + this.isUniformsGroup = true; - get worldUnits() { + Object.defineProperty( this, 'id', { value: _id$8 ++ } ); - return this.useWorldUnits; + this.name = ''; - } + this.usage = StaticDrawUsage; + this.uniforms = []; - set worldUnits( value ) { + } - if ( this.useWorldUnits !== value ) { + add( uniform ) { - this.useWorldUnits = value; - this.needsUpdate = true; + this.uniforms.push( uniform ); - } + return this; } + remove( uniform ) { - get dashed() { + const index = this.uniforms.indexOf( uniform ); - return this.useDash; + if ( index !== - 1 ) this.uniforms.splice( index, 1 ); - } + return this; - set dashed( value ) { + } - if ( this.useDash !== value ) { + setName( name ) { - this.useDash = value; - this.needsUpdate = true; + this.name = name; - } + return this; } + setUsage( value ) { - get alphaToCoverage() { + this.usage = value; - return this.useAlphaToCoverage; + return this; } - set alphaToCoverage( value ) { - - if ( this.useAlphaToCoverage !== value ) { + dispose() { - this.useAlphaToCoverage = value; - this.needsUpdate = true; + this.dispatchEvent( { type: 'dispose' } ); - } + return this; } -} + copy( source ) { -Line2NodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'Line2', Line2NodeMaterial ); + this.name = source.name; + this.usage = source.usage; -const directionToColor = ( node ) => nodeObject( node ).mul( 0.5 ).add( 0.5 ); -const colorToDirection = ( node ) => nodeObject( node ).mul( 2.0 ).sub( 1 ); + const uniformsSource = source.uniforms; -const _defaultValues$a = /*@__PURE__*/ new MeshNormalMaterial(); + this.uniforms.length = 0; -class MeshNormalNodeMaterial extends NodeMaterial { + for ( let i = 0, l = uniformsSource.length; i < l; i ++ ) { - constructor( parameters ) { + const uniforms = Array.isArray( uniformsSource[ i ] ) ? uniformsSource[ i ] : [ uniformsSource[ i ] ]; - super(); + for ( let j = 0; j < uniforms.length; j ++ ) { - this.lights = false; + this.uniforms.push( uniforms[ j ].clone() ); - this.isMeshNormalNodeMaterial = true; + } - this.setDefaultValues( _defaultValues$a ); + } - this.setValues( parameters ); + return this; } - setupDiffuseColor() { - - const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity; + clone() { - diffuseColor.assign( vec4( directionToColor( transformedNormalView ), opacityNode ) ); + return new this.constructor().copy( this ); } -} +}; -MeshNormalNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'MeshNormal', MeshNormalNodeMaterial ); +class InstancedInterleavedBuffer extends InterleavedBuffer { -class EquirectUVNode extends TempNode { + constructor( array, stride, meshPerAttribute = 1 ) { - constructor( dirNode = positionWorldDirection ) { + super( array, stride ); - super( 'vec2' ); + this.isInstancedInterleavedBuffer = true; - this.dirNode = dirNode; + this.meshPerAttribute = meshPerAttribute; } - setup() { + copy( source ) { - const dir = this.dirNode; + super.copy( source ); - const u = dir.z.atan2( dir.x ).mul( 1 / ( Math.PI * 2 ) ).add( 0.5 ); - const v = dir.y.clamp( - 1.0, 1.0 ).asin().mul( 1 / Math.PI ).add( 0.5 ); + this.meshPerAttribute = source.meshPerAttribute; - return vec2( u, v ); + return this; } -} + clone( data ) { -EquirectUVNode.type = /*@__PURE__*/ registerNode( 'EquirectUV', EquirectUVNode ); + const ib = super.clone( data ); -const equirectUV = /*@__PURE__*/ nodeProxy( EquirectUVNode ); + ib.meshPerAttribute = this.meshPerAttribute; -// @TODO: Consider rename WebGLCubeRenderTarget to just CubeRenderTarget + return ib; -class CubeRenderTarget extends WebGLCubeRenderTarget { + } - constructor( size = 1, options = {} ) { + toJSON( data ) { - super( size, options ); + const json = super.toJSON( data ); - this.isCubeRenderTarget = true; + json.isInstancedInterleavedBuffer = true; + json.meshPerAttribute = this.meshPerAttribute; + + return json; } - fromEquirectangularTexture( renderer, texture$1 ) { +} - const currentMinFilter = texture$1.minFilter; - const currentGenerateMipmaps = texture$1.generateMipmaps; +class GLBufferAttribute { - texture$1.generateMipmaps = true; + constructor( buffer, type, itemSize, elementSize, count ) { - this.texture.type = texture$1.type; - this.texture.colorSpace = texture$1.colorSpace; + this.isGLBufferAttribute = true; - this.texture.generateMipmaps = texture$1.generateMipmaps; - this.texture.minFilter = texture$1.minFilter; - this.texture.magFilter = texture$1.magFilter; + this.name = ''; - const geometry = new BoxGeometry( 5, 5, 5 ); + this.buffer = buffer; + this.type = type; + this.itemSize = itemSize; + this.elementSize = elementSize; + this.count = count; - const uvNode = equirectUV( positionWorldDirection ); + this.version = 0; - const material = new NodeMaterial(); - material.colorNode = texture( texture$1, uvNode, 0 ); - material.side = BackSide; - material.blending = NoBlending; + } - const mesh = new Mesh( geometry, material ); + set needsUpdate( value ) { - const scene = new Scene(); - scene.add( mesh ); + if ( value === true ) this.version ++; - // Avoid blurred poles - if ( texture$1.minFilter === LinearMipmapLinearFilter ) texture$1.minFilter = LinearFilter; + } - const camera = new CubeCamera( 1, 10, this ); + setBuffer( buffer ) { - const currentMRT = renderer.getMRT(); - renderer.setMRT( null ); + this.buffer = buffer; - camera.update( renderer, scene ); + return this; - renderer.setMRT( currentMRT ); + } - texture$1.minFilter = currentMinFilter; - texture$1.currentGenerateMipmaps = currentGenerateMipmaps; + setType( type, elementSize ) { - mesh.geometry.dispose(); - mesh.material.dispose(); + this.type = type; + this.elementSize = elementSize; return this; } -} - -const _cache$1 = new WeakMap(); - -class CubeMapNode extends TempNode { - - constructor( envNode ) { + setItemSize( itemSize ) { - super( 'vec3' ); + this.itemSize = itemSize; - this.envNode = envNode; + return this; - this._cubeTexture = null; - this._cubeTextureNode = cubeTexture(); + } - const defaultTexture = new CubeTexture(); - defaultTexture.isRenderTargetTexture = true; + setCount( count ) { - this._defaultTexture = defaultTexture; + this.count = count; - this.updateBeforeType = NodeUpdateType.RENDER; + return this; } - updateBefore( frame ) { +} - const { renderer, material } = frame; +const _matrix = /*@__PURE__*/ new Matrix4(); - const envNode = this.envNode; +class Raycaster { - if ( envNode.isTextureNode || envNode.isMaterialReferenceNode ) { + constructor( origin, direction, near = 0, far = Infinity ) { - const texture = ( envNode.isTextureNode ) ? envNode.value : material[ envNode.property ]; + this.ray = new Ray( origin, direction ); + // direction is assumed to be normalized (for accurate distance calculations) - if ( texture && texture.isTexture ) { + this.near = near; + this.far = far; + this.camera = null; + this.layers = new Layers(); - const mapping = texture.mapping; + this.params = { + Mesh: {}, + Line: { threshold: 1 }, + LOD: {}, + Points: { threshold: 1 }, + Sprite: {} + }; - if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) { + } - // check for converted cubemap map + set( origin, direction ) { - if ( _cache$1.has( texture ) ) { + // direction is assumed to be normalized (for accurate distance calculations) - const cubeMap = _cache$1.get( texture ); + this.ray.set( origin, direction ); - mapTextureMapping( cubeMap, texture.mapping ); - this._cubeTexture = cubeMap; + } - } else { + setFromCamera( coords, camera ) { - // create cube map from equirectangular map + if ( camera.isPerspectiveCamera ) { - const image = texture.image; + this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); + this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); + this.camera = camera; - if ( isEquirectangularMapReady$1( image ) ) { + } else if ( camera.isOrthographicCamera ) { - const renderTarget = new CubeRenderTarget( image.height ); - renderTarget.fromEquirectangularTexture( renderer, texture ); + this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera + this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); + this.camera = camera; - mapTextureMapping( renderTarget.texture, texture.mapping ); - this._cubeTexture = renderTarget.texture; + } else { - _cache$1.set( texture, renderTarget.texture ); + console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type ); - texture.addEventListener( 'dispose', onTextureDispose ); + } - } else { + } - // default cube texture as fallback when equirectangular texture is not yet loaded + setFromXRController( controller ) { - this._cubeTexture = this._defaultTexture; + _matrix.identity().extractRotation( controller.matrixWorld ); - } + this.ray.origin.setFromMatrixPosition( controller.matrixWorld ); + this.ray.direction.set( 0, 0, - 1 ).applyMatrix4( _matrix ); - } + return this; - // + } - this._cubeTextureNode.value = this._cubeTexture; + intersectObject( object, recursive = true, intersects = [] ) { - } else { + intersect( object, this, intersects, recursive ); - // envNode already refers to a cube map + intersects.sort( ascSort ); - this._cubeTextureNode = this.envNode; + return intersects; - } + } - } + intersectObjects( objects, recursive = true, intersects = [] ) { - } + for ( let i = 0, l = objects.length; i < l; i ++ ) { - } + intersect( objects[ i ], this, intersects, recursive ); - setup( builder ) { + } - this.updateBefore( builder ); + intersects.sort( ascSort ); - return this._cubeTextureNode; + return intersects; } } -CubeMapNode.type = /*@__PURE__*/ registerNode( 'CubeMap', CubeMapNode ); - -function isEquirectangularMapReady$1( image ) { - - if ( image === null || image === undefined ) return false; +function ascSort( a, b ) { - return image.height > 0; + return a.distance - b.distance; } -function onTextureDispose( event ) { - - const texture = event.target; - - texture.removeEventListener( 'dispose', onTextureDispose ); +function intersect( object, raycaster, intersects, recursive ) { - const renderTarget = _cache$1.get( texture ); + let propagate = true; - if ( renderTarget !== undefined ) { + if ( object.layers.test( raycaster.layers ) ) { - _cache$1.delete( texture ); + const result = object.raycast( raycaster, intersects ); - renderTarget.dispose(); + if ( result === false ) propagate = false; } -} - -function mapTextureMapping( texture, mapping ) { + if ( propagate === true && recursive === true ) { - if ( mapping === EquirectangularReflectionMapping ) { + const children = object.children; - texture.mapping = CubeReflectionMapping; + for ( let i = 0, l = children.length; i < l; i ++ ) { - } else if ( mapping === EquirectangularRefractionMapping ) { + intersect( children[ i ], raycaster, intersects, true ); - texture.mapping = CubeRefractionMapping; + } } } -const cubeMapNode = /*@__PURE__*/ nodeProxy( CubeMapNode ); - -class BasicEnvironmentNode extends LightingNode { +/** + * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system + * + * phi (the polar angle) is measured from the positive y-axis. The positive y-axis is up. + * theta (the azimuthal angle) is measured from the positive z-axis. + */ +class Spherical { - constructor( envNode = null ) { + constructor( radius = 1, phi = 0, theta = 0 ) { - super(); + this.radius = radius; + this.phi = phi; // polar angle + this.theta = theta; // azimuthal angle - this.envNode = envNode; + return this; } - setup( builder ) { + set( radius, phi, theta ) { - // environment property is used in the finish() method of BasicLightingModel + this.radius = radius; + this.phi = phi; + this.theta = theta; - builder.context.environment = cubeMapNode( this.envNode ); + return this; } -} + copy( other ) { -BasicEnvironmentNode.type = /*@__PURE__*/ registerNode( 'BasicEnvironment', BasicEnvironmentNode ); + this.radius = other.radius; + this.phi = other.phi; + this.theta = other.theta; -class BasicLightMapNode extends LightingNode { + return this; - constructor( lightMapNode = null ) { + } - super(); + // restrict phi to be between EPS and PI-EPS + makeSafe() { - this.lightMapNode = lightMapNode; + const EPS = 0.000001; + this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); + + return this; } - setup( builder ) { + setFromVector3( v ) { - // irradianceLightMap property is used in the indirectDiffuse() method of BasicLightingModel + return this.setFromCartesianCoords( v.x, v.y, v.z ); - const RECIPROCAL_PI = float( 1 / Math.PI ); + } - builder.context.irradianceLightMap = this.lightMapNode.mul( RECIPROCAL_PI ); + setFromCartesianCoords( x, y, z ) { - } + this.radius = Math.sqrt( x * x + y * y + z * z ); -} + if ( this.radius === 0 ) { -BasicLightMapNode.type = /*@__PURE__*/ registerNode( 'BasicLightMap', BasicLightMapNode ); + this.theta = 0; + this.phi = 0; -class LightingModel { + } else { - start( /*input, stack, builder*/ ) { } + this.theta = Math.atan2( x, z ); + this.phi = Math.acos( clamp$1( y / this.radius, - 1, 1 ) ); - finish( /*input, stack, builder*/ ) { } + } - direct( /*input, stack, builder*/ ) { } + return this; - directRectArea( /*input, stack, builder*/ ) {} + } - indirect( /*input, stack, builder*/ ) { } + clone() { - ambientOcclusion( /*input, stack, builder*/ ) { } + return new this.constructor().copy( this ); + + } } -class BasicLightingModel extends LightingModel { +/** + * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system + */ - constructor() { +class Cylindrical { - super(); + constructor( radius = 1, theta = 0, y = 0 ) { - } + this.radius = radius; // distance from the origin to a point in the x-z plane + this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis + this.y = y; // height above the x-z plane - indirect( context, stack, builder ) { - - const ambientOcclusion = context.ambientOcclusion; - const reflectedLight = context.reflectedLight; - const irradianceLightMap = builder.context.irradianceLightMap; - - reflectedLight.indirectDiffuse.assign( vec4( 0.0 ) ); - - // accumulation (baked indirect lighting only) + return this; - if ( irradianceLightMap ) { + } - reflectedLight.indirectDiffuse.addAssign( irradianceLightMap ); + set( radius, theta, y ) { - } else { + this.radius = radius; + this.theta = theta; + this.y = y; - reflectedLight.indirectDiffuse.addAssign( vec4( 1.0, 1.0, 1.0, 0.0 ) ); + return this; - } + } - // modulation + copy( other ) { - reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion ); + this.radius = other.radius; + this.theta = other.theta; + this.y = other.y; - reflectedLight.indirectDiffuse.mulAssign( diffuseColor.rgb ); + return this; } - finish( context, stack, builder ) { - - const material = builder.material; - const outgoingLight = context.outgoingLight; - const envNode = builder.context.environment; + setFromVector3( v ) { - if ( envNode ) { + return this.setFromCartesianCoords( v.x, v.y, v.z ); - switch ( material.combine ) { + } - case MultiplyOperation: - outgoingLight.rgb.assign( mix( outgoingLight.rgb, outgoingLight.rgb.mul( envNode.rgb ), materialSpecularStrength.mul( materialReflectivity ) ) ); - break; + setFromCartesianCoords( x, y, z ) { - case MixOperation: - outgoingLight.rgb.assign( mix( outgoingLight.rgb, envNode.rgb, materialSpecularStrength.mul( materialReflectivity ) ) ); - break; + this.radius = Math.sqrt( x * x + z * z ); + this.theta = Math.atan2( x, z ); + this.y = y; - case AddOperation: - outgoingLight.rgb.addAssign( envNode.rgb.mul( materialSpecularStrength.mul( materialReflectivity ) ) ); - break; + return this; - default: - console.warn( 'THREE.BasicLightingModel: Unsupported .combine value:', material.combine ); - break; + } - } + clone() { - } + return new this.constructor().copy( this ); } } -const _defaultValues$9 = /*@__PURE__*/ new MeshBasicMaterial(); - -class MeshBasicNodeMaterial extends NodeMaterial { - - constructor( parameters ) { - - super(); - - this.isMeshBasicNodeMaterial = true; +class Matrix2 { - this.lights = true; + constructor( n11, n12, n21, n22 ) { - this.setDefaultValues( _defaultValues$9 ); + Matrix2.prototype.isMatrix2 = true; - this.setValues( parameters ); + this.elements = [ + 1, 0, + 0, 1, + ]; - } + if ( n11 !== undefined ) { - setupNormal() { + this.set( n11, n12, n21, n22 ); - return normalView; // see #28839 + } } - setupEnvironment( builder ) { + identity() { - const envNode = super.setupEnvironment( builder ); + this.set( + 1, 0, + 0, 1, + ); - return envNode ? new BasicEnvironmentNode( envNode ) : null; + return this; } - setupLightMap( builder ) { - - let node = null; + fromArray( array, offset = 0 ) { - if ( builder.material.lightMap ) { + for ( let i = 0; i < 4; i ++ ) { - node = new BasicLightMapNode( materialLightMap ); + this.elements[ i ] = array[ i + offset ]; } - return node; + return this; } - setupOutgoingLight() { - - return diffuseColor.rgb; + set( n11, n12, n21, n22 ) { - } + const te = this.elements; - setupLightingModel() { + te[ 0 ] = n11; te[ 2 ] = n12; + te[ 1 ] = n21; te[ 3 ] = n22; - return new BasicLightingModel(); + return this; } } -MeshBasicNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'MeshBasic', MeshBasicNodeMaterial ); +const _vector$4 = /*@__PURE__*/ new Vector2(); -const F_Schlick = /*@__PURE__*/ Fn( ( { f0, f90, dotVH } ) => { +class Box2 { - // Original approximation by Christophe Schlick '94 - // float fresnel = pow( 1.0 - dotVH, 5.0 ); + constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) { - // Optimized variant (presented by Epic at SIGGRAPH '13) - // https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf - const fresnel = dotVH.mul( - 5.55473 ).sub( 6.98316 ).mul( dotVH ).exp2(); + this.isBox2 = true; - return f0.mul( fresnel.oneMinus() ).add( f90.mul( fresnel ) ); + this.min = min; + this.max = max; -} ); // validated + } -const BRDF_Lambert = /*@__PURE__*/ Fn( ( inputs ) => { + set( min, max ) { - return inputs.diffuseColor.mul( 1 / Math.PI ); // punctual light + this.min.copy( min ); + this.max.copy( max ); -} ); // validated + return this; -const G_BlinnPhong_Implicit = () => float( 0.25 ); + } -const D_BlinnPhong = /*@__PURE__*/ Fn( ( { dotNH } ) => { + setFromPoints( points ) { - return shininess.mul( float( 0.5 ) ).add( 1.0 ).mul( float( 1 / Math.PI ) ).mul( dotNH.pow( shininess ) ); + this.makeEmpty(); -} ); + for ( let i = 0, il = points.length; i < il; i ++ ) { -const BRDF_BlinnPhong = /*@__PURE__*/ Fn( ( { lightDirection } ) => { + this.expandByPoint( points[ i ] ); - const halfDir = lightDirection.add( positionViewDirection ).normalize(); + } - const dotNH = transformedNormalView.dot( halfDir ).clamp(); - const dotVH = positionViewDirection.dot( halfDir ).clamp(); + return this; - const F = F_Schlick( { f0: specularColor, f90: 1.0, dotVH } ); - const G = G_BlinnPhong_Implicit(); - const D = D_BlinnPhong( { dotNH } ); + } - return F.mul( G ).mul( D ); + setFromCenterAndSize( center, size ) { -} ); + const halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 ); + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); -class PhongLightingModel extends BasicLightingModel { + return this; - constructor( specular = true ) { + } - super(); + clone() { - this.specular = specular; + return new this.constructor().copy( this ); } - direct( { lightDirection, lightColor, reflectedLight } ) { + copy( box ) { - const dotNL = transformedNormalView.dot( lightDirection ).clamp(); - const irradiance = dotNL.mul( lightColor ); + this.min.copy( box.min ); + this.max.copy( box.max ); - reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) ); + return this; - if ( this.specular === true ) { + } - reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_BlinnPhong( { lightDirection } ) ).mul( materialSpecularStrength ) ); + makeEmpty() { - } + this.min.x = this.min.y = + Infinity; + this.max.x = this.max.y = - Infinity; + + return this; } - indirect( { ambientOcclusion, irradiance, reflectedLight } ) { + isEmpty() { - reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) ); + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion ); + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); } -} + getCenter( target ) { -const _defaultValues$8 = /*@__PURE__*/ new MeshLambertMaterial(); + return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); -class MeshLambertNodeMaterial extends NodeMaterial { + } - constructor( parameters ) { + getSize( target ) { - super(); + return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); - this.isMeshLambertNodeMaterial = true; + } - this.lights = true; + expandByPoint( point ) { - this.setDefaultValues( _defaultValues$8 ); + this.min.min( point ); + this.max.max( point ); - this.setValues( parameters ); + return this; } - setupEnvironment( builder ) { + expandByVector( vector ) { - const envNode = super.setupEnvironment( builder ); + this.min.sub( vector ); + this.max.add( vector ); - return envNode ? new BasicEnvironmentNode( envNode ) : null; + return this; } - setupLightingModel( /*builder*/ ) { - - return new PhongLightingModel( false ); // ( specular ) -> force lambert + expandByScalar( scalar ) { - } + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); -} + return this; -MeshLambertNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'MeshLambert', MeshLambertNodeMaterial ); + } -const _defaultValues$7 = /*@__PURE__*/ new MeshPhongMaterial(); + containsPoint( point ) { -class MeshPhongNodeMaterial extends NodeMaterial { + return point.x >= this.min.x && point.x <= this.max.x && + point.y >= this.min.y && point.y <= this.max.y; - constructor( parameters ) { + } - super(); + containsBox( box ) { - this.isMeshPhongNodeMaterial = true; + return this.min.x <= box.min.x && box.max.x <= this.max.x && + this.min.y <= box.min.y && box.max.y <= this.max.y; - this.lights = true; + } - this.shininessNode = null; - this.specularNode = null; + getParameter( point, target ) { - this.setDefaultValues( _defaultValues$7 ); + // This can potentially have a divide by zero if the box + // has a size dimension of 0. - this.setValues( parameters ); + return target.set( + ( point.x - this.min.x ) / ( this.max.x - this.min.x ), + ( point.y - this.min.y ) / ( this.max.y - this.min.y ) + ); } - setupEnvironment( builder ) { + intersectsBox( box ) { - const envNode = super.setupEnvironment( builder ); + // using 4 splitting planes to rule out intersections - return envNode ? new BasicEnvironmentNode( envNode ) : null; + return box.max.x >= this.min.x && box.min.x <= this.max.x && + box.max.y >= this.min.y && box.min.y <= this.max.y; } - setupLightingModel( /*builder*/ ) { + clampPoint( point, target ) { - return new PhongLightingModel(); + return target.copy( point ).clamp( this.min, this.max ); } - setupVariants() { + distanceToPoint( point ) { - // SHININESS + return this.clampPoint( point, _vector$4 ).distanceTo( point ); - const shininessNode = ( this.shininessNode ? float( this.shininessNode ) : materialShininess ).max( 1e-4 ); // to prevent pow( 0.0, 0.0 ) + } - shininess.assign( shininessNode ); + intersect( box ) { - // SPECULAR COLOR + this.min.max( box.min ); + this.max.min( box.max ); - const specularNode = this.specularNode || materialSpecular; + if ( this.isEmpty() ) this.makeEmpty(); - specularColor.assign( specularNode ); + return this; } - copy( source ) { + union( box ) { - this.shininessNode = source.shininessNode; - this.specularNode = source.specularNode; + this.min.min( box.min ); + this.max.max( box.max ); - return super.copy( source ); + return this; } -} + translate( offset ) { -MeshPhongNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'MeshPhong', MeshPhongNodeMaterial ); + this.min.add( offset ); + this.max.add( offset ); -const getGeometryRoughness = /*@__PURE__*/ Fn( () => { + return this; - const dxy = normalView.dFdx().abs().max( normalView.dFdy().abs() ); - const geometryRoughness = dxy.x.max( dxy.y ).max( dxy.z ); + } - return geometryRoughness; + equals( box ) { -} ); + return box.min.equals( this.min ) && box.max.equals( this.max ); -const getRoughness = /*@__PURE__*/ Fn( ( inputs ) => { + } - const { roughness } = inputs; +} - const geometryRoughness = getGeometryRoughness(); +const _startP = /*@__PURE__*/ new Vector3(); +const _startEnd = /*@__PURE__*/ new Vector3(); - let roughnessFactor = roughness.max( 0.0525 ); // 0.0525 corresponds to the base mip of a 256 cubemap. - roughnessFactor = roughnessFactor.add( geometryRoughness ); - roughnessFactor = roughnessFactor.min( 1.0 ); +class Line3 { - return roughnessFactor; + constructor( start = new Vector3(), end = new Vector3() ) { -} ); + this.start = start; + this.end = end; -// Moving Frostbite to Physically Based Rendering 3.0 - page 12, listing 2 -// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf -const V_GGX_SmithCorrelated = /*@__PURE__*/ Fn( ( { alpha, dotNL, dotNV } ) => { + } - const a2 = alpha.pow2(); + set( start, end ) { - const gv = dotNL.mul( a2.add( a2.oneMinus().mul( dotNV.pow2() ) ).sqrt() ); - const gl = dotNV.mul( a2.add( a2.oneMinus().mul( dotNL.pow2() ) ).sqrt() ); + this.start.copy( start ); + this.end.copy( end ); - return div( 0.5, gv.add( gl ).max( EPSILON ) ); + return this; -} ).setLayout( { - name: 'V_GGX_SmithCorrelated', - type: 'float', - inputs: [ - { name: 'alpha', type: 'float' }, - { name: 'dotNL', type: 'float' }, - { name: 'dotNV', type: 'float' } - ] -} ); // validated + } -// https://google.github.io/filament/Filament.md.html#materialsystem/anisotropicmodel/anisotropicspecularbrdf + copy( line ) { -const V_GGX_SmithCorrelated_Anisotropic = /*@__PURE__*/ Fn( ( { alphaT, alphaB, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL } ) => { + this.start.copy( line.start ); + this.end.copy( line.end ); - const gv = dotNL.mul( vec3( alphaT.mul( dotTV ), alphaB.mul( dotBV ), dotNV ).length() ); - const gl = dotNV.mul( vec3( alphaT.mul( dotTL ), alphaB.mul( dotBL ), dotNL ).length() ); - const v = div( 0.5, gv.add( gl ) ); + return this; - return v.saturate(); + } -} ).setLayout( { - name: 'V_GGX_SmithCorrelated_Anisotropic', - type: 'float', - inputs: [ - { name: 'alphaT', type: 'float', qualifier: 'in' }, - { name: 'alphaB', type: 'float', qualifier: 'in' }, - { name: 'dotTV', type: 'float', qualifier: 'in' }, - { name: 'dotBV', type: 'float', qualifier: 'in' }, - { name: 'dotTL', type: 'float', qualifier: 'in' }, - { name: 'dotBL', type: 'float', qualifier: 'in' }, - { name: 'dotNV', type: 'float', qualifier: 'in' }, - { name: 'dotNL', type: 'float', qualifier: 'in' } - ] -} ); + getCenter( target ) { -// Microfacet Models for Refraction through Rough Surfaces - equation (33) -// http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html -// alpha is "roughness squared" in Disney’s reparameterization -const D_GGX = /*@__PURE__*/ Fn( ( { alpha, dotNH } ) => { + return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); - const a2 = alpha.pow2(); + } - const denom = dotNH.pow2().mul( a2.oneMinus() ).oneMinus(); // avoid alpha = 0 with dotNH = 1 + delta( target ) { - return a2.div( denom.pow2() ).mul( 1 / Math.PI ); + return target.subVectors( this.end, this.start ); -} ).setLayout( { - name: 'D_GGX', - type: 'float', - inputs: [ - { name: 'alpha', type: 'float' }, - { name: 'dotNH', type: 'float' } - ] -} ); // validated + } -const RECIPROCAL_PI = /*@__PURE__*/ float( 1 / Math.PI ); + distanceSq() { -// https://google.github.io/filament/Filament.md.html#materialsystem/anisotropicmodel/anisotropicspecularbrdf + return this.start.distanceToSquared( this.end ); -const D_GGX_Anisotropic = /*@__PURE__*/ Fn( ( { alphaT, alphaB, dotNH, dotTH, dotBH } ) => { + } - const a2 = alphaT.mul( alphaB ); - const v = vec3( alphaB.mul( dotTH ), alphaT.mul( dotBH ), a2.mul( dotNH ) ); - const v2 = v.dot( v ); - const w2 = a2.div( v2 ); + distance() { - return RECIPROCAL_PI.mul( a2.mul( w2.pow2() ) ); + return this.start.distanceTo( this.end ); -} ).setLayout( { - name: 'D_GGX_Anisotropic', - type: 'float', - inputs: [ - { name: 'alphaT', type: 'float', qualifier: 'in' }, - { name: 'alphaB', type: 'float', qualifier: 'in' }, - { name: 'dotNH', type: 'float', qualifier: 'in' }, - { name: 'dotTH', type: 'float', qualifier: 'in' }, - { name: 'dotBH', type: 'float', qualifier: 'in' } - ] -} ); + } -// GGX Distribution, Schlick Fresnel, GGX_SmithCorrelated Visibility -const BRDF_GGX = /*@__PURE__*/ Fn( ( inputs ) => { + at( t, target ) { - const { lightDirection, f0, f90, roughness, f, USE_IRIDESCENCE, USE_ANISOTROPY } = inputs; + return this.delta( target ).multiplyScalar( t ).add( this.start ); - const normalView = inputs.normalView || transformedNormalView; + } - const alpha = roughness.pow2(); // UE4's roughness + closestPointToPointParameter( point, clampToLine ) { - const halfDir = lightDirection.add( positionViewDirection ).normalize(); + _startP.subVectors( point, this.start ); + _startEnd.subVectors( this.end, this.start ); - const dotNL = normalView.dot( lightDirection ).clamp(); - const dotNV = normalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV - const dotNH = normalView.dot( halfDir ).clamp(); - const dotVH = positionViewDirection.dot( halfDir ).clamp(); + const startEnd2 = _startEnd.dot( _startEnd ); + const startEnd_startP = _startEnd.dot( _startP ); - let F = F_Schlick( { f0, f90, dotVH } ); - let V, D; + let t = startEnd_startP / startEnd2; - if ( defined( USE_IRIDESCENCE ) ) { + if ( clampToLine ) { - F = iridescence.mix( F, f ); + t = clamp$1( t, 0, 1 ); - } + } - if ( defined( USE_ANISOTROPY ) ) { + return t; - const dotTL = anisotropyT.dot( lightDirection ); - const dotTV = anisotropyT.dot( positionViewDirection ); - const dotTH = anisotropyT.dot( halfDir ); - const dotBL = anisotropyB.dot( lightDirection ); - const dotBV = anisotropyB.dot( positionViewDirection ); - const dotBH = anisotropyB.dot( halfDir ); + } - V = V_GGX_SmithCorrelated_Anisotropic( { alphaT, alphaB: alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL } ); - D = D_GGX_Anisotropic( { alphaT, alphaB: alpha, dotNH, dotTH, dotBH } ); + closestPointToPoint( point, clampToLine, target ) { - } else { + const t = this.closestPointToPointParameter( point, clampToLine ); - V = V_GGX_SmithCorrelated( { alpha, dotNL, dotNV } ); - D = D_GGX( { alpha, dotNH } ); + return this.delta( target ).multiplyScalar( t ).add( this.start ); } - return F.mul( V ).mul( D ); + applyMatrix4( matrix ) { -} ); // validated + this.start.applyMatrix4( matrix ); + this.end.applyMatrix4( matrix ); -// Analytical approximation of the DFG LUT, one half of the -// split-sum approximation used in indirect specular lighting. -// via 'environmentBRDF' from "Physically Based Shading on Mobile" -// https://www.unrealengine.com/blog/physically-based-shading-on-mobile -const DFGApprox = /*@__PURE__*/ Fn( ( { roughness, dotNV } ) => { + return this; - const c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 ); + } - const c1 = vec4( 1, 0.0425, 1.04, - 0.04 ); + equals( line ) { - const r = roughness.mul( c0 ).add( c1 ); + return line.start.equals( this.start ) && line.end.equals( this.end ); - const a004 = r.x.mul( r.x ).min( dotNV.mul( - 9.28 ).exp2() ).mul( r.x ).add( r.y ); + } - const fab = vec2( - 1.04, 1.04 ).mul( a004 ).add( r.zw ); + clone() { - return fab; + return new this.constructor().copy( this ); -} ).setLayout( { - name: 'DFGApprox', - type: 'vec2', - inputs: [ - { name: 'roughness', type: 'float' }, - { name: 'dotNV', type: 'vec3' } - ] -} ); + } -const EnvironmentBRDF = /*@__PURE__*/ Fn( ( inputs ) => { +} - const { dotNV, specularColor, specularF90, roughness } = inputs; +const _vector$3 = /*@__PURE__*/ new Vector3(); - const fab = DFGApprox( { dotNV, roughness } ); - return specularColor.mul( fab.x ).add( specularF90.mul( fab.y ) ); +class SpotLightHelper extends Object3D { -} ); + constructor( light, color ) { -const Schlick_to_F0 = /*@__PURE__*/ Fn( ( { f, f90, dotVH } ) => { + super(); - const x = dotVH.oneMinus().saturate(); - const x2 = x.mul( x ); - const x5 = x.mul( x2, x2 ).clamp( 0, .9999 ); + this.light = light; - return f.sub( vec3( f90 ).mul( x5 ) ).div( x5.oneMinus() ); + this.matrixAutoUpdate = false; -} ).setLayout( { - name: 'Schlick_to_F0', - type: 'vec3', - inputs: [ - { name: 'f', type: 'vec3' }, - { name: 'f90', type: 'float' }, - { name: 'dotVH', type: 'float' } - ] -} ); + this.color = color; -// https://github.com/google/filament/blob/master/shaders/src/brdf.fs -const D_Charlie = /*@__PURE__*/ Fn( ( { roughness, dotNH } ) => { + this.type = 'SpotLightHelper'; - const alpha = roughness.pow2(); + const geometry = new BufferGeometry(); - // Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF" - const invAlpha = float( 1.0 ).div( alpha ); - const cos2h = dotNH.pow2(); - const sin2h = cos2h.oneMinus().max( 0.0078125 ); // 2^(-14/2), so sin2h^2 > 0 in fp16 + const positions = [ + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 1, 0, 1, + 0, 0, 0, - 1, 0, 1, + 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, - 1, 1 + ]; - return float( 2.0 ).add( invAlpha ).mul( sin2h.pow( invAlpha.mul( 0.5 ) ) ).div( 2.0 * Math.PI ); + for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { -} ).setLayout( { - name: 'D_Charlie', - type: 'float', - inputs: [ - { name: 'roughness', type: 'float' }, - { name: 'dotNH', type: 'float' } - ] -} ); + const p1 = ( i / l ) * Math.PI * 2; + const p2 = ( j / l ) * Math.PI * 2; -// https://github.com/google/filament/blob/master/shaders/src/brdf.fs -const V_Neubelt = /*@__PURE__*/ Fn( ( { dotNV, dotNL } ) => { + positions.push( + Math.cos( p1 ), Math.sin( p1 ), 1, + Math.cos( p2 ), Math.sin( p2 ), 1 + ); - // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886" - return float( 1.0 ).div( float( 4.0 ).mul( dotNL.add( dotNV ).sub( dotNL.mul( dotNV ) ) ) ); + } -} ).setLayout( { - name: 'V_Neubelt', - type: 'float', - inputs: [ - { name: 'dotNV', type: 'float' }, - { name: 'dotNL', type: 'float' } - ] -} ); + geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); -const BRDF_Sheen = /*@__PURE__*/ Fn( ( { lightDirection } ) => { + const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); - const halfDir = lightDirection.add( positionViewDirection ).normalize(); + this.cone = new LineSegments( geometry, material ); + this.add( this.cone ); - const dotNL = transformedNormalView.dot( lightDirection ).clamp(); - const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); - const dotNH = transformedNormalView.dot( halfDir ).clamp(); + this.update(); - const D = D_Charlie( { roughness: sheenRoughness, dotNH } ); - const V = V_Neubelt( { dotNV, dotNL } ); + } - return sheen.mul( D ).mul( V ); + dispose() { -} ); + this.cone.geometry.dispose(); + this.cone.material.dispose(); -// Rect Area Light + } -// Real-Time Polygonal-Light Shading with Linearly Transformed Cosines -// by Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt -// code: https://github.com/selfshadow/ltc_code/ + update() { -const LTC_Uv = /*@__PURE__*/ Fn( ( { N, V, roughness } ) => { + this.light.updateWorldMatrix( true, false ); + this.light.target.updateWorldMatrix( true, false ); - const LUT_SIZE = 64.0; - const LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE; - const LUT_BIAS = 0.5 / LUT_SIZE; + // update the local matrix based on the parent and light target transforms + if ( this.parent ) { - const dotNV = N.dot( V ).saturate(); + this.parent.updateWorldMatrix( true ); - // texture parameterized by sqrt( GGX alpha ) and sqrt( 1 - cos( theta ) ) - const uv = vec2( roughness, dotNV.oneMinus().sqrt() ); + this.matrix + .copy( this.parent.matrixWorld ) + .invert() + .multiply( this.light.matrixWorld ); - uv.assign( uv.mul( LUT_SCALE ).add( LUT_BIAS ) ); + } else { - return uv; + this.matrix.copy( this.light.matrixWorld ); -} ).setLayout( { - name: 'LTC_Uv', - type: 'vec2', - inputs: [ - { name: 'N', type: 'vec3' }, - { name: 'V', type: 'vec3' }, - { name: 'roughness', type: 'float' } - ] -} ); + } -const LTC_ClippedSphereFormFactor = /*@__PURE__*/ Fn( ( { f } ) => { + this.matrixWorld.copy( this.light.matrixWorld ); - // Real-Time Area Lighting: a Journey from Research to Production (p.102) - // An approximation of the form factor of a horizon-clipped rectangle. + const coneLength = this.light.distance ? this.light.distance : 1000; + const coneWidth = coneLength * Math.tan( this.light.angle ); - const l = f.length(); + this.cone.scale.set( coneWidth, coneWidth, coneLength ); - return max$1( l.mul( l ).add( f.z ).div( l.add( 1.0 ) ), 0 ); + _vector$3.setFromMatrixPosition( this.light.target.matrixWorld ); -} ).setLayout( { - name: 'LTC_ClippedSphereFormFactor', - type: 'float', - inputs: [ - { name: 'f', type: 'vec3' } - ] -} ); + this.cone.lookAt( _vector$3 ); -const LTC_EdgeVectorFormFactor = /*@__PURE__*/ Fn( ( { v1, v2 } ) => { + if ( this.color !== undefined ) { - const x = v1.dot( v2 ); - const y = x.abs().toVar(); + this.cone.material.color.set( this.color ); - // rational polynomial approximation to theta / sin( theta ) / 2PI - const a = y.mul( 0.0145206 ).add( 0.4965155 ).mul( y ).add( 0.8543985 ).toVar(); - const b = y.add( 4.1616724 ).mul( y ).add( 3.4175940 ).toVar(); - const v = a.div( b ); + } else { - const theta_sintheta = x.greaterThan( 0.0 ).select( v, max$1( x.mul( x ).oneMinus(), 1e-7 ).inverseSqrt().mul( 0.5 ).sub( v ) ); + this.cone.material.color.copy( this.light.color ); - return v1.cross( v2 ).mul( theta_sintheta ); + } -} ).setLayout( { - name: 'LTC_EdgeVectorFormFactor', - type: 'vec3', - inputs: [ - { name: 'v1', type: 'vec3' }, - { name: 'v2', type: 'vec3' } - ] -} ); + } -const LTC_Evaluate = /*@__PURE__*/ Fn( ( { N, V, P, mInv, p0, p1, p2, p3 } ) => { +} - // bail if point is on back side of plane of light - // assumes ccw winding order of light vertices - const v1 = p1.sub( p0 ).toVar(); - const v2 = p3.sub( p0 ).toVar(); +const _vector$2 = /*@__PURE__*/ new Vector3(); +const _boneMatrix = /*@__PURE__*/ new Matrix4(); +const _matrixWorldInv = /*@__PURE__*/ new Matrix4(); - const lightNormal = v1.cross( v2 ); - const result = vec3().toVar(); - If( lightNormal.dot( P.sub( p0 ) ).greaterThanEqual( 0.0 ), () => { +class SkeletonHelper extends LineSegments { - // construct orthonormal basis around N - const T1 = V.sub( N.mul( V.dot( N ) ) ).normalize(); - const T2 = N.cross( T1 ).negate(); // negated from paper; possibly due to a different handedness of world coordinate system + constructor( object ) { - // compute transform - const mat = mInv.mul( mat3( T1, T2, N ).transpose() ).toVar(); + const bones = getBoneList( object ); - // transform rect - // & project rect onto sphere - const coords0 = mat.mul( p0.sub( P ) ).normalize().toVar(); - const coords1 = mat.mul( p1.sub( P ) ).normalize().toVar(); - const coords2 = mat.mul( p2.sub( P ) ).normalize().toVar(); - const coords3 = mat.mul( p3.sub( P ) ).normalize().toVar(); + const geometry = new BufferGeometry(); - // calculate vector form factor - const vectorFormFactor = vec3( 0 ).toVar(); - vectorFormFactor.addAssign( LTC_EdgeVectorFormFactor( { v1: coords0, v2: coords1 } ) ); - vectorFormFactor.addAssign( LTC_EdgeVectorFormFactor( { v1: coords1, v2: coords2 } ) ); - vectorFormFactor.addAssign( LTC_EdgeVectorFormFactor( { v1: coords2, v2: coords3 } ) ); - vectorFormFactor.addAssign( LTC_EdgeVectorFormFactor( { v1: coords3, v2: coords0 } ) ); + const vertices = []; + const colors = []; - // adjust for horizon clipping - result.assign( vec3( LTC_ClippedSphereFormFactor( { f: vectorFormFactor } ) ) ); + const color1 = new Color( 0, 0, 1 ); + const color2 = new Color( 0, 1, 0 ); - } ); + for ( let i = 0; i < bones.length; i ++ ) { - return result; + const bone = bones[ i ]; -} ).setLayout( { - name: 'LTC_Evaluate', - type: 'vec3', - inputs: [ - { name: 'N', type: 'vec3' }, - { name: 'V', type: 'vec3' }, - { name: 'P', type: 'vec3' }, - { name: 'mInv', type: 'mat3' }, - { name: 'p0', type: 'vec3' }, - { name: 'p1', type: 'vec3' }, - { name: 'p2', type: 'vec3' }, - { name: 'p3', type: 'vec3' } - ] -} ); + if ( bone.parent && bone.parent.isBone ) { -// Mipped Bicubic Texture Filtering by N8 -// https://www.shadertoy.com/view/Dl2SDW + vertices.push( 0, 0, 0 ); + vertices.push( 0, 0, 0 ); + colors.push( color1.r, color1.g, color1.b ); + colors.push( color2.r, color2.g, color2.b ); -const bC = 1.0 / 6.0; + } -const w0 = ( a ) => mul( bC, mul( a, mul( a, a.negate().add( 3.0 ) ).sub( 3.0 ) ).add( 1.0 ) ); + } -const w1 = ( a ) => mul( bC, mul( a, mul( a, mul( 3.0, a ).sub( 6.0 ) ) ).add( 4.0 ) ); + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); -const w2 = ( a ) => mul( bC, mul( a, mul( a, mul( - 3.0, a ).add( 3.0 ) ).add( 3.0 ) ).add( 1.0 ) ); + const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } ); -const w3 = ( a ) => mul( bC, pow( a, 3 ) ); + super( geometry, material ); -const g0 = ( a ) => w0( a ).add( w1( a ) ); + this.isSkeletonHelper = true; -const g1 = ( a ) => w2( a ).add( w3( a ) ); + this.type = 'SkeletonHelper'; -// h0 and h1 are the two offset functions -const h0 = ( a ) => add( - 1.0, w1( a ).div( w0( a ).add( w1( a ) ) ) ); + this.root = object; + this.bones = bones; -const h1 = ( a ) => add( 1.0, w3( a ).div( w2( a ).add( w3( a ) ) ) ); + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; -const bicubic = ( textureNode, texelSize, lod ) => { + } - const uv = textureNode.uvNode; - const uvScaled = mul( uv, texelSize.zw ).add( 0.5 ); + updateMatrixWorld( force ) { - const iuv = floor( uvScaled ); - const fuv = fract( uvScaled ); + const bones = this.bones; - const g0x = g0( fuv.x ); - const g1x = g1( fuv.x ); - const h0x = h0( fuv.x ); - const h1x = h1( fuv.x ); - const h0y = h0( fuv.y ); - const h1y = h1( fuv.y ); + const geometry = this.geometry; + const position = geometry.getAttribute( 'position' ); - const p0 = vec2( iuv.x.add( h0x ), iuv.y.add( h0y ) ).sub( 0.5 ).mul( texelSize.xy ); - const p1 = vec2( iuv.x.add( h1x ), iuv.y.add( h0y ) ).sub( 0.5 ).mul( texelSize.xy ); - const p2 = vec2( iuv.x.add( h0x ), iuv.y.add( h1y ) ).sub( 0.5 ).mul( texelSize.xy ); - const p3 = vec2( iuv.x.add( h1x ), iuv.y.add( h1y ) ).sub( 0.5 ).mul( texelSize.xy ); + _matrixWorldInv.copy( this.root.matrixWorld ).invert(); - const a = g0( fuv.y ).mul( add( g0x.mul( textureNode.uv( p0 ).level( lod ) ), g1x.mul( textureNode.uv( p1 ).level( lod ) ) ) ); - const b = g1( fuv.y ).mul( add( g0x.mul( textureNode.uv( p2 ).level( lod ) ), g1x.mul( textureNode.uv( p3 ).level( lod ) ) ) ); + for ( let i = 0, j = 0; i < bones.length; i ++ ) { - return a.add( b ); + const bone = bones[ i ]; -}; + if ( bone.parent && bone.parent.isBone ) { -const textureBicubic = /*@__PURE__*/ Fn( ( [ textureNode, lodNode = float( 3 ) ] ) => { + _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld ); + _vector$2.setFromMatrixPosition( _boneMatrix ); + position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z ); - const fLodSize = vec2( textureNode.size( int( lodNode ) ) ); - const cLodSize = vec2( textureNode.size( int( lodNode.add( 1.0 ) ) ) ); - const fLodSizeInv = div( 1.0, fLodSize ); - const cLodSizeInv = div( 1.0, cLodSize ); - const fSample = bicubic( textureNode, vec4( fLodSizeInv, fLodSize ), floor( lodNode ) ); - const cSample = bicubic( textureNode, vec4( cLodSizeInv, cLodSize ), ceil( lodNode ) ); + _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld ); + _vector$2.setFromMatrixPosition( _boneMatrix ); + position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z ); - return fract( lodNode ).mix( fSample, cSample ); + j += 2; -} ); + } -// -// Transmission -// + } -const getVolumeTransmissionRay = /*@__PURE__*/ Fn( ( [ n, v, thickness, ior, modelMatrix ] ) => { + geometry.getAttribute( 'position' ).needsUpdate = true; - // Direction of refracted light. - const refractionVector = vec3( refract( v.negate(), normalize( n ), div( 1.0, ior ) ) ); + super.updateMatrixWorld( force ); - // Compute rotation-independant scaling of the model matrix. - const modelScale = vec3( - length( modelMatrix[ 0 ].xyz ), - length( modelMatrix[ 1 ].xyz ), - length( modelMatrix[ 2 ].xyz ) - ); + } - // The thickness is specified in local space. - return normalize( refractionVector ).mul( thickness.mul( modelScale ) ); + dispose() { -} ).setLayout( { - name: 'getVolumeTransmissionRay', - type: 'vec3', - inputs: [ - { name: 'n', type: 'vec3' }, - { name: 'v', type: 'vec3' }, - { name: 'thickness', type: 'float' }, - { name: 'ior', type: 'float' }, - { name: 'modelMatrix', type: 'mat4' } - ] -} ); + this.geometry.dispose(); + this.material.dispose(); -const applyIorToRoughness = /*@__PURE__*/ Fn( ( [ roughness, ior ] ) => { + } - // Scale roughness with IOR so that an IOR of 1.0 results in no microfacet refraction and - // an IOR of 1.5 results in the default amount of microfacet refraction. - return roughness.mul( clamp( ior.mul( 2.0 ).sub( 2.0 ), 0.0, 1.0 ) ); +} -} ).setLayout( { - name: 'applyIorToRoughness', - type: 'float', - inputs: [ - { name: 'roughness', type: 'float' }, - { name: 'ior', type: 'float' } - ] -} ); -const singleViewportMipTexture = /*@__PURE__*/ viewportMipTexture(); +function getBoneList( object ) { -const getTransmissionSample = /*@__PURE__*/ Fn( ( [ fragCoord, roughness, ior ] ) => { + const boneList = []; - const transmissionSample = singleViewportMipTexture.uv( fragCoord ); - //const transmissionSample = viewportMipTexture( fragCoord ); + if ( object.isBone === true ) { - const lod = log2( float( viewportResolution.x ) ).mul( applyIorToRoughness( roughness, ior ) ); + boneList.push( object ); - return textureBicubic( transmissionSample, lod ); + } -} ); + for ( let i = 0; i < object.children.length; i ++ ) { -const volumeAttenuation = /*@__PURE__*/ Fn( ( [ transmissionDistance, attenuationColor, attenuationDistance ] ) => { + boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); - If( attenuationDistance.notEqual( 0 ), () => { + } - // Compute light attenuation using Beer's law. - const attenuationCoefficient = log( attenuationColor ).negate().div( attenuationDistance ); - const transmittance = exp( attenuationCoefficient.negate().mul( transmissionDistance ) ); + return boneList; - return transmittance; +} - } ); +class PointLightHelper extends Mesh { - // Attenuation distance is +∞, i.e. the transmitted color is not attenuated at all. - return vec3( 1.0 ); + constructor( light, sphereSize, color ) { -} ).setLayout( { - name: 'volumeAttenuation', - type: 'vec3', - inputs: [ - { name: 'transmissionDistance', type: 'float' }, - { name: 'attenuationColor', type: 'vec3' }, - { name: 'attenuationDistance', type: 'float' } - ] -} ); + const geometry = new SphereGeometry( sphereSize, 4, 2 ); + const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); -const getIBLVolumeRefraction = /*@__PURE__*/ Fn( ( [ n, v, roughness, diffuseColor, specularColor, specularF90, position, modelMatrix, viewMatrix, projMatrix, ior, thickness, attenuationColor, attenuationDistance, dispersion ] ) => { + super( geometry, material ); - let transmittedLight, transmittance; + this.light = light; - if ( dispersion ) { + this.color = color; - transmittedLight = vec4().toVar(); - transmittance = vec3().toVar(); + this.type = 'PointLightHelper'; - const halfSpread = ior.sub( 1.0 ).mul( dispersion.mul( 0.025 ) ); - const iors = vec3( ior.sub( halfSpread ), ior, ior.add( halfSpread ) ); + this.matrix = this.light.matrixWorld; + this.matrixAutoUpdate = false; - Loop( { start: 0, end: 3 }, ( { i } ) => { + this.update(); - const ior = iors.element( i ); - const transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix ); - const refractedRayExit = position.add( transmissionRay ); + /* + // TODO: delete this comment? + const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); + const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); - // Project refracted vector on the framebuffer, while mapping to normalized device coordinates. - const ndcPos = projMatrix.mul( viewMatrix.mul( vec4( refractedRayExit, 1.0 ) ) ); - const refractionCoords = vec2( ndcPos.xy.div( ndcPos.w ) ).toVar(); - refractionCoords.addAssign( 1.0 ); - refractionCoords.divAssign( 2.0 ); - refractionCoords.assign( vec2( refractionCoords.x, refractionCoords.y.oneMinus() ) ); // webgpu + this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); + this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); - // Sample framebuffer to get pixel the refracted ray hits. - const transmissionSample = getTransmissionSample( refractionCoords, roughness, ior ); + const d = light.distance; - transmittedLight.element( i ).assign( transmissionSample.element( i ) ); - transmittedLight.a.addAssign( transmissionSample.a ); + if ( d === 0.0 ) { - transmittance.element( i ).assign( diffuseColor.element( i ).mul( volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ).element( i ) ) ); + this.lightDistance.visible = false; - } ); + } else { - transmittedLight.a.divAssign( 3.0 ); + this.lightDistance.scale.set( d, d, d ); - } else { + } - const transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix ); - const refractedRayExit = position.add( transmissionRay ); + this.add( this.lightDistance ); + */ - // Project refracted vector on the framebuffer, while mapping to normalized device coordinates. - const ndcPos = projMatrix.mul( viewMatrix.mul( vec4( refractedRayExit, 1.0 ) ) ); - const refractionCoords = vec2( ndcPos.xy.div( ndcPos.w ) ).toVar(); - refractionCoords.addAssign( 1.0 ); - refractionCoords.divAssign( 2.0 ); - refractionCoords.assign( vec2( refractionCoords.x, refractionCoords.y.oneMinus() ) ); // webgpu + } - // Sample framebuffer to get pixel the refracted ray hits. - transmittedLight = getTransmissionSample( refractionCoords, roughness, ior ); - transmittance = diffuseColor.mul( volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ) ); + dispose() { + + this.geometry.dispose(); + this.material.dispose(); } - const attenuatedColor = transmittance.rgb.mul( transmittedLight.rgb ); - const dotNV = n.dot( v ).clamp(); + update() { - // Get the specular component. - const F = vec3( EnvironmentBRDF( { // n, v, specularColor, specularF90, roughness - dotNV, - specularColor, - specularF90, - roughness - } ) ); + this.light.updateWorldMatrix( true, false ); - // As less light is transmitted, the opacity should be increased. This simple approximation does a decent job - // of modulating a CSS background, and has no effect when the buffer is opaque, due to a solid object or clear color. - const transmittanceFactor = transmittance.r.add( transmittance.g, transmittance.b ).div( 3.0 ); + if ( this.color !== undefined ) { - return vec4( F.oneMinus().mul( attenuatedColor ), transmittedLight.a.oneMinus().mul( transmittanceFactor ).oneMinus() ); + this.material.color.set( this.color ); -} ); + } else { -// -// Iridescence -// + this.material.color.copy( this.light.color ); -// XYZ to linear-sRGB color space -const XYZ_TO_REC709 = /*@__PURE__*/ mat3( - 3.2404542, - 0.9692660, 0.0556434, - - 1.5371385, 1.8760108, - 0.2040259, - - 0.4985314, 0.0415560, 1.0572252 -); + } -// Assume air interface for top -// Note: We don't handle the case fresnel0 == 1 -const Fresnel0ToIor = ( fresnel0 ) => { + /* + const d = this.light.distance; - const sqrtF0 = fresnel0.sqrt(); - return vec3( 1.0 ).add( sqrtF0 ).div( vec3( 1.0 ).sub( sqrtF0 ) ); + if ( d === 0.0 ) { -}; + this.lightDistance.visible = false; -// ior is a value between 1.0 and 3.0. 1.0 is air interface -const IorToFresnel0 = ( transmittedIor, incidentIor ) => { + } else { - return transmittedIor.sub( incidentIor ).div( transmittedIor.add( incidentIor ) ).pow2(); + this.lightDistance.visible = true; + this.lightDistance.scale.set( d, d, d ); -}; + } + */ -// Fresnel equations for dielectric/dielectric interfaces. -// Ref: https://belcour.github.io/blog/research/2017/05/01/brdf-thin-film.html -// Evaluation XYZ sensitivity curves in Fourier space -const evalSensitivity = ( OPD, shift ) => { + } - const phase = OPD.mul( 2.0 * Math.PI * 1.0e-9 ); - const val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 ); - const pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 ); - const VAR = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 ); +} - const x = float( 9.7470e-14 * Math.sqrt( 2.0 * Math.PI * 4.5282e+09 ) ).mul( phase.mul( 2.2399e+06 ).add( shift.x ).cos() ).mul( phase.pow2().mul( - 4.5282e+09 ).exp() ); +const _vector$1 = /*@__PURE__*/ new Vector3(); +const _color1 = /*@__PURE__*/ new Color(); +const _color2 = /*@__PURE__*/ new Color(); - let xyz = val.mul( VAR.mul( 2.0 * Math.PI ).sqrt() ).mul( pos.mul( phase ).add( shift ).cos() ).mul( phase.pow2().negate().mul( VAR ).exp() ); - xyz = vec3( xyz.x.add( x ), xyz.y, xyz.z ).div( 1.0685e-7 ); +class HemisphereLightHelper extends Object3D { - const rgb = XYZ_TO_REC709.mul( xyz ); + constructor( light, size, color ) { - return rgb; + super(); -}; + this.light = light; -const evalIridescence = /*@__PURE__*/ Fn( ( { outsideIOR, eta2, cosTheta1, thinFilmThickness, baseF0 } ) => { + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - // Force iridescenceIOR -> outsideIOR when thinFilmThickness -> 0.0 - const iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) ); - // Evaluate the cosTheta on the base layer (Snell law) - const sinTheta2Sq = outsideIOR.div( iridescenceIOR ).pow2().mul( float( 1 ).sub( cosTheta1.pow2() ) ); + this.color = color; - // Handle TIR: - const cosTheta2Sq = float( 1 ).sub( sinTheta2Sq ); - /*if ( cosTheta2Sq < 0.0 ) { + this.type = 'HemisphereLightHelper'; - return vec3( 1.0 ); + const geometry = new OctahedronGeometry( size ); + geometry.rotateY( Math.PI * 0.5 ); - }*/ + this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); + if ( this.color === undefined ) this.material.vertexColors = true; - const cosTheta2 = cosTheta2Sq.sqrt(); + const position = geometry.getAttribute( 'position' ); + const colors = new Float32Array( position.count * 3 ); - // First interface - const R0 = IorToFresnel0( iridescenceIOR, outsideIOR ); - const R12 = F_Schlick( { f0: R0, f90: 1.0, dotVH: cosTheta1 } ); - //const R21 = R12; - const T121 = R12.oneMinus(); - const phi12 = iridescenceIOR.lessThan( outsideIOR ).select( Math.PI, 0.0 ); - const phi21 = float( Math.PI ).sub( phi12 ); - - // Second interface - const baseIOR = Fresnel0ToIor( baseF0.clamp( 0.0, 0.9999 ) ); // guard against 1.0 - const R1 = IorToFresnel0( baseIOR, iridescenceIOR.toVec3() ); - const R23 = F_Schlick( { f0: R1, f90: 1.0, dotVH: cosTheta2 } ); - const phi23 = vec3( - baseIOR.x.lessThan( iridescenceIOR ).select( Math.PI, 0.0 ), - baseIOR.y.lessThan( iridescenceIOR ).select( Math.PI, 0.0 ), - baseIOR.z.lessThan( iridescenceIOR ).select( Math.PI, 0.0 ) - ); - - // Phase shift - const OPD = iridescenceIOR.mul( thinFilmThickness, cosTheta2, 2.0 ); - const phi = vec3( phi21 ).add( phi23 ); - - // Compound terms - const R123 = R12.mul( R23 ).clamp( 1e-5, 0.9999 ); - const r123 = R123.sqrt(); - const Rs = T121.pow2().mul( R23 ).div( vec3( 1.0 ).sub( R123 ) ); - - // Reflectance term for m = 0 (DC term amplitude) - const C0 = R12.add( Rs ); - let I = C0; + geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) ); - // Reflectance term for m > 0 (pairs of diracs) - let Cm = Rs.sub( T121 ); - for ( let m = 1; m <= 2; ++ m ) { + this.add( new Mesh( geometry, this.material ) ); - Cm = Cm.mul( r123 ); - const Sm = evalSensitivity( float( m ).mul( OPD ), float( m ).mul( phi ) ).mul( 2.0 ); - I = I.add( Cm.mul( Sm ) ); + this.update(); } - // Since out of gamut colors might be produced, negative color values are clamped to 0. - return I.max( vec3( 0.0 ) ); + dispose() { -} ).setLayout( { - name: 'evalIridescence', - type: 'vec3', - inputs: [ - { name: 'outsideIOR', type: 'float' }, - { name: 'eta2', type: 'float' }, - { name: 'cosTheta1', type: 'float' }, - { name: 'thinFilmThickness', type: 'float' }, - { name: 'baseF0', type: 'vec3' } - ] -} ); + this.children[ 0 ].geometry.dispose(); + this.children[ 0 ].material.dispose(); -// -// Sheen -// + } -// This is a curve-fit approxmation to the "Charlie sheen" BRDF integrated over the hemisphere from -// Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF". The analysis can be found -// in the Sheen section of https://drive.google.com/file/d/1T0D1VSyR4AllqIJTQAraEIzjlb5h4FKH/view?usp=sharing -const IBLSheenBRDF = /*@__PURE__*/ Fn( ( { normal, viewDir, roughness } ) => { + update() { - const dotNV = normal.dot( viewDir ).saturate(); + const mesh = this.children[ 0 ]; - const r2 = roughness.pow2(); + if ( this.color !== undefined ) { - const a = select( - roughness.lessThan( 0.25 ), - float( - 339.2 ).mul( r2 ).add( float( 161.4 ).mul( roughness ) ).sub( 25.9 ), - float( - 8.48 ).mul( r2 ).add( float( 14.3 ).mul( roughness ) ).sub( 9.95 ) - ); + this.material.color.set( this.color ); - const b = select( - roughness.lessThan( 0.25 ), - float( 44.0 ).mul( r2 ).sub( float( 23.7 ).mul( roughness ) ).add( 3.26 ), - float( 1.97 ).mul( r2 ).sub( float( 3.27 ).mul( roughness ) ).add( 0.72 ) - ); + } else { - const DG = select( roughness.lessThan( 0.25 ), 0.0, float( 0.1 ).mul( roughness ).sub( 0.025 ) ).add( a.mul( dotNV ).add( b ).exp() ); + const colors = mesh.geometry.getAttribute( 'color' ); - return DG.mul( 1.0 / Math.PI ).saturate(); + _color1.copy( this.light.color ); + _color2.copy( this.light.groundColor ); -} ); + for ( let i = 0, l = colors.count; i < l; i ++ ) { -const clearcoatF0 = vec3( 0.04 ); -const clearcoatF90 = float( 1 ); + const color = ( i < ( l / 2 ) ) ? _color1 : _color2; -// + colors.setXYZ( i, color.r, color.g, color.b ); -class PhysicalLightingModel extends LightingModel { + } - constructor( clearcoat = false, sheen = false, iridescence = false, anisotropy = false, transmission = false, dispersion = false ) { + colors.needsUpdate = true; - super(); + } - this.clearcoat = clearcoat; - this.sheen = sheen; - this.iridescence = iridescence; - this.anisotropy = anisotropy; - this.transmission = transmission; - this.dispersion = dispersion; + this.light.updateWorldMatrix( true, false ); - this.clearcoatRadiance = null; - this.clearcoatSpecularDirect = null; - this.clearcoatSpecularIndirect = null; - this.sheenSpecularDirect = null; - this.sheenSpecularIndirect = null; - this.iridescenceFresnel = null; - this.iridescenceF0 = null; + mesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() ); } - start( context ) { - - if ( this.clearcoat === true ) { +} - this.clearcoatRadiance = vec3().toVar( 'clearcoatRadiance' ); - this.clearcoatSpecularDirect = vec3().toVar( 'clearcoatSpecularDirect' ); - this.clearcoatSpecularIndirect = vec3().toVar( 'clearcoatSpecularIndirect' ); +class GridHelper extends LineSegments { - } + constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) { - if ( this.sheen === true ) { + color1 = new Color( color1 ); + color2 = new Color( color2 ); - this.sheenSpecularDirect = vec3().toVar( 'sheenSpecularDirect' ); - this.sheenSpecularIndirect = vec3().toVar( 'sheenSpecularIndirect' ); + const center = divisions / 2; + const step = size / divisions; + const halfSize = size / 2; - } + const vertices = [], colors = []; - if ( this.iridescence === true ) { + for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { - const dotNVi = transformedNormalView.dot( positionViewDirection ).clamp(); + vertices.push( - halfSize, 0, k, halfSize, 0, k ); + vertices.push( k, 0, - halfSize, k, 0, halfSize ); - this.iridescenceFresnel = evalIridescence( { - outsideIOR: float( 1.0 ), - eta2: iridescenceIOR, - cosTheta1: dotNVi, - thinFilmThickness: iridescenceThickness, - baseF0: specularColor - } ); + const color = i === center ? color1 : color2; - this.iridescenceF0 = Schlick_to_F0( { f: this.iridescenceFresnel, f90: 1.0, dotVH: dotNVi } ); + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; } - if ( this.transmission === true ) { + const geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - const position = positionWorld; - const v = cameraPosition.sub( positionWorld ).normalize(); // TODO: Create Node for this, same issue in MaterialX - const n = transformedNormalWorld; + const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); - context.backdrop = getIBLVolumeRefraction( - n, - v, - roughness, - diffuseColor, - specularColor, - specularF90, // specularF90 - position, // positionWorld - modelWorldMatrix, // modelMatrix - cameraViewMatrix, // viewMatrix - cameraProjectionMatrix, // projMatrix - ior, - thickness, - attenuationColor, - attenuationDistance, - this.dispersion ? dispersion : null - ); + super( geometry, material ); - context.backdropAlpha = transmission; + this.type = 'GridHelper'; - diffuseColor.a.mulAssign( mix( 1, context.backdrop.a, transmission ) ); + } - } + dispose() { + + this.geometry.dispose(); + this.material.dispose(); } - // Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting" - // Approximates multiscattering in order to preserve energy. - // http://www.jcgt.org/published/0008/01/03/ +} - computeMultiscattering( singleScatter, multiScatter, specularF90 ) { +class PolarGridHelper extends LineSegments { - const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV + constructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) { - const fab = DFGApprox( { roughness, dotNV } ); + color1 = new Color( color1 ); + color2 = new Color( color2 ); - const Fr = this.iridescenceF0 ? iridescence.mix( specularColor, this.iridescenceF0 ) : specularColor; + const vertices = []; + const colors = []; - const FssEss = Fr.mul( fab.x ).add( specularF90.mul( fab.y ) ); + // create the sectors - const Ess = fab.x.add( fab.y ); - const Ems = Ess.oneMinus(); + if ( sectors > 1 ) { - const Favg = specularColor.add( specularColor.oneMinus().mul( 0.047619 ) ); // 1/21 - const Fms = FssEss.mul( Favg ).div( Ems.mul( Favg ).oneMinus() ); + for ( let i = 0; i < sectors; i ++ ) { - singleScatter.addAssign( FssEss ); - multiScatter.addAssign( Fms.mul( Ems ) ); + const v = ( i / sectors ) * ( Math.PI * 2 ); - } + const x = Math.sin( v ) * radius; + const z = Math.cos( v ) * radius; - direct( { lightDirection, lightColor, reflectedLight } ) { + vertices.push( 0, 0, 0 ); + vertices.push( x, 0, z ); - const dotNL = transformedNormalView.dot( lightDirection ).clamp(); - const irradiance = dotNL.mul( lightColor ); + const color = ( i & 1 ) ? color1 : color2; - if ( this.sheen === true ) { + colors.push( color.r, color.g, color.b ); + colors.push( color.r, color.g, color.b ); - this.sheenSpecularDirect.addAssign( irradiance.mul( BRDF_Sheen( { lightDirection } ) ) ); + } } - if ( this.clearcoat === true ) { + // create the rings - const dotNLcc = transformedClearcoatNormalView.dot( lightDirection ).clamp(); - const ccIrradiance = dotNLcc.mul( lightColor ); + for ( let i = 0; i < rings; i ++ ) { - this.clearcoatSpecularDirect.addAssign( ccIrradiance.mul( BRDF_GGX( { lightDirection, f0: clearcoatF0, f90: clearcoatF90, roughness: clearcoatRoughness, normalView: transformedClearcoatNormalView } ) ) ); + const color = ( i & 1 ) ? color1 : color2; - } + const r = radius - ( radius / rings * i ); - reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) ); + for ( let j = 0; j < divisions; j ++ ) { - reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_GGX( { lightDirection, f0: specularColor, f90: 1, roughness, iridescence: this.iridescence, f: this.iridescenceFresnel, USE_IRIDESCENCE: this.iridescence, USE_ANISOTROPY: this.anisotropy } ) ) ); + // first vertex - } + let v = ( j / divisions ) * ( Math.PI * 2 ); - directRectArea( { lightColor, lightPosition, halfWidth, halfHeight, reflectedLight, ltc_1, ltc_2 } ) { + let x = Math.sin( v ) * r; + let z = Math.cos( v ) * r; - const p0 = lightPosition.add( halfWidth ).sub( halfHeight ); // counterclockwise; light shines in local neg z direction - const p1 = lightPosition.sub( halfWidth ).sub( halfHeight ); - const p2 = lightPosition.sub( halfWidth ).add( halfHeight ); - const p3 = lightPosition.add( halfWidth ).add( halfHeight ); + vertices.push( x, 0, z ); + colors.push( color.r, color.g, color.b ); - const N = transformedNormalView; - const V = positionViewDirection; - const P = positionView.toVar(); + // second vertex - const uv = LTC_Uv( { N, V, roughness } ); + v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); - const t1 = ltc_1.uv( uv ).toVar(); - const t2 = ltc_2.uv( uv ).toVar(); + x = Math.sin( v ) * r; + z = Math.cos( v ) * r; - const mInv = mat3( - vec3( t1.x, 0, t1.y ), - vec3( 0, 1, 0 ), - vec3( t1.z, 0, t1.w ) - ).toVar(); + vertices.push( x, 0, z ); + colors.push( color.r, color.g, color.b ); - // LTC Fresnel Approximation by Stephen Hill - // http://blog.selfshadow.com/publications/s2016-advances/s2016_ltc_fresnel.pdf - const fresnel = specularColor.mul( t2.x ).add( specularColor.oneMinus().mul( t2.y ) ).toVar(); + } - reflectedLight.directSpecular.addAssign( lightColor.mul( fresnel ).mul( LTC_Evaluate( { N, V, P, mInv, p0, p1, p2, p3 } ) ) ); + } - reflectedLight.directDiffuse.addAssign( lightColor.mul( diffuseColor ).mul( LTC_Evaluate( { N, V, P, mInv: mat3( 1, 0, 0, 0, 1, 0, 0, 0, 1 ), p0, p1, p2, p3 } ) ) ); + const geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - } + const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); - indirect( context, stack, builder ) { + super( geometry, material ); - this.indirectDiffuse( context, stack, builder ); - this.indirectSpecular( context, stack, builder ); - this.ambientOcclusion( context, stack, builder ); + this.type = 'PolarGridHelper'; } - indirectDiffuse( { irradiance, reflectedLight } ) { + dispose() { - reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) ); + this.geometry.dispose(); + this.material.dispose(); } - indirectSpecular( { radiance, iblIrradiance, reflectedLight } ) { +} - if ( this.sheen === true ) { +const _v1 = /*@__PURE__*/ new Vector3(); +const _v2 = /*@__PURE__*/ new Vector3(); +const _v3 = /*@__PURE__*/ new Vector3(); - this.sheenSpecularIndirect.addAssign( iblIrradiance.mul( - sheen, - IBLSheenBRDF( { - normal: transformedNormalView, - viewDir: positionViewDirection, - roughness: sheenRoughness - } ) - ) ); +class DirectionalLightHelper extends Object3D { - } + constructor( light, size, color ) { - if ( this.clearcoat === true ) { + super(); - const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp(); + this.light = light; - const clearcoatEnv = EnvironmentBRDF( { - dotNV: dotNVcc, - specularColor: clearcoatF0, - specularF90: clearcoatF90, - roughness: clearcoatRoughness - } ); + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - this.clearcoatSpecularIndirect.addAssign( this.clearcoatRadiance.mul( clearcoatEnv ) ); + this.color = color; - } + this.type = 'DirectionalLightHelper'; - // Both indirect specular and indirect diffuse light accumulate here + if ( size === undefined ) size = 1; - const singleScattering = vec3().toVar( 'singleScattering' ); - const multiScattering = vec3().toVar( 'multiScattering' ); - const cosineWeightedIrradiance = iblIrradiance.mul( 1 / Math.PI ); + let geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( [ + - size, size, 0, + size, size, 0, + size, - size, 0, + - size, - size, 0, + - size, size, 0 + ], 3 ) ); - this.computeMultiscattering( singleScattering, multiScattering, specularF90 ); + const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); - const totalScattering = singleScattering.add( multiScattering ); + this.lightPlane = new Line( geometry, material ); + this.add( this.lightPlane ); - const diffuse = diffuseColor.mul( totalScattering.r.max( totalScattering.g ).max( totalScattering.b ).oneMinus() ); + geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); - reflectedLight.indirectSpecular.addAssign( radiance.mul( singleScattering ) ); - reflectedLight.indirectSpecular.addAssign( multiScattering.mul( cosineWeightedIrradiance ) ); + this.targetLine = new Line( geometry, material ); + this.add( this.targetLine ); - reflectedLight.indirectDiffuse.addAssign( diffuse.mul( cosineWeightedIrradiance ) ); + this.update(); } - ambientOcclusion( { ambientOcclusion, reflectedLight } ) { + dispose() { - const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV + this.lightPlane.geometry.dispose(); + this.lightPlane.material.dispose(); + this.targetLine.geometry.dispose(); + this.targetLine.material.dispose(); - const aoNV = dotNV.add( ambientOcclusion ); - const aoExp = roughness.mul( - 16.0 ).oneMinus().negate().exp2(); + } - const aoNode = ambientOcclusion.sub( aoNV.pow( aoExp ).oneMinus() ).clamp(); + update() { - if ( this.clearcoat === true ) { + this.light.updateWorldMatrix( true, false ); + this.light.target.updateWorldMatrix( true, false ); - this.clearcoatSpecularIndirect.mulAssign( ambientOcclusion ); + _v1.setFromMatrixPosition( this.light.matrixWorld ); + _v2.setFromMatrixPosition( this.light.target.matrixWorld ); + _v3.subVectors( _v2, _v1 ); - } + this.lightPlane.lookAt( _v2 ); - if ( this.sheen === true ) { + if ( this.color !== undefined ) { - this.sheenSpecularIndirect.mulAssign( ambientOcclusion ); + this.lightPlane.material.color.set( this.color ); + this.targetLine.material.color.set( this.color ); + + } else { + + this.lightPlane.material.color.copy( this.light.color ); + this.targetLine.material.color.copy( this.light.color ); } - reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion ); - reflectedLight.indirectSpecular.mulAssign( aoNode ); + this.targetLine.lookAt( _v2 ); + this.targetLine.scale.z = _v3.length(); } - finish( context ) { +} - const { outgoingLight } = context; +const _vector = /*@__PURE__*/ new Vector3(); +const _camera$1 = /*@__PURE__*/ new Camera(); - if ( this.clearcoat === true ) { +/** + * - shows frustum, line of sight and up of the camera + * - suitable for fast updates + * - based on frustum visualization in lightgl.js shadowmap example + * https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html + */ - const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp(); +class CameraHelper extends LineSegments { - const Fcc = F_Schlick( { - dotVH: dotNVcc, - f0: clearcoatF0, - f90: clearcoatF90 - } ); + constructor( camera ) { - const clearcoatLight = outgoingLight.mul( clearcoat.mul( Fcc ).oneMinus() ).add( this.clearcoatSpecularDirect.add( this.clearcoatSpecularIndirect ).mul( clearcoat ) ); + const geometry = new BufferGeometry(); + const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } ); - outgoingLight.assign( clearcoatLight ); + const vertices = []; + const colors = []; - } + const pointMap = {}; - if ( this.sheen === true ) { + // near - const sheenEnergyComp = sheen.r.max( sheen.g ).max( sheen.b ).mul( 0.157 ).oneMinus(); - const sheenLight = outgoingLight.mul( sheenEnergyComp ).add( this.sheenSpecularDirect, this.sheenSpecularIndirect ); + addLine( 'n1', 'n2' ); + addLine( 'n2', 'n4' ); + addLine( 'n4', 'n3' ); + addLine( 'n3', 'n1' ); - outgoingLight.assign( sheenLight ); + // far - } + addLine( 'f1', 'f2' ); + addLine( 'f2', 'f4' ); + addLine( 'f4', 'f3' ); + addLine( 'f3', 'f1' ); - } + // sides -} + addLine( 'n1', 'f1' ); + addLine( 'n2', 'f2' ); + addLine( 'n3', 'f3' ); + addLine( 'n4', 'f4' ); -// These defines must match with PMREMGenerator + // cone -const cubeUV_r0 = /*@__PURE__*/ float( 1.0 ); -const cubeUV_m0 = /*@__PURE__*/ float( - 2.0 ); -const cubeUV_r1 = /*@__PURE__*/ float( 0.8 ); -const cubeUV_m1 = /*@__PURE__*/ float( - 1.0 ); -const cubeUV_r4 = /*@__PURE__*/ float( 0.4 ); -const cubeUV_m4 = /*@__PURE__*/ float( 2.0 ); -const cubeUV_r5 = /*@__PURE__*/ float( 0.305 ); -const cubeUV_m5 = /*@__PURE__*/ float( 3.0 ); -const cubeUV_r6 = /*@__PURE__*/ float( 0.21 ); -const cubeUV_m6 = /*@__PURE__*/ float( 4.0 ); + addLine( 'p', 'n1' ); + addLine( 'p', 'n2' ); + addLine( 'p', 'n3' ); + addLine( 'p', 'n4' ); -const cubeUV_minMipLevel = /*@__PURE__*/ float( 4.0 ); -const cubeUV_minTileSize = /*@__PURE__*/ float( 16.0 ); + // up -// These shader functions convert between the UV coordinates of a single face of -// a cubemap, the 0-5 integer index of a cube face, and the direction vector for -// sampling a textureCube (not generally normalized ). + addLine( 'u1', 'u2' ); + addLine( 'u2', 'u3' ); + addLine( 'u3', 'u1' ); -const getFace = /*@__PURE__*/ Fn( ( [ direction ] ) => { + // target - const absDirection = vec3( abs( direction ) ).toVar(); - const face = float( - 1.0 ).toVar(); + addLine( 'c', 't' ); + addLine( 'p', 'c' ); - If( absDirection.x.greaterThan( absDirection.z ), () => { + // cross - If( absDirection.x.greaterThan( absDirection.y ), () => { + addLine( 'cn1', 'cn2' ); + addLine( 'cn3', 'cn4' ); - face.assign( select( direction.x.greaterThan( 0.0 ), 0.0, 3.0 ) ); + addLine( 'cf1', 'cf2' ); + addLine( 'cf3', 'cf4' ); - } ).Else( () => { + function addLine( a, b ) { - face.assign( select( direction.y.greaterThan( 0.0 ), 1.0, 4.0 ) ); + addPoint( a ); + addPoint( b ); - } ); + } - } ).Else( () => { + function addPoint( id ) { - If( absDirection.z.greaterThan( absDirection.y ), () => { + vertices.push( 0, 0, 0 ); + colors.push( 0, 0, 0 ); - face.assign( select( direction.z.greaterThan( 0.0 ), 2.0, 5.0 ) ); + if ( pointMap[ id ] === undefined ) { - } ).Else( () => { + pointMap[ id ] = []; - face.assign( select( direction.y.greaterThan( 0.0 ), 1.0, 4.0 ) ); + } - } ); + pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); - } ); + } - return face; + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); -} ).setLayout( { - name: 'getFace', - type: 'float', - inputs: [ - { name: 'direction', type: 'vec3' } - ] -} ); + super( geometry, material ); -// RH coordinate system; PMREM face-indexing convention -const getUV = /*@__PURE__*/ Fn( ( [ direction, face ] ) => { + this.type = 'CameraHelper'; - const uv = vec2().toVar(); + this.camera = camera; + if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); - If( face.equal( 0.0 ), () => { + this.matrix = camera.matrixWorld; + this.matrixAutoUpdate = false; - uv.assign( vec2( direction.z, direction.y ).div( abs( direction.x ) ) ); // pos x + this.pointMap = pointMap; - } ).ElseIf( face.equal( 1.0 ), () => { + this.update(); - uv.assign( vec2( direction.x.negate(), direction.z.negate() ).div( abs( direction.y ) ) ); // pos y + // colors - } ).ElseIf( face.equal( 2.0 ), () => { + const colorFrustum = new Color( 0xffaa00 ); + const colorCone = new Color( 0xff0000 ); + const colorUp = new Color( 0x00aaff ); + const colorTarget = new Color( 0xffffff ); + const colorCross = new Color( 0x333333 ); - uv.assign( vec2( direction.x.negate(), direction.y ).div( abs( direction.z ) ) ); // pos z + this.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross ); - } ).ElseIf( face.equal( 3.0 ), () => { + } - uv.assign( vec2( direction.z.negate(), direction.y ).div( abs( direction.x ) ) ); // neg x + setColors( frustum, cone, up, target, cross ) { - } ).ElseIf( face.equal( 4.0 ), () => { + const geometry = this.geometry; - uv.assign( vec2( direction.x.negate(), direction.z ).div( abs( direction.y ) ) ); // neg y + const colorAttribute = geometry.getAttribute( 'color' ); - } ).Else( () => { + // near - uv.assign( vec2( direction.x, direction.y ).div( abs( direction.z ) ) ); // neg z + colorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2 + colorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4 + colorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3 + colorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1 - } ); + // far - return mul( 0.5, uv.add( 1.0 ) ); + colorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2 + colorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4 + colorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3 + colorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1 -} ).setLayout( { - name: 'getUV', - type: 'vec2', - inputs: [ - { name: 'direction', type: 'vec3' }, - { name: 'face', type: 'float' } - ] -} ); + // sides -const roughnessToMip = /*@__PURE__*/ Fn( ( [ roughness ] ) => { + colorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1 + colorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2 + colorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3 + colorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4 - const mip = float( 0.0 ).toVar(); + // cone - If( roughness.greaterThanEqual( cubeUV_r1 ), () => { + colorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1 + colorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2 + colorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3 + colorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4 - mip.assign( cubeUV_r0.sub( roughness ).mul( cubeUV_m1.sub( cubeUV_m0 ) ).div( cubeUV_r0.sub( cubeUV_r1 ) ).add( cubeUV_m0 ) ); + // up - } ).ElseIf( roughness.greaterThanEqual( cubeUV_r4 ), () => { + colorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2 + colorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3 + colorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1 - mip.assign( cubeUV_r1.sub( roughness ).mul( cubeUV_m4.sub( cubeUV_m1 ) ).div( cubeUV_r1.sub( cubeUV_r4 ) ).add( cubeUV_m1 ) ); + // target - } ).ElseIf( roughness.greaterThanEqual( cubeUV_r5 ), () => { + colorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t + colorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c - mip.assign( cubeUV_r4.sub( roughness ).mul( cubeUV_m5.sub( cubeUV_m4 ) ).div( cubeUV_r4.sub( cubeUV_r5 ) ).add( cubeUV_m4 ) ); + // cross - } ).ElseIf( roughness.greaterThanEqual( cubeUV_r6 ), () => { + colorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2 + colorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4 - mip.assign( cubeUV_r5.sub( roughness ).mul( cubeUV_m6.sub( cubeUV_m5 ) ).div( cubeUV_r5.sub( cubeUV_r6 ) ).add( cubeUV_m5 ) ); + colorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2 + colorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4 - } ).Else( () => { + colorAttribute.needsUpdate = true; - mip.assign( float( - 2.0 ).mul( log2( mul( 1.16, roughness ) ) ) ); // 1.16 = 1.79^0.25 + } - } ); + update() { - return mip; + const geometry = this.geometry; + const pointMap = this.pointMap; -} ).setLayout( { - name: 'roughnessToMip', - type: 'float', - inputs: [ - { name: 'roughness', type: 'float' } - ] -} ); + const w = 1, h = 1; -// RH coordinate system; PMREM face-indexing convention -const getDirection = /*@__PURE__*/ Fn( ( [ uv_immutable, face ] ) => { + // we need just camera projection matrix inverse + // world matrix must be identity - const uv = uv_immutable.toVar(); - uv.assign( mul( 2.0, uv ).sub( 1.0 ) ); - const direction = vec3( uv, 1.0 ).toVar(); + _camera$1.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); - If( face.equal( 0.0 ), () => { + // center / target - direction.assign( direction.zyx ); // ( 1, v, u ) pos x + setPoint( 'c', pointMap, geometry, _camera$1, 0, 0, - 1 ); + setPoint( 't', pointMap, geometry, _camera$1, 0, 0, 1 ); - } ).ElseIf( face.equal( 1.0 ), () => { + // near - direction.assign( direction.xzy ); - direction.xz.mulAssign( - 1.0 ); // ( -u, 1, -v ) pos y + setPoint( 'n1', pointMap, geometry, _camera$1, - w, - h, - 1 ); + setPoint( 'n2', pointMap, geometry, _camera$1, w, - h, - 1 ); + setPoint( 'n3', pointMap, geometry, _camera$1, - w, h, - 1 ); + setPoint( 'n4', pointMap, geometry, _camera$1, w, h, - 1 ); - } ).ElseIf( face.equal( 2.0 ), () => { + // far - direction.x.mulAssign( - 1.0 ); // ( -u, v, 1 ) pos z + setPoint( 'f1', pointMap, geometry, _camera$1, - w, - h, 1 ); + setPoint( 'f2', pointMap, geometry, _camera$1, w, - h, 1 ); + setPoint( 'f3', pointMap, geometry, _camera$1, - w, h, 1 ); + setPoint( 'f4', pointMap, geometry, _camera$1, w, h, 1 ); - } ).ElseIf( face.equal( 3.0 ), () => { + // up - direction.assign( direction.zyx ); - direction.xz.mulAssign( - 1.0 ); // ( -1, v, -u ) neg x + setPoint( 'u1', pointMap, geometry, _camera$1, w * 0.7, h * 1.1, - 1 ); + setPoint( 'u2', pointMap, geometry, _camera$1, - w * 0.7, h * 1.1, - 1 ); + setPoint( 'u3', pointMap, geometry, _camera$1, 0, h * 2, - 1 ); - } ).ElseIf( face.equal( 4.0 ), () => { + // cross - direction.assign( direction.xzy ); - direction.xy.mulAssign( - 1.0 ); // ( -u, -1, v ) neg y + setPoint( 'cf1', pointMap, geometry, _camera$1, - w, 0, 1 ); + setPoint( 'cf2', pointMap, geometry, _camera$1, w, 0, 1 ); + setPoint( 'cf3', pointMap, geometry, _camera$1, 0, - h, 1 ); + setPoint( 'cf4', pointMap, geometry, _camera$1, 0, h, 1 ); - } ).ElseIf( face.equal( 5.0 ), () => { + setPoint( 'cn1', pointMap, geometry, _camera$1, - w, 0, - 1 ); + setPoint( 'cn2', pointMap, geometry, _camera$1, w, 0, - 1 ); + setPoint( 'cn3', pointMap, geometry, _camera$1, 0, - h, - 1 ); + setPoint( 'cn4', pointMap, geometry, _camera$1, 0, h, - 1 ); - direction.z.mulAssign( - 1.0 ); // ( u, v, -1 ) neg zS + geometry.getAttribute( 'position' ).needsUpdate = true; - } ); + } - return direction; + dispose() { -} ).setLayout( { - name: 'getDirection', - type: 'vec3', - inputs: [ - { name: 'uv', type: 'vec2' }, - { name: 'face', type: 'float' } - ] -} ); + this.geometry.dispose(); + this.material.dispose(); -// + } -const textureCubeUV = /*@__PURE__*/ Fn( ( [ envMap, sampleDir_immutable, roughness_immutable, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ] ) => { +} - const roughness = float( roughness_immutable ); - const sampleDir = vec3( sampleDir_immutable ); - const mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP ); - const mipF = fract( mip ); - const mipInt = floor( mip ); - const color0 = vec3( bilinearCubeUV( envMap, sampleDir, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ) ).toVar(); +function setPoint( point, pointMap, geometry, camera, x, y, z ) { - If( mipF.notEqual( 0.0 ), () => { + _vector.set( x, y, z ).unproject( camera ); - const color1 = vec3( bilinearCubeUV( envMap, sampleDir, mipInt.add( 1.0 ), CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ) ).toVar(); + const points = pointMap[ point ]; - color0.assign( mix( color0, color1, mipF ) ); + if ( points !== undefined ) { - } ); + const position = geometry.getAttribute( 'position' ); - return color0; + for ( let i = 0, l = points.length; i < l; i ++ ) { -} ); + position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z ); -const bilinearCubeUV = /*@__PURE__*/ Fn( ( [ envMap, direction_immutable, mipInt_immutable, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ] ) => { + } - const mipInt = float( mipInt_immutable ).toVar(); - const direction = vec3( direction_immutable ); - const face = float( getFace( direction ) ).toVar(); - const filterInt = float( max$1( cubeUV_minMipLevel.sub( mipInt ), 0.0 ) ).toVar(); - mipInt.assign( max$1( mipInt, cubeUV_minMipLevel ) ); - const faceSize = float( exp2( mipInt ) ).toVar(); - const uv = vec2( getUV( direction, face ).mul( faceSize.sub( 2.0 ) ).add( 1.0 ) ).toVar(); + } - If( face.greaterThan( 2.0 ), () => { +} - uv.y.addAssign( faceSize ); - face.subAssign( 3.0 ); +const _box = /*@__PURE__*/ new Box3(); - } ); +class BoxHelper extends LineSegments { - uv.x.addAssign( face.mul( faceSize ) ); - uv.x.addAssign( filterInt.mul( mul( 3.0, cubeUV_minTileSize ) ) ); - uv.y.addAssign( mul( 4.0, exp2( CUBEUV_MAX_MIP ).sub( faceSize ) ) ); - uv.x.mulAssign( CUBEUV_TEXEL_WIDTH ); - uv.y.mulAssign( CUBEUV_TEXEL_HEIGHT ); + constructor( object, color = 0xffff00 ) { - return envMap.uv( uv ).grad( vec2(), vec2() ); // disable anisotropic filtering + const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); + const positions = new Float32Array( 8 * 3 ); -} ); + const geometry = new BufferGeometry(); + geometry.setIndex( new BufferAttribute( indices, 1 ) ); + geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) ); -const getSample = /*@__PURE__*/ Fn( ( { envMap, mipInt, outputDirection, theta, axis, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) => { + super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - const cosTheta = cos( theta ); + this.object = object; + this.type = 'BoxHelper'; - // Rodrigues' axis-angle rotation - const sampleDirection = outputDirection.mul( cosTheta ) - .add( axis.cross( outputDirection ).mul( sin( theta ) ) ) - .add( axis.mul( axis.dot( outputDirection ).mul( cosTheta.oneMinus() ) ) ); + this.matrixAutoUpdate = false; - return bilinearCubeUV( envMap, sampleDirection, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ); + this.update(); -} ); + } -const blur = /*@__PURE__*/ Fn( ( { n, latitudinal, poleAxis, outputDirection, weights, samples, dTheta, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) => { + update( object ) { - const axis = vec3( select( latitudinal, poleAxis, cross( poleAxis, outputDirection ) ) ).toVar(); + if ( object !== undefined ) { - If( all( axis.equals( vec3( 0.0 ) ) ), () => { + console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); - axis.assign( vec3( outputDirection.z, 0.0, outputDirection.x.negate() ) ); + } - } ); + if ( this.object !== undefined ) { - axis.assign( normalize( axis ) ); + _box.setFromObject( this.object ); - const gl_FragColor = vec3().toVar(); - gl_FragColor.addAssign( weights.element( int( 0 ) ).mul( getSample( { theta: 0.0, axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) ) ); + } - Loop( { start: int( 1 ), end: n }, ( { i } ) => { + if ( _box.isEmpty() ) return; - If( i.greaterThanEqual( samples ), () => { + const min = _box.min; + const max = _box.max; - Break(); + /* + 5____4 + 1/___0/| + | 6__|_7 + 2/___3/ - } ); + 0: max.x, max.y, max.z + 1: min.x, max.y, max.z + 2: min.x, min.y, max.z + 3: max.x, min.y, max.z + 4: max.x, max.y, min.z + 5: min.x, max.y, min.z + 6: min.x, min.y, min.z + 7: max.x, min.y, min.z + */ - const theta = float( dTheta.mul( float( i ) ) ).toVar(); - gl_FragColor.addAssign( weights.element( i ).mul( getSample( { theta: theta.mul( - 1.0 ), axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) ) ); - gl_FragColor.addAssign( weights.element( i ).mul( getSample( { theta, axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) ) ); + const position = this.geometry.attributes.position; + const array = position.array; - } ); + array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; + array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; + array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; + array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; + array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; + array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; + array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; + array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; - return vec4( gl_FragColor, 1 ); + position.needsUpdate = true; -} ); + this.geometry.computeBoundingSphere(); -let _generator = null; + } -const _cache = new WeakMap(); + setFromObject( object ) { -function _generateCubeUVSize( imageHeight ) { + this.object = object; + this.update(); - const maxMip = Math.log2( imageHeight ) - 2; + return this; - const texelHeight = 1.0 / imageHeight; + } - const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) ); + copy( source, recursive ) { - return { texelWidth, texelHeight, maxMip }; + super.copy( source, recursive ); -} + this.object = source.object; -function _getPMREMFromTexture( texture ) { + return this; - let cacheTexture = _cache.get( texture ); + } - const pmremVersion = cacheTexture !== undefined ? cacheTexture.pmremVersion : - 1; + dispose() { - if ( pmremVersion !== texture.pmremVersion ) { + this.geometry.dispose(); + this.material.dispose(); - const image = texture.image; + } - if ( texture.isCubeTexture ) { +} - if ( isCubeMapReady( image ) ) { +class Box3Helper extends LineSegments { - cacheTexture = _generator.fromCubemap( texture, cacheTexture ); + constructor( box, color = 0xffff00 ) { - } else { + const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); - return null; + const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ]; - } + const geometry = new BufferGeometry(); + geometry.setIndex( new BufferAttribute( indices, 1 ) ); - } else { + geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - if ( isEquirectangularMapReady( image ) ) { + super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - cacheTexture = _generator.fromEquirectangular( texture, cacheTexture ); + this.box = box; - } else { + this.type = 'Box3Helper'; - return null; + this.geometry.computeBoundingSphere(); - } + } - } + updateMatrixWorld( force ) { - cacheTexture.pmremVersion = texture.pmremVersion; + const box = this.box; - _cache.set( texture, cacheTexture ); + if ( box.isEmpty() ) return; + + box.getCenter( this.position ); + + box.getSize( this.scale ); + + this.scale.multiplyScalar( 0.5 ); + + super.updateMatrixWorld( force ); } - return cacheTexture.texture; + dispose() { -} + this.geometry.dispose(); + this.material.dispose(); -class PMREMNode extends TempNode { + } - constructor( value, uvNode = null, levelNode = null ) { +} - super( 'vec3' ); +class PlaneHelper extends Line { - this._value = value; - this._pmrem = null; + constructor( plane, size = 1, hex = 0xffff00 ) { - this.uvNode = uvNode; - this.levelNode = levelNode; + const color = hex; - this._generator = null; + const positions = [ 1, - 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, - 1, 0, 1, 1, 0 ]; - const defaultTexture = new Texture(); - defaultTexture.isRenderTargetTexture = true; + const geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + geometry.computeBoundingSphere(); - this._texture = texture( defaultTexture ); + super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - this._width = uniform( 0 ); - this._height = uniform( 0 ); - this._maxMip = uniform( 0 ); + this.type = 'PlaneHelper'; - this.updateBeforeType = NodeUpdateType.RENDER; + this.plane = plane; - } + this.size = size; - set value( value ) { + const positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ]; - this._value = value; - this._pmrem = null; + const geometry2 = new BufferGeometry(); + geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); + geometry2.computeBoundingSphere(); + + this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) ); } - get value() { + updateMatrixWorld( force ) { - return this._value; + this.position.set( 0, 0, 0 ); - } + this.scale.set( 0.5 * this.size, 0.5 * this.size, 1 ); - updateFromTexture( texture ) { + this.lookAt( this.plane.normal ); - const cubeUVSize = _generateCubeUVSize( texture.image.height ); + this.translateZ( - this.plane.constant ); - this._texture.value = texture; - this._width.value = cubeUVSize.texelWidth; - this._height.value = cubeUVSize.texelHeight; - this._maxMip.value = cubeUVSize.maxMip; + super.updateMatrixWorld( force ); } - updateBefore() { + dispose() { - let pmrem = this._pmrem; + this.geometry.dispose(); + this.material.dispose(); + this.children[ 0 ].geometry.dispose(); + this.children[ 0 ].material.dispose(); - const pmremVersion = pmrem ? pmrem.pmremVersion : - 1; - const texture = this._value; + } - if ( pmremVersion !== texture.pmremVersion ) { +} - if ( texture.isPMREMTexture === true ) { +const _axis = /*@__PURE__*/ new Vector3(); +let _lineGeometry, _coneGeometry; - pmrem = texture; +class ArrowHelper extends Object3D { - } else { + // dir is assumed to be normalized - pmrem = _getPMREMFromTexture( texture ); + constructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) { - } + super(); - if ( pmrem !== null ) { + this.type = 'ArrowHelper'; - this._pmrem = pmrem; + if ( _lineGeometry === undefined ) { - this.updateFromTexture( pmrem ); + _lineGeometry = new BufferGeometry(); + _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); - } + _coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 ); + _coneGeometry.translate( 0, - 0.5, 0 ); } - } - - setup( builder ) { + this.position.copy( origin ); - if ( _generator === null ) { + this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + this.line.matrixAutoUpdate = false; + this.add( this.line ); - _generator = builder.createPMREMGenerator(); + this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) ); + this.cone.matrixAutoUpdate = false; + this.add( this.cone ); - } + this.setDirection( dir ); + this.setLength( length, headLength, headWidth ); - // + } - this.updateBefore( builder ); + setDirection( dir ) { - // + // dir is assumed to be normalized - let uvNode = this.uvNode; + if ( dir.y > 0.99999 ) { - if ( uvNode === null && builder.context.getUV ) { + this.quaternion.set( 0, 0, 0, 1 ); - uvNode = builder.context.getUV( this ); + } else if ( dir.y < - 0.99999 ) { - } + this.quaternion.set( 1, 0, 0, 0 ); - // + } else { - const texture = this.value; + _axis.set( dir.z, 0, - dir.x ).normalize(); - if ( builder.renderer.coordinateSystem === WebGLCoordinateSystem && texture.isPMREMTexture !== true && texture.isRenderTargetTexture === true ) { + const radians = Math.acos( dir.y ); - uvNode = vec3( uvNode.x.negate(), uvNode.yz ); + this.quaternion.setFromAxisAngle( _axis, radians ); } - // + } - let levelNode = this.levelNode; + setLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) { - if ( levelNode === null && builder.context.getTextureLevel ) { + this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458 + this.line.updateMatrix(); - levelNode = builder.context.getTextureLevel( this ); + this.cone.scale.set( headWidth, headLength, headWidth ); + this.cone.position.y = length; + this.cone.updateMatrix(); - } + } - // + setColor( color ) { - return textureCubeUV( this._texture, uvNode, levelNode, this._width, this._height, this._maxMip ); + this.line.material.color.set( color ); + this.cone.material.color.set( color ); } -} + copy( source ) { -PMREMNode.type = /*@__PURE__*/ registerNode( 'PMREM', PMREMNode ); + super.copy( source, false ); -function isCubeMapReady( image ) { + this.line.copy( source.line ); + this.cone.copy( source.cone ); - if ( image === null || image === undefined ) return false; + return this; - let count = 0; - const length = 6; + } - for ( let i = 0; i < length; i ++ ) { + dispose() { - if ( image[ i ] !== undefined ) count ++; + this.line.geometry.dispose(); + this.line.material.dispose(); + this.cone.geometry.dispose(); + this.cone.material.dispose(); } - return count === length; - - } -function isEquirectangularMapReady( image ) { +class AxesHelper extends LineSegments { - if ( image === null || image === undefined ) return false; + constructor( size = 1 ) { - return image.height > 0; + const vertices = [ + 0, 0, 0, size, 0, 0, + 0, 0, 0, 0, size, 0, + 0, 0, 0, 0, 0, size + ]; -} + const colors = [ + 1, 0, 0, 1, 0.6, 0, + 0, 1, 0, 0.6, 1, 0, + 0, 0, 1, 0, 0.6, 1 + ]; -const pmremTexture = /*@__PURE__*/ nodeProxy( PMREMNode ); + const geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); -const _envNodeCache = new WeakMap(); + const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); -class EnvironmentNode extends LightingNode { + super( geometry, material ); - constructor( envNode = null ) { + this.type = 'AxesHelper'; - super(); + } - this.envNode = envNode; + setColors( xAxisColor, yAxisColor, zAxisColor ) { - } + const color = new Color(); + const array = this.geometry.attributes.color.array; - setup( builder ) { + color.set( xAxisColor ); + color.toArray( array, 0 ); + color.toArray( array, 3 ); - const { material } = builder; + color.set( yAxisColor ); + color.toArray( array, 6 ); + color.toArray( array, 9 ); - let envNode = this.envNode; + color.set( zAxisColor ); + color.toArray( array, 12 ); + color.toArray( array, 15 ); - if ( envNode.isTextureNode || envNode.isMaterialReferenceNode ) { + this.geometry.attributes.color.needsUpdate = true; - const value = ( envNode.isTextureNode ) ? envNode.value : material[ envNode.property ]; + return this; - let cacheEnvNode = _envNodeCache.get( value ); + } - if ( cacheEnvNode === undefined ) { + dispose() { - cacheEnvNode = pmremTexture( value ); + this.geometry.dispose(); + this.material.dispose(); - _envNodeCache.set( value, cacheEnvNode ); + } - } +} - envNode = cacheEnvNode; +class ShapePath { - } + constructor() { - // + this.type = 'ShapePath'; - const envMap = material.envMap; - const intensity = envMap ? reference( 'envMapIntensity', 'float', builder.material ) : reference( 'environmentIntensity', 'float', builder.scene ); // @TODO: Add materialEnvIntensity in MaterialNode + this.color = new Color(); - const useAnisotropy = material.useAnisotropy === true || material.anisotropy > 0; - const radianceNormalView = useAnisotropy ? transformedBentNormalView : transformedNormalView; + this.subPaths = []; + this.currentPath = null; - const radiance = envNode.context( createRadianceContext( roughness, radianceNormalView ) ).mul( intensity ); - const irradiance = envNode.context( createIrradianceContext( transformedNormalWorld ) ).mul( Math.PI ).mul( intensity ); + } - const isolateRadiance = cache( radiance ); - const isolateIrradiance = cache( irradiance ); + moveTo( x, y ) { - // + this.currentPath = new Path(); + this.subPaths.push( this.currentPath ); + this.currentPath.moveTo( x, y ); - builder.context.radiance.addAssign( isolateRadiance ); + return this; - builder.context.iblIrradiance.addAssign( isolateIrradiance ); + } - // + lineTo( x, y ) { - const clearcoatRadiance = builder.context.lightingModel.clearcoatRadiance; + this.currentPath.lineTo( x, y ); - if ( clearcoatRadiance ) { + return this; - const clearcoatRadianceContext = envNode.context( createRadianceContext( clearcoatRoughness, transformedClearcoatNormalView ) ).mul( intensity ); - const isolateClearcoatRadiance = cache( clearcoatRadianceContext ); + } - clearcoatRadiance.addAssign( isolateClearcoatRadiance ); + quadraticCurveTo( aCPx, aCPy, aX, aY ) { - } + this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); + + return this; } -} + bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { -EnvironmentNode.type = /*@__PURE__*/ registerNode( 'Environment', EnvironmentNode ); + this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); -const createRadianceContext = ( roughnessNode, normalViewNode ) => { + return this; - let reflectVec = null; + } - return { - getUV: () => { + splineThru( pts ) { - if ( reflectVec === null ) { + this.currentPath.splineThru( pts ); - reflectVec = positionViewDirection.negate().reflect( normalViewNode ); + return this; - // Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane. - reflectVec = roughnessNode.mul( roughnessNode ).mix( reflectVec, normalViewNode ).normalize(); + } - reflectVec = reflectVec.transformDirection( cameraViewMatrix ); + toShapes( isCCW ) { - } + function toShapesNoHoles( inSubpaths ) { - return reflectVec; + const shapes = []; - }, - getTextureLevel: () => { + for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) { - return roughnessNode; + const tmpPath = inSubpaths[ i ]; - } - }; + const tmpShape = new Shape(); + tmpShape.curves = tmpPath.curves; -}; + shapes.push( tmpShape ); -const createIrradianceContext = ( normalWorldNode ) => { + } - return { - getUV: () => { + return shapes; - return normalWorldNode; + } - }, - getTextureLevel: () => { + function isPointInsidePolygon( inPt, inPolygon ) { - return float( 1.0 ); + const polyLen = inPolygon.length; - } - }; + // inPt on polygon contour => immediate success or + // toggling of inside/outside at every single! intersection point of an edge + // with the horizontal line through inPt, left of inPt + // not counting lowerY endpoints of edges and whole edges on that line + let inside = false; + for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { -}; + let edgeLowPt = inPolygon[ p ]; + let edgeHighPt = inPolygon[ q ]; -const _defaultValues$6 = /*@__PURE__*/ new MeshStandardMaterial(); + let edgeDx = edgeHighPt.x - edgeLowPt.x; + let edgeDy = edgeHighPt.y - edgeLowPt.y; -class MeshStandardNodeMaterial extends NodeMaterial { + if ( Math.abs( edgeDy ) > Number.EPSILON ) { - constructor( parameters ) { + // not parallel + if ( edgeDy < 0 ) { - super(); + edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; + edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; - this.isMeshStandardNodeMaterial = true; + } - this.lights = true; + if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; - this.emissiveNode = null; + if ( inPt.y === edgeLowPt.y ) { - this.metalnessNode = null; - this.roughnessNode = null; + if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? + // continue; // no intersection or edgeLowPt => doesn't count !!! - this.setDefaultValues( _defaultValues$6 ); + } else { - this.setValues( parameters ); + const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); + if ( perpEdge === 0 ) return true; // inPt is on contour ? + if ( perpEdge < 0 ) continue; + inside = ! inside; // true intersection left of inPt - } + } - setupEnvironment( builder ) { + } else { - let envNode = super.setupEnvironment( builder ); + // parallel or collinear + if ( inPt.y !== edgeLowPt.y ) continue; // parallel + // edge lies on the same horizontal line as inPt + if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || + ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! + // continue; - if ( envNode === null && builder.environmentNode ) { + } - envNode = builder.environmentNode; + } + + return inside; } - return envNode ? new EnvironmentNode( envNode ) : null; + const isClockWise = ShapeUtils.isClockWise; - } + const subPaths = this.subPaths; + if ( subPaths.length === 0 ) return []; - setupLightingModel( /*builder*/ ) { + let solid, tmpPath, tmpShape; + const shapes = []; - return new PhysicalLightingModel(); + if ( subPaths.length === 1 ) { - } + tmpPath = subPaths[ 0 ]; + tmpShape = new Shape(); + tmpShape.curves = tmpPath.curves; + shapes.push( tmpShape ); + return shapes; - setupSpecular() { + } - const specularColorNode = mix( vec3( 0.04 ), diffuseColor.rgb, metalness ); + let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); + holesFirst = isCCW ? ! holesFirst : holesFirst; - specularColor.assign( specularColorNode ); - specularF90.assign( 1.0 ); + // console.log("Holes first", holesFirst); - } + const betterShapeHoles = []; + const newShapes = []; + let newShapeHoles = []; + let mainIdx = 0; + let tmpPoints; - setupVariants() { + newShapes[ mainIdx ] = undefined; + newShapeHoles[ mainIdx ] = []; - // METALNESS + for ( let i = 0, l = subPaths.length; i < l; i ++ ) { - const metalnessNode = this.metalnessNode ? float( this.metalnessNode ) : materialMetalness; + tmpPath = subPaths[ i ]; + tmpPoints = tmpPath.getPoints(); + solid = isClockWise( tmpPoints ); + solid = isCCW ? ! solid : solid; - metalness.assign( metalnessNode ); + if ( solid ) { - // ROUGHNESS + if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; - let roughnessNode = this.roughnessNode ? float( this.roughnessNode ) : materialRoughness; - roughnessNode = getRoughness( { roughness: roughnessNode } ); + newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; + newShapes[ mainIdx ].s.curves = tmpPath.curves; - roughness.assign( roughnessNode ); + if ( holesFirst ) mainIdx ++; + newShapeHoles[ mainIdx ] = []; - // SPECULAR COLOR + //console.log('cw', i); - this.setupSpecular(); + } else { - // DIFFUSE COLOR + newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); - diffuseColor.assign( vec4( diffuseColor.rgb.mul( metalnessNode.oneMinus() ), diffuseColor.a ) ); + //console.log('ccw', i); - } + } - copy( source ) { + } - this.emissiveNode = source.emissiveNode; + // only Holes? -> probably all Shapes with wrong orientation + if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); - this.metalnessNode = source.metalnessNode; - this.roughnessNode = source.roughnessNode; - return super.copy( source ); + if ( newShapes.length > 1 ) { - } + let ambiguous = false; + let toChange = 0; -} + for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { -MeshStandardNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'MeshStandard', MeshStandardNodeMaterial ); + betterShapeHoles[ sIdx ] = []; -const _defaultValues$5 = /*@__PURE__*/ new MeshPhysicalMaterial(); + } -class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { + for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - constructor( parameters ) { + const sho = newShapeHoles[ sIdx ]; - super(); + for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) { - this.isMeshPhysicalNodeMaterial = true; + const ho = sho[ hIdx ]; + let hole_unassigned = true; - this.clearcoatNode = null; - this.clearcoatRoughnessNode = null; - this.clearcoatNormalNode = null; + for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { - this.sheenNode = null; - this.sheenRoughnessNode = null; + if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { - this.iridescenceNode = null; - this.iridescenceIORNode = null; - this.iridescenceThicknessNode = null; + if ( sIdx !== s2Idx ) toChange ++; - this.specularIntensityNode = null; - this.specularColorNode = null; + if ( hole_unassigned ) { - this.iorNode = null; - this.transmissionNode = null; - this.thicknessNode = null; - this.attenuationDistanceNode = null; - this.attenuationColorNode = null; - this.dispersionNode = null; + hole_unassigned = false; + betterShapeHoles[ s2Idx ].push( ho ); - this.anisotropyNode = null; + } else { - this.setDefaultValues( _defaultValues$5 ); + ambiguous = true; - this.setValues( parameters ); + } - } + } - get useClearcoat() { + } - return this.clearcoat > 0 || this.clearcoatNode !== null; + if ( hole_unassigned ) { - } + betterShapeHoles[ sIdx ].push( ho ); - get useIridescence() { + } - return this.iridescence > 0 || this.iridescenceNode !== null; + } - } + } - get useSheen() { + if ( toChange > 0 && ambiguous === false ) { - return this.sheen > 0 || this.sheenNode !== null; + newShapeHoles = betterShapeHoles; - } + } - get useAnisotropy() { + } - return this.anisotropy > 0 || this.anisotropyNode !== null; + let tmpHoles; - } + for ( let i = 0, il = newShapes.length; i < il; i ++ ) { - get useTransmission() { + tmpShape = newShapes[ i ].s; + shapes.push( tmpShape ); + tmpHoles = newShapeHoles[ i ]; - return this.transmission > 0 || this.transmissionNode !== null; + for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) { - } + tmpShape.holes.push( tmpHoles[ j ].h ); - get useDispersion() { + } - return this.dispersion > 0 || this.dispersionNode !== null; + } - } + //console.log("shape", shapes); - setupSpecular() { + return shapes; - const iorNode = this.iorNode ? float( this.iorNode ) : materialIOR; + } - ior.assign( iorNode ); - specularColor.assign( mix( min$1( pow2( ior.sub( 1.0 ).div( ior.add( 1.0 ) ) ).mul( materialSpecularColor ), vec3( 1.0 ) ).mul( materialSpecularIntensity ), diffuseColor.rgb, metalness ) ); - specularF90.assign( mix( materialSpecularIntensity, 1.0, metalness ) ); +} - } +class Controls extends EventDispatcher { - setupLightingModel( /*builder*/ ) { + constructor( object, domElement = null ) { - return new PhysicalLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion ); + super(); - } + this.object = object; + this.domElement = domElement; - setupVariants( builder ) { + this.enabled = true; - super.setupVariants( builder ); + this.state = - 1; - // CLEARCOAT + this.keys = {}; + this.mouseButtons = { LEFT: null, MIDDLE: null, RIGHT: null }; + this.touches = { ONE: null, TWO: null }; - if ( this.useClearcoat ) { + } - const clearcoatNode = this.clearcoatNode ? float( this.clearcoatNode ) : materialClearcoat; - const clearcoatRoughnessNode = this.clearcoatRoughnessNode ? float( this.clearcoatRoughnessNode ) : materialClearcoatRoughness; + connect() {} - clearcoat.assign( clearcoatNode ); - clearcoatRoughness.assign( getRoughness( { roughness: clearcoatRoughnessNode } ) ); + disconnect() {} - } + dispose() {} - // SHEEN + update( /* delta */ ) {} - if ( this.useSheen ) { +} - const sheenNode = this.sheenNode ? vec3( this.sheenNode ) : materialSheen; - const sheenRoughnessNode = this.sheenRoughnessNode ? float( this.sheenRoughnessNode ) : materialSheenRoughness; +class WebGLMultipleRenderTargets extends WebGLRenderTarget { // @deprecated, r162 - sheen.assign( sheenNode ); - sheenRoughness.assign( sheenRoughnessNode ); + constructor( width = 1, height = 1, count = 1, options = {} ) { - } + console.warn( 'THREE.WebGLMultipleRenderTargets has been deprecated and will be removed in r172. Use THREE.WebGLRenderTarget and set the "count" parameter to enable MRT.' ); - // IRIDESCENCE + super( width, height, { ...options, count } ); - if ( this.useIridescence ) { + this.isWebGLMultipleRenderTargets = true; - const iridescenceNode = this.iridescenceNode ? float( this.iridescenceNode ) : materialIridescence; - const iridescenceIORNode = this.iridescenceIORNode ? float( this.iridescenceIORNode ) : materialIridescenceIOR; - const iridescenceThicknessNode = this.iridescenceThicknessNode ? float( this.iridescenceThicknessNode ) : materialIridescenceThickness; + } - iridescence.assign( iridescenceNode ); - iridescenceIOR.assign( iridescenceIORNode ); - iridescenceThickness.assign( iridescenceThicknessNode ); + get texture() { - } + return this.textures; - // ANISOTROPY + } - if ( this.useAnisotropy ) { +} - const anisotropyV = ( this.anisotropyNode ? vec2( this.anisotropyNode ) : materialAnisotropy ).toVar(); +const refreshUniforms = [ + 'alphaMap', + 'alphaTest', + 'anisotropy', + 'anisotropyMap', + 'anisotropyRotation', + 'aoMap', + 'attenuationColor', + 'attenuationDistance', + 'bumpMap', + 'clearcoat', + 'clearcoatMap', + 'clearcoatNormalMap', + 'clearcoatNormalScale', + 'clearcoatRoughness', + 'color', + 'dispersion', + 'displacementMap', + 'emissive', + 'emissiveMap', + 'envMap', + 'gradientMap', + 'ior', + 'iridescence', + 'iridescenceIOR', + 'iridescenceMap', + 'iridescenceThicknessMap', + 'lightMap', + 'map', + 'matcap', + 'metalness', + 'metalnessMap', + 'normalMap', + 'normalScale', + 'opacity', + 'roughness', + 'roughnessMap', + 'sheen', + 'sheenColor', + 'sheenColorMap', + 'sheenRoughnessMap', + 'shininess', + 'specular', + 'specularColor', + 'specularColorMap', + 'specularIntensity', + 'specularIntensityMap', + 'specularMap', + 'thickness', + 'transmission', + 'transmissionMap' +]; - anisotropy.assign( anisotropyV.length() ); +class NodeMaterialObserver { - If( anisotropy.equal( 0.0 ), () => { + constructor( builder ) { - anisotropyV.assign( vec2( 1.0, 0.0 ) ); + this.renderObjects = new WeakMap(); + this.hasNode = this.containsNode( builder ); + this.hasAnimation = builder.object.isSkinnedMesh === true; + this.refreshUniforms = refreshUniforms; + this.renderId = 0; - } ).Else( () => { + } - anisotropyV.divAssign( vec2( anisotropy ) ); - anisotropy.assign( anisotropy.saturate() ); + firstInitialization( renderObject ) { - } ); + const hasInitialized = this.renderObjects.has( renderObject ); - // Roughness along the anisotropy bitangent is the material roughness, while the tangent roughness increases with anisotropy. - alphaT.assign( anisotropy.pow2().mix( roughness.pow2(), 1.0 ) ); + if ( hasInitialized === false ) { - anisotropyT.assign( TBNViewMatrix[ 0 ].mul( anisotropyV.x ).add( TBNViewMatrix[ 1 ].mul( anisotropyV.y ) ) ); - anisotropyB.assign( TBNViewMatrix[ 1 ].mul( anisotropyV.x ).sub( TBNViewMatrix[ 0 ].mul( anisotropyV.y ) ) ); + this.getRenderObjectData( renderObject ); + + return true; } - // TRANSMISSION + return false; - if ( this.useTransmission ) { + } - const transmissionNode = this.transmissionNode ? float( this.transmissionNode ) : materialTransmission; - const thicknessNode = this.thicknessNode ? float( this.thicknessNode ) : materialThickness; - const attenuationDistanceNode = this.attenuationDistanceNode ? float( this.attenuationDistanceNode ) : materialAttenuationDistance; - const attenuationColorNode = this.attenuationColorNode ? vec3( this.attenuationColorNode ) : materialAttenuationColor; + getRenderObjectData( renderObject ) { - transmission.assign( transmissionNode ); - thickness.assign( thicknessNode ); - attenuationDistance.assign( attenuationDistanceNode ); - attenuationColor.assign( attenuationColorNode ); + let data = this.renderObjects.get( renderObject ); - if ( this.useDispersion ) { + if ( data === undefined ) { - const dispersionNode = this.dispersionNode ? float( this.dispersionNode ) : materialDispersion; + data = { + material: this.getMaterialData( renderObject.material ), + worldMatrix: renderObject.object.matrixWorld.clone() + }; - dispersion.assign( dispersionNode ); + if ( renderObject.object.center ) { + + data.center = renderObject.object.center.clone(); } - } + if ( renderObject.object.morphTargetInfluences ) { - } + data.morphTargetInfluences = renderObject.object.morphTargetInfluences.slice(); - setupClearcoatNormal() { + } - return this.clearcoatNormalNode ? vec3( this.clearcoatNormalNode ) : materialClearcoatNormal; + if ( renderObject.bundle !== null ) { - } + data.version = renderObject.bundle.version; - setup( builder ) { + } - builder.context.setupClearcoatNormal = () => this.setupClearcoatNormal( builder ); + this.renderObjects.set( renderObject, data ); - super.setup( builder ); + } - } + return data; - copy( source ) { + } - this.clearcoatNode = source.clearcoatNode; - this.clearcoatRoughnessNode = source.clearcoatRoughnessNode; - this.clearcoatNormalNode = source.clearcoatNormalNode; + containsNode( builder ) { - this.sheenNode = source.sheenNode; - this.sheenRoughnessNode = source.sheenRoughnessNode; + const material = builder.material; - this.iridescenceNode = source.iridescenceNode; - this.iridescenceIORNode = source.iridescenceIORNode; - this.iridescenceThicknessNode = source.iridescenceThicknessNode; + for ( const property in material ) { - this.specularIntensityNode = source.specularIntensityNode; - this.specularColorNode = source.specularColorNode; + if ( material[ property ] && material[ property ].isNode ) + return true; - this.transmissionNode = source.transmissionNode; - this.thicknessNode = source.thicknessNode; - this.attenuationDistanceNode = source.attenuationDistanceNode; - this.attenuationColorNode = source.attenuationColorNode; - this.dispersionNode = source.dispersionNode; + } - this.anisotropyNode = source.anisotropyNode; + if ( builder.renderer.nodes.modelViewMatrix !== null || builder.renderer.nodes.modelNormalViewMatrix !== null ) + return true; - return super.copy( source ); + return false; } -} + getMaterialData( material ) { -MeshPhysicalNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'MeshPhysical', MeshPhysicalNodeMaterial ); + const data = {}; -class SSSLightingModel extends PhysicalLightingModel { + for ( const property of this.refreshUniforms ) { - constructor( useClearcoat, useSheen, useIridescence, useSSS ) { + const value = material[ property ]; - super( useClearcoat, useSheen, useIridescence ); + if ( value === null || value === undefined ) continue; - this.useSSS = useSSS; + if ( typeof value === 'object' && value.clone !== undefined ) { - } + if ( value.isTexture === true ) { - direct( { lightDirection, lightColor, reflectedLight }, stack, builder ) { + data[ property ] = { id: value.id, version: value.version }; - if ( this.useSSS === true ) { + } else { - const material = builder.material; + data[ property ] = value.clone(); - const { thicknessColorNode, thicknessDistortionNode, thicknessAmbientNode, thicknessAttenuationNode, thicknessPowerNode, thicknessScaleNode } = material; + } - const scatteringHalf = lightDirection.add( transformedNormalView.mul( thicknessDistortionNode ) ).normalize(); - const scatteringDot = float( positionViewDirection.dot( scatteringHalf.negate() ).saturate().pow( thicknessPowerNode ).mul( thicknessScaleNode ) ); - const scatteringIllu = vec3( scatteringDot.add( thicknessAmbientNode ).mul( thicknessColorNode ) ); + } else { - reflectedLight.directDiffuse.addAssign( scatteringIllu.mul( thicknessAttenuationNode.mul( lightColor ) ) ); + data[ property ] = value; + + } } - super.direct( { lightDirection, lightColor, reflectedLight }, stack, builder ); + return data; } -} + equals( renderObject ) { -class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial { + const { object, material } = renderObject; - constructor( parameters ) { + const renderObjectData = this.getRenderObjectData( renderObject ); - super( parameters ); + // world matrix - this.thicknessColorNode = null; - this.thicknessDistortionNode = float( 0.1 ); - this.thicknessAmbientNode = float( 0.0 ); - this.thicknessAttenuationNode = float( .1 ); - this.thicknessPowerNode = float( 2.0 ); - this.thicknessScaleNode = float( 10.0 ); + if ( renderObjectData.worldMatrix.equals( object.matrixWorld ) !== true ) { - } + renderObjectData.worldMatrix.copy( object.matrixWorld ); - get useSSS() { + return false; - return this.thicknessColorNode !== null; + } - } + // material - setupLightingModel( /*builder*/ ) { + const materialData = renderObjectData.material; - return new SSSLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useSSS ); + for ( const property in materialData ) { - } + const value = materialData[ property ]; + const mtlValue = material[ property ]; - copy( source ) { + if ( value.equals !== undefined ) { - this.thicknessColorNode = source.thicknessColorNode; - this.thicknessDistortionNode = source.thicknessDistortionNode; - this.thicknessAmbientNode = source.thicknessAmbientNode; - this.thicknessAttenuationNode = source.thicknessAttenuationNode; - this.thicknessPowerNode = source.thicknessPowerNode; - this.thicknessScaleNode = source.thicknessScaleNode; + if ( value.equals( mtlValue ) === false ) { - return super.copy( source ); + value.copy( mtlValue ); - } + return false; -} + } -MeshSSSNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'MeshSSS', MeshSSSNodeMaterial ); + } else if ( mtlValue.isTexture === true ) { -const getGradientIrradiance = /*@__PURE__*/ Fn( ( { normal, lightDirection, builder } ) => { + if ( value.id !== mtlValue.id || value.version !== mtlValue.version ) { - // dotNL will be from -1.0 to 1.0 - const dotNL = normal.dot( lightDirection ); - const coord = vec2( dotNL.mul( 0.5 ).add( 0.5 ), 0.0 ); + value.id = mtlValue.id; + value.version = mtlValue.version; - if ( builder.material.gradientMap ) { + return false; - const gradientMap = materialReference( 'gradientMap', 'texture' ).context( { getUV: () => coord } ); + } - return vec3( gradientMap.r ); + } else if ( value !== mtlValue ) { - } else { + materialData[ property ] = mtlValue; - const fw = coord.fwidth().mul( 0.5 ); + return false; - return mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( float( 0.7 ).sub( fw.x ), float( 0.7 ).add( fw.x ), coord.x ) ); + } - } + } -} ); + // morph targets -class ToonLightingModel extends LightingModel { + if ( renderObjectData.morphTargetInfluences ) { - direct( { lightDirection, lightColor, reflectedLight }, stack, builder ) { + let morphChanged = false; - const irradiance = getGradientIrradiance( { normal: normalGeometry, lightDirection, builder } ).mul( lightColor ); + for ( let i = 0; i < renderObjectData.morphTargetInfluences.length; i ++ ) { - reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) ); + if ( renderObjectData.morphTargetInfluences[ i ] !== object.morphTargetInfluences[ i ] ) { - } + morphChanged = true; - indirect( { ambientOcclusion, irradiance, reflectedLight } ) { + } - reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) ); + } - reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion ); + if ( morphChanged ) return true; - } + } -} + // center -const _defaultValues$4 = /*@__PURE__*/ new MeshToonMaterial(); + if ( renderObjectData.center ) { -class MeshToonNodeMaterial extends NodeMaterial { + if ( renderObjectData.center.equals( object.center ) === false ) { - constructor( parameters ) { + renderObjectData.center.copy( object.center ); - super(); + return true; - this.isMeshToonNodeMaterial = true; + } - this.lights = true; + } - this.setDefaultValues( _defaultValues$4 ); + // bundle - this.setValues( parameters ); + if ( renderObject.bundle !== null ) { - } + renderObjectData.version = renderObject.bundle.version; - setupLightingModel( /*builder*/ ) { + } - return new ToonLightingModel(); + return true; } -} + needsRefresh( renderObject, nodeFrame ) { -MeshToonNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'MeshToon', MeshToonNodeMaterial ); + if ( this.hasNode || this.hasAnimation || this.firstInitialization( renderObject ) ) + return true; -class MatcapUVNode extends TempNode { + const { renderId } = nodeFrame; - constructor() { + if ( this.renderId !== renderId ) { - super( 'vec2' ); + this.renderId = renderId; - } + return true; - setup() { + } - const x = vec3( positionViewDirection.z, 0, positionViewDirection.x.negate() ).normalize(); - const y = positionViewDirection.cross( x ); + const isStatic = renderObject.object.static === true; + const isBundle = renderObject.bundle !== null && renderObject.bundle.static === true && this.getRenderObjectData( renderObject ).version === renderObject.bundle.version; - return vec2( x.dot( transformedNormalView ), y.dot( transformedNormalView ) ).mul( 0.495 ).add( 0.5 ); // 0.495 to remove artifacts caused by undersized matcap disks + if ( isStatic || isBundle ) + return false; + + const notEqual = this.equals( renderObject ) !== true; + + return notEqual; } } -MatcapUVNode.type = /*@__PURE__*/ registerNode( 'MatcapUV', MatcapUVNode ); +// cyrb53 (c) 2018 bryc (github.com/bryc). License: Public domain. Attribution appreciated. +// A fast and simple 64-bit (or 53-bit) string hash function with decent collision resistance. +// Largely inspired by MurmurHash2/3, but with a focus on speed/simplicity. +// See https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript/52171480#52171480 +// https://github.com/bryc/code/blob/master/jshash/experimental/cyrb53.js +function cyrb53( value, seed = 0 ) { -const matcapUV = /*@__PURE__*/ nodeImmutable( MatcapUVNode ); + let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; -const _defaultValues$3 = /*@__PURE__*/ new MeshMatcapMaterial(); + if ( value instanceof Array ) { -class MeshMatcapNodeMaterial extends NodeMaterial { + for ( let i = 0, val; i < value.length; i ++ ) { - constructor( parameters ) { + val = value[ i ]; + h1 = Math.imul( h1 ^ val, 2654435761 ); + h2 = Math.imul( h2 ^ val, 1597334677 ); - super(); + } - this.lights = false; + } else { - this.isMeshMatcapNodeMaterial = true; + for ( let i = 0, ch; i < value.length; i ++ ) { - this.setDefaultValues( _defaultValues$3 ); + ch = value.charCodeAt( i ); + h1 = Math.imul( h1 ^ ch, 2654435761 ); + h2 = Math.imul( h2 ^ ch, 1597334677 ); - this.setValues( parameters ); + } } - setupVariants( builder ) { - - const uv = matcapUV; + h1 = Math.imul( h1 ^ ( h1 >>> 16 ), 2246822507 ); + h1 ^= Math.imul( h2 ^ ( h2 >>> 13 ), 3266489909 ); + h2 = Math.imul( h2 ^ ( h2 >>> 16 ), 2246822507 ); + h2 ^= Math.imul( h1 ^ ( h1 >>> 13 ), 3266489909 ); - let matcapColor; + return 4294967296 * ( 2097151 & h2 ) + ( h1 >>> 0 ); - if ( builder.material.matcap ) { +} - matcapColor = materialReference( 'matcap', 'texture' ).context( { getUV: () => uv } ); +const hashString = ( str ) => cyrb53( str ); +const hashArray = ( array ) => cyrb53( array ); +const hash$1 = ( ...params ) => cyrb53( params ); - } else { +function getCacheKey$1( object, force = false ) { - matcapColor = vec3( mix( 0.2, 0.8, uv.y ) ); // default if matcap is missing + const values = []; - } + if ( object.isNode === true ) { - diffuseColor.rgb.mulAssign( matcapColor.rgb ); + values.push( object.id ); + object = object.getSelf(); } -} + for ( const { property, childNode } of getNodeChildren( object ) ) { -MeshMatcapNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'MeshMatcap', MeshMatcapNodeMaterial ); + values.push( values, cyrb53( property.slice( 0, - 4 ) ), childNode.getCacheKey( force ) ); -const _defaultValues$2 = /*@__PURE__*/ new PointsMaterial(); + } -class PointsNodeMaterial extends NodeMaterial { + return cyrb53( values ); - constructor( parameters ) { +} - super(); +function* getNodeChildren( node, toJSON = false ) { - this.isPointsNodeMaterial = true; + for ( const property in node ) { - this.lights = false; - this.transparent = true; + // Ignore private properties. + if ( property.startsWith( '_' ) === true ) continue; - this.sizeNode = null; + const object = node[ property ]; - this.setDefaultValues( _defaultValues$2 ); + if ( Array.isArray( object ) === true ) { - this.setValues( parameters ); + for ( let i = 0; i < object.length; i ++ ) { - } + const child = object[ i ]; - copy( source ) { + if ( child && ( child.isNode === true || toJSON && typeof child.toJSON === 'function' ) ) { - this.sizeNode = source.sizeNode; + yield { property, index: i, childNode: child }; - return super.copy( source ); + } - } + } -} + } else if ( object && object.isNode === true ) { -PointsNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'Points', PointsNodeMaterial ); + yield { property, childNode: object }; -class RotateNode extends TempNode { + } else if ( typeof object === 'object' ) { - constructor( positionNode, rotationNode ) { + for ( const subProperty in object ) { - super(); + const child = object[ subProperty ]; - this.positionNode = positionNode; - this.rotationNode = rotationNode; + if ( child && ( child.isNode === true || toJSON && typeof child.toJSON === 'function' ) ) { - } + yield { property, index: subProperty, childNode: child }; - getNodeType( builder ) { + } - return this.positionNode.getNodeType( builder ); + } + + } } - setup( builder ) { +} - const { rotationNode, positionNode } = this; +function getValueType( value ) { - const nodeType = this.getNodeType( builder ); + if ( value === undefined || value === null ) return null; - if ( nodeType === 'vec2' ) { + const typeOf = typeof value; - const cosAngle = rotationNode.cos(); - const sinAngle = rotationNode.sin(); + if ( value.isNode === true ) { - const rotationMatrix = mat2( - cosAngle, sinAngle, - sinAngle.negate(), cosAngle - ); + return 'node'; - return rotationMatrix.mul( positionNode ); + } else if ( typeOf === 'number' ) { - } else { + return 'float'; - const rotation = rotationNode; - const rotationXMatrix = mat4( vec4( 1.0, 0.0, 0.0, 0.0 ), vec4( 0.0, cos( rotation.x ), sin( rotation.x ).negate(), 0.0 ), vec4( 0.0, sin( rotation.x ), cos( rotation.x ), 0.0 ), vec4( 0.0, 0.0, 0.0, 1.0 ) ); - const rotationYMatrix = mat4( vec4( cos( rotation.y ), 0.0, sin( rotation.y ), 0.0 ), vec4( 0.0, 1.0, 0.0, 0.0 ), vec4( sin( rotation.y ).negate(), 0.0, cos( rotation.y ), 0.0 ), vec4( 0.0, 0.0, 0.0, 1.0 ) ); - const rotationZMatrix = mat4( vec4( cos( rotation.z ), sin( rotation.z ).negate(), 0.0, 0.0 ), vec4( sin( rotation.z ), cos( rotation.z ), 0.0, 0.0 ), vec4( 0.0, 0.0, 1.0, 0.0 ), vec4( 0.0, 0.0, 0.0, 1.0 ) ); + } else if ( typeOf === 'boolean' ) { - return rotationXMatrix.mul( rotationYMatrix ).mul( rotationZMatrix ).mul( vec4( positionNode, 1.0 ) ).xyz; + return 'bool'; - } + } else if ( typeOf === 'string' ) { - } + return 'string'; -} + } else if ( typeOf === 'function' ) { -RotateNode.type = /*@__PURE__*/ registerNode( 'Rotate', RotateNode ); + return 'shader'; -const rotate = /*@__PURE__*/ nodeProxy( RotateNode ); + } else if ( value.isVector2 === true ) { -const _defaultValues$1 = /*@__PURE__*/ new SpriteMaterial(); + return 'vec2'; -class SpriteNodeMaterial extends NodeMaterial { + } else if ( value.isVector3 === true ) { - constructor( parameters ) { + return 'vec3'; - super(); + } else if ( value.isVector4 === true ) { - this.isSpriteNodeMaterial = true; + return 'vec4'; - this.lights = false; + } else if ( value.isMatrix3 === true ) { - this.positionNode = null; - this.rotationNode = null; - this.scaleNode = null; + return 'mat3'; - this.setDefaultValues( _defaultValues$1 ); + } else if ( value.isMatrix4 === true ) { - this.setValues( parameters ); + return 'mat4'; - } + } else if ( value.isColor === true ) { - setupPosition( { object, context } ) { + return 'color'; - // < VERTEX STAGE > + } else if ( value instanceof ArrayBuffer ) { - const { positionNode, rotationNode, scaleNode } = this; + return 'ArrayBuffer'; - const vertex = positionLocal; + } - let mvPosition = modelViewMatrix.mul( vec3( positionNode || 0 ) ); + return null; - let scale = vec2( modelWorldMatrix[ 0 ].xyz.length(), modelWorldMatrix[ 1 ].xyz.length() ); +} - if ( scaleNode !== null ) { +function getValueFromType( type, ...params ) { - scale = scale.mul( scaleNode ); + const last4 = type ? type.slice( - 4 ) : undefined; - } + if ( params.length === 1 ) { // ensure same behaviour as in NodeBuilder.format() - let alignedPosition = vertex.xy; + if ( last4 === 'vec2' ) params = [ params[ 0 ], params[ 0 ] ]; + else if ( last4 === 'vec3' ) params = [ params[ 0 ], params[ 0 ], params[ 0 ] ]; + else if ( last4 === 'vec4' ) params = [ params[ 0 ], params[ 0 ], params[ 0 ], params[ 0 ] ]; - if ( object.center && object.center.isVector2 === true ) { + } - alignedPosition = alignedPosition.sub( uniform( object.center ).sub( 0.5 ) ); + if ( type === 'color' ) { - } + return new Color( ...params ); - alignedPosition = alignedPosition.mul( scale ); + } else if ( last4 === 'vec2' ) { - const rotation = float( rotationNode || materialRotation ); + return new Vector2( ...params ); - const rotatedPosition = rotate( alignedPosition, rotation ); + } else if ( last4 === 'vec3' ) { - mvPosition = vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw ); + return new Vector3( ...params ); - const modelViewProjection = cameraProjectionMatrix.mul( mvPosition ); + } else if ( last4 === 'vec4' ) { - context.vertex = vertex; + return new Vector4( ...params ); - return modelViewProjection; + } else if ( last4 === 'mat3' ) { - } + return new Matrix3( ...params ); - copy( source ) { + } else if ( last4 === 'mat4' ) { - this.positionNode = source.positionNode; - this.rotationNode = source.rotationNode; - this.scaleNode = source.scaleNode; + return new Matrix4( ...params ); - return super.copy( source ); + } else if ( type === 'bool' ) { - } + return params[ 0 ] || false; -} + } else if ( ( type === 'float' ) || ( type === 'int' ) || ( type === 'uint' ) ) { -SpriteNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'Sprite', SpriteNodeMaterial ); + return params[ 0 ] || 0; -class ShadowMaskModel extends LightingModel { + } else if ( type === 'string' ) { - constructor() { + return params[ 0 ] || ''; - super(); + } else if ( type === 'ArrayBuffer' ) { - this.shadowNode = float( 1 ).toVar( 'shadowMask' ); + return base64ToArrayBuffer( params[ 0 ] ); } - direct( { shadowMask } ) { + return null; - this.shadowNode.mulAssign( shadowMask ); +} - } +function arrayBufferToBase64( arrayBuffer ) { - finish( context ) { + let chars = ''; - diffuseColor.a.mulAssign( this.shadowNode.oneMinus() ); + const array = new Uint8Array( arrayBuffer ); - context.outgoingLight.rgb.assign( diffuseColor.rgb ); // TODO: Optimize LightsNode to avoid this assignment + for ( let i = 0; i < array.length; i ++ ) { + + chars += String.fromCharCode( array[ i ] ); } + return btoa( chars ); + } -const _defaultValues = /*@__PURE__*/ new ShadowMaterial(); +function base64ToArrayBuffer( base64 ) { -class ShadowNodeMaterial extends NodeMaterial { + return Uint8Array.from( atob( base64 ), c => c.charCodeAt( 0 ) ).buffer; - constructor( parameters ) { +} - super(); +var NodeUtils = /*#__PURE__*/Object.freeze({ + __proto__: null, + arrayBufferToBase64: arrayBufferToBase64, + base64ToArrayBuffer: base64ToArrayBuffer, + getCacheKey: getCacheKey$1, + getNodeChildren: getNodeChildren, + getValueFromType: getValueFromType, + getValueType: getValueType, + hash: hash$1, + hashArray: hashArray, + hashString: hashString +}); - this.isShadowNodeMaterial = true; +const NodeShaderStage = { + VERTEX: 'vertex', + FRAGMENT: 'fragment' +}; - this.lights = true; +const NodeUpdateType = { + NONE: 'none', + FRAME: 'frame', + RENDER: 'render', + OBJECT: 'object' +}; - this.setDefaultValues( _defaultValues ); +const NodeType = { + BOOLEAN: 'bool', + INTEGER: 'int', + FLOAT: 'float', + VECTOR2: 'vec2', + VECTOR3: 'vec3', + VECTOR4: 'vec4', + MATRIX2: 'mat2', + MATRIX3: 'mat3', + MATRIX4: 'mat4' +}; - this.setValues( parameters ); +const defaultShaderStages = [ 'fragment', 'vertex' ]; +const defaultBuildStages = [ 'setup', 'analyze', 'generate' ]; +const shaderStages = [ ...defaultShaderStages, 'compute' ]; +const vectorComponents = [ 'x', 'y', 'z', 'w' ]; - } +let _nodeId = 0; - setupLightingModel( /*builder*/ ) { +class Node extends EventDispatcher { - return new ShadowMaskModel(); + static get type() { - } + return 'Node'; -} + } -ShadowNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'Shadow', ShadowNodeMaterial ); + constructor( nodeType = null ) { -const normal = Fn( ( { texture, uv } ) => { + super(); - const epsilon = 0.0001; + this.nodeType = nodeType; - const ret = vec3().temp(); + this.updateType = NodeUpdateType.NONE; + this.updateBeforeType = NodeUpdateType.NONE; + this.updateAfterType = NodeUpdateType.NONE; - If( uv.x.lessThan( epsilon ), () => { + this.uuid = MathUtils.generateUUID(); - ret.assign( vec3( 1, 0, 0 ) ); + this.version = 0; - } ).ElseIf( uv.y.lessThan( epsilon ), () => { + this._cacheKey = null; + this._cacheKeyVersion = 0; - ret.assign( vec3( 0, 1, 0 ) ); + this.global = false; - } ).ElseIf( uv.z.lessThan( epsilon ), () => { + this.isNode = true; - ret.assign( vec3( 0, 0, 1 ) ); + Object.defineProperty( this, 'id', { value: _nodeId ++ } ); - } ).ElseIf( uv.x.greaterThan( 1 - epsilon ), () => { + } - ret.assign( vec3( - 1, 0, 0 ) ); + set needsUpdate( value ) { - } ).ElseIf( uv.y.greaterThan( 1 - epsilon ), () => { + if ( value === true ) { - ret.assign( vec3( 0, - 1, 0 ) ); + this.version ++; - } ).ElseIf( uv.z.greaterThan( 1 - epsilon ), () => { + } - ret.assign( vec3( 0, 0, - 1 ) ); + } - } ).Else( () => { + get type() { - const step = 0.01; + return this.constructor.type; - const x = texture.uv( uv.add( vec3( - step, 0.0, 0.0 ) ) ).r.sub( texture.uv( uv.add( vec3( step, 0.0, 0.0 ) ) ).r ); - const y = texture.uv( uv.add( vec3( 0.0, - step, 0.0 ) ) ).r.sub( texture.uv( uv.add( vec3( 0.0, step, 0.0 ) ) ).r ); - const z = texture.uv( uv.add( vec3( 0.0, 0.0, - step ) ) ).r.sub( texture.uv( uv.add( vec3( 0.0, 0.0, step ) ) ).r ); + } - ret.assign( vec3( x, y, z ) ); + onUpdate( callback, updateType ) { - } ); + this.updateType = updateType; + this.update = callback.bind( this.getSelf() ); - return ret.normalize(); + return this; -} ); + } + onFrameUpdate( callback ) { -class Texture3DNode extends TextureNode { + return this.onUpdate( callback, NodeUpdateType.FRAME ); - constructor( value, uvNode = null, levelNode = null ) { + } - super( value, uvNode, levelNode ); + onRenderUpdate( callback ) { - this.isTexture3DNode = true; + return this.onUpdate( callback, NodeUpdateType.RENDER ); } - getInputType( /*builder*/ ) { + onObjectUpdate( callback ) { - return 'texture3D'; + return this.onUpdate( callback, NodeUpdateType.OBJECT ); } - getDefaultUV() { + onReference( callback ) { - return vec3( 0.5, 0.5, 0.5 ); + this.updateReference = callback.bind( this.getSelf() ); + + return this; } - setUpdateMatrix( /*updateMatrix*/ ) { } // Ignore .updateMatrix for 3d TextureNode + getSelf() { - setupUV( builder, uvNode ) { + // Returns non-node object. - return uvNode; + return this.self || this; } - generateUV( builder, uvNode ) { + updateReference( /*state*/ ) { - return uvNode.build( builder, 'vec3' ); + return this; } - normal( uvNode ) { + isGlobal( /*builder*/ ) { - return normal( { texture: this, uv: uvNode } ); + return this.global; } -} - -Texture3DNode.type = /*@__PURE__*/ registerNode( 'Texture3D', Texture3DNode ); + * getChildren() { -const texture3D = /*@__PURE__*/ nodeProxy( Texture3DNode ); + for ( const { childNode } of getNodeChildren( this ) ) { -class VolumeNodeMaterial extends NodeMaterial { + yield childNode; - constructor( params = {} ) { + } - super(); + } - this.lights = false; - this.isVolumeNodeMaterial = true; - this.testNode = null; + dispose() { - this.setValues( params ); + this.dispatchEvent( { type: 'dispose' } ); } - setup( builder ) { + traverse( callback ) { - const map = texture3D( this.map, null, 0 ); + callback( this ); - const hitBox = Fn( ( { orig, dir } ) => { + for ( const childNode of this.getChildren() ) { - const box_min = vec3( - 0.5 ); - const box_max = vec3( 0.5 ); + childNode.traverse( callback ); - const inv_dir = dir.reciprocal(); + } - const tmin_tmp = box_min.sub( orig ).mul( inv_dir ); - const tmax_tmp = box_max.sub( orig ).mul( inv_dir ); + } - const tmin = min$1( tmin_tmp, tmax_tmp ); - const tmax = max$1( tmin_tmp, tmax_tmp ); + getCacheKey( force = false ) { - const t0 = max$1( tmin.x, max$1( tmin.y, tmin.z ) ); - const t1 = min$1( tmax.x, min$1( tmax.y, tmax.z ) ); + force = force || this.version !== this._cacheKeyVersion; - return vec2( t0, t1 ); + if ( force === true || this._cacheKey === null ) { - } ); + this._cacheKey = getCacheKey$1( this, force ); + this._cacheKeyVersion = this.version; - this.fragmentNode = Fn( () => { + } - const vOrigin = varying( vec3( modelWorldMatrixInverse.mul( vec4( cameraPosition, 1.0 ) ) ) ); - const vDirection = varying( positionGeometry.sub( vOrigin ) ); + return this._cacheKey; - const rayDir = vDirection.normalize(); - const bounds = property( 'vec2', 'bounds' ).assign( hitBox( { orig: vOrigin, dir: rayDir } ) ); + } - bounds.x.greaterThan( bounds.y ).discard(); + getScope() { - bounds.assign( vec2( max$1( bounds.x, 0.0 ), bounds.y ) ); + return this; - const p = property( 'vec3', 'p' ).assign( vOrigin.add( bounds.x.mul( rayDir ) ) ); - const inc = property( 'vec3', 'inc' ).assign( vec3( rayDir.abs().reciprocal() ) ); - const delta = property( 'float', 'delta' ).assign( min$1( inc.x, min$1( inc.y, inc.z ) ) ); + } - delta.divAssign( materialReference( 'steps', 'float' ) ); + getHash( /*builder*/ ) { - const ac = property( 'vec4', 'ac' ).assign( vec4( materialReference( 'base', 'color' ), 0.0 ) ); + return this.uuid; - Loop( { type: 'float', start: bounds.x, end: bounds.y, update: '+= delta' }, () => { + } - const d = property( 'float', 'd' ).assign( map.uv( p.add( 0.5 ) ).r ); + getUpdateType() { - if ( this.testNode !== null ) { + return this.updateType; - this.testNode( { map: map, mapValue: d, probe: p, finalColor: ac } ).append(); + } - } else { + getUpdateBeforeType() { - // default to show surface of mesh - ac.a.assign( 1 ); - Break(); + return this.updateBeforeType; - } + } - p.addAssign( rayDir.mul( delta ) ); + getUpdateAfterType() { - } ); + return this.updateAfterType; - ac.a.equal( 0 ).discard(); + } - return vec4( ac ); + getElementType( builder ) { - } )(); + const type = this.getNodeType( builder ); + const elementType = builder.getElementType( type ); - super.setup( builder ); + return elementType; } -} + getNodeType( builder ) { -VolumeNodeMaterial.type = /*@__PURE__*/ registerNodeMaterial( 'Volume', VolumeNodeMaterial ); + const nodeProperties = builder.getNodeProperties( this ); -// converts an array to a specific type -function convertArray( array, type, forceClone ) { + if ( nodeProperties.outputNode ) { - if ( ! array || // let 'undefined' and 'null' pass - ! forceClone && array.constructor === type ) return array; + return nodeProperties.outputNode.getNodeType( builder ); - if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { + } - return new type( array ); // create typed array + return this.nodeType; } - return Array.prototype.slice.call( array ); // create Array + getShared( builder ) { -} + const hash = this.getHash( builder ); + const nodeFromHash = builder.getNodeFromHash( hash ); -function isTypedArray( object ) { + return nodeFromHash || this; - return ArrayBuffer.isView( object ) && - ! ( object instanceof DataView ); + } -} + setup( builder ) { -// returns an array by which times and values can be sorted -function getKeyframeOrder( times ) { + const nodeProperties = builder.getNodeProperties( this ); - function compareTime( i, j ) { + let index = 0; - return times[ i ] - times[ j ]; + for ( const childNode of this.getChildren() ) { + + nodeProperties[ 'node' + index ++ ] = childNode; + + } + + // return a outputNode if exists + return null; } - const n = times.length; - const result = new Array( n ); - for ( let i = 0; i !== n; ++ i ) result[ i ] = i; + analyze( builder ) { - result.sort( compareTime ); + const usageCount = builder.increaseUsage( this ); - return result; + if ( usageCount === 1 ) { -} + // node flow children -// uses the array previously returned by 'getKeyframeOrder' to sort data -function sortedArray( values, stride, order ) { + const nodeProperties = builder.getNodeProperties( this ); - const nValues = values.length; - const result = new values.constructor( nValues ); + for ( const childNode of Object.values( nodeProperties ) ) { - for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { + if ( childNode && childNode.isNode === true ) { - const srcOffset = order[ i ] * stride; + childNode.build( builder ); - for ( let j = 0; j !== stride; ++ j ) { + } - result[ dstOffset ++ ] = values[ srcOffset + j ]; + } } } - return result; + generate( builder, output ) { -} + const { outputNode } = builder.getNodeProperties( this ); -// function for parsing AOS keyframe formats -function flattenJSON( jsonKeys, times, values, valuePropertyName ) { + if ( outputNode && outputNode.isNode === true ) { - let i = 1, key = jsonKeys[ 0 ]; + return outputNode.build( builder, output ); - while ( key !== undefined && key[ valuePropertyName ] === undefined ) { + } - key = jsonKeys[ i ++ ]; + } + + updateBefore( /*frame*/ ) { + + console.warn( 'Abstract function.' ); } - if ( key === undefined ) return; // no data + updateAfter( /*frame*/ ) { - let value = key[ valuePropertyName ]; - if ( value === undefined ) return; // no data + console.warn( 'Abstract function.' ); - if ( Array.isArray( value ) ) { + } - do { + update( /*frame*/ ) { - value = key[ valuePropertyName ]; + console.warn( 'Abstract function.' ); - if ( value !== undefined ) { + } - times.push( key.time ); - values.push.apply( values, value ); // push all elements + build( builder, output = null ) { - } + const refNode = this.getShared( builder ); - key = jsonKeys[ i ++ ]; + if ( this !== refNode ) { - } while ( key !== undefined ); + return refNode.build( builder, output ); - } else if ( value.toArray !== undefined ) { + } - // ...assume THREE.Math-ish + builder.addNode( this ); + builder.addChain( this ); - do { + /* Build stages expected results: + - "setup" -> Node + - "analyze" -> null + - "generate" -> String + */ + let result = null; - value = key[ valuePropertyName ]; + const buildStage = builder.getBuildStage(); - if ( value !== undefined ) { + if ( buildStage === 'setup' ) { - times.push( key.time ); - value.toArray( values, values.length ); + this.updateReference( builder ); - } + const properties = builder.getNodeProperties( this ); - key = jsonKeys[ i ++ ]; + if ( properties.initialized !== true ) { - } while ( key !== undefined ); + const stackNodesBeforeSetup = builder.stack.nodes.length; - } else { + properties.initialized = true; + properties.outputNode = this.setup( builder ); - // otherwise push as-is + if ( properties.outputNode !== null && builder.stack.nodes.length !== stackNodesBeforeSetup ) ; - do { + for ( const childNode of Object.values( properties ) ) { - value = key[ valuePropertyName ]; + if ( childNode && childNode.isNode === true ) { - if ( value !== undefined ) { + childNode.build( builder ); - times.push( key.time ); - values.push( value ); + } - } + } - key = jsonKeys[ i ++ ]; + } - } while ( key !== undefined ); + } else if ( buildStage === 'analyze' ) { - } + this.analyze( builder ); -} + } else if ( buildStage === 'generate' ) { -function subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) { + const isGenerateOnce = this.generate.length === 1; - const clip = sourceClip.clone(); + if ( isGenerateOnce ) { - clip.name = name; + const type = this.getNodeType( builder ); + const nodeData = builder.getDataFromNode( this ); - const tracks = []; + result = nodeData.snippet; - for ( let i = 0; i < clip.tracks.length; ++ i ) { + if ( result === undefined ) { - const track = clip.tracks[ i ]; - const valueSize = track.getValueSize(); + result = this.generate( builder ) || ''; - const times = []; - const values = []; + nodeData.snippet = result; - for ( let j = 0; j < track.times.length; ++ j ) { + } else if ( nodeData.flowCodes !== undefined && builder.context.nodeBlock !== undefined ) { - const frame = track.times[ j ] * fps; + builder.addFlowCodeHierarchy( this, builder.context.nodeBlock ); - if ( frame < startFrame || frame >= endFrame ) continue; + } - times.push( track.times[ j ] ); + result = builder.format( result, type, output ); - for ( let k = 0; k < valueSize; ++ k ) { + } else { - values.push( track.values[ j * valueSize + k ] ); + result = this.generate( builder, output ) || ''; } } - if ( times.length === 0 ) continue; - - track.times = convertArray( times, track.times.constructor ); - track.values = convertArray( values, track.values.constructor ); + builder.removeChain( this ); - tracks.push( track ); + return result; } - clip.tracks = tracks; - - // find minimum .times value across all tracks in the trimmed clip + getSerializeChildren() { - let minStartTime = Infinity; + return getNodeChildren( this ); - for ( let i = 0; i < clip.tracks.length; ++ i ) { + } - if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) { + serialize( json ) { - minStartTime = clip.tracks[ i ].times[ 0 ]; + const nodeChildren = this.getSerializeChildren(); - } + const inputNodes = {}; - } + for ( const { property, index, childNode } of nodeChildren ) { - // shift all tracks such that clip begins at t=0 + if ( index !== undefined ) { - for ( let i = 0; i < clip.tracks.length; ++ i ) { + if ( inputNodes[ property ] === undefined ) { - clip.tracks[ i ].shift( - 1 * minStartTime ); + inputNodes[ property ] = Number.isInteger( index ) ? [] : {}; - } + } - clip.resetDuration(); + inputNodes[ property ][ index ] = childNode.toJSON( json.meta ).uuid; - return clip; + } else { -} + inputNodes[ property ] = childNode.toJSON( json.meta ).uuid; -function makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) { + } - if ( fps <= 0 ) fps = 30; + } - const numTracks = referenceClip.tracks.length; - const referenceTime = referenceFrame / fps; + if ( Object.keys( inputNodes ).length > 0 ) { - // Make each track's values relative to the values at the reference frame - for ( let i = 0; i < numTracks; ++ i ) { + json.inputNodes = inputNodes; - const referenceTrack = referenceClip.tracks[ i ]; - const referenceTrackType = referenceTrack.ValueTypeName; + } - // Skip this track if it's non-numeric - if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue; + } - // Find the track in the target clip whose name and type matches the reference track - const targetTrack = targetClip.tracks.find( function ( track ) { + deserialize( json ) { - return track.name === referenceTrack.name - && track.ValueTypeName === referenceTrackType; + if ( json.inputNodes !== undefined ) { - } ); + const nodes = json.meta.nodes; - if ( targetTrack === undefined ) continue; + for ( const property in json.inputNodes ) { - let referenceOffset = 0; - const referenceValueSize = referenceTrack.getValueSize(); + if ( Array.isArray( json.inputNodes[ property ] ) ) { - if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { + const inputArray = []; - referenceOffset = referenceValueSize / 3; + for ( const uuid of json.inputNodes[ property ] ) { - } + inputArray.push( nodes[ uuid ] ); - let targetOffset = 0; - const targetValueSize = targetTrack.getValueSize(); + } - if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { + this[ property ] = inputArray; - targetOffset = targetValueSize / 3; + } else if ( typeof json.inputNodes[ property ] === 'object' ) { - } + const inputObject = {}; - const lastIndex = referenceTrack.times.length - 1; - let referenceValue; + for ( const subProperty in json.inputNodes[ property ] ) { - // Find the value to subtract out of the track - if ( referenceTime <= referenceTrack.times[ 0 ] ) { + const uuid = json.inputNodes[ property ][ subProperty ]; - // Reference frame is earlier than the first keyframe, so just use the first keyframe - const startIndex = referenceOffset; - const endIndex = referenceValueSize - referenceOffset; - referenceValue = referenceTrack.values.slice( startIndex, endIndex ); + inputObject[ subProperty ] = nodes[ uuid ]; - } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) { + } - // Reference frame is after the last keyframe, so just use the last keyframe - const startIndex = lastIndex * referenceValueSize + referenceOffset; - const endIndex = startIndex + referenceValueSize - referenceOffset; - referenceValue = referenceTrack.values.slice( startIndex, endIndex ); + this[ property ] = inputObject; - } else { + } else { - // Interpolate to the reference value - const interpolant = referenceTrack.createInterpolant(); - const startIndex = referenceOffset; - const endIndex = referenceValueSize - referenceOffset; - interpolant.evaluate( referenceTime ); - referenceValue = interpolant.resultBuffer.slice( startIndex, endIndex ); + const uuid = json.inputNodes[ property ]; - } + this[ property ] = nodes[ uuid ]; - // Conjugate the quaternion - if ( referenceTrackType === 'quaternion' ) { + } - const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate(); - referenceQuat.toArray( referenceValue ); + } } - // Subtract the reference value from all of the track values + } - const numTimes = targetTrack.times.length; - for ( let j = 0; j < numTimes; ++ j ) { + toJSON( meta ) { - const valueStart = j * targetValueSize + targetOffset; + const { uuid, type } = this; + const isRoot = ( meta === undefined || typeof meta === 'string' ); - if ( referenceTrackType === 'quaternion' ) { + if ( isRoot ) { - // Multiply the conjugate for quaternion track types - Quaternion.multiplyQuaternionsFlat( - targetTrack.values, - valueStart, - referenceValue, - 0, - targetTrack.values, - valueStart - ); + meta = { + textures: {}, + images: {}, + nodes: {} + }; - } else { + } - const valueEnd = targetValueSize - targetOffset * 2; + // serialize - // Subtract each value for all other numeric track types - for ( let k = 0; k < valueEnd; ++ k ) { + let data = meta.nodes[ uuid ]; - targetTrack.values[ valueStart + k ] -= referenceValue[ k ]; + if ( data === undefined ) { + data = { + uuid, + type, + meta, + metadata: { + version: 4.6, + type: 'Node', + generator: 'Node.toJSON' } + }; - } + if ( isRoot !== true ) meta.nodes[ data.uuid ] = data; - } + this.serialize( data ); - } + delete data.meta; - targetClip.blendMode = AdditiveAnimationBlendMode; + } - return targetClip; + // TODO: Copied from Object3D.toJSON -} + function extractFromCache( cache ) { -const AnimationUtils = { - convertArray: convertArray, - isTypedArray: isTypedArray, - getKeyframeOrder: getKeyframeOrder, - sortedArray: sortedArray, - flattenJSON: flattenJSON, - subclip: subclip, - makeClipAdditive: makeClipAdditive -}; + const values = []; -/** - * Abstract base class of interpolants over parametric samples. - * - * The parameter domain is one dimensional, typically the time or a path - * along a curve defined by the data. - * - * The sample values can have any dimensionality and derived classes may - * apply special interpretations to the data. - * - * This class provides the interval seek in a Template Method, deferring - * the actual interpolation to derived classes. - * - * Time complexity is O(1) for linear access crossing at most two points - * and O(log N) for random access, where N is the number of positions. - * - * References: - * - * http://www.oodesign.com/template-method-pattern.html - * - */ + for ( const key in cache ) { -class Interpolant { + const data = cache[ key ]; + delete data.metadata; + values.push( data ); - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + } - this.parameterPositions = parameterPositions; - this._cachedIndex = 0; + return values; - this.resultBuffer = resultBuffer !== undefined ? - resultBuffer : new sampleValues.constructor( sampleSize ); - this.sampleValues = sampleValues; - this.valueSize = sampleSize; + } - this.settings = null; - this.DefaultSettings_ = {}; + if ( isRoot ) { - } + const textures = extractFromCache( meta.textures ); + const images = extractFromCache( meta.images ); + const nodes = extractFromCache( meta.nodes ); - evaluate( t ) { + if ( textures.length > 0 ) data.textures = textures; + if ( images.length > 0 ) data.images = images; + if ( nodes.length > 0 ) data.nodes = nodes; - const pp = this.parameterPositions; - let i1 = this._cachedIndex, - t1 = pp[ i1 ], - t0 = pp[ i1 - 1 ]; + } - validate_interval: { + return data; - seek: { + } - let right; +} - linear_scan: { +class ArrayElementNode extends Node { - //- See http://jsperf.com/comparison-to-undefined/3 - //- slower code: - //- - //- if ( t >= t1 || t1 === undefined ) { - forward_scan: if ( ! ( t < t1 ) ) { + static get type() { - for ( let giveUpAt = i1 + 2; ; ) { + return 'ArrayElementNode'; - if ( t1 === undefined ) { + } // @TODO: If extending from TempNode it breaks webgpu_compute - if ( t < t0 ) break forward_scan; + constructor( node, indexNode ) { - // after end + super(); - i1 = pp.length; - this._cachedIndex = i1; - return this.copySampleValue_( i1 - 1 ); + this.node = node; + this.indexNode = indexNode; - } + this.isArrayElementNode = true; - if ( i1 === giveUpAt ) break; // this loop + } - t0 = t1; - t1 = pp[ ++ i1 ]; + getNodeType( builder ) { - if ( t < t1 ) { + return this.node.getElementType( builder ); - // we have arrived at the sought interval - break seek; + } - } + generate( builder ) { - } + const nodeSnippet = this.node.build( builder ); + const indexSnippet = this.indexNode.build( builder, 'uint' ); - // prepare binary search on the right side of the index - right = pp.length; - break linear_scan; + return `${nodeSnippet}[ ${indexSnippet} ]`; - } + } - //- slower code: - //- if ( t < t0 || t0 === undefined ) { - if ( ! ( t >= t0 ) ) { +} - // looping? +class ConvertNode extends Node { - const t1global = pp[ 1 ]; + static get type() { - if ( t < t1global ) { + return 'ConvertNode'; - i1 = 2; // + 1, using the scan for the details - t0 = t1global; + } - } + constructor( node, convertTo ) { - // linear reverse scan + super(); - for ( let giveUpAt = i1 - 2; ; ) { + this.node = node; + this.convertTo = convertTo; - if ( t0 === undefined ) { + } - // before start + getNodeType( builder ) { - this._cachedIndex = 0; - return this.copySampleValue_( 0 ); + const requestType = this.node.getNodeType( builder ); - } + let convertTo = null; - if ( i1 === giveUpAt ) break; // this loop + for ( const overloadingType of this.convertTo.split( '|' ) ) { - t1 = t0; - t0 = pp[ -- i1 - 1 ]; + if ( convertTo === null || builder.getTypeLength( requestType ) === builder.getTypeLength( overloadingType ) ) { - if ( t >= t0 ) { + convertTo = overloadingType; - // we have arrived at the sought interval - break seek; + } - } + } - } + return convertTo; - // prepare binary search on the left side of the index - right = i1; - i1 = 0; - break linear_scan; + } - } + serialize( data ) { - // the interval is valid + super.serialize( data ); - break validate_interval; + data.convertTo = this.convertTo; - } // linear scan + } - // binary search + deserialize( data ) { - while ( i1 < right ) { + super.deserialize( data ); - const mid = ( i1 + right ) >>> 1; + this.convertTo = data.convertTo; - if ( t < pp[ mid ] ) { + } - right = mid; + generate( builder, output ) { - } else { + const node = this.node; + const type = this.getNodeType( builder ); - i1 = mid + 1; + const snippet = node.build( builder, type ); - } + return builder.format( snippet, type, output ); - } + } - t1 = pp[ i1 ]; - t0 = pp[ i1 - 1 ]; +} - // check boundary cases, again +class TempNode extends Node { - if ( t0 === undefined ) { + static get type() { - this._cachedIndex = 0; - return this.copySampleValue_( 0 ); + return 'TempNode'; - } + } - if ( t1 === undefined ) { + constructor( type ) { - i1 = pp.length; - this._cachedIndex = i1; - return this.copySampleValue_( i1 - 1 ); + super( type ); - } + this.isTempNode = true; - } // seek + } - this._cachedIndex = i1; + hasDependencies( builder ) { - this.intervalChanged_( i1, t0, t1 ); + return builder.getDataFromNode( this ).usageCount > 1; - } // validate_interval + } - return this.interpolate_( i1, t0, t, t1 ); + build( builder, output ) { - } + const buildStage = builder.getBuildStage(); - getSettings_() { + if ( buildStage === 'generate' ) { - return this.settings || this.DefaultSettings_; + const type = builder.getVectorType( this.getNodeType( builder, output ) ); + const nodeData = builder.getDataFromNode( this ); - } + if ( nodeData.propertyName !== undefined ) { - copySampleValue_( index ) { + return builder.format( nodeData.propertyName, type, output ); - // copies a sample value to the result buffer + } else if ( type !== 'void' && output !== 'void' && this.hasDependencies( builder ) ) { - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - offset = index * stride; + const snippet = super.build( builder, type ); - for ( let i = 0; i !== stride; ++ i ) { + const nodeVar = builder.getVarFromNode( this, null, type ); + const propertyName = builder.getPropertyName( nodeVar ); - result[ i ] = values[ offset + i ]; + builder.addLineFlowCode( `${propertyName} = ${snippet}`, this ); + + nodeData.snippet = snippet; + nodeData.propertyName = propertyName; + + return builder.format( nodeData.propertyName, type, output ); + + } } - return result; + return super.build( builder, output ); } - // Template methods for derived classes: +} - interpolate_( /* i1, t0, t, t1 */ ) { +class JoinNode extends TempNode { - throw new Error( 'call to abstract method' ); - // implementations shall return this.resultBuffer + static get type() { + + return 'JoinNode'; } - intervalChanged_( /* i1, t0, t1 */ ) { + constructor( nodes = [], nodeType = null ) { - // empty + super( nodeType ); + + this.nodes = nodes; } -} + getNodeType( builder ) { -/** - * Fast and simple cubic spline interpolant. - * - * It was derived from a Hermitian construction setting the first derivative - * at each sample position to the linear slope between neighboring positions - * over their parameter interval. - */ + if ( this.nodeType !== null ) { -class CubicInterpolant extends Interpolant { + return builder.getVectorType( this.nodeType ); - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + } - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); + return builder.getTypeFromLength( this.nodes.reduce( ( count, cur ) => count + builder.getTypeLength( cur.getNodeType( builder ) ), 0 ) ); - this._weightPrev = - 0; - this._offsetPrev = - 0; - this._weightNext = - 0; - this._offsetNext = - 0; + } - this.DefaultSettings_ = { + generate( builder, output ) { - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding + const type = this.getNodeType( builder ); + const nodes = this.nodes; - }; + const primitiveType = builder.getComponentType( type ); - } + const snippetValues = []; - intervalChanged_( i1, t0, t1 ) { + for ( const input of nodes ) { - const pp = this.parameterPositions; - let iPrev = i1 - 2, - iNext = i1 + 1, + let inputSnippet = input.build( builder ); - tPrev = pp[ iPrev ], - tNext = pp[ iNext ]; + const inputPrimitiveType = builder.getComponentType( input.getNodeType( builder ) ); - if ( tPrev === undefined ) { + if ( inputPrimitiveType !== primitiveType ) { - switch ( this.getSettings_().endingStart ) { + inputSnippet = builder.format( inputSnippet, inputPrimitiveType, primitiveType ); - case ZeroSlopeEnding: + } - // f'(t0) = 0 - iPrev = i1; - tPrev = 2 * t0 - t1; + snippetValues.push( inputSnippet ); - break; + } - case WrapAroundEnding: + const snippet = `${ builder.getType( type ) }( ${ snippetValues.join( ', ' ) } )`; - // use the other end of the curve - iPrev = pp.length - 2; - tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; + return builder.format( snippet, type, output ); - break; + } - default: // ZeroCurvatureEnding +} - // f''(t0) = 0 a.k.a. Natural Spline - iPrev = i1; - tPrev = t1; +const stringVectorComponents = vectorComponents.join( '' ); - } +class SplitNode extends Node { - } + static get type() { - if ( tNext === undefined ) { + return 'SplitNode'; - switch ( this.getSettings_().endingEnd ) { + } - case ZeroSlopeEnding: + constructor( node, components = 'x' ) { - // f'(tN) = 0 - iNext = i1; - tNext = 2 * t1 - t0; + super(); - break; + this.node = node; + this.components = components; - case WrapAroundEnding: + this.isSplitNode = true; - // use the other end of the curve - iNext = 1; - tNext = t1 + pp[ 1 ] - pp[ 0 ]; + } - break; + getVectorLength() { - default: // ZeroCurvatureEnding + let vectorLength = this.components.length; - // f''(tN) = 0, a.k.a. Natural Spline - iNext = i1 - 1; - tNext = t0; + for ( const c of this.components ) { - } + vectorLength = Math.max( vectorComponents.indexOf( c ) + 1, vectorLength ); } - const halfDt = ( t1 - t0 ) * 0.5, - stride = this.valueSize; + return vectorLength; - this._weightPrev = halfDt / ( t0 - tPrev ); - this._weightNext = halfDt / ( tNext - t1 ); - this._offsetPrev = iPrev * stride; - this._offsetNext = iNext * stride; + } + + getComponentType( builder ) { + + return builder.getComponentType( this.node.getNodeType( builder ) ); } - interpolate_( i1, t0, t, t1 ) { + getNodeType( builder ) { - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + return builder.getTypeFromLength( this.components.length, this.getComponentType( builder ) ); - o1 = i1 * stride, o0 = o1 - stride, - oP = this._offsetPrev, oN = this._offsetNext, - wP = this._weightPrev, wN = this._weightNext, + } - p = ( t - t0 ) / ( t1 - t0 ), - pp = p * p, - ppp = pp * p; + generate( builder, output ) { - // evaluate polynomials + const node = this.node; + const nodeTypeLength = builder.getTypeLength( node.getNodeType( builder ) ); - const sP = - wP * ppp + 2 * wP * pp - wP * p; - const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; - const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; - const sN = wN * ppp - wN * pp; + let snippet = null; - // combine data linearly + if ( nodeTypeLength > 1 ) { - for ( let i = 0; i !== stride; ++ i ) { + let type = null; - result[ i ] = - sP * values[ oP + i ] + - s0 * values[ o0 + i ] + - s1 * values[ o1 + i ] + - sN * values[ oN + i ]; + const componentsLength = this.getVectorLength(); - } + if ( componentsLength >= nodeTypeLength ) { - return result; + // needed expand the input node - } + type = builder.getTypeFromLength( this.getVectorLength(), this.getComponentType( builder ) ); -} + } -class LinearInterpolant extends Interpolant { + const nodeSnippet = node.build( builder, type ); - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + if ( this.components.length === nodeTypeLength && this.components === stringVectorComponents.slice( 0, this.components.length ) ) { - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); + // unnecessary swizzle - } + snippet = builder.format( nodeSnippet, type, output ); - interpolate_( i1, t0, t, t1 ) { + } else { - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + snippet = builder.format( `${nodeSnippet}.${this.components}`, this.getNodeType( builder ), output ); - offset1 = i1 * stride, - offset0 = offset1 - stride, + } - weight1 = ( t - t0 ) / ( t1 - t0 ), - weight0 = 1 - weight1; + } else { - for ( let i = 0; i !== stride; ++ i ) { + // ignore .components if .node returns float/integer - result[ i ] = - values[ offset0 + i ] * weight0 + - values[ offset1 + i ] * weight1; + snippet = node.build( builder, output ); } - return result; + return snippet; } -} - -/** - * - * Interpolant that evaluates to the sample value at the position preceding - * the parameter. - */ - -class DiscreteInterpolant extends Interpolant { + serialize( data ) { - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + super.serialize( data ); - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); + data.components = this.components; } - interpolate_( i1 /*, t0, t, t1 */ ) { + deserialize( data ) { - return this.copySampleValue_( i1 - 1 ); + super.deserialize( data ); + + this.components = data.components; } } -class KeyframeTrack { +class SetNode extends TempNode { - constructor( name, times, values, interpolation ) { + static get type() { - if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); - if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); + return 'SetNode'; - this.name = name; + } - this.times = convertArray( times, this.TimeBufferType ); - this.values = convertArray( values, this.ValueBufferType ); + constructor( sourceNode, components, targetNode ) { - this.setInterpolation( interpolation || this.DefaultInterpolation ); + super(); + + this.sourceNode = sourceNode; + this.components = components; + this.targetNode = targetNode; } - // Serialization (in static context, because of constructor invocation - // and automatic invocation of .toJSON): + getNodeType( builder ) { - static toJSON( track ) { + return this.sourceNode.getNodeType( builder ); - const trackType = track.constructor; + } - let json; + generate( builder ) { - // derived classes can define a static toJSON method - if ( trackType.toJSON !== this.toJSON ) { + const { sourceNode, components, targetNode } = this; - json = trackType.toJSON( track ); + const sourceType = this.getNodeType( builder ); + const targetType = builder.getTypeFromLength( components.length, targetNode.getNodeType( builder ) ); - } else { + const targetSnippet = targetNode.build( builder, targetType ); + const sourceSnippet = sourceNode.build( builder, sourceType ); - // by default, we assume the data can be serialized as-is - json = { + const length = builder.getTypeLength( sourceType ); + const snippetValues = []; - 'name': track.name, - 'times': convertArray( track.times, Array ), - 'values': convertArray( track.values, Array ) + for ( let i = 0; i < length; i ++ ) { - }; + const component = vectorComponents[ i ]; - const interpolation = track.getInterpolation(); + if ( component === components[ 0 ] ) { - if ( interpolation !== track.DefaultInterpolation ) { + snippetValues.push( targetSnippet ); - json.interpolation = interpolation; + i += components.length - 1; + + } else { + + snippetValues.push( sourceSnippet + '.' + component ); } } - json.type = track.ValueTypeName; // mandatory - - return json; + return `${ builder.getType( sourceType ) }( ${ snippetValues.join( ', ' ) } )`; } - InterpolantFactoryMethodDiscrete( result ) { - - return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); +} - } +class FlipNode extends TempNode { - InterpolantFactoryMethodLinear( result ) { + static get type() { - return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); + return 'FlipNode'; } - InterpolantFactoryMethodSmooth( result ) { + constructor( sourceNode, components ) { - return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); + super(); - } + this.sourceNode = sourceNode; + this.components = components; - setInterpolation( interpolation ) { + } - let factoryMethod; + getNodeType( builder ) { - switch ( interpolation ) { + return this.sourceNode.getNodeType( builder ); - case InterpolateDiscrete: + } - factoryMethod = this.InterpolantFactoryMethodDiscrete; + generate( builder ) { - break; + const { components, sourceNode } = this; - case InterpolateLinear: + const sourceType = this.getNodeType( builder ); + const sourceSnippet = sourceNode.build( builder ); - factoryMethod = this.InterpolantFactoryMethodLinear; + const sourceCache = builder.getVarFromNode( this ); + const sourceProperty = builder.getPropertyName( sourceCache ); - break; + builder.addLineFlowCode( sourceProperty + ' = ' + sourceSnippet, this ); - case InterpolateSmooth: + const length = builder.getTypeLength( sourceType ); + const snippetValues = []; - factoryMethod = this.InterpolantFactoryMethodSmooth; + let componentIndex = 0; - break; + for ( let i = 0; i < length; i ++ ) { - } + const component = vectorComponents[ i ]; - if ( factoryMethod === undefined ) { + if ( component === components[ componentIndex ] ) { - const message = 'unsupported interpolation for ' + - this.ValueTypeName + ' keyframe track named ' + this.name; + snippetValues.push( '1.0 - ' + ( sourceProperty + '.' + component ) ); - if ( this.createInterpolant === undefined ) { + componentIndex ++; - // fall back to default, unless the default itself is messed up - if ( interpolation !== this.DefaultInterpolation ) { + } else { - this.setInterpolation( this.DefaultInterpolation ); + snippetValues.push( sourceProperty + '.' + component ); - } else { + } - throw new Error( message ); // fatal, in this case + } - } + return `${ builder.getType( sourceType ) }( ${ snippetValues.join( ', ' ) } )`; - } + } - console.warn( 'THREE.KeyframeTrack:', message ); - return this; +} - } +class InputNode extends Node { - this.createInterpolant = factoryMethod; + static get type() { - return this; + return 'InputNode'; } - getInterpolation() { + constructor( value, nodeType = null ) { - switch ( this.createInterpolant ) { + super( nodeType ); - case this.InterpolantFactoryMethodDiscrete: + this.isInputNode = true; - return InterpolateDiscrete; + this.value = value; + this.precision = null; - case this.InterpolantFactoryMethodLinear: + } - return InterpolateLinear; + getNodeType( /*builder*/ ) { - case this.InterpolantFactoryMethodSmooth: + if ( this.nodeType === null ) { - return InterpolateSmooth; + return getValueType( this.value ); } + return this.nodeType; + } - getValueSize() { + getInputType( builder ) { - return this.values.length / this.times.length; + return this.getNodeType( builder ); } - // move all keyframes either forwards or backwards in time - shift( timeOffset ) { + setPrecision( precision ) { - if ( timeOffset !== 0.0 ) { + this.precision = precision; - const times = this.times; + return this; - for ( let i = 0, n = times.length; i !== n; ++ i ) { + } - times[ i ] += timeOffset; + serialize( data ) { - } + super.serialize( data ); - } + data.value = this.value; - return this; + if ( this.value && this.value.toArray ) data.value = this.value.toArray(); - } + data.valueType = getValueType( this.value ); + data.nodeType = this.nodeType; - // scale all keyframe times by a factor (useful for frame <-> seconds conversions) - scale( timeScale ) { + if ( data.valueType === 'ArrayBuffer' ) data.value = arrayBufferToBase64( data.value ); - if ( timeScale !== 1.0 ) { + data.precision = this.precision; - const times = this.times; + } - for ( let i = 0, n = times.length; i !== n; ++ i ) { + deserialize( data ) { - times[ i ] *= timeScale; + super.deserialize( data ); - } + this.nodeType = data.nodeType; + this.value = Array.isArray( data.value ) ? getValueFromType( data.valueType, ...data.value ) : data.value; - } + this.precision = data.precision || null; - return this; + if ( this.value && this.value.fromArray ) this.value = this.value.fromArray( data.value ); } - // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. - // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values - trim( startTime, endTime ) { + generate( /*builder, output*/ ) { - const times = this.times, - nKeys = times.length; + console.warn( 'Abstract function.' ); - let from = 0, - to = nKeys - 1; + } - while ( from !== nKeys && times[ from ] < startTime ) { +} - ++ from; +class ConstNode extends InputNode { - } - - while ( to !== - 1 && times[ to ] > endTime ) { - - -- to; - - } + static get type() { - ++ to; // inclusive -> exclusive bound + return 'ConstNode'; - if ( from !== 0 || to !== nKeys ) { + } - // empty tracks are forbidden, so keep at least one keyframe - if ( from >= to ) { + constructor( value, nodeType = null ) { - to = Math.max( to, 1 ); - from = to - 1; + super( value, nodeType ); - } + this.isConstNode = true; - const stride = this.getValueSize(); - this.times = times.slice( from, to ); - this.values = this.values.slice( from * stride, to * stride ); + } - } + generateConst( builder ) { - return this; + return builder.generateConst( this.getNodeType( builder ), this.value ); } - // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable - validate() { + generate( builder, output ) { - let valid = true; + const type = this.getNodeType( builder ); - const valueSize = this.getValueSize(); - if ( valueSize - Math.floor( valueSize ) !== 0 ) { + return builder.format( this.generateConst( builder ), type, output ); - console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); - valid = false; + } - } +} - const times = this.times, - values = this.values, +// - nKeys = times.length; +let currentStack = null; - if ( nKeys === 0 ) { +const NodeElements = new Map(); - console.error( 'THREE.KeyframeTrack: Track is empty.', this ); - valid = false; +function addMethodChaining( name, nodeElement ) { - } + if ( NodeElements.has( name ) ) { - let prevTime = null; + console.warn( `Redefinition of method chaining ${ name }` ); + return; - for ( let i = 0; i !== nKeys; i ++ ) { + } - const currTime = times[ i ]; + if ( typeof nodeElement !== 'function' ) throw new Error( `Node element ${ name } is not a function` ); - if ( typeof currTime === 'number' && isNaN( currTime ) ) { + NodeElements.set( name, nodeElement ); - console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); - valid = false; - break; +} - } +const parseSwizzle = ( props ) => props.replace( /r|s/g, 'x' ).replace( /g|t/g, 'y' ).replace( /b|p/g, 'z' ).replace( /a|q/g, 'w' ); +const parseSwizzleAndSort = ( props ) => parseSwizzle( props ).split( '' ).sort().join( '' ); - if ( prevTime !== null && prevTime > currTime ) { +const shaderNodeHandler = { - console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); - valid = false; - break; + setup( NodeClosure, params ) { - } + const inputs = params.shift(); - prevTime = currTime; + return NodeClosure( nodeObjects( inputs ), ...params ); - } + }, - if ( values !== undefined ) { + get( node, prop, nodeObj ) { - if ( isTypedArray( values ) ) { + if ( typeof prop === 'string' && node[ prop ] === undefined ) { - for ( let i = 0, n = values.length; i !== n; ++ i ) { + if ( node.isStackNode !== true && prop === 'assign' ) { - const value = values[ i ]; + return ( ...params ) => { - if ( isNaN( value ) ) { + currentStack.assign( nodeObj, ...params ); - console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); - valid = false; - break; + return nodeObj; - } + }; - } + } else if ( NodeElements.has( prop ) ) { - } + const nodeElement = NodeElements.get( prop ); - } + return node.isStackNode ? ( ...params ) => nodeObj.add( nodeElement( ...params ) ) : ( ...params ) => nodeElement( nodeObj, ...params ); - return valid; + } else if ( prop === 'self' ) { - } + return node; - // removes equivalent sequential keys as common in morph target sequences - // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) - optimize() { + } else if ( prop.endsWith( 'Assign' ) && NodeElements.has( prop.slice( 0, prop.length - 'Assign'.length ) ) ) { - // times or values may be shared with other tracks, so overwriting is unsafe - const times = this.times.slice(), - values = this.values.slice(), - stride = this.getValueSize(), + const nodeElement = NodeElements.get( prop.slice( 0, prop.length - 'Assign'.length ) ); - smoothInterpolation = this.getInterpolation() === InterpolateSmooth, + return node.isStackNode ? ( ...params ) => nodeObj.assign( params[ 0 ], nodeElement( ...params ) ) : ( ...params ) => nodeObj.assign( nodeElement( nodeObj, ...params ) ); - lastIndex = times.length - 1; + } else if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true ) { - let writeIndex = 1; + // accessing properties ( swizzle ) - for ( let i = 1; i < lastIndex; ++ i ) { + prop = parseSwizzle( prop ); - let keep = false; + return nodeObject( new SplitNode( nodeObj, prop ) ); - const time = times[ i ]; - const timeNext = times[ i + 1 ]; + } else if ( /^set[XYZWRGBASTPQ]{1,4}$/.test( prop ) === true ) { - // remove adjacent keyframes scheduled at the same time + // set properties ( swizzle ) and sort to xyzw sequence - if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) { + prop = parseSwizzleAndSort( prop.slice( 3 ).toLowerCase() ); - if ( ! smoothInterpolation ) { + return ( value ) => nodeObject( new SetNode( node, prop, value ) ); - // remove unnecessary keyframes same as their neighbors + } else if ( /^flip[XYZWRGBASTPQ]{1,4}$/.test( prop ) === true ) { - const offset = i * stride, - offsetP = offset - stride, - offsetN = offset + stride; + // set properties ( swizzle ) and sort to xyzw sequence - for ( let j = 0; j !== stride; ++ j ) { + prop = parseSwizzleAndSort( prop.slice( 4 ).toLowerCase() ); - const value = values[ offset + j ]; + return () => nodeObject( new FlipNode( nodeObject( node ), prop ) ); - if ( value !== values[ offsetP + j ] || - value !== values[ offsetN + j ] ) { + } else if ( prop === 'width' || prop === 'height' || prop === 'depth' ) { - keep = true; - break; + // accessing property - } + if ( prop === 'width' ) prop = 'x'; + else if ( prop === 'height' ) prop = 'y'; + else if ( prop === 'depth' ) prop = 'z'; - } + return nodeObject( new SplitNode( node, prop ) ); - } else { + } else if ( /^\d+$/.test( prop ) === true ) { - keep = true; + // accessing array - } + return nodeObject( new ArrayElementNode( nodeObj, new ConstNode( Number( prop ), 'uint' ) ) ); } - // in-place compaction - - if ( keep ) { + } - if ( i !== writeIndex ) { + return Reflect.get( node, prop, nodeObj ); - times[ writeIndex ] = times[ i ]; + }, - const readOffset = i * stride, - writeOffset = writeIndex * stride; + set( node, prop, value, nodeObj ) { - for ( let j = 0; j !== stride; ++ j ) { + if ( typeof prop === 'string' && node[ prop ] === undefined ) { - values[ writeOffset + j ] = values[ readOffset + j ]; + // setting properties - } + if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true || prop === 'width' || prop === 'height' || prop === 'depth' || /^\d+$/.test( prop ) === true ) { - } + nodeObj[ prop ].assign( value ); - ++ writeIndex; + return true; } } - // flush last keyframe (compaction looks ahead) - - if ( lastIndex > 0 ) { + return Reflect.set( node, prop, value, nodeObj ); - times[ writeIndex ] = times[ lastIndex ]; + } - for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { +}; - values[ writeOffset + j ] = values[ readOffset + j ]; +const nodeObjectsCacheMap = new WeakMap(); +const nodeBuilderFunctionsCacheMap = new WeakMap(); - } +const ShaderNodeObject = function ( obj, altType = null ) { - ++ writeIndex; + const type = getValueType( obj ); - } + if ( type === 'node' ) { - if ( writeIndex !== times.length ) { + let nodeObject = nodeObjectsCacheMap.get( obj ); - this.times = times.slice( 0, writeIndex ); - this.values = values.slice( 0, writeIndex * stride ); + if ( nodeObject === undefined ) { - } else { + nodeObject = new Proxy( obj, shaderNodeHandler ); - this.times = times; - this.values = values; + nodeObjectsCacheMap.set( obj, nodeObject ); + nodeObjectsCacheMap.set( nodeObject, nodeObject ); } - return this; - - } - - clone() { + return nodeObject; - const times = this.times.slice(); - const values = this.values.slice(); + } else if ( ( altType === null && ( type === 'float' || type === 'boolean' ) ) || ( type && type !== 'shader' && type !== 'string' ) ) { - const TypedKeyframeTrack = this.constructor; - const track = new TypedKeyframeTrack( this.name, times, values ); + return nodeObject( getConstNode( obj, altType ) ); - // Interpolant argument to constructor is not saved, so copy the factory method directly. - track.createInterpolant = this.createInterpolant; + } else if ( type === 'shader' ) { - return track; + return Fn( obj ); } -} + return obj; -KeyframeTrack.prototype.TimeBufferType = Float32Array; -KeyframeTrack.prototype.ValueBufferType = Float32Array; -KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; +}; -/** - * A Track of Boolean keyframe values. - */ -class BooleanKeyframeTrack extends KeyframeTrack { +const ShaderNodeObjects = function ( objects, altType = null ) { - // No interpolation parameter because only InterpolateDiscrete is valid. - constructor( name, times, values ) { + for ( const name in objects ) { - super( name, times, values ); + objects[ name ] = nodeObject( objects[ name ], altType ); } -} + return objects; -BooleanKeyframeTrack.prototype.ValueTypeName = 'bool'; -BooleanKeyframeTrack.prototype.ValueBufferType = Array; -BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; -BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; -BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; +}; -/** - * A Track of keyframe values that represent color. - */ -class ColorKeyframeTrack extends KeyframeTrack {} +const ShaderNodeArray = function ( array, altType = null ) { -ColorKeyframeTrack.prototype.ValueTypeName = 'color'; + const len = array.length; -/** - * A Track of numeric keyframe values. - */ -class NumberKeyframeTrack extends KeyframeTrack {} + for ( let i = 0; i < len; i ++ ) { -NumberKeyframeTrack.prototype.ValueTypeName = 'number'; + array[ i ] = nodeObject( array[ i ], altType ); -/** - * Spherical linear unit quaternion interpolant. - */ + } -class QuaternionLinearInterpolant extends Interpolant { + return array; - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { +}; - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); +const ShaderNodeProxy = function ( NodeClass, scope = null, factor = null, settings = null ) { - } + const assignNode = ( node ) => nodeObject( settings !== null ? Object.assign( node, settings ) : node ); - interpolate_( i1, t0, t, t1 ) { + if ( scope === null ) { - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + return ( ...params ) => { - alpha = ( t - t0 ) / ( t1 - t0 ); + return assignNode( new NodeClass( ...nodeArray( params ) ) ); - let offset = i1 * stride; + }; - for ( let end = offset + stride; offset !== end; offset += 4 ) { + } else if ( factor !== null ) { - Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); + factor = nodeObject( factor ); - } + return ( ...params ) => { - return result; + return assignNode( new NodeClass( scope, ...nodeArray( params ), factor ) ); - } + }; -} + } else { -/** - * A Track of quaternion keyframe values. - */ -class QuaternionKeyframeTrack extends KeyframeTrack { + return ( ...params ) => { - InterpolantFactoryMethodLinear( result ) { + return assignNode( new NodeClass( scope, ...nodeArray( params ) ) ); - return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); + }; } -} +}; -QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion'; -// ValueBufferType is inherited -// DefaultInterpolation is inherited; -QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; +const ShaderNodeImmutable = function ( NodeClass, ...params ) { -/** - * A Track that interpolates Strings - */ -class StringKeyframeTrack extends KeyframeTrack { + return nodeObject( new NodeClass( ...nodeArray( params ) ) ); - // No interpolation parameter because only InterpolateDiscrete is valid. - constructor( name, times, values ) { +}; - super( name, times, values ); +class ShaderCallNodeInternal extends Node { + + constructor( shaderNode, inputNodes ) { + + super(); + + this.shaderNode = shaderNode; + this.inputNodes = inputNodes; } -} + getNodeType( builder ) { -StringKeyframeTrack.prototype.ValueTypeName = 'string'; -StringKeyframeTrack.prototype.ValueBufferType = Array; -StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; -StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; -StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; + return this.shaderNode.nodeType || this.getOutputNode( builder ).getNodeType( builder ); -/** - * A Track of vectored keyframe values. - */ -class VectorKeyframeTrack extends KeyframeTrack {} + } -VectorKeyframeTrack.prototype.ValueTypeName = 'vector'; + call( builder ) { -class AnimationClip { + const { shaderNode, inputNodes } = this; - constructor( name = '', duration = - 1, tracks = [], blendMode = NormalAnimationBlendMode ) { + const properties = builder.getNodeProperties( shaderNode ); + if ( properties.onceOutput ) return properties.onceOutput; - this.name = name; - this.tracks = tracks; - this.duration = duration; - this.blendMode = blendMode; + // - this.uuid = generateUUID(); + let result = null; - // this means it should figure out its duration by scanning the tracks - if ( this.duration < 0 ) { + if ( shaderNode.layout ) { - this.resetDuration(); + let functionNodesCacheMap = nodeBuilderFunctionsCacheMap.get( builder.constructor ); - } + if ( functionNodesCacheMap === undefined ) { - } + functionNodesCacheMap = new WeakMap(); + nodeBuilderFunctionsCacheMap.set( builder.constructor, functionNodesCacheMap ); - static parse( json ) { + } - const tracks = [], - jsonTracks = json.tracks, - frameTime = 1.0 / ( json.fps || 1.0 ); + let functionNode = functionNodesCacheMap.get( shaderNode ); - for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) { + if ( functionNode === undefined ) { - tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) ); + functionNode = nodeObject( builder.buildFunctionNode( shaderNode ) ); - } + functionNodesCacheMap.set( shaderNode, functionNode ); - const clip = new this( json.name, json.duration, tracks, json.blendMode ); - clip.uuid = json.uuid; + } - return clip; + if ( builder.currentFunctionNode !== null ) { - } + builder.currentFunctionNode.includes.push( functionNode ); - static toJSON( clip ) { + } - const tracks = [], - clipTracks = clip.tracks; + result = nodeObject( functionNode.call( inputNodes ) ); - const json = { + } else { - 'name': clip.name, - 'duration': clip.duration, - 'tracks': tracks, - 'uuid': clip.uuid, - 'blendMode': clip.blendMode + const jsFunc = shaderNode.jsFunc; + const outputNode = inputNodes !== null ? jsFunc( inputNodes, builder ) : jsFunc( builder ); - }; + result = nodeObject( outputNode ); - for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) { + } - tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); + if ( shaderNode.once ) { + + properties.onceOutput = result; } - return json; + return result; } - static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) { + getOutputNode( builder ) { - const numMorphTargets = morphTargetSequence.length; - const tracks = []; + const properties = builder.getNodeProperties( this ); - for ( let i = 0; i < numMorphTargets; i ++ ) { + if ( properties.outputNode === null ) { - let times = []; - let values = []; + properties.outputNode = this.setupOutput( builder ); - times.push( - ( i + numMorphTargets - 1 ) % numMorphTargets, - i, - ( i + 1 ) % numMorphTargets ); + } - values.push( 0, 1, 0 ); + return properties.outputNode; - const order = getKeyframeOrder( times ); - times = sortedArray( times, 1, order ); - values = sortedArray( values, 1, order ); + } - // if there is a key at the first frame, duplicate it as the - // last frame as well for perfect loop. - if ( ! noLoop && times[ 0 ] === 0 ) { + setup( builder ) { - times.push( numMorphTargets ); - values.push( values[ 0 ] ); + return this.getOutputNode( builder ); - } + } - tracks.push( - new NumberKeyframeTrack( - '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', - times, values - ).scale( 1.0 / fps ) ); + setupOutput( builder ) { - } + builder.addStack(); - return new this( name, - 1, tracks ); + builder.stack.outputNode = this.call( builder ); + + return builder.removeStack(); } - static findByName( objectOrClipArray, name ) { + generate( builder, output ) { - let clipArray = objectOrClipArray; + const outputNode = this.getOutputNode( builder ); - if ( ! Array.isArray( objectOrClipArray ) ) { + return outputNode.build( builder, output ); - const o = objectOrClipArray; - clipArray = o.geometry && o.geometry.animations || o.animations; + } - } +} - for ( let i = 0; i < clipArray.length; i ++ ) { +class ShaderNodeInternal extends Node { - if ( clipArray[ i ].name === name ) { + constructor( jsFunc, nodeType ) { - return clipArray[ i ]; + super( nodeType ); - } + this.jsFunc = jsFunc; + this.layout = null; - } + this.global = true; - return null; + this.once = false; } - static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) { + setLayout( layout ) { - const animationToMorphTargets = {}; + this.layout = layout; - // tested with https://regex101.com/ on trick sequences - // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 - const pattern = /^([\w-]*?)([\d]+)$/; + return this; - // sort morph target names into animation groups based - // patterns like Walk_001, Walk_002, Run_001, Run_002 - for ( let i = 0, il = morphTargets.length; i < il; i ++ ) { + } - const morphTarget = morphTargets[ i ]; - const parts = morphTarget.name.match( pattern ); + call( inputs = null ) { - if ( parts && parts.length > 1 ) { + nodeObjects( inputs ); - const name = parts[ 1 ]; + return nodeObject( new ShaderCallNodeInternal( this, inputs ) ); - let animationMorphTargets = animationToMorphTargets[ name ]; + } - if ( ! animationMorphTargets ) { + setup() { - animationToMorphTargets[ name ] = animationMorphTargets = []; + return this.call(); - } + } - animationMorphTargets.push( morphTarget ); +} - } +const bools = [ false, true ]; +const uints = [ 0, 1, 2, 3 ]; +const ints = [ - 1, - 2 ]; +const floats = [ 0.5, 1.5, 1 / 3, 1e-6, 1e6, Math.PI, Math.PI * 2, 1 / Math.PI, 2 / Math.PI, 1 / ( Math.PI * 2 ), Math.PI / 2 ]; - } - - const clips = []; - - for ( const name in animationToMorphTargets ) { +const boolsCacheMap = new Map(); +for ( const bool of bools ) boolsCacheMap.set( bool, new ConstNode( bool ) ); - clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); +const uintsCacheMap = new Map(); +for ( const uint of uints ) uintsCacheMap.set( uint, new ConstNode( uint, 'uint' ) ); - } +const intsCacheMap = new Map( [ ...uintsCacheMap ].map( el => new ConstNode( el.value, 'int' ) ) ); +for ( const int of ints ) intsCacheMap.set( int, new ConstNode( int, 'int' ) ); - return clips; +const floatsCacheMap = new Map( [ ...intsCacheMap ].map( el => new ConstNode( el.value ) ) ); +for ( const float of floats ) floatsCacheMap.set( float, new ConstNode( float ) ); +for ( const float of floats ) floatsCacheMap.set( - float, new ConstNode( - float ) ); - } +const cacheMaps = { bool: boolsCacheMap, uint: uintsCacheMap, ints: intsCacheMap, float: floatsCacheMap }; - // parse the animation.hierarchy format - static parseAnimation( animation, bones ) { +const constNodesCacheMap = new Map( [ ...boolsCacheMap, ...floatsCacheMap ] ); - if ( ! animation ) { +const getConstNode = ( value, type ) => { - console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); - return null; + if ( constNodesCacheMap.has( value ) ) { - } + return constNodesCacheMap.get( value ); - const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { + } else if ( value.isNode === true ) { - // only return track if there are actually keys. - if ( animationKeys.length !== 0 ) { + return value; - const times = []; - const values = []; + } else { - flattenJSON( animationKeys, times, values, propertyName ); + return new ConstNode( value, type ); - // empty keys are filtered out, so check again - if ( times.length !== 0 ) { + } - destTracks.push( new trackType( trackName, times, values ) ); +}; - } +const safeGetNodeType = ( node ) => { - } + try { - }; + return node.getNodeType(); - const tracks = []; + } catch ( _ ) { - const clipName = animation.name || 'default'; - const fps = animation.fps || 30; - const blendMode = animation.blendMode; + return undefined; - // automatic length determination in AnimationClip. - let duration = animation.length || - 1; + } - const hierarchyTracks = animation.hierarchy || []; +}; - for ( let h = 0; h < hierarchyTracks.length; h ++ ) { +const ConvertType = function ( type, cacheMap = null ) { - const animationKeys = hierarchyTracks[ h ].keys; + return ( ...params ) => { - // skip empty tracks - if ( ! animationKeys || animationKeys.length === 0 ) continue; + if ( params.length === 0 || ( ! [ 'bool', 'float', 'int', 'uint' ].includes( type ) && params.every( param => typeof param !== 'object' ) ) ) { - // process morph targets - if ( animationKeys[ 0 ].morphTargets ) { + params = [ getValueFromType( type, ...params ) ]; - // figure out all morph targets used in this track - const morphTargetNames = {}; + } - let k; + if ( params.length === 1 && cacheMap !== null && cacheMap.has( params[ 0 ] ) ) { - for ( k = 0; k < animationKeys.length; k ++ ) { + return nodeObject( cacheMap.get( params[ 0 ] ) ); - if ( animationKeys[ k ].morphTargets ) { + } - for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { + if ( params.length === 1 ) { - morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; + const node = getConstNode( params[ 0 ], type ); + if ( safeGetNodeType( node ) === type ) return nodeObject( node ); + return nodeObject( new ConvertNode( node, type ) ); - } + } - } + const nodes = params.map( param => getConstNode( param ) ); + return nodeObject( new JoinNode( nodes, type ) ); - } + }; - // create a track for each morph target with all zero - // morphTargetInfluences except for the keys in which - // the morphTarget is named. - for ( const morphTargetName in morphTargetNames ) { +}; - const times = []; - const values = []; +// exports - for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { +const defined = ( v ) => typeof v === 'object' && v !== null ? v.value : v; // TODO: remove boolean conversion and defined function - const animationKey = animationKeys[ k ]; +// utils - times.push( animationKey.time ); - values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); +const getConstNodeType = ( value ) => ( value !== undefined && value !== null ) ? ( value.nodeType || value.convertTo || ( typeof value === 'string' ? value : null ) ) : null; - } +// shader node base - tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); +function ShaderNode( jsFunc, nodeType ) { - } + return new Proxy( new ShaderNodeInternal( jsFunc, nodeType ), shaderNodeHandler ); - duration = morphTargetNames.length * fps; +} - } else { +const nodeObject = ( val, altType = null ) => /* new */ ShaderNodeObject( val, altType ); +const nodeObjects = ( val, altType = null ) => new ShaderNodeObjects( val, altType ); +const nodeArray = ( val, altType = null ) => new ShaderNodeArray( val, altType ); +const nodeProxy = ( ...params ) => new ShaderNodeProxy( ...params ); +const nodeImmutable = ( ...params ) => new ShaderNodeImmutable( ...params ); - // ...assume skeletal animation +const Fn = ( jsFunc, nodeType ) => { - const boneName = '.bones[' + bones[ h ].name + ']'; + const shaderNode = new ShaderNode( jsFunc, nodeType ); - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.position', - animationKeys, 'pos', tracks ); + const fn = ( ...params ) => { - addNonemptyTrack( - QuaternionKeyframeTrack, boneName + '.quaternion', - animationKeys, 'rot', tracks ); + let inputs; - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.scale', - animationKeys, 'scl', tracks ); + nodeObjects( params ); - } + if ( params[ 0 ] && params[ 0 ].isNode ) { - } + inputs = [ ...params ]; - if ( tracks.length === 0 ) { + } else { - return null; + inputs = params[ 0 ]; } - const clip = new this( clipName, duration, tracks, blendMode ); - - return clip; - - } - - resetDuration() { - - const tracks = this.tracks; - let duration = 0; + return shaderNode.call( inputs ); - for ( let i = 0, n = tracks.length; i !== n; ++ i ) { + }; - const track = this.tracks[ i ]; + fn.shaderNode = shaderNode; - duration = Math.max( duration, track.times[ track.times.length - 1 ] ); + fn.setLayout = ( layout ) => { - } + shaderNode.setLayout( layout ); - this.duration = duration; + return fn; - return this; + }; - } + fn.once = () => { - trim() { + shaderNode.once = true; - for ( let i = 0; i < this.tracks.length; i ++ ) { + return fn; - this.tracks[ i ].trim( 0, this.duration ); + }; - } + return fn; - return this; +}; - } +const tslFn = ( ...params ) => { // @deprecated, r168 - validate() { + console.warn( 'TSL.ShaderNode: tslFn() has been renamed to Fn().' ); + return Fn( ...params ); - let valid = true; +}; - for ( let i = 0; i < this.tracks.length; i ++ ) { +// - valid = valid && this.tracks[ i ].validate(); +addMethodChaining( 'toGlobal', ( node ) => { - } + node.global = true; - return valid; + return node; - } +} ); - optimize() { +// - for ( let i = 0; i < this.tracks.length; i ++ ) { +const setCurrentStack = ( stack ) => { - this.tracks[ i ].optimize(); + currentStack = stack; - } +}; - return this; +const getCurrentStack = () => currentStack; - } +const If = ( ...params ) => currentStack.If( ...params ); - clone() { +function append( node ) { - const tracks = []; + if ( currentStack ) currentStack.add( node ); - for ( let i = 0; i < this.tracks.length; i ++ ) { + return node; - tracks.push( this.tracks[ i ].clone() ); +} - } +addMethodChaining( 'append', append ); - return new this.constructor( this.name, this.duration, tracks, this.blendMode ); +// types - } +const color = new ConvertType( 'color' ); - toJSON() { +const float = new ConvertType( 'float', cacheMaps.float ); +const int = new ConvertType( 'int', cacheMaps.ints ); +const uint = new ConvertType( 'uint', cacheMaps.uint ); +const bool = new ConvertType( 'bool', cacheMaps.bool ); - return this.constructor.toJSON( this ); +const vec2 = new ConvertType( 'vec2' ); +const ivec2 = new ConvertType( 'ivec2' ); +const uvec2 = new ConvertType( 'uvec2' ); +const bvec2 = new ConvertType( 'bvec2' ); - } +const vec3 = new ConvertType( 'vec3' ); +const ivec3 = new ConvertType( 'ivec3' ); +const uvec3 = new ConvertType( 'uvec3' ); +const bvec3 = new ConvertType( 'bvec3' ); -} +const vec4 = new ConvertType( 'vec4' ); +const ivec4 = new ConvertType( 'ivec4' ); +const uvec4 = new ConvertType( 'uvec4' ); +const bvec4 = new ConvertType( 'bvec4' ); -function getTrackTypeForValueTypeName( typeName ) { +const mat2 = new ConvertType( 'mat2' ); +const mat3 = new ConvertType( 'mat3' ); +const mat4 = new ConvertType( 'mat4' ); - switch ( typeName.toLowerCase() ) { +const string = ( value = '' ) => nodeObject( new ConstNode( value, 'string' ) ); +const arrayBuffer = ( value ) => nodeObject( new ConstNode( value, 'ArrayBuffer' ) ); - case 'scalar': - case 'double': - case 'float': - case 'number': - case 'integer': +addMethodChaining( 'toColor', color ); +addMethodChaining( 'toFloat', float ); +addMethodChaining( 'toInt', int ); +addMethodChaining( 'toUint', uint ); +addMethodChaining( 'toBool', bool ); +addMethodChaining( 'toVec2', vec2 ); +addMethodChaining( 'toIVec2', ivec2 ); +addMethodChaining( 'toUVec2', uvec2 ); +addMethodChaining( 'toBVec2', bvec2 ); +addMethodChaining( 'toVec3', vec3 ); +addMethodChaining( 'toIVec3', ivec3 ); +addMethodChaining( 'toUVec3', uvec3 ); +addMethodChaining( 'toBVec3', bvec3 ); +addMethodChaining( 'toVec4', vec4 ); +addMethodChaining( 'toIVec4', ivec4 ); +addMethodChaining( 'toUVec4', uvec4 ); +addMethodChaining( 'toBVec4', bvec4 ); +addMethodChaining( 'toMat2', mat2 ); +addMethodChaining( 'toMat3', mat3 ); +addMethodChaining( 'toMat4', mat4 ); - return NumberKeyframeTrack; +// basic nodes - case 'vector': - case 'vector2': - case 'vector3': - case 'vector4': +const element = /*@__PURE__*/ nodeProxy( ArrayElementNode ); +const convert = ( node, types ) => nodeObject( new ConvertNode( nodeObject( node ), types ) ); +const split = ( node, channels ) => nodeObject( new SplitNode( nodeObject( node ), channels ) ); - return VectorKeyframeTrack; +addMethodChaining( 'element', element ); +addMethodChaining( 'convert', convert ); - case 'color': +class UniformGroupNode extends Node { - return ColorKeyframeTrack; + static get type() { - case 'quaternion': + return 'UniformGroupNode'; - return QuaternionKeyframeTrack; + } - case 'bool': - case 'boolean': + constructor( name, shared = false, order = 1 ) { - return BooleanKeyframeTrack; + super( 'string' ); - case 'string': + this.name = name; + this.version = 0; - return StringKeyframeTrack; + this.shared = shared; + this.order = order; + this.isUniformGroup = true; } - throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); - -} - -function parseKeyframeTrack( json ) { - - if ( json.type === undefined ) { + set needsUpdate( value ) { - throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); + if ( value === true ) this.version ++; } - const trackType = getTrackTypeForValueTypeName( json.type ); - - if ( json.times === undefined ) { - - const times = [], values = []; + serialize( data ) { - flattenJSON( json.keys, times, values, 'value' ); + super.serialize( data ); - json.times = times; - json.values = values; + data.name = this.name; + data.version = this.version; + data.shared = this.shared; } - // derived classes can define a static parse method - if ( trackType.parse !== undefined ) { - - return trackType.parse( json ); + deserialize( data ) { - } else { + super.deserialize( data ); - // by default, we assume a constructor compatible with the base - return new trackType( json.name, json.times, json.values, json.interpolation ); + this.name = data.name; + this.version = data.version; + this.shared = data.shared; } } -const Cache = { +const uniformGroup = ( name ) => new UniformGroupNode( name ); +const sharedUniformGroup = ( name, order = 0 ) => new UniformGroupNode( name, true, order ); - enabled: false, +const frameGroup = /*@__PURE__*/ sharedUniformGroup( 'frame' ); +const renderGroup = /*@__PURE__*/ sharedUniformGroup( 'render' ); +const objectGroup = /*@__PURE__*/ uniformGroup( 'object' ); - files: {}, +class UniformNode extends InputNode { - add: function ( key, file ) { + static get type() { - if ( this.enabled === false ) return; + return 'UniformNode'; - // console.log( 'THREE.Cache', 'Adding key:', key ); + } - this.files[ key ] = file; + constructor( value, nodeType = null ) { - }, + super( value, nodeType ); - get: function ( key ) { + this.isUniformNode = true; - if ( this.enabled === false ) return; + this.name = ''; + this.groupNode = objectGroup; - // console.log( 'THREE.Cache', 'Checking key:', key ); + } - return this.files[ key ]; + label( name ) { - }, + this.name = name; - remove: function ( key ) { + return this; - delete this.files[ key ]; + } - }, + setGroup( group ) { - clear: function () { + this.groupNode = group; - this.files = {}; + return this; } -}; + getGroup() { -class LoadingManager { + return this.groupNode; - constructor( onLoad, onProgress, onError ) { + } - const scope = this; + getUniformHash( builder ) { - let isLoading = false; - let itemsLoaded = 0; - let itemsTotal = 0; - let urlModifier = undefined; - const handlers = []; + return this.getHash( builder ); - // Refer to #5689 for the reason why we don't set .onStart - // in the constructor + } - this.onStart = undefined; - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; + onUpdate( callback, updateType ) { - this.itemStart = function ( url ) { + const self = this.getSelf(); - itemsTotal ++; + callback = callback.bind( self ); - if ( isLoading === false ) { + return super.onUpdate( ( frame ) => { - if ( scope.onStart !== undefined ) { + const value = callback( frame, self ); - scope.onStart( url, itemsLoaded, itemsTotal ); + if ( value !== undefined ) { - } + this.value = value; } - isLoading = true; - - }; - - this.itemEnd = function ( url ) { + }, updateType ); - itemsLoaded ++; + } - if ( scope.onProgress !== undefined ) { + generate( builder, output ) { - scope.onProgress( url, itemsLoaded, itemsTotal ); + const type = this.getNodeType( builder ); - } + const hash = this.getUniformHash( builder ); - if ( itemsLoaded === itemsTotal ) { + let sharedNode = builder.getNodeFromHash( hash ); - isLoading = false; + if ( sharedNode === undefined ) { - if ( scope.onLoad !== undefined ) { + builder.setHashNode( this, hash ); - scope.onLoad(); + sharedNode = this; - } + } - } + const sharedNodeType = sharedNode.getInputType( builder ); - }; + const nodeUniform = builder.getUniformFromNode( sharedNode, sharedNodeType, builder.shaderStage, this.name || builder.context.label ); + const propertyName = builder.getPropertyName( nodeUniform ); - this.itemError = function ( url ) { + if ( builder.context.label !== undefined ) delete builder.context.label; - if ( scope.onError !== undefined ) { + return builder.format( propertyName, type, output ); - scope.onError( url ); + } - } +} - }; +const uniform = ( arg1, arg2 ) => { - this.resolveURL = function ( url ) { + const nodeType = getConstNodeType( arg2 || arg1 ); - if ( urlModifier ) { + // @TODO: get ConstNode from .traverse() in the future + const value = ( arg1 && arg1.isNode === true ) ? ( arg1.node && arg1.node.value ) || arg1.value : arg1; - return urlModifier( url ); + return nodeObject( new UniformNode( value, nodeType ) ); - } +}; - return url; +class PropertyNode extends Node { - }; + static get type() { - this.setURLModifier = function ( transform ) { + return 'PropertyNode'; - urlModifier = transform; + } - return this; + constructor( nodeType, name = null, varying = false ) { - }; + super( nodeType ); - this.addHandler = function ( regex, loader ) { + this.name = name; + this.varying = varying; - handlers.push( regex, loader ); + this.isPropertyNode = true; - return this; + } - }; + getHash( builder ) { - this.removeHandler = function ( regex ) { + return this.name || super.getHash( builder ); - const index = handlers.indexOf( regex ); + } - if ( index !== - 1 ) { + isGlobal( /*builder*/ ) { - handlers.splice( index, 2 ); + return true; - } + } - return this; + generate( builder ) { - }; + let nodeVar; - this.getHandler = function ( file ) { + if ( this.varying === true ) { - for ( let i = 0, l = handlers.length; i < l; i += 2 ) { + nodeVar = builder.getVaryingFromNode( this, this.name ); + nodeVar.needsInterpolation = true; - const regex = handlers[ i ]; - const loader = handlers[ i + 1 ]; + } else { - if ( regex.global ) regex.lastIndex = 0; // see #17920 + nodeVar = builder.getVarFromNode( this, this.name ); - if ( regex.test( file ) ) { + } - return loader; + return builder.getPropertyName( nodeVar ); - } + } - } +} - return null; +const property = ( type, name ) => nodeObject( new PropertyNode( type, name ) ); +const varyingProperty = ( type, name ) => nodeObject( new PropertyNode( type, name, true ) ); - }; +const diffuseColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec4', 'DiffuseColor' ); +const emissive = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'EmissiveColor' ); +const roughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Roughness' ); +const metalness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Metalness' ); +const clearcoat = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Clearcoat' ); +const clearcoatRoughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'ClearcoatRoughness' ); +const sheen = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'Sheen' ); +const sheenRoughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'SheenRoughness' ); +const iridescence = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Iridescence' ); +const iridescenceIOR = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IridescenceIOR' ); +const iridescenceThickness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IridescenceThickness' ); +const alphaT = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'AlphaT' ); +const anisotropy = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Anisotropy' ); +const anisotropyT = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'AnisotropyT' ); +const anisotropyB = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'AnisotropyB' ); +const specularColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'color', 'SpecularColor' ); +const specularF90 = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'SpecularF90' ); +const shininess = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Shininess' ); +const output = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec4', 'Output' ); +const dashSize = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'dashSize' ); +const gapSize = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'gapSize' ); +const pointWidth = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'pointWidth' ); +const ior = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IOR' ); +const transmission = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Transmission' ); +const thickness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Thickness' ); +const attenuationDistance = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'AttenuationDistance' ); +const attenuationColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'color', 'AttenuationColor' ); +const dispersion = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Dispersion' ); - } +class AssignNode extends TempNode { -} + static get type() { -const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager(); + return 'AssignNode'; -class Loader { + } - constructor( manager ) { + constructor( targetNode, sourceNode ) { - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + super(); - this.crossOrigin = 'anonymous'; - this.withCredentials = false; - this.path = ''; - this.resourcePath = ''; - this.requestHeader = {}; + this.targetNode = targetNode; + this.sourceNode = sourceNode; } - load( /* url, onLoad, onProgress, onError */ ) {} - - loadAsync( url, onProgress ) { + hasDependencies() { - const scope = this; + return false; - return new Promise( function ( resolve, reject ) { + } - scope.load( url, resolve, onProgress, reject ); + getNodeType( builder, output ) { - } ); + return output !== 'void' ? this.targetNode.getNodeType( builder ) : 'void'; } - parse( /* data */ ) {} + needsSplitAssign( builder ) { - setCrossOrigin( crossOrigin ) { + const { targetNode } = this; - this.crossOrigin = crossOrigin; - return this; + if ( builder.isAvailable( 'swizzleAssign' ) === false && targetNode.isSplitNode && targetNode.components.length > 1 ) { - } + const targetLength = builder.getTypeLength( targetNode.node.getNodeType( builder ) ); + const assignDiferentVector = vectorComponents.join( '' ).slice( 0, targetLength ) !== targetNode.components; - setWithCredentials( value ) { + return assignDiferentVector; - this.withCredentials = value; - return this; + } - } + return false; - setPath( path ) { + } - this.path = path; - return this; + generate( builder, output ) { - } + const { targetNode, sourceNode } = this; - setResourcePath( resourcePath ) { + const needsSplitAssign = this.needsSplitAssign( builder ); - this.resourcePath = resourcePath; - return this; + const targetType = targetNode.getNodeType( builder ); - } + const target = targetNode.context( { assign: true } ).build( builder ); + const source = sourceNode.build( builder, targetType ); - setRequestHeader( requestHeader ) { + const sourceType = sourceNode.getNodeType( builder ); - this.requestHeader = requestHeader; - return this; + const nodeData = builder.getDataFromNode( this ); - } + // -} + let snippet; -Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT'; + if ( nodeData.initialized === true ) { -const loading = {}; + if ( output !== 'void' ) { -class HttpError extends Error { + snippet = target; - constructor( message, response ) { + } - super( message ); - this.response = response; + } else if ( needsSplitAssign ) { - } + const sourceVar = builder.getVarFromNode( this, null, targetType ); + const sourceProperty = builder.getPropertyName( sourceVar ); -} + builder.addLineFlowCode( `${ sourceProperty } = ${ source }`, this ); -class FileLoader extends Loader { + const targetRoot = targetNode.node.context( { assign: true } ).build( builder ); - constructor( manager ) { + for ( let i = 0; i < targetNode.components.length; i ++ ) { - super( manager ); + const component = targetNode.components[ i ]; - } + builder.addLineFlowCode( `${ targetRoot }.${ component } = ${ sourceProperty }[ ${ i } ]`, this ); - load( url, onLoad, onProgress, onError ) { + } - if ( url === undefined ) url = ''; + if ( output !== 'void' ) { - if ( this.path !== undefined ) url = this.path + url; + snippet = target; - url = this.manager.resolveURL( url ); + } - const cached = Cache.get( url ); + } else { - if ( cached !== undefined ) { + snippet = `${ target } = ${ source }`; - this.manager.itemStart( url ); + if ( output === 'void' || sourceType === 'void' ) { - setTimeout( () => { + builder.addLineFlowCode( snippet, this ); - if ( onLoad ) onLoad( cached ); + if ( output !== 'void' ) { - this.manager.itemEnd( url ); + snippet = target; - }, 0 ); + } - return cached; + } } - // Check if request is duplicate + nodeData.initialized = true; - if ( loading[ url ] !== undefined ) { + return builder.format( snippet, targetType, output ); - loading[ url ].push( { + } - onLoad: onLoad, - onProgress: onProgress, - onError: onError +} - } ); +const assign = /*@__PURE__*/ nodeProxy( AssignNode ); - return; +addMethodChaining( 'assign', assign ); - } +class FunctionCallNode extends TempNode { - // Initialise array for duplicate requests - loading[ url ] = []; + static get type() { - loading[ url ].push( { - onLoad: onLoad, - onProgress: onProgress, - onError: onError, - } ); + return 'FunctionCallNode'; - // create request - const req = new Request( url, { - headers: new Headers( this.requestHeader ), - credentials: this.withCredentials ? 'include' : 'same-origin', - // An abort controller could be added within a future PR - } ); + } - // record states ( avoid data race ) - const mimeType = this.mimeType; - const responseType = this.responseType; + constructor( functionNode = null, parameters = {} ) { - // start the fetch - fetch( req ) - .then( response => { + super(); - if ( response.status === 200 || response.status === 0 ) { + this.functionNode = functionNode; + this.parameters = parameters; - // Some browsers return HTTP Status 0 when using non-http protocol - // e.g. 'file://' or 'data://'. Handle as success. + } - if ( response.status === 0 ) { + setParameters( parameters ) { - console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); + this.parameters = parameters; - } + return this; - // Workaround: Checking if response.body === undefined for Alipay browser #23548 + } - if ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) { + getParameters() { - return response; + return this.parameters; - } + } - const callbacks = loading[ url ]; - const reader = response.body.getReader(); + getNodeType( builder ) { - // Nginx needs X-File-Size check - // https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content - const contentLength = response.headers.get( 'X-File-Size' ) || response.headers.get( 'Content-Length' ); - const total = contentLength ? parseInt( contentLength ) : 0; - const lengthComputable = total !== 0; - let loaded = 0; + return this.functionNode.getNodeType( builder ); - // periodically read data into the new stream tracking while download progress - const stream = new ReadableStream( { - start( controller ) { + } - readData(); + generate( builder ) { - function readData() { + const params = []; - reader.read().then( ( { done, value } ) => { + const functionNode = this.functionNode; - if ( done ) { + const inputs = functionNode.getInputs( builder ); + const parameters = this.parameters; - controller.close(); + if ( Array.isArray( parameters ) ) { - } else { + for ( let i = 0; i < parameters.length; i ++ ) { - loaded += value.byteLength; + const inputNode = inputs[ i ]; + const node = parameters[ i ]; - const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } ); - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { + params.push( node.build( builder, inputNode.type ) ); - const callback = callbacks[ i ]; - if ( callback.onProgress ) callback.onProgress( event ); + } - } + } else { - controller.enqueue( value ); - readData(); + for ( const inputNode of inputs ) { - } + const node = parameters[ inputNode.name ]; - }, ( e ) => { + if ( node !== undefined ) { - controller.error( e ); + params.push( node.build( builder, inputNode.type ) ); - } ); + } else { - } + throw new Error( `FunctionCallNode: Input '${inputNode.name}' not found in FunctionNode.` ); - } + } - } ); + } - return new Response( stream ); + } - } else { + const functionName = functionNode.build( builder, 'property' ); - throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response ); + return `${functionName}( ${params.join( ', ' )} )`; - } + } - } ) - .then( response => { +} - switch ( responseType ) { +const call = ( func, ...params ) => { - case 'arraybuffer': + params = params.length > 1 || ( params[ 0 ] && params[ 0 ].isNode === true ) ? nodeArray( params ) : nodeObjects( params[ 0 ] ); - return response.arrayBuffer(); + return nodeObject( new FunctionCallNode( nodeObject( func ), params ) ); - case 'blob': +}; - return response.blob(); +addMethodChaining( 'call', call ); - case 'document': +class OperatorNode extends TempNode { - return response.text() - .then( text => { + static get type() { - const parser = new DOMParser(); - return parser.parseFromString( text, mimeType ); + return 'OperatorNode'; - } ); + } - case 'json': + constructor( op, aNode, bNode, ...params ) { - return response.json(); + super(); - default: + if ( params.length > 0 ) { - if ( mimeType === undefined ) { + let finalOp = new OperatorNode( op, aNode, bNode ); - return response.text(); + for ( let i = 0; i < params.length - 1; i ++ ) { - } else { + finalOp = new OperatorNode( op, finalOp, params[ i ] ); - // sniff encoding - const re = /charset="?([^;"\s]*)"?/i; - const exec = re.exec( mimeType ); - const label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined; - const decoder = new TextDecoder( label ); - return response.arrayBuffer().then( ab => decoder.decode( ab ) ); + } - } + aNode = finalOp; + bNode = params[ params.length - 1 ]; - } + } - } ) - .then( data => { + this.op = op; + this.aNode = aNode; + this.bNode = bNode; - // Add to cache only on HTTP success, so that we do not cache - // error response bodies as proper responses to requests. - Cache.add( url, data ); + } - const callbacks = loading[ url ]; - delete loading[ url ]; + getNodeType( builder, output ) { - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { + const op = this.op; - const callback = callbacks[ i ]; - if ( callback.onLoad ) callback.onLoad( data ); + const aNode = this.aNode; + const bNode = this.bNode; - } + const typeA = aNode.getNodeType( builder ); + const typeB = typeof bNode !== 'undefined' ? bNode.getNodeType( builder ) : null; - } ) - .catch( err => { + if ( typeA === 'void' || typeB === 'void' ) { - // Abort errors and other errors are handled the same + return 'void'; - const callbacks = loading[ url ]; + } else if ( op === '%' ) { - if ( callbacks === undefined ) { + return typeA; - // When onLoad was called and url was deleted in `loading` - this.manager.itemError( url ); - throw err; + } else if ( op === '~' || op === '&' || op === '|' || op === '^' || op === '>>' || op === '<<' ) { - } + return builder.getIntegerType( typeA ); - delete loading[ url ]; + } else if ( op === '!' || op === '==' || op === '&&' || op === '||' || op === '^^' ) { - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { + return 'bool'; - const callback = callbacks[ i ]; - if ( callback.onError ) callback.onError( err ); + } else if ( op === '<' || op === '>' || op === '<=' || op === '>=' ) { - } + const typeLength = output ? builder.getTypeLength( output ) : Math.max( builder.getTypeLength( typeA ), builder.getTypeLength( typeB ) ); - this.manager.itemError( url ); + return typeLength > 1 ? `bvec${ typeLength }` : 'bool'; - } ) - .finally( () => { + } else { - this.manager.itemEnd( url ); + if ( typeA === 'float' && builder.isMatrix( typeB ) ) { - } ); + return typeB; - this.manager.itemStart( url ); + } else if ( builder.isMatrix( typeA ) && builder.isVector( typeB ) ) { - } + // matrix x vector - setResponseType( value ) { + return builder.getVectorFromMatrix( typeA ); - this.responseType = value; - return this; + } else if ( builder.isVector( typeA ) && builder.isMatrix( typeB ) ) { - } + // vector x matrix - setMimeType( value ) { + return builder.getVectorFromMatrix( typeB ); - this.mimeType = value; - return this; + } else if ( builder.getTypeLength( typeB ) > builder.getTypeLength( typeA ) ) { - } + // anytype x anytype: use the greater length vector -} + return typeB; -class AnimationLoader extends Loader { + } - constructor( manager ) { + return typeA; - super( manager ); + } } - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { + generate( builder, output ) { - try { + const op = this.op; - onLoad( scope.parse( JSON.parse( text ) ) ); + const aNode = this.aNode; + const bNode = this.bNode; - } catch ( e ) { + const type = this.getNodeType( builder, output ); - if ( onError ) { + let typeA = null; + let typeB = null; - onError( e ); + if ( type !== 'void' ) { - } else { + typeA = aNode.getNodeType( builder ); + typeB = typeof bNode !== 'undefined' ? bNode.getNodeType( builder ) : null; - console.error( e ); + if ( op === '<' || op === '>' || op === '<=' || op === '>=' || op === '==' ) { - } + if ( builder.isVector( typeA ) ) { - scope.manager.itemError( url ); + typeB = typeA; - } + } else if ( typeA !== typeB ) { - }, onProgress, onError ); + typeA = typeB = 'float'; - } + } - parse( json ) { + } else if ( op === '>>' || op === '<<' ) { - const animations = []; + typeA = type; + typeB = builder.changeComponentType( typeB, 'uint' ); - for ( let i = 0; i < json.length; i ++ ) { + } else if ( builder.isMatrix( typeA ) && builder.isVector( typeB ) ) { - const clip = AnimationClip.parse( json[ i ] ); + // matrix x vector - animations.push( clip ); + typeB = builder.getVectorFromMatrix( typeA ); - } + } else if ( builder.isVector( typeA ) && builder.isMatrix( typeB ) ) { - return animations; + // vector x matrix - } + typeA = builder.getVectorFromMatrix( typeB ); -} + } else { -/** - * Abstract Base class to block based textures loader (dds, pvr, ...) - * - * Sub classes have to implement the parse() method which will be used in load(). - */ + // anytype x anytype -class CompressedTextureLoader extends Loader { + typeA = typeB = type; - constructor( manager ) { + } - super( manager ); + } else { - } + typeA = typeB = type; - load( url, onLoad, onProgress, onError ) { + } - const scope = this; + const a = aNode.build( builder, typeA ); + const b = typeof bNode !== 'undefined' ? bNode.build( builder, typeB ) : null; - const images = []; + const outputLength = builder.getTypeLength( output ); + const fnOpSnippet = builder.getFunctionOperator( op ); - const texture = new CompressedTexture(); + if ( output !== 'void' ) { - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setResponseType( 'arraybuffer' ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); + if ( op === '<' && outputLength > 1 ) { - let loaded = 0; + if ( builder.useComparisonMethod ) { - function loadTexture( i ) { + return builder.format( `${ builder.getMethod( 'lessThan', output ) }( ${ a }, ${ b } )`, type, output ); - loader.load( url[ i ], function ( buffer ) { + } else { - const texDatas = scope.parse( buffer, true ); + return builder.format( `( ${ a } < ${ b } )`, type, output ); - images[ i ] = { - width: texDatas.width, - height: texDatas.height, - format: texDatas.format, - mipmaps: texDatas.mipmaps - }; + } - loaded += 1; + } else if ( op === '<=' && outputLength > 1 ) { - if ( loaded === 6 ) { + if ( builder.useComparisonMethod ) { - if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter; + return builder.format( `${ builder.getMethod( 'lessThanEqual', output ) }( ${ a }, ${ b } )`, type, output ); - texture.image = images; - texture.format = texDatas.format; - texture.needsUpdate = true; + } else { - if ( onLoad ) onLoad( texture ); + return builder.format( `( ${ a } <= ${ b } )`, type, output ); } - }, onProgress, onError ); + } else if ( op === '>' && outputLength > 1 ) { - } + if ( builder.useComparisonMethod ) { - if ( Array.isArray( url ) ) { + return builder.format( `${ builder.getMethod( 'greaterThan', output ) }( ${ a }, ${ b } )`, type, output ); - for ( let i = 0, il = url.length; i < il; ++ i ) { + } else { - loadTexture( i ); - - } - - } else { - - // compressed cubemap texture stored in a single DDS file + return builder.format( `( ${ a } > ${ b } )`, type, output ); - loader.load( url, function ( buffer ) { + } - const texDatas = scope.parse( buffer, true ); + } else if ( op === '>=' && outputLength > 1 ) { - if ( texDatas.isCubemap ) { + if ( builder.useComparisonMethod ) { - const faces = texDatas.mipmaps.length / texDatas.mipmapCount; + return builder.format( `${ builder.getMethod( 'greaterThanEqual', output ) }( ${ a }, ${ b } )`, type, output ); - for ( let f = 0; f < faces; f ++ ) { + } else { - images[ f ] = { mipmaps: [] }; + return builder.format( `( ${ a } >= ${ b } )`, type, output ); - for ( let i = 0; i < texDatas.mipmapCount; i ++ ) { + } - images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); - images[ f ].format = texDatas.format; - images[ f ].width = texDatas.width; - images[ f ].height = texDatas.height; + } else if ( op === '!' || op === '~' ) { - } + return builder.format( `(${op}${a})`, typeA, output ); - } + } else if ( fnOpSnippet ) { - texture.image = images; + return builder.format( `${ fnOpSnippet }( ${ a }, ${ b } )`, type, output ); - } else { + } else { - texture.image.width = texDatas.width; - texture.image.height = texDatas.height; - texture.mipmaps = texDatas.mipmaps; + return builder.format( `( ${ a } ${ op } ${ b } )`, type, output ); - } + } - if ( texDatas.mipmapCount === 1 ) { + } else if ( typeA !== 'void' ) { - texture.minFilter = LinearFilter; + if ( fnOpSnippet ) { - } + return builder.format( `${ fnOpSnippet }( ${ a }, ${ b } )`, type, output ); - texture.format = texDatas.format; - texture.needsUpdate = true; + } else { - if ( onLoad ) onLoad( texture ); + return builder.format( `${ a } ${ op } ${ b }`, type, output ); - }, onProgress, onError ); + } } - return texture; - } -} - -class ImageLoader extends Loader { + serialize( data ) { - constructor( manager ) { + super.serialize( data ); - super( manager ); + data.op = this.op; } - load( url, onLoad, onProgress, onError ) { - - if ( this.path !== undefined ) url = this.path + url; + deserialize( data ) { - url = this.manager.resolveURL( url ); + super.deserialize( data ); - const scope = this; + this.op = data.op; - const cached = Cache.get( url ); + } - if ( cached !== undefined ) { +} - scope.manager.itemStart( url ); +const add = /*@__PURE__*/ nodeProxy( OperatorNode, '+' ); +const sub = /*@__PURE__*/ nodeProxy( OperatorNode, '-' ); +const mul = /*@__PURE__*/ nodeProxy( OperatorNode, '*' ); +const div = /*@__PURE__*/ nodeProxy( OperatorNode, '/' ); +const modInt = /*@__PURE__*/ nodeProxy( OperatorNode, '%' ); +const equal = /*@__PURE__*/ nodeProxy( OperatorNode, '==' ); +const notEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '!=' ); +const lessThan = /*@__PURE__*/ nodeProxy( OperatorNode, '<' ); +const greaterThan = /*@__PURE__*/ nodeProxy( OperatorNode, '>' ); +const lessThanEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '<=' ); +const greaterThanEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '>=' ); +const and = /*@__PURE__*/ nodeProxy( OperatorNode, '&&' ); +const or = /*@__PURE__*/ nodeProxy( OperatorNode, '||' ); +const not = /*@__PURE__*/ nodeProxy( OperatorNode, '!' ); +const xor = /*@__PURE__*/ nodeProxy( OperatorNode, '^^' ); +const bitAnd = /*@__PURE__*/ nodeProxy( OperatorNode, '&' ); +const bitNot = /*@__PURE__*/ nodeProxy( OperatorNode, '~' ); +const bitOr = /*@__PURE__*/ nodeProxy( OperatorNode, '|' ); +const bitXor = /*@__PURE__*/ nodeProxy( OperatorNode, '^' ); +const shiftLeft = /*@__PURE__*/ nodeProxy( OperatorNode, '<<' ); +const shiftRight = /*@__PURE__*/ nodeProxy( OperatorNode, '>>' ); - setTimeout( function () { +addMethodChaining( 'add', add ); +addMethodChaining( 'sub', sub ); +addMethodChaining( 'mul', mul ); +addMethodChaining( 'div', div ); +addMethodChaining( 'modInt', modInt ); +addMethodChaining( 'equal', equal ); +addMethodChaining( 'notEqual', notEqual ); +addMethodChaining( 'lessThan', lessThan ); +addMethodChaining( 'greaterThan', greaterThan ); +addMethodChaining( 'lessThanEqual', lessThanEqual ); +addMethodChaining( 'greaterThanEqual', greaterThanEqual ); +addMethodChaining( 'and', and ); +addMethodChaining( 'or', or ); +addMethodChaining( 'not', not ); +addMethodChaining( 'xor', xor ); +addMethodChaining( 'bitAnd', bitAnd ); +addMethodChaining( 'bitNot', bitNot ); +addMethodChaining( 'bitOr', bitOr ); +addMethodChaining( 'bitXor', bitXor ); +addMethodChaining( 'shiftLeft', shiftLeft ); +addMethodChaining( 'shiftRight', shiftRight ); - if ( onLoad ) onLoad( cached ); - scope.manager.itemEnd( url ); +const remainder = ( ...params ) => { // @deprecated, r168 - }, 0 ); + console.warn( 'TSL.OperatorNode: .remainder() has been renamed to .modInt().' ); + return modInt( ...params ); - return cached; +}; - } +addMethodChaining( 'remainder', remainder ); - const image = createElementNS( 'img' ); +class MathNode extends TempNode { - function onImageLoad() { + static get type() { - removeEventListeners(); + return 'MathNode'; - Cache.add( url, this ); + } - if ( onLoad ) onLoad( this ); + constructor( method, aNode, bNode = null, cNode = null ) { - scope.manager.itemEnd( url ); + super(); - } + this.method = method; - function onImageError( event ) { + this.aNode = aNode; + this.bNode = bNode; + this.cNode = cNode; - removeEventListeners(); + } - if ( onError ) onError( event ); + getInputType( builder ) { - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); + const aType = this.aNode.getNodeType( builder ); + const bType = this.bNode ? this.bNode.getNodeType( builder ) : null; + const cType = this.cNode ? this.cNode.getNodeType( builder ) : null; - } + const aLen = builder.isMatrix( aType ) ? 0 : builder.getTypeLength( aType ); + const bLen = builder.isMatrix( bType ) ? 0 : builder.getTypeLength( bType ); + const cLen = builder.isMatrix( cType ) ? 0 : builder.getTypeLength( cType ); - function removeEventListeners() { + if ( aLen > bLen && aLen > cLen ) { - image.removeEventListener( 'load', onImageLoad, false ); - image.removeEventListener( 'error', onImageError, false ); + return aType; - } + } else if ( bLen > cLen ) { - image.addEventListener( 'load', onImageLoad, false ); - image.addEventListener( 'error', onImageError, false ); + return bType; - if ( url.slice( 0, 5 ) !== 'data:' ) { + } else if ( cLen > aLen ) { - if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; + return cType; } - scope.manager.itemStart( url ); - - image.src = url; - - return image; - - } - -} - -class CubeTextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); + return aType; } - load( urls, onLoad, onProgress, onError ) { - - const texture = new CubeTexture(); - texture.colorSpace = SRGBColorSpace; - - const loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); + getNodeType( builder ) { - let loaded = 0; + const method = this.method; - function loadTexture( i ) { + if ( method === MathNode.LENGTH || method === MathNode.DISTANCE || method === MathNode.DOT ) { - loader.load( urls[ i ], function ( image ) { + return 'float'; - texture.images[ i ] = image; + } else if ( method === MathNode.CROSS ) { - loaded ++; + return 'vec3'; - if ( loaded === 6 ) { + } else if ( method === MathNode.ALL ) { - texture.needsUpdate = true; + return 'bool'; - if ( onLoad ) onLoad( texture ); + } else if ( method === MathNode.EQUALS ) { - } + return builder.changeComponentType( this.aNode.getNodeType( builder ), 'bool' ); - }, undefined, onError ); + } else if ( method === MathNode.MOD ) { - } + return this.aNode.getNodeType( builder ); - for ( let i = 0; i < urls.length; ++ i ) { + } else { - loadTexture( i ); + return this.getInputType( builder ); } - return texture; - } -} - -/** - * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) - * - * Sub classes have to implement the parse() method which will be used in load(). - */ - -class DataTextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } + generate( builder, output ) { - load( url, onLoad, onProgress, onError ) { + const method = this.method; - const scope = this; + const type = this.getNodeType( builder ); + const inputType = this.getInputType( builder ); - const texture = new DataTexture(); + const a = this.aNode; + const b = this.bNode; + const c = this.cNode; - const loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.setRequestHeader( this.requestHeader ); - loader.setPath( this.path ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( buffer ) { + const isWebGL = builder.renderer.isWebGLRenderer === true; - let texData; + if ( method === MathNode.TRANSFORM_DIRECTION ) { - try { + // dir can be either a direction vector or a normal vector + // upper-left 3x3 of matrix is assumed to be orthogonal - texData = scope.parse( buffer ); + let tA = a; + let tB = b; - } catch ( error ) { + if ( builder.isMatrix( tA.getNodeType( builder ) ) ) { - if ( onError !== undefined ) { + tB = vec4( vec3( tB ), 0.0 ); - onError( error ); + } else { - } else { + tA = vec4( vec3( tA ), 0.0 ); - console.error( error ); - return; + } - } + const mulNode = mul( tA, tB ).xyz; - } + return normalize( mulNode ).build( builder, output ); - if ( texData.image !== undefined ) { + } else if ( method === MathNode.NEGATE ) { - texture.image = texData.image; + return builder.format( '( - ' + a.build( builder, inputType ) + ' )', type, output ); - } else if ( texData.data !== undefined ) { + } else if ( method === MathNode.ONE_MINUS ) { - texture.image.width = texData.width; - texture.image.height = texData.height; - texture.image.data = texData.data; + return sub( 1.0, a ).build( builder, output ); - } + } else if ( method === MathNode.RECIPROCAL ) { - texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; - texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; + return div( 1.0, a ).build( builder, output ); - texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; - texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter; + } else if ( method === MathNode.DIFFERENCE ) { - texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; + return abs( sub( a, b ) ).build( builder, output ); - if ( texData.colorSpace !== undefined ) { + } else { - texture.colorSpace = texData.colorSpace; + const params = []; - } + if ( method === MathNode.CROSS || method === MathNode.MOD ) { - if ( texData.flipY !== undefined ) { + params.push( + a.build( builder, type ), + b.build( builder, type ) + ); - texture.flipY = texData.flipY; + } else if ( isWebGL && method === MathNode.STEP ) { - } + params.push( + a.build( builder, builder.getTypeLength( a.getNodeType( builder ) ) === 1 ? 'float' : inputType ), + b.build( builder, inputType ) + ); - if ( texData.format !== undefined ) { + } else if ( ( isWebGL && ( method === MathNode.MIN || method === MathNode.MAX ) ) || method === MathNode.MOD ) { - texture.format = texData.format; + params.push( + a.build( builder, inputType ), + b.build( builder, builder.getTypeLength( b.getNodeType( builder ) ) === 1 ? 'float' : inputType ) + ); - } + } else if ( method === MathNode.REFRACT ) { - if ( texData.type !== undefined ) { + params.push( + a.build( builder, inputType ), + b.build( builder, inputType ), + c.build( builder, 'float' ) + ); - texture.type = texData.type; + } else if ( method === MathNode.MIX ) { - } + params.push( + a.build( builder, inputType ), + b.build( builder, inputType ), + c.build( builder, builder.getTypeLength( c.getNodeType( builder ) ) === 1 ? 'float' : inputType ) + ); - if ( texData.mipmaps !== undefined ) { + } else { - texture.mipmaps = texData.mipmaps; - texture.minFilter = LinearMipmapLinearFilter; // presumably... + params.push( a.build( builder, inputType ) ); + if ( b !== null ) params.push( b.build( builder, inputType ) ); + if ( c !== null ) params.push( c.build( builder, inputType ) ); } - if ( texData.mipmapCount === 1 ) { - - texture.minFilter = LinearFilter; + return builder.format( `${ builder.getMethod( method, type ) }( ${params.join( ', ' )} )`, type, output ); - } + } - if ( texData.generateMipmaps !== undefined ) { + } - texture.generateMipmaps = texData.generateMipmaps; + serialize( data ) { - } + super.serialize( data ); - texture.needsUpdate = true; + data.method = this.method; - if ( onLoad ) onLoad( texture, texData ); + } - }, onProgress, onError ); + deserialize( data ) { + super.deserialize( data ); - return texture; + this.method = data.method; } } -class TextureLoader extends Loader { +// 1 input - constructor( manager ) { +MathNode.ALL = 'all'; +MathNode.ANY = 'any'; +MathNode.EQUALS = 'equals'; - super( manager ); +MathNode.RADIANS = 'radians'; +MathNode.DEGREES = 'degrees'; +MathNode.EXP = 'exp'; +MathNode.EXP2 = 'exp2'; +MathNode.LOG = 'log'; +MathNode.LOG2 = 'log2'; +MathNode.SQRT = 'sqrt'; +MathNode.INVERSE_SQRT = 'inversesqrt'; +MathNode.FLOOR = 'floor'; +MathNode.CEIL = 'ceil'; +MathNode.NORMALIZE = 'normalize'; +MathNode.FRACT = 'fract'; +MathNode.SIN = 'sin'; +MathNode.COS = 'cos'; +MathNode.TAN = 'tan'; +MathNode.ASIN = 'asin'; +MathNode.ACOS = 'acos'; +MathNode.ATAN = 'atan'; +MathNode.ABS = 'abs'; +MathNode.SIGN = 'sign'; +MathNode.LENGTH = 'length'; +MathNode.NEGATE = 'negate'; +MathNode.ONE_MINUS = 'oneMinus'; +MathNode.DFDX = 'dFdx'; +MathNode.DFDY = 'dFdy'; +MathNode.ROUND = 'round'; +MathNode.RECIPROCAL = 'reciprocal'; +MathNode.TRUNC = 'trunc'; +MathNode.FWIDTH = 'fwidth'; +MathNode.BITCAST = 'bitcast'; +MathNode.TRANSPOSE = 'transpose'; - } +// 2 inputs - load( url, onLoad, onProgress, onError ) { +MathNode.ATAN2 = 'atan2'; +MathNode.MIN = 'min'; +MathNode.MAX = 'max'; +MathNode.MOD = 'mod'; +MathNode.STEP = 'step'; +MathNode.REFLECT = 'reflect'; +MathNode.DISTANCE = 'distance'; +MathNode.DIFFERENCE = 'difference'; +MathNode.DOT = 'dot'; +MathNode.CROSS = 'cross'; +MathNode.POW = 'pow'; +MathNode.TRANSFORM_DIRECTION = 'transformDirection'; - const texture = new Texture(); +// 3 inputs - const loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); +MathNode.MIX = 'mix'; +MathNode.CLAMP = 'clamp'; +MathNode.REFRACT = 'refract'; +MathNode.SMOOTHSTEP = 'smoothstep'; +MathNode.FACEFORWARD = 'faceforward'; - loader.load( url, function ( image ) { +const EPSILON = /*@__PURE__*/ float( 1e-6 ); +const INFINITY = /*@__PURE__*/ float( 1e6 ); +const PI = /*@__PURE__*/ float( Math.PI ); +const PI2 = /*@__PURE__*/ float( Math.PI * 2 ); - texture.image = image; - texture.needsUpdate = true; +const all = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ALL ); +const any = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ANY ); +const equals = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EQUALS ); - if ( onLoad !== undefined ) { +const radians = /*@__PURE__*/ nodeProxy( MathNode, MathNode.RADIANS ); +const degrees = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DEGREES ); +const exp = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EXP ); +const exp2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EXP2 ); +const log = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LOG ); +const log2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LOG2 ); +const sqrt = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SQRT ); +const inverseSqrt = /*@__PURE__*/ nodeProxy( MathNode, MathNode.INVERSE_SQRT ); +const floor = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FLOOR ); +const ceil = /*@__PURE__*/ nodeProxy( MathNode, MathNode.CEIL ); +const normalize = /*@__PURE__*/ nodeProxy( MathNode, MathNode.NORMALIZE ); +const fract = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FRACT ); +const sin = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SIN ); +const cos = /*@__PURE__*/ nodeProxy( MathNode, MathNode.COS ); +const tan = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TAN ); +const asin = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ASIN ); +const acos = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ACOS ); +const atan = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ATAN ); +const abs = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ABS ); +const sign = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SIGN ); +const length = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LENGTH ); +const negate = /*@__PURE__*/ nodeProxy( MathNode, MathNode.NEGATE ); +const oneMinus = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ONE_MINUS ); +const dFdx = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DFDX ); +const dFdy = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DFDY ); +const round = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ROUND ); +const reciprocal = /*@__PURE__*/ nodeProxy( MathNode, MathNode.RECIPROCAL ); +const trunc = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRUNC ); +const fwidth = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FWIDTH ); +const bitcast = /*@__PURE__*/ nodeProxy( MathNode, MathNode.BITCAST ); +const transpose = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRANSPOSE ); - onLoad( texture ); +const atan2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ATAN2 ); +const min$1 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MIN ); +const max$1 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MAX ); +const mod = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MOD ); +const step = /*@__PURE__*/ nodeProxy( MathNode, MathNode.STEP ); +const reflect = /*@__PURE__*/ nodeProxy( MathNode, MathNode.REFLECT ); +const distance = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DISTANCE ); +const difference = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DIFFERENCE ); +const dot = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DOT ); +const cross = /*@__PURE__*/ nodeProxy( MathNode, MathNode.CROSS ); +const pow = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW ); +const pow2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 2 ); +const pow3 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 3 ); +const pow4 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 4 ); +const transformDirection = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRANSFORM_DIRECTION ); - } +const cbrt = ( a ) => mul( sign( a ), pow( abs( a ), 1.0 / 3.0 ) ); +const lengthSq = ( a ) => dot( a, a ); +const mix = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MIX ); +const clamp = ( value, low = 0, high = 1 ) => nodeObject( new MathNode( MathNode.CLAMP, nodeObject( value ), nodeObject( low ), nodeObject( high ) ) ); +const saturate = ( value ) => clamp( value ); +const refract = /*@__PURE__*/ nodeProxy( MathNode, MathNode.REFRACT ); +const smoothstep = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SMOOTHSTEP ); +const faceForward = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FACEFORWARD ); - }, onProgress, onError ); +const rand = /*@__PURE__*/ Fn( ( [ uv ] ) => { - return texture; + const a = 12.9898, b = 78.233, c = 43758.5453; + const dt = dot( uv.xy, vec2( a, b ) ), sn = mod( dt, PI ); - } + return fract( sin( sn ).mul( c ) ); -} +} ); -class Light extends Object3D { +const mixElement = ( t, e1, e2 ) => mix( e1, e2, t ); +const smoothstepElement = ( x, low, high ) => smoothstep( low, high, x ); - constructor( color, intensity = 1 ) { +addMethodChaining( 'all', all ); +addMethodChaining( 'any', any ); +addMethodChaining( 'equals', equals ); - super(); +addMethodChaining( 'radians', radians ); +addMethodChaining( 'degrees', degrees ); +addMethodChaining( 'exp', exp ); +addMethodChaining( 'exp2', exp2 ); +addMethodChaining( 'log', log ); +addMethodChaining( 'log2', log2 ); +addMethodChaining( 'sqrt', sqrt ); +addMethodChaining( 'inverseSqrt', inverseSqrt ); +addMethodChaining( 'floor', floor ); +addMethodChaining( 'ceil', ceil ); +addMethodChaining( 'normalize', normalize ); +addMethodChaining( 'fract', fract ); +addMethodChaining( 'sin', sin ); +addMethodChaining( 'cos', cos ); +addMethodChaining( 'tan', tan ); +addMethodChaining( 'asin', asin ); +addMethodChaining( 'acos', acos ); +addMethodChaining( 'atan', atan ); +addMethodChaining( 'abs', abs ); +addMethodChaining( 'sign', sign ); +addMethodChaining( 'length', length ); +addMethodChaining( 'lengthSq', lengthSq ); +addMethodChaining( 'negate', negate ); +addMethodChaining( 'oneMinus', oneMinus ); +addMethodChaining( 'dFdx', dFdx ); +addMethodChaining( 'dFdy', dFdy ); +addMethodChaining( 'round', round ); +addMethodChaining( 'reciprocal', reciprocal ); +addMethodChaining( 'trunc', trunc ); +addMethodChaining( 'fwidth', fwidth ); +addMethodChaining( 'atan2', atan2 ); +addMethodChaining( 'min', min$1 ); +addMethodChaining( 'max', max$1 ); +addMethodChaining( 'mod', mod ); +addMethodChaining( 'step', step ); +addMethodChaining( 'reflect', reflect ); +addMethodChaining( 'distance', distance ); +addMethodChaining( 'dot', dot ); +addMethodChaining( 'cross', cross ); +addMethodChaining( 'pow', pow ); +addMethodChaining( 'pow2', pow2 ); +addMethodChaining( 'pow3', pow3 ); +addMethodChaining( 'pow4', pow4 ); +addMethodChaining( 'transformDirection', transformDirection ); +addMethodChaining( 'mix', mixElement ); +addMethodChaining( 'clamp', clamp ); +addMethodChaining( 'refract', refract ); +addMethodChaining( 'smoothstep', smoothstepElement ); +addMethodChaining( 'faceForward', faceForward ); +addMethodChaining( 'difference', difference ); +addMethodChaining( 'saturate', saturate ); +addMethodChaining( 'cbrt', cbrt ); +addMethodChaining( 'transpose', transpose ); +addMethodChaining( 'rand', rand ); - this.isLight = true; +class ConditionalNode extends Node { - this.type = 'Light'; + static get type() { - this.color = new Color( color ); - this.intensity = intensity; + return 'ConditionalNode'; } - dispose() { + constructor( condNode, ifNode, elseNode = null ) { - // Empty here in base class; some subclasses override. + super(); + + this.condNode = condNode; + + this.ifNode = ifNode; + this.elseNode = elseNode; } - copy( source, recursive ) { + getNodeType( builder ) { - super.copy( source, recursive ); + const ifType = this.ifNode.getNodeType( builder ); - this.color.copy( source.color ); - this.intensity = source.intensity; + if ( this.elseNode !== null ) { - return this; + const elseType = this.elseNode.getNodeType( builder ); + + if ( builder.getTypeLength( elseType ) > builder.getTypeLength( ifType ) ) { + + return elseType; + + } + + } + + return ifType; } - toJSON( meta ) { + setup( builder ) { - const data = super.toJSON( meta ); + const condNode = this.condNode.cache(); + const ifNode = this.ifNode.cache(); + const elseNode = this.elseNode ? this.elseNode.cache() : null; - data.object.color = this.color.getHex(); - data.object.intensity = this.intensity; + // - if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); + const currentNodeBlock = builder.context.nodeBlock; - if ( this.distance !== undefined ) data.object.distance = this.distance; - if ( this.angle !== undefined ) data.object.angle = this.angle; - if ( this.decay !== undefined ) data.object.decay = this.decay; - if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; + builder.getDataFromNode( ifNode ).parentNodeBlock = currentNodeBlock; + if ( elseNode !== null ) builder.getDataFromNode( elseNode ).parentNodeBlock = currentNodeBlock; - if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); - if ( this.target !== undefined ) data.object.target = this.target.uuid; + // - return data; + const properties = builder.getNodeProperties( this ); + properties.condNode = condNode; + properties.ifNode = ifNode.context( { nodeBlock: ifNode } ); + properties.elseNode = elseNode ? elseNode.context( { nodeBlock: elseNode } ) : null; } -} + generate( builder, output ) { -class HemisphereLight extends Light { + const type = this.getNodeType( builder ); - constructor( skyColor, groundColor, intensity ) { + const nodeData = builder.getDataFromNode( this ); - super( skyColor, intensity ); + if ( nodeData.nodeProperty !== undefined ) { - this.isHemisphereLight = true; + return nodeData.nodeProperty; - this.type = 'HemisphereLight'; + } - this.position.copy( Object3D.DEFAULT_UP ); - this.updateMatrix(); + const { condNode, ifNode, elseNode } = builder.getNodeProperties( this ); - this.groundColor = new Color( groundColor ); + const needsOutput = output !== 'void'; + const nodeProperty = needsOutput ? property( type ).build( builder ) : ''; - } + nodeData.nodeProperty = nodeProperty; - copy( source, recursive ) { + const nodeSnippet = condNode.build( builder, 'bool' ); - super.copy( source, recursive ); + builder.addFlowCode( `\n${ builder.tab }if ( ${ nodeSnippet } ) {\n\n` ).addFlowTab(); - this.groundColor.copy( source.groundColor ); + let ifSnippet = ifNode.build( builder, type ); - return this; + if ( ifSnippet ) { - } + if ( needsOutput ) { -} + ifSnippet = nodeProperty + ' = ' + ifSnippet + ';'; -const _projScreenMatrix$2 = /*@__PURE__*/ new Matrix4(); -const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3(); -const _lookTarget$1 = /*@__PURE__*/ new Vector3(); + } else { -class LightShadow { + ifSnippet = 'return ' + ifSnippet + ';'; - constructor( camera ) { + } - this.camera = camera; + } - this.intensity = 1; + builder.removeFlowTab().addFlowCode( builder.tab + '\t' + ifSnippet + '\n\n' + builder.tab + '}' ); - this.bias = 0; - this.normalBias = 0; - this.radius = 1; - this.blurSamples = 8; + if ( elseNode !== null ) { - this.mapSize = new Vector2( 512, 512 ); + builder.addFlowCode( ' else {\n\n' ).addFlowTab(); - this.map = null; - this.mapPass = null; - this.matrix = new Matrix4(); + let elseSnippet = elseNode.build( builder, type ); - this.autoUpdate = true; - this.needsUpdate = false; + if ( elseSnippet ) { - this._frustum = new Frustum(); - this._frameExtents = new Vector2( 1, 1 ); + if ( needsOutput ) { - this._viewportCount = 1; + elseSnippet = nodeProperty + ' = ' + elseSnippet + ';'; - this._viewports = [ + } else { - new Vector4( 0, 0, 1, 1 ) + elseSnippet = 'return ' + elseSnippet + ';'; - ]; + } - } + } - getViewportCount() { + builder.removeFlowTab().addFlowCode( builder.tab + '\t' + elseSnippet + '\n\n' + builder.tab + '}\n\n' ); - return this._viewportCount; + } else { - } + builder.addFlowCode( '\n\n' ); - getFrustum() { + } - return this._frustum; + return builder.format( nodeProperty, type, output ); } - updateMatrices( light ) { +} - const shadowCamera = this.camera; - const shadowMatrix = this.matrix; +const select = /*@__PURE__*/ nodeProxy( ConditionalNode ); - _lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld ); - shadowCamera.position.copy( _lightPositionWorld$1 ); +addMethodChaining( 'select', select ); - _lookTarget$1.setFromMatrixPosition( light.target.matrixWorld ); - shadowCamera.lookAt( _lookTarget$1 ); - shadowCamera.updateMatrixWorld(); +// - _projScreenMatrix$2.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); - this._frustum.setFromProjectionMatrix( _projScreenMatrix$2 ); +const cond = ( ...params ) => { // @deprecated, r168 - shadowMatrix.set( - 0.5, 0.0, 0.0, 0.5, - 0.0, 0.5, 0.0, 0.5, - 0.0, 0.0, 0.5, 0.5, - 0.0, 0.0, 0.0, 1.0 - ); + console.warn( 'TSL.ConditionalNode: cond() has been renamed to select().' ); + return select( ...params ); - shadowMatrix.multiply( _projScreenMatrix$2 ); +}; - } +addMethodChaining( 'cond', cond ); - getViewport( viewportIndex ) { +class ContextNode extends Node { - return this._viewports[ viewportIndex ]; + static get type() { + + return 'ContextNode'; } - getFrameExtents() { + constructor( node, value = {} ) { - return this._frameExtents; + super(); - } + this.isContextNode = true; - dispose() { + this.node = node; + this.value = value; - if ( this.map ) { + } - this.map.dispose(); + getScope() { - } + return this.node.getScope(); - if ( this.mapPass ) { + } - this.mapPass.dispose(); + getNodeType( builder ) { - } + return this.node.getNodeType( builder ); } - copy( source ) { + analyze( builder ) { - this.camera = source.camera.clone(); + this.node.build( builder ); - this.intensity = source.intensity; + } - this.bias = source.bias; - this.radius = source.radius; + setup( builder ) { - this.mapSize.copy( source.mapSize ); + const previousContext = builder.getContext(); - return this; + builder.setContext( { ...builder.context, ...this.value } ); - } + const node = this.node.build( builder ); - clone() { + builder.setContext( previousContext ); - return new this.constructor().copy( this ); + return node; } - toJSON() { + generate( builder, output ) { - const object = {}; + const previousContext = builder.getContext(); - if ( this.intensity !== 1 ) object.intensity = this.intensity; - if ( this.bias !== 0 ) object.bias = this.bias; - if ( this.normalBias !== 0 ) object.normalBias = this.normalBias; - if ( this.radius !== 1 ) object.radius = this.radius; - if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); + builder.setContext( { ...builder.context, ...this.value } ); - object.camera = this.camera.toJSON( false ).object; - delete object.camera.matrix; + const snippet = this.node.build( builder, output ); - return object; + builder.setContext( previousContext ); + + return snippet; } } -class SpotLightShadow extends LightShadow { +const context = /*@__PURE__*/ nodeProxy( ContextNode ); +const label = ( node, name ) => context( node, { label: name } ); - constructor() { +addMethodChaining( 'context', context ); +addMethodChaining( 'label', label ); - super( new PerspectiveCamera( 50, 1, 0.5, 500 ) ); +class VarNode extends Node { - this.isSpotLightShadow = true; + static get type() { - this.focus = 1; + return 'VarNode'; } - updateMatrices( light ) { - - const camera = this.camera; - - const fov = RAD2DEG * 2 * light.angle * this.focus; - const aspect = this.mapSize.width / this.mapSize.height; - const far = light.distance || camera.far; + constructor( node, name = null ) { - if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { + super(); - camera.fov = fov; - camera.aspect = aspect; - camera.far = far; - camera.updateProjectionMatrix(); + this.node = node; + this.name = name; - } + this.global = true; - super.updateMatrices( light ); + this.isVarNode = true; } - copy( source ) { + getHash( builder ) { - super.copy( source ); + return this.name || super.getHash( builder ); - this.focus = source.focus; + } - return this; + getNodeType( builder ) { + + return this.node.getNodeType( builder ); } -} + generate( builder ) { -class SpotLight extends Light { + const { node, name } = this; - constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2 ) { + const nodeVar = builder.getVarFromNode( this, name, builder.getVectorType( this.getNodeType( builder ) ) ); - super( color, intensity ); + const propertyName = builder.getPropertyName( nodeVar ); - this.isSpotLight = true; + const snippet = node.build( builder, nodeVar.type ); - this.type = 'SpotLight'; + builder.addLineFlowCode( `${propertyName} = ${snippet}`, this ); - this.position.copy( Object3D.DEFAULT_UP ); - this.updateMatrix(); + return propertyName; - this.target = new Object3D(); + } - this.distance = distance; - this.angle = angle; - this.penumbra = penumbra; - this.decay = decay; +} - this.map = null; +const temp = /*@__PURE__*/ nodeProxy( VarNode ); - this.shadow = new SpotLightShadow(); +addMethodChaining( 'temp', temp ); // @TODO: Will be removed in the future +addMethodChaining( 'toVar', ( ...params ) => temp( ...params ).append() ); - } +class VaryingNode extends Node { - get power() { + static get type() { - // compute the light's luminous power (in lumens) from its intensity (in candela) - // by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd) - return this.intensity * Math.PI; + return 'VaryingNode'; } - set power( power ) { + constructor( node, name = null ) { - // set the light's intensity (in candela) from the desired luminous power (in lumens) - this.intensity = power / Math.PI; + super(); + + this.node = node; + this.name = name; + + this.isVaryingNode = true; } - dispose() { + isGlobal() { - this.shadow.dispose(); + return true; } - copy( source, recursive ) { + getHash( builder ) { - super.copy( source, recursive ); + return this.name || super.getHash( builder ); - this.distance = source.distance; - this.angle = source.angle; - this.penumbra = source.penumbra; - this.decay = source.decay; + } - this.target = source.target.clone(); + getNodeType( builder ) { - this.shadow = source.shadow.clone(); + // VaryingNode is auto type - return this; + return this.node.getNodeType( builder ); } -} + setupVarying( builder ) { -const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4(); -const _lightPositionWorld = /*@__PURE__*/ new Vector3(); -const _lookTarget = /*@__PURE__*/ new Vector3(); + const properties = builder.getNodeProperties( this ); -class PointLightShadow extends LightShadow { + let varying = properties.varying; - constructor() { + if ( varying === undefined ) { - super( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); + const name = this.name; + const type = this.getNodeType( builder ); - this.isPointLightShadow = true; + properties.varying = varying = builder.getVaryingFromNode( this, name, type ); + properties.node = this.node; - this._frameExtents = new Vector2( 4, 2 ); + } - this._viewportCount = 6; + // this property can be used to check if the varying can be optimized for a variable + varying.needsInterpolation || ( varying.needsInterpolation = ( builder.shaderStage === 'fragment' ) ); - this._viewports = [ - // These viewports map a cube-map onto a 2D texture with the - // following orientation: - // - // xzXZ - // y Y - // - // X - Positive x direction - // x - Negative x direction - // Y - Positive y direction - // y - Negative y direction - // Z - Positive z direction - // z - Negative z direction + return varying; - // positive X - new Vector4( 2, 1, 1, 1 ), - // negative X - new Vector4( 0, 1, 1, 1 ), - // positive Z - new Vector4( 3, 1, 1, 1 ), - // negative Z - new Vector4( 1, 1, 1, 1 ), - // positive Y - new Vector4( 3, 0, 1, 1 ), - // negative Y - new Vector4( 1, 0, 1, 1 ) - ]; + } - this._cubeDirections = [ - new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ), - new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 ) - ]; + setup( builder ) { - this._cubeUps = [ - new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), - new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 ) - ]; + this.setupVarying( builder ); } - updateMatrices( light, viewportIndex = 0 ) { + analyze( builder ) { - const camera = this.camera; - const shadowMatrix = this.matrix; + this.setupVarying( builder ); - const far = light.distance || camera.far; + return this.node.analyze( builder ); - if ( far !== camera.far ) { + } - camera.far = far; - camera.updateProjectionMatrix(); + generate( builder ) { - } + const properties = builder.getNodeProperties( this ); + const varying = this.setupVarying( builder ); - _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); - camera.position.copy( _lightPositionWorld ); + if ( properties.propertyName === undefined ) { - _lookTarget.copy( camera.position ); - _lookTarget.add( this._cubeDirections[ viewportIndex ] ); - camera.up.copy( this._cubeUps[ viewportIndex ] ); - camera.lookAt( _lookTarget ); - camera.updateMatrixWorld(); + const type = this.getNodeType( builder ); + const propertyName = builder.getPropertyName( varying, NodeShaderStage.VERTEX ); - shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); + // force node run in vertex stage + builder.flowNodeFromShaderStage( NodeShaderStage.VERTEX, this.node, type, propertyName ); - _projScreenMatrix$1.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 ); + properties.propertyName = propertyName; + + } + + return builder.getPropertyName( varying ); } } -class PointLight extends Light { - - constructor( color, intensity, distance = 0, decay = 2 ) { +const varying = /*@__PURE__*/ nodeProxy( VaryingNode ); - super( color, intensity ); +addMethodChaining( 'varying', varying ); - this.isPointLight = true; +const WORKING_COLOR_SPACE = 'WorkingColorSpace'; +const OUTPUT_COLOR_SPACE = 'OutputColorSpace'; - this.type = 'PointLight'; +function getColorSpaceName( colorSpace ) { - this.distance = distance; - this.decay = decay; + let method = null; - this.shadow = new PointLightShadow(); + if ( colorSpace === LinearSRGBColorSpace ) { - } + method = 'Linear'; - get power() { + } else if ( colorSpace === SRGBColorSpace ) { - // compute the light's luminous power (in lumens) from its intensity (in candela) - // for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd) - return this.intensity * 4 * Math.PI; + method = 'sRGB'; } - set power( power ) { + return method; - // set the light's intensity (in candela) from the desired luminous power (in lumens) - this.intensity = power / ( 4 * Math.PI ); +} - } +function getColorSpaceMethod( source, target ) { - dispose() { + return getColorSpaceName( source ) + 'To' + getColorSpaceName( target ); - this.shadow.dispose(); +} - } +class ColorSpaceNode extends TempNode { - copy( source, recursive ) { + static get type() { - super.copy( source, recursive ); + return 'ColorSpaceNode'; - this.distance = source.distance; - this.decay = source.decay; + } - this.shadow = source.shadow.clone(); + constructor( colorNode, source, target ) { - return this; + super( 'vec4' ); + + this.colorNode = colorNode; + this.source = source; + this.target = target; } -} + getColorSpace( builder, colorSpace ) { -class OrthographicCamera extends Camera { + if ( colorSpace === WORKING_COLOR_SPACE ) { - constructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) { + return ColorManagement.workingColorSpace; - super(); + } else if ( colorSpace === OUTPUT_COLOR_SPACE ) { - this.isOrthographicCamera = true; + return builder.context.outputColorSpace || builder.renderer.outputColorSpace; - this.type = 'OrthographicCamera'; + } - this.zoom = 1; - this.view = null; + return colorSpace; - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; + } - this.near = near; - this.far = far; + setup( builder ) { - this.updateProjectionMatrix(); + const { renderer } = builder; + const { colorNode } = this; - } + const source = this.getColorSpace( builder, this.source ); + const target = this.getColorSpace( builder, this.target ); - copy( source, recursive ) { + if ( source === target ) return colorNode; - super.copy( source, recursive ); + const colorSpace = getColorSpaceMethod( source, target ); - this.left = source.left; - this.right = source.right; - this.top = source.top; - this.bottom = source.bottom; - this.near = source.near; - this.far = source.far; + let outputNode = null; - this.zoom = source.zoom; - this.view = source.view === null ? null : Object.assign( {}, source.view ); + const colorSpaceFn = renderer.nodes.library.getColorSpaceFunction( colorSpace ); - return this; + if ( colorSpaceFn !== null ) { - } + outputNode = vec4( colorSpaceFn( colorNode.rgb ), colorNode.a ); - setViewOffset( fullWidth, fullHeight, x, y, width, height ) { + } else { - if ( this.view === null ) { + console.error( 'ColorSpaceNode: Unsupported Color Space configuration.', colorSpace ); - this.view = { - enabled: true, - fullWidth: 1, - fullHeight: 1, - offsetX: 0, - offsetY: 0, - width: 1, - height: 1 - }; + outputNode = colorNode; } - this.view.enabled = true; - this.view.fullWidth = fullWidth; - this.view.fullHeight = fullHeight; - this.view.offsetX = x; - this.view.offsetY = y; - this.view.width = width; - this.view.height = height; - - this.updateProjectionMatrix(); + return outputNode; } - clearViewOffset() { - - if ( this.view !== null ) { - - this.view.enabled = false; +} - } +const toOutputColorSpace = ( node ) => nodeObject( new ColorSpaceNode( nodeObject( node ), WORKING_COLOR_SPACE, OUTPUT_COLOR_SPACE ) ); +const toWorkingColorSpace = ( node ) => nodeObject( new ColorSpaceNode( nodeObject( node ), OUTPUT_COLOR_SPACE, WORKING_COLOR_SPACE ) ); - this.updateProjectionMatrix(); +const workingToColorSpace = ( node, colorSpace ) => nodeObject( new ColorSpaceNode( nodeObject( node ), WORKING_COLOR_SPACE, colorSpace ) ); +const colorSpaceToWorking = ( node, colorSpace ) => nodeObject( new ColorSpaceNode( nodeObject( node ), colorSpace, WORKING_COLOR_SPACE ) ); - } +addMethodChaining( 'toOutputColorSpace', toOutputColorSpace ); +addMethodChaining( 'toWorkingColorSpace', toWorkingColorSpace ); - updateProjectionMatrix() { +addMethodChaining( 'workingToColorSpace', workingToColorSpace ); +addMethodChaining( 'colorSpaceToWorking', colorSpaceToWorking ); - const dx = ( this.right - this.left ) / ( 2 * this.zoom ); - const dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); - const cx = ( this.right + this.left ) / 2; - const cy = ( this.top + this.bottom ) / 2; +let ReferenceElementNode$1 = class ReferenceElementNode extends ArrayElementNode { - let left = cx - dx; - let right = cx + dx; - let top = cy + dy; - let bottom = cy - dy; + static get type() { - if ( this.view !== null && this.view.enabled ) { + return 'ReferenceElementNode'; - const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom; - const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom; + } - left += scaleW * this.view.offsetX; - right = left + scaleW * this.view.width; - top -= scaleH * this.view.offsetY; - bottom = top - scaleH * this.view.height; + constructor( referenceNode, indexNode ) { - } + super( referenceNode, indexNode ); - this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem ); + this.referenceNode = referenceNode; - this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); + this.isReferenceElementNode = true; } - toJSON( meta ) { + getNodeType() { - const data = super.toJSON( meta ); + return this.referenceNode.uniformType; - data.object.zoom = this.zoom; - data.object.left = this.left; - data.object.right = this.right; - data.object.top = this.top; - data.object.bottom = this.bottom; - data.object.near = this.near; - data.object.far = this.far; + } - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); + generate( builder ) { - return data; + const snippet = super.generate( builder ); + const arrayType = this.referenceNode.getNodeType(); + const elementType = this.getNodeType(); - } + return builder.format( snippet, arrayType, elementType ); -} + } -class DirectionalLightShadow extends LightShadow { +}; - constructor() { +class ReferenceBaseNode extends Node { - super( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); + static get type() { - this.isDirectionalLightShadow = true; + return 'ReferenceBaseNode'; } -} + constructor( property, uniformType, object = null, count = null ) { -class DirectionalLight extends Light { + super(); - constructor( color, intensity ) { + this.property = property; + this.uniformType = uniformType; + this.object = object; + this.count = count; - super( color, intensity ); + this.properties = property.split( '.' ); + this.reference = object; + this.node = null; + this.group = null; - this.isDirectionalLight = true; + this.updateType = NodeUpdateType.OBJECT; - this.type = 'DirectionalLight'; + } - this.position.copy( Object3D.DEFAULT_UP ); - this.updateMatrix(); + setGroup( group ) { - this.target = new Object3D(); + this.group = group; - this.shadow = new DirectionalLightShadow(); + return this; } - dispose() { + element( indexNode ) { - this.shadow.dispose(); + return nodeObject( new ReferenceElementNode$1( this, nodeObject( indexNode ) ) ); } - copy( source ) { + setNodeType( uniformType ) { - super.copy( source ); + const node = uniform( null, uniformType ).getSelf(); - this.target = source.target.clone(); - this.shadow = source.shadow.clone(); + if ( this.group !== null ) { - return this; + node.setGroup( this.group ); - } + } -} + this.node = node; -class AmbientLight extends Light { + } - constructor( color, intensity ) { + getNodeType( builder ) { - super( color, intensity ); + if ( this.node === null ) { - this.isAmbientLight = true; + this.updateReference( builder ); + this.updateValue(); - this.type = 'AmbientLight'; + } + + return this.node.getNodeType( builder ); } -} + getValueFromReference( object = this.reference ) { -class RectAreaLight extends Light { + const { properties } = this; - constructor( color, intensity, width = 10, height = 10 ) { + let value = object[ properties[ 0 ] ]; - super( color, intensity ); + for ( let i = 1; i < properties.length; i ++ ) { - this.isRectAreaLight = true; + value = value[ properties[ i ] ]; - this.type = 'RectAreaLight'; + } - this.width = width; - this.height = height; + return value; } - get power() { + updateReference( state ) { - // compute the light's luminous power (in lumens) from its intensity (in nits) - return this.intensity * this.width * this.height * Math.PI; + this.reference = this.object !== null ? this.object : state.object; + + return this.reference; } - set power( power ) { + setup() { - // set the light's intensity (in nits) from the desired luminous power (in lumens) - this.intensity = power / ( this.width * this.height * Math.PI ); + this.updateValue(); + + return this.node; } - copy( source ) { + update( /*frame*/ ) { - super.copy( source ); + this.updateValue(); - this.width = source.width; - this.height = source.height; + } - return this; + updateValue() { - } + if ( this.node === null ) this.setNodeType( this.uniformType ); - toJSON( meta ) { + const value = this.getValueFromReference(); - const data = super.toJSON( meta ); + if ( Array.isArray( value ) ) { - data.object.width = this.width; - data.object.height = this.height; + this.node.array = value; - return data; + } else { + + this.node.value = value; + + } } } -/** - * Primary reference: - * https://graphics.stanford.edu/papers/envmap/envmap.pdf - * - * Secondary reference: - * https://www.ppsloan.org/publications/StupidSH36.pdf - */ +const reference$1 = ( name, type, object ) => nodeObject( new ReferenceBaseNode( name, type, object ) ); -// 3-band SH defined by 9 coefficients +class RendererReferenceNode extends ReferenceBaseNode { -class SphericalHarmonics3 { + static get type() { - constructor() { + return 'RendererReferenceNode'; - this.isSphericalHarmonics3 = true; + } - this.coefficients = []; + constructor( property, inputType, renderer = null ) { - for ( let i = 0; i < 9; i ++ ) { + super( property, inputType, renderer ); - this.coefficients.push( new Vector3() ); + this.renderer = renderer; - } + this.setGroup( renderGroup ); } - set( coefficients ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].copy( coefficients[ i ] ); + updateReference( state ) { - } + this.reference = this.renderer !== null ? this.renderer : state.renderer; - return this; + return this.reference; } - zero() { +} - for ( let i = 0; i < 9; i ++ ) { +const rendererReference = ( name, type, renderer ) => nodeObject( new RendererReferenceNode( name, type, renderer ) ); - this.coefficients[ i ].set( 0, 0, 0 ); +class ToneMappingNode extends TempNode { - } + static get type() { - return this; + return 'ToneMappingNode'; } - // get the radiance in the direction of the normal - // target is a Vector3 - getAt( normal, target ) { - - // normal is assumed to be unit length + constructor( toneMapping, exposureNode = toneMappingExposure, colorNode = null ) { - const x = normal.x, y = normal.y, z = normal.z; + super( 'vec3' ); - const coeff = this.coefficients; + this.toneMapping = toneMapping; - // band 0 - target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 ); + this.exposureNode = exposureNode; + this.colorNode = colorNode; - // band 1 - target.addScaledVector( coeff[ 1 ], 0.488603 * y ); - target.addScaledVector( coeff[ 2 ], 0.488603 * z ); - target.addScaledVector( coeff[ 3 ], 0.488603 * x ); + } - // band 2 - target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) ); - target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) ); - target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) ); - target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) ); - target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) ); + getCacheKey() { - return target; + return hash$1( super.getCacheKey(), this.toneMapping ); } - // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal - // target is a Vector3 - // https://graphics.stanford.edu/papers/envmap/envmap.pdf - getIrradianceAt( normal, target ) { - - // normal is assumed to be unit length - - const x = normal.x, y = normal.y, z = normal.z; + setup( builder ) { - const coeff = this.coefficients; + const colorNode = this.colorNode || builder.context.color; + const toneMapping = this.toneMapping; - // band 0 - target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095 + if ( toneMapping === NoToneMapping ) return colorNode; - // band 1 - target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603 - target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z ); - target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x ); + let outputNode = null; - // band 2 - target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548 - target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z ); - target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3 - target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z ); - target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274 + const toneMappingFn = builder.renderer.nodes.library.getToneMappingFunction( toneMapping ); - return target; + if ( toneMappingFn !== null ) { - } + outputNode = vec4( toneMappingFn( colorNode.rgb, this.exposureNode ), colorNode.a ); - add( sh ) { + } else { - for ( let i = 0; i < 9; i ++ ) { + console.error( 'ToneMappingNode: Unsupported Tone Mapping configuration.', toneMapping ); - this.coefficients[ i ].add( sh.coefficients[ i ] ); + outputNode = colorNode; } - return this; + return outputNode; } - addScaledSH( sh, s ) { +} - for ( let i = 0; i < 9; i ++ ) { +const toneMapping = ( mapping, exposure, color ) => nodeObject( new ToneMappingNode( mapping, nodeObject( exposure ), nodeObject( color ) ) ); +const toneMappingExposure = /*@__PURE__*/ rendererReference( 'toneMappingExposure', 'float' ); - this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s ); +addMethodChaining( 'toneMapping', ( color, mapping, exposure ) => toneMapping( mapping, exposure, color ) ); - } +class BufferAttributeNode extends InputNode { - return this; + static get type() { + + return 'BufferAttributeNode'; } - scale( s ) { + constructor( value, bufferType = null, bufferStride = 0, bufferOffset = 0 ) { - for ( let i = 0; i < 9; i ++ ) { + super( value, bufferType ); - this.coefficients[ i ].multiplyScalar( s ); + this.isBufferNode = true; - } + this.bufferType = bufferType; + this.bufferStride = bufferStride; + this.bufferOffset = bufferOffset; - return this; + this.usage = StaticDrawUsage; + this.instanced = false; - } + this.attribute = null; - lerp( sh, alpha ) { + this.global = true; - for ( let i = 0; i < 9; i ++ ) { + if ( value && value.isBufferAttribute === true ) { - this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha ); + this.attribute = value; + this.usage = value.usage; + this.instanced = value.isInstancedBufferAttribute; } - return this; - } - equals( sh ) { + getHash( builder ) { - for ( let i = 0; i < 9; i ++ ) { + if ( this.bufferStride === 0 && this.bufferOffset === 0 ) { - if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) { + let bufferData = builder.globalCache.getData( this.value ); - return false; + if ( bufferData === undefined ) { + + bufferData = { + node: this + }; + + builder.globalCache.setData( this.value, bufferData ); } + return bufferData.node.uuid; + } - return true; + return this.uuid; } - copy( sh ) { + getNodeType( builder ) { - return this.set( sh.coefficients ); + if ( this.bufferType === null ) { - } + this.bufferType = builder.getTypeFromAttribute( this.attribute ); - clone() { + } - return new this.constructor().copy( this ); + return this.bufferType; } - fromArray( array, offset = 0 ) { + setup( builder ) { - const coefficients = this.coefficients; + if ( this.attribute !== null ) return; - for ( let i = 0; i < 9; i ++ ) { + const type = this.getNodeType( builder ); + const array = this.value; + const itemSize = builder.getTypeLength( type ); + const stride = this.bufferStride || itemSize; + const offset = this.bufferOffset; - coefficients[ i ].fromArray( array, offset + ( i * 3 ) ); + const buffer = array.isInterleavedBuffer === true ? array : new InterleavedBuffer( array, stride ); + const bufferAttribute = new InterleavedBufferAttribute( buffer, itemSize, offset ); - } + buffer.setUsage( this.usage ); - return this; + this.attribute = bufferAttribute; + this.attribute.isInstancedBufferAttribute = this.instanced; // @TODO: Add a possible: InstancedInterleavedBufferAttribute } - toArray( array = [], offset = 0 ) { - - const coefficients = this.coefficients; + generate( builder ) { - for ( let i = 0; i < 9; i ++ ) { + const nodeType = this.getNodeType( builder ); - coefficients[ i ].toArray( array, offset + ( i * 3 ) ); + const nodeAttribute = builder.getBufferAttributeFromNode( this, nodeType ); + const propertyName = builder.getPropertyName( nodeAttribute ); - } + let output = null; - return array; + if ( builder.shaderStage === 'vertex' || builder.shaderStage === 'compute' ) { - } + this.name = propertyName; - // evaluate the basis functions - // shBasis is an Array[ 9 ] - static getBasisAt( normal, shBasis ) { + output = propertyName; - // normal is assumed to be unit length + } else { - const x = normal.x, y = normal.y, z = normal.z; + const nodeVarying = varying( this ); - // band 0 - shBasis[ 0 ] = 0.282095; + output = nodeVarying.build( builder, nodeType ); - // band 1 - shBasis[ 1 ] = 0.488603 * y; - shBasis[ 2 ] = 0.488603 * z; - shBasis[ 3 ] = 0.488603 * x; + } - // band 2 - shBasis[ 4 ] = 1.092548 * x * y; - shBasis[ 5 ] = 1.092548 * y * z; - shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 ); - shBasis[ 7 ] = 1.092548 * x * z; - shBasis[ 8 ] = 0.546274 * ( x * x - y * y ); + return output; } -} - -class LightProbe extends Light { - - constructor( sh = new SphericalHarmonics3(), intensity = 1 ) { + getInputType( /*builder*/ ) { - super( undefined, intensity ); + return 'bufferAttribute'; - this.isLightProbe = true; + } - this.sh = sh; + setUsage( value ) { - } + this.usage = value; - copy( source ) { + if ( this.attribute && this.attribute.isBufferAttribute === true ) { - super.copy( source ); + this.attribute.usage = value; - this.sh.copy( source.sh ); + } return this; } - fromJSON( json ) { + setInstanced( value ) { - this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON(); - this.sh.fromArray( json.sh ); + this.instanced = value; return this; } - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.sh = this.sh.toArray(); +} - return data; +const bufferAttribute = ( array, type, stride, offset ) => nodeObject( new BufferAttributeNode( array, type, stride, offset ) ); +const dynamicBufferAttribute = ( array, type, stride, offset ) => bufferAttribute( array, type, stride, offset ).setUsage( DynamicDrawUsage ); - } +const instancedBufferAttribute = ( array, type, stride, offset ) => bufferAttribute( array, type, stride, offset ).setInstanced( true ); +const instancedDynamicBufferAttribute = ( array, type, stride, offset ) => dynamicBufferAttribute( array, type, stride, offset ).setInstanced( true ); -} +addMethodChaining( 'toAttribute', ( bufferNode ) => bufferAttribute( bufferNode.value ) ); -class MaterialLoader extends Loader { +class ComputeNode extends Node { - constructor( manager ) { + static get type() { - super( manager ); - this.textures = {}; + return 'ComputeNode'; } - load( url, onLoad, onProgress, onError ) { + constructor( computeNode, count, workgroupSize = [ 64 ] ) { - const scope = this; + super( 'void' ); - const loader = new FileLoader( scope.manager ); - loader.setPath( scope.path ); - loader.setRequestHeader( scope.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( text ) { + this.isComputeNode = true; - try { - - onLoad( scope.parse( JSON.parse( text ) ) ); + this.computeNode = computeNode; - } catch ( e ) { + this.count = count; + this.workgroupSize = workgroupSize; + this.dispatchCount = 0; - if ( onError ) { + this.version = 1; + this.updateBeforeType = NodeUpdateType.OBJECT; - onError( e ); + this.updateDispatchCount(); - } else { + } - console.error( e ); + dispose() { - } + this.dispatchEvent( { type: 'dispose' } ); - scope.manager.itemError( url ); + } - } + set needsUpdate( value ) { - }, onProgress, onError ); + if ( value === true ) this.version ++; } - parse( json ) { + updateDispatchCount() { - const textures = this.textures; + const { count, workgroupSize } = this; - function getTexture( name ) { + let size = workgroupSize[ 0 ]; - if ( textures[ name ] === undefined ) { + for ( let i = 1; i < workgroupSize.length; i ++ ) + size *= workgroupSize[ i ]; - console.warn( 'THREE.MaterialLoader: Undefined texture', name ); + this.dispatchCount = Math.ceil( count / size ); - } + } - return textures[ name ]; + onInit() { } - } + updateBefore( { renderer } ) { - const material = MaterialLoader.createMaterialFromType( json.type ); + renderer.compute( this ); - if ( json.uuid !== undefined ) material.uuid = json.uuid; - if ( json.name !== undefined ) material.name = json.name; - if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color ); - if ( json.roughness !== undefined ) material.roughness = json.roughness; - if ( json.metalness !== undefined ) material.metalness = json.metalness; - if ( json.sheen !== undefined ) material.sheen = json.sheen; - if ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor ); - if ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness; - if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive ); - if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular ); - if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity; - if ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor ); - if ( json.shininess !== undefined ) material.shininess = json.shininess; - if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat; - if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness; - if ( json.dispersion !== undefined ) material.dispersion = json.dispersion; - if ( json.iridescence !== undefined ) material.iridescence = json.iridescence; - if ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR; - if ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange; - if ( json.transmission !== undefined ) material.transmission = json.transmission; - if ( json.thickness !== undefined ) material.thickness = json.thickness; - if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance; - if ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor ); - if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy; - if ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation; - if ( json.fog !== undefined ) material.fog = json.fog; - if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; - if ( json.blending !== undefined ) material.blending = json.blending; - if ( json.combine !== undefined ) material.combine = json.combine; - if ( json.side !== undefined ) material.side = json.side; - if ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide; - if ( json.opacity !== undefined ) material.opacity = json.opacity; - if ( json.transparent !== undefined ) material.transparent = json.transparent; - if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; - if ( json.alphaHash !== undefined ) material.alphaHash = json.alphaHash; - if ( json.depthFunc !== undefined ) material.depthFunc = json.depthFunc; - if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; - if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; - if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; - if ( json.blendSrc !== undefined ) material.blendSrc = json.blendSrc; - if ( json.blendDst !== undefined ) material.blendDst = json.blendDst; - if ( json.blendEquation !== undefined ) material.blendEquation = json.blendEquation; - if ( json.blendSrcAlpha !== undefined ) material.blendSrcAlpha = json.blendSrcAlpha; - if ( json.blendDstAlpha !== undefined ) material.blendDstAlpha = json.blendDstAlpha; - if ( json.blendEquationAlpha !== undefined ) material.blendEquationAlpha = json.blendEquationAlpha; - if ( json.blendColor !== undefined && material.blendColor !== undefined ) material.blendColor.setHex( json.blendColor ); - if ( json.blendAlpha !== undefined ) material.blendAlpha = json.blendAlpha; - if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask; - if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc; - if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef; - if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask; - if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail; - if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail; - if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass; - if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite; + } - if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; - if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; - if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; - if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; + generate( builder ) { - if ( json.rotation !== undefined ) material.rotation = json.rotation; + const { shaderStage } = builder; - if ( json.linewidth !== undefined ) material.linewidth = json.linewidth; - if ( json.dashSize !== undefined ) material.dashSize = json.dashSize; - if ( json.gapSize !== undefined ) material.gapSize = json.gapSize; - if ( json.scale !== undefined ) material.scale = json.scale; + if ( shaderStage === 'compute' ) { - if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset; - if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor; - if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits; + const snippet = this.computeNode.build( builder, 'void' ); - if ( json.dithering !== undefined ) material.dithering = json.dithering; + if ( snippet !== '' ) { - if ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage; - if ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha; - if ( json.forceSinglePass !== undefined ) material.forceSinglePass = json.forceSinglePass; + builder.addLineFlowCode( snippet, this ); - if ( json.visible !== undefined ) material.visible = json.visible; + } - if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped; + } - if ( json.userData !== undefined ) material.userData = json.userData; + } - if ( json.vertexColors !== undefined ) { +} - if ( typeof json.vertexColors === 'number' ) { +const compute = ( node, count, workgroupSize ) => nodeObject( new ComputeNode( nodeObject( node ), count, workgroupSize ) ); - material.vertexColors = ( json.vertexColors > 0 ) ? true : false; +addMethodChaining( 'compute', compute ); - } else { +class CacheNode extends Node { - material.vertexColors = json.vertexColors; + static get type() { - } + return 'CacheNode'; - } + } - // Shader Material + constructor( node, parent = true ) { - if ( json.uniforms !== undefined ) { + super(); - for ( const name in json.uniforms ) { + this.node = node; + this.parent = parent; - const uniform = json.uniforms[ name ]; + this.isCacheNode = true; - material.uniforms[ name ] = {}; + } - switch ( uniform.type ) { + getNodeType( builder ) { - case 't': - material.uniforms[ name ].value = getTexture( uniform.value ); - break; + return this.node.getNodeType( builder ); - case 'c': - material.uniforms[ name ].value = new Color().setHex( uniform.value ); - break; + } - case 'v2': - material.uniforms[ name ].value = new Vector2().fromArray( uniform.value ); - break; + build( builder, ...params ) { - case 'v3': - material.uniforms[ name ].value = new Vector3().fromArray( uniform.value ); - break; + const previousCache = builder.getCache(); + const cache = builder.getCacheFromNode( this, this.parent ); - case 'v4': - material.uniforms[ name ].value = new Vector4().fromArray( uniform.value ); - break; + builder.setCache( cache ); - case 'm3': - material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value ); - break; + const data = this.node.build( builder, ...params ); - case 'm4': - material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value ); - break; + builder.setCache( previousCache ); - default: - material.uniforms[ name ].value = uniform.value; + return data; - } + } - } +} - } +const cache = ( node, ...params ) => nodeObject( new CacheNode( nodeObject( node ), ...params ) ); - if ( json.defines !== undefined ) material.defines = json.defines; - if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; - if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; - if ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion; +addMethodChaining( 'cache', cache ); - if ( json.extensions !== undefined ) { +class BypassNode extends Node { - for ( const key in json.extensions ) { + static get type() { - material.extensions[ key ] = json.extensions[ key ]; + return 'BypassNode'; - } + } - } + constructor( returnNode, callNode ) { - if ( json.lights !== undefined ) material.lights = json.lights; - if ( json.clipping !== undefined ) material.clipping = json.clipping; + super(); - // for PointsMaterial + this.isBypassNode = true; - if ( json.size !== undefined ) material.size = json.size; - if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; + this.outputNode = returnNode; + this.callNode = callNode; - // maps + } - if ( json.map !== undefined ) material.map = getTexture( json.map ); - if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap ); + getNodeType( builder ) { - if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap ); + return this.outputNode.getNodeType( builder ); - if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); - if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; + } - if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); - if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType; - if ( json.normalScale !== undefined ) { + generate( builder ) { - let normalScale = json.normalScale; + const snippet = this.callNode.build( builder, 'void' ); - if ( Array.isArray( normalScale ) === false ) { + if ( snippet !== '' ) { - // Blender exporter used to export a scalar. See #7459 + builder.addLineFlowCode( snippet, this ); - normalScale = [ normalScale, normalScale ]; + } - } + return this.outputNode.build( builder ); - material.normalScale = new Vector2().fromArray( normalScale ); + } - } +} - if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); - if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; - if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; +const bypass = /*@__PURE__*/ nodeProxy( BypassNode ); - if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); - if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); +addMethodChaining( 'bypass', bypass ); - if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); - if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; +class RemapNode extends Node { - if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); - if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap ); - if ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap ); + static get type() { - if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); - if ( json.envMapRotation !== undefined ) material.envMapRotation.fromArray( json.envMapRotation ); - if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity; + return 'RemapNode'; - if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; - if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio; + } - if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); - if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; + constructor( node, inLowNode, inHighNode, outLowNode = float( 0 ), outHighNode = float( 1 ) ) { - if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); - if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; + super(); - if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); + this.node = node; + this.inLowNode = inLowNode; + this.inHighNode = inHighNode; + this.outLowNode = outLowNode; + this.outHighNode = outHighNode; - if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap ); - if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap ); - if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap ); - if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale ); + this.doClamp = true; - if ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap ); - if ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap ); + } - if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap ); - if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap ); + setup() { - if ( json.anisotropyMap !== undefined ) material.anisotropyMap = getTexture( json.anisotropyMap ); + const { node, inLowNode, inHighNode, outLowNode, outHighNode, doClamp } = this; - if ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap ); - if ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap ); + let t = node.sub( inLowNode ).div( inHighNode.sub( inLowNode ) ); - return material; + if ( doClamp === true ) t = t.clamp(); + + return t.mul( outHighNode.sub( outLowNode ) ).add( outLowNode ); } - setTextures( value ) { +} - this.textures = value; - return this; +const remap = /*@__PURE__*/ nodeProxy( RemapNode, null, null, { doClamp: false } ); +const remapClamp = /*@__PURE__*/ nodeProxy( RemapNode ); - } +addMethodChaining( 'remap', remap ); +addMethodChaining( 'remapClamp', remapClamp ); - static createMaterialFromType( type ) { +class ExpressionNode extends Node { - const materialLib = { - ShadowMaterial, - SpriteMaterial, - RawShaderMaterial, - ShaderMaterial, - PointsMaterial, - MeshPhysicalMaterial, - MeshStandardMaterial, - MeshPhongMaterial, - MeshToonMaterial, - MeshNormalMaterial, - MeshLambertMaterial, - MeshDepthMaterial, - MeshDistanceMaterial, - MeshBasicMaterial, - MeshMatcapMaterial, - LineDashedMaterial, - LineBasicMaterial, - Material - }; + static get type() { - return new materialLib[ type ](); + return 'ExpressionNode'; } -} - -class LoaderUtils { + constructor( snippet = '', nodeType = 'void' ) { - static decodeText( array ) { // @deprecated, r165 + super( nodeType ); - console.warn( 'THREE.LoaderUtils: decodeText() has been deprecated with r165 and will be removed with r175. Use TextDecoder instead.' ); + this.snippet = snippet; - if ( typeof TextDecoder !== 'undefined' ) { + } - return new TextDecoder().decode( array ); + generate( builder, output ) { - } + const type = this.getNodeType( builder ); + const snippet = this.snippet; - // Avoid the String.fromCharCode.apply(null, array) shortcut, which - // throws a "maximum call stack size exceeded" error for large arrays. + if ( type === 'void' ) { - let s = ''; + builder.addLineFlowCode( snippet, this ); - for ( let i = 0, il = array.length; i < il; i ++ ) { + } else { - // Implicitly assumes little-endian. - s += String.fromCharCode( array[ i ] ); + return builder.format( `( ${ snippet } )`, type, output ); } - try { + } - // merges multi-byte utf-8 characters. +} - return decodeURIComponent( escape( s ) ); +const expression = /*@__PURE__*/ nodeProxy( ExpressionNode ); - } catch ( e ) { // see #16358 +const Discard = ( conditional ) => ( conditional ? select( conditional, expression( 'discard' ) ) : expression( 'discard' ) ).append(); +const Return = () => expression( 'return' ).append(); - return s; +addMethodChaining( 'discard', Discard ); - } +class RenderOutputNode extends TempNode { + + static get type() { + + return 'RenderOutputNode'; } - static extractUrlBase( url ) { + constructor( colorNode, toneMapping, outputColorSpace ) { - const index = url.lastIndexOf( '/' ); + super( 'vec4' ); - if ( index === - 1 ) return './'; + this.colorNode = colorNode; + this.toneMapping = toneMapping; + this.outputColorSpace = outputColorSpace; - return url.slice( 0, index + 1 ); + this.isRenderOutput = true; } - static resolveURL( url, path ) { + setup( { context } ) { - // Invalid URL - if ( typeof url !== 'string' || url === '' ) return ''; + let outputNode = this.colorNode || context.color; - // Host Relative URL - if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) { + // tone mapping - path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' ); + const toneMapping = ( this.toneMapping !== null ? this.toneMapping : context.toneMapping ) || NoToneMapping; + const outputColorSpace = ( this.outputColorSpace !== null ? this.outputColorSpace : context.outputColorSpace ) || NoColorSpace; + + if ( toneMapping !== NoToneMapping ) { + + outputNode = outputNode.toneMapping( toneMapping ); } - // Absolute URL http://,https://,// - if ( /^(https?:)?\/\//i.test( url ) ) return url; + // working to output color space - // Data URI - if ( /^data:.*,.*$/i.test( url ) ) return url; + if ( outputColorSpace !== NoColorSpace && outputColorSpace !== ColorManagement.workingColorSpace ) { - // Blob URL - if ( /^blob:.*$/i.test( url ) ) return url; + outputNode = outputNode.workingToColorSpace( outputColorSpace ); - // Relative URL - return path + url; + } + + return outputNode; } } -class InstancedBufferGeometry extends BufferGeometry { +const renderOutput = ( color, toneMapping = null, outputColorSpace = null ) => nodeObject( new RenderOutputNode( nodeObject( color ), toneMapping, outputColorSpace ) ); - constructor() { +addMethodChaining( 'renderOutput', renderOutput ); - super(); +// Non-PURE exports list, side-effects are required here. +// TSL Base Syntax - this.isInstancedBufferGeometry = true; - this.type = 'InstancedBufferGeometry'; - this.instanceCount = Infinity; +function addNodeElement( name/*, nodeElement*/ ) { - } + console.warn( 'THREE.TSLBase: AddNodeElement has been removed in favor of tree-shaking. Trying add', name ); - copy( source ) { +} - super.copy( source ); +class AttributeNode extends Node { - this.instanceCount = source.instanceCount; + static get type() { - return this; + return 'AttributeNode'; } - toJSON() { - - const data = super.toJSON(); + constructor( attributeName, nodeType = null ) { - data.instanceCount = this.instanceCount; + super( nodeType ); - data.isInstancedBufferGeometry = true; + this.global = true; - return data; + this._attributeName = attributeName; } -} + getHash( builder ) { -class BufferGeometryLoader extends Loader { + return this.getAttributeName( builder ); - constructor( manager ) { + } - super( manager ); + getNodeType( builder ) { - } + let nodeType = this.nodeType; - load( url, onLoad, onProgress, onError ) { + if ( nodeType === null ) { - const scope = this; + const attributeName = this.getAttributeName( builder ); - const loader = new FileLoader( scope.manager ); - loader.setPath( scope.path ); - loader.setRequestHeader( scope.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( text ) { + if ( builder.hasGeometryAttribute( attributeName ) ) { - try { + const attribute = builder.geometry.getAttribute( attributeName ); - onLoad( scope.parse( JSON.parse( text ) ) ); + nodeType = builder.getTypeFromAttribute( attribute ); - } catch ( e ) { + } else { - if ( onError ) { + nodeType = 'float'; - onError( e ); + } - } else { + } - console.error( e ); + return nodeType; - } + } - scope.manager.itemError( url ); + setAttributeName( attributeName ) { - } + this._attributeName = attributeName; - }, onProgress, onError ); + return this; } - parse( json ) { + getAttributeName( /*builder*/ ) { - const interleavedBufferMap = {}; - const arrayBufferMap = {}; + return this._attributeName; - function getInterleavedBuffer( json, uuid ) { + } - if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ]; + generate( builder ) { - const interleavedBuffers = json.interleavedBuffers; - const interleavedBuffer = interleavedBuffers[ uuid ]; + const attributeName = this.getAttributeName( builder ); + const nodeType = this.getNodeType( builder ); + const geometryAttribute = builder.hasGeometryAttribute( attributeName ); - const buffer = getArrayBuffer( json, interleavedBuffer.buffer ); + if ( geometryAttribute === true ) { - const array = getTypedArray( interleavedBuffer.type, buffer ); - const ib = new InterleavedBuffer( array, interleavedBuffer.stride ); - ib.uuid = interleavedBuffer.uuid; + const attribute = builder.geometry.getAttribute( attributeName ); + const attributeType = builder.getTypeFromAttribute( attribute ); - interleavedBufferMap[ uuid ] = ib; + const nodeAttribute = builder.getAttribute( attributeName, attributeType ); - return ib; + if ( builder.shaderStage === 'vertex' ) { - } + return builder.format( nodeAttribute.name, attributeType, nodeType ); - function getArrayBuffer( json, uuid ) { + } else { - if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ]; + const nodeVarying = varying( this ); - const arrayBuffers = json.arrayBuffers; - const arrayBuffer = arrayBuffers[ uuid ]; + return nodeVarying.build( builder, nodeType ); - const ab = new Uint32Array( arrayBuffer ).buffer; + } - arrayBufferMap[ uuid ] = ab; + } else { - return ab; + console.warn( `AttributeNode: Vertex attribute "${ attributeName }" not found on geometry.` ); + + return builder.generateConst( nodeType ); } - const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry(); + } - const index = json.data.index; + serialize( data ) { - if ( index !== undefined ) { + super.serialize( data ); - const typedArray = getTypedArray( index.type, index.array ); - geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); - - } - - const attributes = json.data.attributes; - - for ( const key in attributes ) { - - const attribute = attributes[ key ]; - let bufferAttribute; + data.global = this.global; + data._attributeName = this._attributeName; - if ( attribute.isInterleavedBufferAttribute ) { + } - const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); - bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); + deserialize( data ) { - } else { + super.deserialize( data ); - const typedArray = getTypedArray( attribute.type, attribute.array ); - const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute; - bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized ); + this.global = data.global; + this._attributeName = data._attributeName; - } + } - if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; - if ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage ); +} - geometry.setAttribute( key, bufferAttribute ); +const attribute = ( name, nodeType ) => nodeObject( new AttributeNode( name, nodeType ) ); - } +const uv = ( index ) => attribute( 'uv' + ( index > 0 ? index : '' ), 'vec2' ); - const morphAttributes = json.data.morphAttributes; +class TextureSizeNode extends Node { - if ( morphAttributes ) { + static get type() { - for ( const key in morphAttributes ) { + return 'TextureSizeNode'; - const attributeArray = morphAttributes[ key ]; + } - const array = []; + constructor( textureNode, levelNode = null ) { - for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { + super( 'uvec2' ); - const attribute = attributeArray[ i ]; - let bufferAttribute; + this.isTextureSizeNode = true; - if ( attribute.isInterleavedBufferAttribute ) { + this.textureNode = textureNode; + this.levelNode = levelNode; - const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); - bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); + } - } else { + generate( builder, output ) { - const typedArray = getTypedArray( attribute.type, attribute.array ); - bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ); + const textureProperty = this.textureNode.build( builder, 'property' ); + const level = this.levelNode === null ? '0' : this.levelNode.build( builder, 'int' ); - } + return builder.format( `${ builder.getMethod( 'textureDimensions' ) }( ${ textureProperty }, ${ level } )`, this.getNodeType( builder ), output ); - if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; - array.push( bufferAttribute ); + } - } +} - geometry.morphAttributes[ key ] = array; +const textureSize = /*@__PURE__*/ nodeProxy( TextureSizeNode ); - } +class MaxMipLevelNode extends UniformNode { - } + static get type() { - const morphTargetsRelative = json.data.morphTargetsRelative; + return 'MaxMipLevelNode'; - if ( morphTargetsRelative ) { + } - geometry.morphTargetsRelative = true; + constructor( textureNode ) { - } + super( 0 ); - const groups = json.data.groups || json.data.drawcalls || json.data.offsets; + this._textureNode = textureNode; - if ( groups !== undefined ) { + this.updateType = NodeUpdateType.FRAME; - for ( let i = 0, n = groups.length; i !== n; ++ i ) { + } - const group = groups[ i ]; + get textureNode() { - geometry.addGroup( group.start, group.count, group.materialIndex ); + return this._textureNode; - } + } - } + get texture() { - const boundingSphere = json.data.boundingSphere; + return this._textureNode.value; - if ( boundingSphere !== undefined ) { + } - const center = new Vector3(); + update() { - if ( boundingSphere.center !== undefined ) { + const texture = this.texture; + const images = texture.images; + const image = ( images && images.length > 0 ) ? ( ( images[ 0 ] && images[ 0 ].image ) || images[ 0 ] ) : texture.image; - center.fromArray( boundingSphere.center ); + if ( image && image.width !== undefined ) { - } + const { width, height } = image; - geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); + this.value = Math.log2( Math.max( width, height ) ); } - if ( json.name ) geometry.name = json.name; - if ( json.userData ) geometry.userData = json.userData; - - return geometry; - } } -class ObjectLoader extends Loader { +const maxMipLevel = /*@__PURE__*/ nodeProxy( MaxMipLevelNode ); - constructor( manager ) { +class TextureNode extends UniformNode { - super( manager ); + static get type() { - } + return 'TextureNode'; - load( url, onLoad, onProgress, onError ) { + } - const scope = this; + constructor( value, uvNode = null, levelNode = null, biasNode = null ) { - const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; - this.resourcePath = this.resourcePath || path; + super( value ); - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { + this.isTextureNode = true; - let json = null; + this.uvNode = uvNode; + this.levelNode = levelNode; + this.biasNode = biasNode; + this.compareNode = null; + this.depthNode = null; + this.gradNode = null; - try { + this.sampler = true; + this.updateMatrix = false; + this.updateType = NodeUpdateType.NONE; - json = JSON.parse( text ); + this.referenceNode = null; - } catch ( error ) { + this._value = value; + this._matrixUniform = null; - if ( onError !== undefined ) onError( error ); + this.setUpdateMatrix( uvNode === null ); - console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); + } - return; + set value( value ) { - } + if ( this.referenceNode ) { - const metadata = json.metadata; + this.referenceNode.value = value; - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { + } else { - if ( onError !== undefined ) onError( new Error( 'THREE.ObjectLoader: Can\'t load ' + url ) ); + this._value = value; - console.error( 'THREE.ObjectLoader: Can\'t load ' + url ); - return; + } - } + } - scope.parse( json, onLoad ); + get value() { - }, onProgress, onError ); + return this.referenceNode ? this.referenceNode.value : this._value; } - async loadAsync( url, onProgress ) { + getUniformHash( /*builder*/ ) { - const scope = this; + return this.value.uuid; - const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; - this.resourcePath = this.resourcePath || path; + } - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); + getNodeType( /*builder*/ ) { - const text = await loader.loadAsync( url, onProgress ); + if ( this.value.isDepthTexture === true ) return 'float'; - const json = JSON.parse( text ); + if ( this.value.type === UnsignedIntType ) { - const metadata = json.metadata; + return 'uvec4'; - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { + } else if ( this.value.type === IntType ) { - throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url ); + return 'ivec4'; } - return await scope.parseAsync( json ); + return 'vec4'; } - parse( json, onLoad ) { + getInputType( /*builder*/ ) { - const animations = this.parseAnimations( json.animations ); - const shapes = this.parseShapes( json.shapes ); - const geometries = this.parseGeometries( json.geometries, shapes ); + return 'texture'; - const images = this.parseImages( json.images, function () { + } - if ( onLoad !== undefined ) onLoad( object ); + getDefaultUV() { - } ); + return uv( this.value.channel ); - const textures = this.parseTextures( json.textures, images ); - const materials = this.parseMaterials( json.materials, textures ); + } - const object = this.parseObject( json.object, geometries, materials, textures, animations ); - const skeletons = this.parseSkeletons( json.skeletons, object ); + updateReference( /*state*/ ) { - this.bindSkeletons( object, skeletons ); - this.bindLightTargets( object ); + return this.value; - // + } - if ( onLoad !== undefined ) { + getTransformedUV( uvNode ) { - let hasImages = false; + if ( this._matrixUniform === null ) this._matrixUniform = uniform( this.value.matrix ); - for ( const uuid in images ) { + return this._matrixUniform.mul( vec3( uvNode, 1 ) ).xy; - if ( images[ uuid ].data instanceof HTMLImageElement ) { + } - hasImages = true; - break; + setUpdateMatrix( value ) { - } + this.updateMatrix = value; + this.updateType = value ? NodeUpdateType.FRAME : NodeUpdateType.NONE; - } + return this; - if ( hasImages === false ) onLoad( object ); + } - } + setupUV( builder, uvNode ) { - return object; + const texture = this.value; - } + if ( builder.isFlipY() && ( texture.isRenderTargetTexture === true || texture.isFramebufferTexture === true || texture.isDepthTexture === true ) ) { - async parseAsync( json ) { + if ( this.sampler ) { - const animations = this.parseAnimations( json.animations ); - const shapes = this.parseShapes( json.shapes ); - const geometries = this.parseGeometries( json.geometries, shapes ); + uvNode = uvNode.flipY(); - const images = await this.parseImagesAsync( json.images ); + } else { - const textures = this.parseTextures( json.textures, images ); - const materials = this.parseMaterials( json.materials, textures ); + uvNode = uvNode.setY( int( textureSize( this, this.levelNode ).y ).sub( uvNode.y ).sub( 1 ) ); - const object = this.parseObject( json.object, geometries, materials, textures, animations ); - const skeletons = this.parseSkeletons( json.skeletons, object ); + } - this.bindSkeletons( object, skeletons ); - this.bindLightTargets( object ); + } - return object; + return uvNode; } - parseShapes( json ) { - - const shapes = {}; + setup( builder ) { - if ( json !== undefined ) { + const properties = builder.getNodeProperties( this ); + properties.referenceNode = this.referenceNode; - for ( let i = 0, l = json.length; i < l; i ++ ) { + // - const shape = new Shape().fromJSON( json[ i ] ); + let uvNode = this.uvNode; - shapes[ shape.uuid ] = shape; + if ( ( uvNode === null || builder.context.forceUVContext === true ) && builder.context.getUV ) { - } + uvNode = builder.context.getUV( this ); } - return shapes; - - } + if ( ! uvNode ) uvNode = this.getDefaultUV(); - parseSkeletons( json, object ) { + if ( this.updateMatrix === true ) { - const skeletons = {}; - const bones = {}; + uvNode = this.getTransformedUV( uvNode ); - // generate bone lookup table + } - object.traverse( function ( child ) { + uvNode = this.setupUV( builder, uvNode ); - if ( child.isBone ) bones[ child.uuid ] = child; + // - } ); + let levelNode = this.levelNode; - // create skeletons + if ( levelNode === null && builder.context.getTextureLevel ) { - if ( json !== undefined ) { + levelNode = builder.context.getTextureLevel( this ); - for ( let i = 0, l = json.length; i < l; i ++ ) { + } - const skeleton = new Skeleton().fromJSON( json[ i ], bones ); + // - skeletons[ skeleton.uuid ] = skeleton; + properties.uvNode = uvNode; + properties.levelNode = levelNode; + properties.biasNode = this.biasNode; + properties.compareNode = this.compareNode; + properties.gradNode = this.gradNode; + properties.depthNode = this.depthNode; - } + } - } + generateUV( builder, uvNode ) { - return skeletons; + return uvNode.build( builder, this.sampler === true ? 'vec2' : 'ivec2' ); } - parseGeometries( json, shapes ) { + generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet ) { - const geometries = {}; + const texture = this.value; - if ( json !== undefined ) { + let snippet; - const bufferGeometryLoader = new BufferGeometryLoader(); + if ( levelSnippet ) { - for ( let i = 0, l = json.length; i < l; i ++ ) { + snippet = builder.generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet ); - let geometry; - const data = json[ i ]; + } else if ( biasSnippet ) { - switch ( data.type ) { + snippet = builder.generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet ); - case 'BufferGeometry': - case 'InstancedBufferGeometry': + } else if ( gradSnippet ) { - geometry = bufferGeometryLoader.parse( data ); - break; + snippet = builder.generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet ); - default: + } else if ( compareSnippet ) { - if ( data.type in Geometries$1 ) { + snippet = builder.generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet ); - geometry = Geometries$1[ data.type ].fromJSON( data, shapes ); + } else if ( this.sampler === false ) { - } else { + snippet = builder.generateTextureLoad( texture, textureProperty, uvSnippet, depthSnippet ); - console.warn( `THREE.ObjectLoader: Unsupported geometry type "${ data.type }"` ); + } else { - } + snippet = builder.generateTexture( texture, textureProperty, uvSnippet, depthSnippet ); - } + } - geometry.uuid = data.uuid; + return snippet; - if ( data.name !== undefined ) geometry.name = data.name; - if ( data.userData !== undefined ) geometry.userData = data.userData; + } - geometries[ data.uuid ] = geometry; + generate( builder, output ) { - } + const properties = builder.getNodeProperties( this ); - } + const texture = this.value; - return geometries; + if ( ! texture || texture.isTexture !== true ) { - } + throw new Error( 'TextureNode: Need a three.js texture.' ); - parseMaterials( json, textures ) { + } - const cache = {}; // MultiMaterial - const materials = {}; + const textureProperty = super.generate( builder, 'property' ); - if ( json !== undefined ) { + if ( output === 'sampler' ) { - const loader = new MaterialLoader(); - loader.setTextures( textures ); + return textureProperty + '_sampler'; - for ( let i = 0, l = json.length; i < l; i ++ ) { + } else if ( builder.isReference( output ) ) { - const data = json[ i ]; + return textureProperty; - if ( cache[ data.uuid ] === undefined ) { + } else { - cache[ data.uuid ] = loader.parse( data ); + const nodeData = builder.getDataFromNode( this ); - } + let propertyName = nodeData.propertyName; - materials[ data.uuid ] = cache[ data.uuid ]; + if ( propertyName === undefined ) { - } + const { uvNode, levelNode, biasNode, compareNode, depthNode, gradNode } = properties; - } + const uvSnippet = this.generateUV( builder, uvNode ); + const levelSnippet = levelNode ? levelNode.build( builder, 'float' ) : null; + const biasSnippet = biasNode ? biasNode.build( builder, 'float' ) : null; + const depthSnippet = depthNode ? depthNode.build( builder, 'int' ) : null; + const compareSnippet = compareNode ? compareNode.build( builder, 'float' ) : null; + const gradSnippet = gradNode ? [ gradNode[ 0 ].build( builder, 'vec2' ), gradNode[ 1 ].build( builder, 'vec2' ) ] : null; - return materials; + const nodeVar = builder.getVarFromNode( this ); - } + propertyName = builder.getPropertyName( nodeVar ); - parseAnimations( json ) { + const snippet = this.generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet ); - const animations = {}; + builder.addLineFlowCode( `${propertyName} = ${snippet}`, this ); - if ( json !== undefined ) { + nodeData.snippet = snippet; + nodeData.propertyName = propertyName; - for ( let i = 0; i < json.length; i ++ ) { + } - const data = json[ i ]; + let snippet = propertyName; + const nodeType = this.getNodeType( builder ); - const clip = AnimationClip.parse( data ); + if ( builder.needsToWorkingColorSpace( texture ) ) { - animations[ clip.uuid ] = clip; + snippet = colorSpaceToWorking( expression( snippet, nodeType ), texture.colorSpace ).setup( builder ).build( builder, nodeType ); } - } + return builder.format( snippet, nodeType, output ); - return animations; + } } - parseImages( json, onLoad ) { + setSampler( value ) { - const scope = this; - const images = {}; + this.sampler = value; - let loader; + return this; - function loadImage( url ) { + } - scope.manager.itemStart( url ); + getSampler() { - return loader.load( url, function () { + return this.sampler; - scope.manager.itemEnd( url ); + } - }, undefined, function () { + // @TODO: Move to TSL - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); + uv( uvNode ) { - } ); + const textureNode = this.clone(); + textureNode.uvNode = nodeObject( uvNode ); + textureNode.referenceNode = this.getSelf(); - } + return nodeObject( textureNode ); - function deserializeImage( image ) { + } - if ( typeof image === 'string' ) { + blur( amountNode ) { - const url = image; + const textureNode = this.clone(); + textureNode.biasNode = nodeObject( amountNode ).mul( maxMipLevel( textureNode ) ); + textureNode.referenceNode = this.getSelf(); - const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; + return nodeObject( textureNode ); - return loadImage( path ); + } - } else { + level( levelNode ) { - if ( image.data ) { + const textureNode = this.clone(); + textureNode.levelNode = nodeObject( levelNode ); + textureNode.referenceNode = this.getSelf(); - return { - data: getTypedArray( image.type, image.data ), - width: image.width, - height: image.height - }; + return nodeObject( textureNode ); - } else { + } - return null; + size( levelNode ) { - } + return textureSize( this, levelNode ); - } + } - } + bias( biasNode ) { - if ( json !== undefined && json.length > 0 ) { + const textureNode = this.clone(); + textureNode.biasNode = nodeObject( biasNode ); + textureNode.referenceNode = this.getSelf(); - const manager = new LoadingManager( onLoad ); + return nodeObject( textureNode ); - loader = new ImageLoader( manager ); - loader.setCrossOrigin( this.crossOrigin ); + } - for ( let i = 0, il = json.length; i < il; i ++ ) { + compare( compareNode ) { - const image = json[ i ]; - const url = image.url; + const textureNode = this.clone(); + textureNode.compareNode = nodeObject( compareNode ); + textureNode.referenceNode = this.getSelf(); - if ( Array.isArray( url ) ) { + return nodeObject( textureNode ); - // load array of images e.g CubeTexture + } - const imageArray = []; + grad( gradNodeX, gradNodeY ) { - for ( let j = 0, jl = url.length; j < jl; j ++ ) { + const textureNode = this.clone(); + textureNode.gradNode = [ nodeObject( gradNodeX ), nodeObject( gradNodeY ) ]; + textureNode.referenceNode = this.getSelf(); - const currentUrl = url[ j ]; + return nodeObject( textureNode ); - const deserializedImage = deserializeImage( currentUrl ); + } - if ( deserializedImage !== null ) { + depth( depthNode ) { - if ( deserializedImage instanceof HTMLImageElement ) { + const textureNode = this.clone(); + textureNode.depthNode = nodeObject( depthNode ); + textureNode.referenceNode = this.getSelf(); - imageArray.push( deserializedImage ); + return nodeObject( textureNode ); - } else { + } - // special case: handle array of data textures for cube textures + // -- - imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); + serialize( data ) { - } + super.serialize( data ); - } + data.value = this.value.toJSON( data.meta ).uuid; + data.sampler = this.sampler; + data.updateMatrix = this.updateMatrix; + data.updateType = this.updateType; - } + } - images[ image.uuid ] = new Source( imageArray ); + deserialize( data ) { - } else { + super.deserialize( data ); - // load single image + this.value = data.meta.textures[ data.value ]; + this.sampler = data.sampler; + this.updateMatrix = data.updateMatrix; + this.updateType = data.updateType; - const deserializedImage = deserializeImage( image.url ); - images[ image.uuid ] = new Source( deserializedImage ); + } + update() { - } + const texture = this.value; + const matrixUniform = this._matrixUniform; - } + if ( matrixUniform !== null ) matrixUniform.value = texture.matrix; - } + if ( texture.matrixAutoUpdate === true ) { - return images; + texture.updateMatrix(); + + } } - async parseImagesAsync( json ) { + clone() { - const scope = this; - const images = {}; + const newNode = new this.constructor( this.value, this.uvNode, this.levelNode, this.biasNode ); + newNode.sampler = this.sampler; - let loader; + return newNode; - async function deserializeImage( image ) { + } - if ( typeof image === 'string' ) { +} - const url = image; +const texture = /*@__PURE__*/ nodeProxy( TextureNode ); +const textureLoad = ( ...params ) => texture( ...params ).setSampler( false ); - const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; +//export const textureLevel = ( value, uv, level ) => texture( value, uv ).level( level ); - return await loader.loadAsync( path ); +const sampler = ( aTexture ) => ( aTexture.isNode === true ? aTexture : texture( aTexture ) ).convert( 'sampler' ); - } else { +const cameraNear = /*@__PURE__*/ uniform( 'float' ).label( 'cameraNear' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.near ); +const cameraFar = /*@__PURE__*/ uniform( 'float' ).label( 'cameraFar' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.far ); +const cameraLogDepth = /*@__PURE__*/ uniform( 'float' ).label( 'cameraLogDepth' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); +const cameraProjectionMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraProjectionMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.projectionMatrix ); +const cameraProjectionMatrixInverse = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraProjectionMatrixInverse' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.projectionMatrixInverse ); +const cameraViewMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraViewMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.matrixWorldInverse ); +const cameraWorldMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraWorldMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.matrixWorld ); +const cameraNormalMatrix = /*@__PURE__*/ uniform( 'mat3' ).label( 'cameraNormalMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.normalMatrix ); +const cameraPosition = /*@__PURE__*/ uniform( new Vector3() ).label( 'cameraPosition' ).setGroup( renderGroup ).onRenderUpdate( ( { camera }, self ) => self.value.setFromMatrixPosition( camera.matrixWorld ) ); - if ( image.data ) { +class Object3DNode extends Node { - return { - data: getTypedArray( image.type, image.data ), - width: image.width, - height: image.height - }; + static get type() { - } else { + return 'Object3DNode'; - return null; + } - } + constructor( scope, object3d = null ) { - } + super(); - } + this.scope = scope; + this.object3d = object3d; - if ( json !== undefined && json.length > 0 ) { + this.updateType = NodeUpdateType.OBJECT; - loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); + this._uniformNode = new UniformNode( null ); - for ( let i = 0, il = json.length; i < il; i ++ ) { + } - const image = json[ i ]; - const url = image.url; + getNodeType() { - if ( Array.isArray( url ) ) { + const scope = this.scope; - // load array of images e.g CubeTexture + if ( scope === Object3DNode.WORLD_MATRIX ) { - const imageArray = []; + return 'mat4'; - for ( let j = 0, jl = url.length; j < jl; j ++ ) { + } else if ( scope === Object3DNode.POSITION || scope === Object3DNode.VIEW_POSITION || scope === Object3DNode.DIRECTION || scope === Object3DNode.SCALE ) { - const currentUrl = url[ j ]; + return 'vec3'; - const deserializedImage = await deserializeImage( currentUrl ); + } - if ( deserializedImage !== null ) { + } - if ( deserializedImage instanceof HTMLImageElement ) { + update( frame ) { - imageArray.push( deserializedImage ); + const object = this.object3d; + const uniformNode = this._uniformNode; + const scope = this.scope; - } else { + if ( scope === Object3DNode.WORLD_MATRIX ) { - // special case: handle array of data textures for cube textures + uniformNode.value = object.matrixWorld; - imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); + } else if ( scope === Object3DNode.POSITION ) { - } + uniformNode.value = uniformNode.value || new Vector3(); - } + uniformNode.value.setFromMatrixPosition( object.matrixWorld ); - } + } else if ( scope === Object3DNode.SCALE ) { - images[ image.uuid ] = new Source( imageArray ); + uniformNode.value = uniformNode.value || new Vector3(); - } else { + uniformNode.value.setFromMatrixScale( object.matrixWorld ); - // load single image + } else if ( scope === Object3DNode.DIRECTION ) { - const deserializedImage = await deserializeImage( image.url ); - images[ image.uuid ] = new Source( deserializedImage ); + uniformNode.value = uniformNode.value || new Vector3(); - } + object.getWorldDirection( uniformNode.value ); - } + } else if ( scope === Object3DNode.VIEW_POSITION ) { - } + const camera = frame.camera; - return images; + uniformNode.value = uniformNode.value || new Vector3(); + uniformNode.value.setFromMatrixPosition( object.matrixWorld ); + + uniformNode.value.applyMatrix4( camera.matrixWorldInverse ); + + } } - parseTextures( json, images ) { + generate( builder ) { - function parseConstant( value, type ) { + const scope = this.scope; - if ( typeof value === 'number' ) return value; + if ( scope === Object3DNode.WORLD_MATRIX ) { - console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); + this._uniformNode.nodeType = 'mat4'; - return type[ value ]; + } else if ( scope === Object3DNode.POSITION || scope === Object3DNode.VIEW_POSITION || scope === Object3DNode.DIRECTION || scope === Object3DNode.SCALE ) { - } + this._uniformNode.nodeType = 'vec3'; - const textures = {}; + } - if ( json !== undefined ) { + return this._uniformNode.build( builder ); - for ( let i = 0, l = json.length; i < l; i ++ ) { + } - const data = json[ i ]; + serialize( data ) { - if ( data.image === undefined ) { + super.serialize( data ); - console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); + data.scope = this.scope; - } + } - if ( images[ data.image ] === undefined ) { + deserialize( data ) { - console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); + super.deserialize( data ); - } + this.scope = data.scope; - const source = images[ data.image ]; - const image = source.data; + } - let texture; +} - if ( Array.isArray( image ) ) { +Object3DNode.WORLD_MATRIX = 'worldMatrix'; +Object3DNode.POSITION = 'position'; +Object3DNode.SCALE = 'scale'; +Object3DNode.VIEW_POSITION = 'viewPosition'; +Object3DNode.DIRECTION = 'direction'; - texture = new CubeTexture(); +const objectDirection = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.DIRECTION ); +const objectWorldMatrix = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.WORLD_MATRIX ); +const objectPosition = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.POSITION ); +const objectScale = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.SCALE ); +const objectViewPosition = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.VIEW_POSITION ); - if ( image.length === 6 ) texture.needsUpdate = true; +class ModelNode extends Object3DNode { - } else { + static get type() { - if ( image && image.data ) { + return 'ModelNode'; - texture = new DataTexture(); + } - } else { + constructor( scope ) { - texture = new Texture(); + super( scope ); - } + } - if ( image ) texture.needsUpdate = true; // textures can have undefined image data + update( frame ) { - } + this.object3d = frame.object; - texture.source = source; + super.update( frame ); - texture.uuid = data.uuid; + } - if ( data.name !== undefined ) texture.name = data.name; +} - if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); - if ( data.channel !== undefined ) texture.channel = data.channel; +const modelDirection = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.DIRECTION ); +const modelWorldMatrix = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.WORLD_MATRIX ); +const modelPosition = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.POSITION ); +const modelScale = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.SCALE ); +const modelViewPosition = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.VIEW_POSITION ); +const modelNormalMatrix = /*@__PURE__*/ uniform( new Matrix3() ).onObjectUpdate( ( { object }, self ) => self.value.getNormalMatrix( object.matrixWorld ) ); +const modelWorldMatrixInverse = /*@__PURE__*/ uniform( new Matrix4() ).onObjectUpdate( ( { object }, self ) => self.value.copy( object.matrixWorld ).invert() ); +const modelViewMatrix = /*@__PURE__*/ cameraViewMatrix.mul( modelWorldMatrix ).toVar( 'modelViewMatrix' ); - if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); - if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); - if ( data.center !== undefined ) texture.center.fromArray( data.center ); - if ( data.rotation !== undefined ) texture.rotation = data.rotation; +const highPrecisionModelViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { - if ( data.wrap !== undefined ) { + builder.context.isHighPrecisionModelViewMatrix = true; - texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); - texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); + return uniform( 'mat4' ).onObjectUpdate( ( { object, camera } ) => { - } + return object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - if ( data.format !== undefined ) texture.format = data.format; - if ( data.internalFormat !== undefined ) texture.internalFormat = data.internalFormat; - if ( data.type !== undefined ) texture.type = data.type; - if ( data.colorSpace !== undefined ) texture.colorSpace = data.colorSpace; + } ); - if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); - if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); - if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; +} ).once() )().toVar( 'highPrecisionModelViewMatrix' ); - if ( data.flipY !== undefined ) texture.flipY = data.flipY; +const highPrecisionModelNormalViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { - if ( data.generateMipmaps !== undefined ) texture.generateMipmaps = data.generateMipmaps; - if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha; - if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment; - if ( data.compareFunction !== undefined ) texture.compareFunction = data.compareFunction; + const isHighPrecisionModelViewMatrix = builder.context.isHighPrecisionModelViewMatrix; - if ( data.userData !== undefined ) texture.userData = data.userData; + return uniform( 'mat3' ).onObjectUpdate( ( { object, camera } ) => { - textures[ data.uuid ] = texture; + if ( isHighPrecisionModelViewMatrix !== true ) { - } + object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); } - return textures; + return object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); - } + } ); - parseObject( data, geometries, materials, textures, animations ) { +} ).once() )().toVar( 'highPrecisionModelNormalMatrix' ); - let object; +const positionGeometry = /*@__PURE__*/ attribute( 'position', 'vec3' ); +const positionLocal = /*@__PURE__*/ positionGeometry.varying( 'positionLocal' ); +const positionPrevious = /*@__PURE__*/ positionGeometry.varying( 'positionPrevious' ); +const positionWorld = /*@__PURE__*/ modelWorldMatrix.mul( positionLocal ).xyz.varying( 'v_positionWorld' ); +const positionWorldDirection = /*@__PURE__*/ positionLocal.transformDirection( modelWorldMatrix ).varying( 'v_positionWorldDirection' ).normalize().toVar( 'positionWorldDirection' ); +const positionView = /*@__PURE__*/ modelViewMatrix.mul( positionLocal ).xyz.varying( 'v_positionView' ); +const positionViewDirection = /*@__PURE__*/ positionView.negate().varying( 'v_positionViewDirection' ).normalize().toVar( 'positionViewDirection' ); - function getGeometry( name ) { +class FrontFacingNode extends Node { - if ( geometries[ name ] === undefined ) { + static get type() { - console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); + return 'FrontFacingNode'; - } + } - return geometries[ name ]; + constructor() { - } + super( 'bool' ); - function getMaterial( name ) { + this.isFrontFacingNode = true; - if ( name === undefined ) return undefined; + } - if ( Array.isArray( name ) ) { + generate( builder ) { - const array = []; + const { renderer, material } = builder; - for ( let i = 0, l = name.length; i < l; i ++ ) { + if ( renderer.coordinateSystem === WebGLCoordinateSystem ) { - const uuid = name[ i ]; + if ( material.side === BackSide ) { - if ( materials[ uuid ] === undefined ) { + return 'false'; - console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); + } - } + } - array.push( materials[ uuid ] ); + return builder.getFrontFacing(); - } + } - return array; +} - } +const frontFacing = /*@__PURE__*/ nodeImmutable( FrontFacingNode ); +const faceDirection = /*@__PURE__*/ float( frontFacing ).mul( 2.0 ).sub( 1.0 ); - if ( materials[ name ] === undefined ) { +const normalGeometry = /*@__PURE__*/ attribute( 'normal', 'vec3' ); - console.warn( 'THREE.ObjectLoader: Undefined material', name ); +const normalLocal = /*@__PURE__*/ ( Fn( ( builder ) => { - } + if ( builder.geometry.hasAttribute( 'normal' ) === false ) { - return materials[ name ]; + console.warn( 'TSL.NormalNode: Vertex attribute "normal" not found on geometry.' ); - } + return vec3( 0, 1, 0 ); - function getTexture( uuid ) { + } - if ( textures[ uuid ] === undefined ) { + return normalGeometry; - console.warn( 'THREE.ObjectLoader: Undefined texture', uuid ); +}, 'vec3' ).once() )().toVar( 'normalLocal' ); - } +const normalFlat = /*@__PURE__*/ positionView.dFdx().cross( positionView.dFdy() ).normalize().toVar( 'normalFlat' ); - return textures[ uuid ]; +const normalView = /*@__PURE__*/ ( Fn( ( builder ) => { - } + let node; - let geometry, material; + if ( builder.material.flatShading === true ) { - switch ( data.type ) { + node = normalFlat; - case 'Scene': + } else { - object = new Scene(); + node = varying( transformNormalToView( normalLocal ), 'v_normalView' ).normalize(); - if ( data.background !== undefined ) { + } - if ( Number.isInteger( data.background ) ) { + return node; - object.background = new Color( data.background ); +}, 'vec3' ).once() )().toVar( 'normalView' ); - } else { +const normalWorld = /*@__PURE__*/ varying( normalView.transformDirection( cameraViewMatrix ), 'v_normalWorld' ).normalize().toVar( 'normalWorld' ); - object.background = getTexture( data.background ); +const transformedNormalView = /*@__PURE__*/ ( Fn( ( builder ) => { - } + return builder.context.setupNormal(); - } +}, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedNormalView' ); - if ( data.environment !== undefined ) { - object.environment = getTexture( data.environment ); +const transformedNormalWorld = /*@__PURE__*/ transformedNormalView.transformDirection( cameraViewMatrix ).toVar( 'transformedNormalWorld' ); - } +const transformedClearcoatNormalView = /*@__PURE__*/ ( Fn( ( builder ) => { - if ( data.fog !== undefined ) { + return builder.context.setupClearcoatNormal(); - if ( data.fog.type === 'Fog' ) { +}, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedClearcoatNormalView' ); - object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); +const transformNormal = /*@__PURE__*/ Fn( ( [ normal, matrix = modelWorldMatrix ] ) => { - } else if ( data.fog.type === 'FogExp2' ) { + const m = mat3( matrix ); - object.fog = new FogExp2( data.fog.color, data.fog.density ); + const transformedNormal = normal.div( vec3( m[ 0 ].dot( m[ 0 ] ), m[ 1 ].dot( m[ 1 ] ), m[ 2 ].dot( m[ 2 ] ) ) ); - } + return m.mul( transformedNormal ).xyz; - if ( data.fog.name !== '' ) { +} ); - object.fog.name = data.fog.name; +const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) => { - } + const modelNormalViewMatrix = builder.renderer.nodes.modelNormalViewMatrix; - } + if ( modelNormalViewMatrix !== null ) { - if ( data.backgroundBlurriness !== undefined ) object.backgroundBlurriness = data.backgroundBlurriness; - if ( data.backgroundIntensity !== undefined ) object.backgroundIntensity = data.backgroundIntensity; - if ( data.backgroundRotation !== undefined ) object.backgroundRotation.fromArray( data.backgroundRotation ); + return modelNormalViewMatrix.transformDirection( normal ); - if ( data.environmentIntensity !== undefined ) object.environmentIntensity = data.environmentIntensity; - if ( data.environmentRotation !== undefined ) object.environmentRotation.fromArray( data.environmentRotation ); + } - break; + // - case 'PerspectiveCamera': + const transformedNormal = modelNormalMatrix.mul( normal ); - object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); + return cameraViewMatrix.transformDirection( transformedNormal ); - if ( data.focus !== undefined ) object.focus = data.focus; - if ( data.zoom !== undefined ) object.zoom = data.zoom; - if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; - if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; - if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); +} ); - break; +const materialRefractionRatio = /*@__PURE__*/ uniform( 0 ).onReference( ( { material } ) => material ).onRenderUpdate( ( { material } ) => material.refractionRatio ); - case 'OrthographicCamera': +const reflectView = /*@__PURE__*/ positionViewDirection.negate().reflect( transformedNormalView ); +const refractView = /*@__PURE__*/ positionViewDirection.negate().refract( transformedNormalView, materialRefractionRatio ); - object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); +const reflectVector = /*@__PURE__*/ reflectView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' ); +const refractVector = /*@__PURE__*/ refractView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' ); - if ( data.zoom !== undefined ) object.zoom = data.zoom; - if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); +class CubeTextureNode extends TextureNode { - break; + static get type() { - case 'AmbientLight': + return 'CubeTextureNode'; - object = new AmbientLight( data.color, data.intensity ); + } - break; + constructor( value, uvNode = null, levelNode = null, biasNode = null ) { - case 'DirectionalLight': + super( value, uvNode, levelNode, biasNode ); - object = new DirectionalLight( data.color, data.intensity ); - object.target = data.target || ''; + this.isCubeTextureNode = true; - break; + } - case 'PointLight': + getInputType( /*builder*/ ) { - object = new PointLight( data.color, data.intensity, data.distance, data.decay ); + return 'cubeTexture'; - break; + } - case 'RectAreaLight': + getDefaultUV() { - object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); + const texture = this.value; - break; + if ( texture.mapping === CubeReflectionMapping ) { - case 'SpotLight': + return reflectVector; - object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); - object.target = data.target || ''; + } else if ( texture.mapping === CubeRefractionMapping ) { - break; + return refractVector; - case 'HemisphereLight': + } else { - object = new HemisphereLight( data.color, data.groundColor, data.intensity ); + console.error( 'THREE.CubeTextureNode: Mapping "%s" not supported.', texture.mapping ); - break; + return vec3( 0, 0, 0 ); - case 'LightProbe': + } - object = new LightProbe().fromJSON( data ); + } - break; + setUpdateMatrix( /*updateMatrix*/ ) { } // Ignore .updateMatrix for CubeTextureNode - case 'SkinnedMesh': + setupUV( builder, uvNode ) { - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); + const texture = this.value; - object = new SkinnedMesh( geometry, material ); + if ( builder.renderer.coordinateSystem === WebGPUCoordinateSystem || ! texture.isRenderTargetTexture ) { - if ( data.bindMode !== undefined ) object.bindMode = data.bindMode; - if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix ); - if ( data.skeleton !== undefined ) object.skeleton = data.skeleton; + return vec3( uvNode.x.negate(), uvNode.yz ); - break; + } else { - case 'Mesh': + return uvNode; - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); + } - object = new Mesh( geometry, material ); + } - break; + generateUV( builder, cubeUV ) { - case 'InstancedMesh': + return cubeUV.build( builder, 'vec3' ); - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); - const count = data.count; - const instanceMatrix = data.instanceMatrix; - const instanceColor = data.instanceColor; + } - object = new InstancedMesh( geometry, material, count ); - object.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 ); - if ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize ); +} - break; +const cubeTexture = /*@__PURE__*/ nodeProxy( CubeTextureNode ); - case 'BatchedMesh': +class BufferNode extends UniformNode { - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); + static get type() { - object = new BatchedMesh( data.maxInstanceCount, data.maxVertexCount, data.maxIndexCount, material ); - object.geometry = geometry; - object.perObjectFrustumCulled = data.perObjectFrustumCulled; - object.sortObjects = data.sortObjects; + return 'BufferNode'; - object._drawRanges = data.drawRanges; - object._reservedRanges = data.reservedRanges; + } - object._visibility = data.visibility; - object._active = data.active; - object._bounds = data.bounds.map( bound => { + constructor( value, bufferType, bufferCount = 0 ) { - const box = new Box3(); - box.min.fromArray( bound.boxMin ); - box.max.fromArray( bound.boxMax ); + super( value, bufferType ); - const sphere = new Sphere(); - sphere.radius = bound.sphereRadius; - sphere.center.fromArray( bound.sphereCenter ); + this.isBufferNode = true; - return { - boxInitialized: bound.boxInitialized, - box: box, + this.bufferType = bufferType; + this.bufferCount = bufferCount; - sphereInitialized: bound.sphereInitialized, - sphere: sphere - }; + } - } ); + getElementType( builder ) { - object._maxInstanceCount = data.maxInstanceCount; - object._maxVertexCount = data.maxVertexCount; - object._maxIndexCount = data.maxIndexCount; + return this.getNodeType( builder ); - object._geometryInitialized = data.geometryInitialized; - object._geometryCount = data.geometryCount; + } - object._matricesTexture = getTexture( data.matricesTexture.uuid ); - if ( data.colorsTexture !== undefined ) object._colorsTexture = getTexture( data.colorsTexture.uuid ); + getInputType( /*builder*/ ) { - break; + return 'buffer'; - case 'LOD': + } - object = new LOD(); +} - break; +const buffer = ( value, type, count ) => nodeObject( new BufferNode( value, type, count ) ); - case 'Line': +class UniformArrayElementNode extends ArrayElementNode { - object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) ); + static get type() { - break; + return 'UniformArrayElementNode'; - case 'LineLoop': + } - object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); + constructor( arrayBuffer, indexNode ) { - break; + super( arrayBuffer, indexNode ); - case 'LineSegments': + this.isArrayBufferElementNode = true; - object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); + } - break; + generate( builder ) { - case 'PointCloud': - case 'Points': + const snippet = super.generate( builder ); + const type = this.getNodeType(); - object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); + return builder.format( snippet, 'vec4', type ); - break; + } - case 'Sprite': +} - object = new Sprite( getMaterial( data.material ) ); +class UniformArrayNode extends BufferNode { - break; + static get type() { - case 'Group': + return 'UniformArrayNode'; - object = new Group(); + } - break; + constructor( value, elementType = null ) { - case 'Bone': + super( null, 'vec4' ); - object = new Bone(); + this.array = value; + this.elementType = elementType; - break; + this._elementType = null; + this._elementLength = 0; - default: + this.updateType = NodeUpdateType.RENDER; - object = new Object3D(); + this.isArrayBufferNode = true; - } + } - object.uuid = data.uuid; + getElementType() { - if ( data.name !== undefined ) object.name = data.name; + return this.elementType || this._elementType; - if ( data.matrix !== undefined ) { + } - object.matrix.fromArray( data.matrix ); + getElementLength() { - if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate; - if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale ); + return this._elementLength; - } else { + } - if ( data.position !== undefined ) object.position.fromArray( data.position ); - if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); - if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); - if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); + update( /*frame*/ ) { - } + const { array, value } = this; - if ( data.up !== undefined ) object.up.fromArray( data.up ); + const elementLength = this.getElementLength(); + const elementType = this.getElementType(); - if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; - if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; + if ( elementLength === 1 ) { - if ( data.shadow ) { + for ( let i = 0; i < array.length; i ++ ) { - if ( data.shadow.intensity !== undefined ) object.shadow.intensity = data.shadow.intensity; - if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; - if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias; - if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; - if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); - if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); + const index = i * 4; - } + value[ index ] = array[ i ]; - if ( data.visible !== undefined ) object.visible = data.visible; - if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled; - if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder; - if ( data.userData !== undefined ) object.userData = data.userData; - if ( data.layers !== undefined ) object.layers.mask = data.layers; + } - if ( data.children !== undefined ) { + } else if ( elementType === 'color' ) { - const children = data.children; + for ( let i = 0; i < array.length; i ++ ) { - for ( let i = 0; i < children.length; i ++ ) { + const index = i * 4; + const vector = array[ i ]; - object.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) ); + value[ index ] = vector.r; + value[ index + 1 ] = vector.g; + value[ index + 2 ] = vector.b || 0; + //value[ index + 3 ] = vector.a || 0; } - } - - if ( data.animations !== undefined ) { - - const objectAnimations = data.animations; + } else { - for ( let i = 0; i < objectAnimations.length; i ++ ) { + for ( let i = 0; i < array.length; i ++ ) { - const uuid = objectAnimations[ i ]; + const index = i * 4; + const vector = array[ i ]; - object.animations.push( animations[ uuid ] ); + value[ index ] = vector.x; + value[ index + 1 ] = vector.y; + value[ index + 2 ] = vector.z || 0; + value[ index + 3 ] = vector.w || 0; } } - if ( data.type === 'LOD' ) { - - if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate; - - const levels = data.levels; - - for ( let l = 0; l < levels.length; l ++ ) { + } - const level = levels[ l ]; - const child = object.getObjectByProperty( 'uuid', level.object ); + setup( builder ) { - if ( child !== undefined ) { + const length = this.array.length; - object.addLevel( child, level.distance, level.hysteresis ); + this._elementType = this.elementType === null ? getValueType( this.array[ 0 ] ) : this.elementType; + this._elementLength = builder.getTypeLength( this._elementType ); - } + let arrayType = Float32Array; - } + if ( this._elementType.charAt( 0 ) === 'i' ) arrayType = Int32Array; + else if ( this._elementType.charAt( 0 ) === 'u' ) arrayType = Uint32Array; - } + this.value = new arrayType( length * 4 ); + this.bufferCount = length; + this.bufferType = builder.changeComponentType( 'vec4', builder.getComponentType( this._elementType ) ); - return object; + return super.setup( builder ); } - bindSkeletons( object, skeletons ) { + element( indexNode ) { - if ( Object.keys( skeletons ).length === 0 ) return; + return nodeObject( new UniformArrayElementNode( this, nodeObject( indexNode ) ) ); - object.traverse( function ( child ) { + } - if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) { +} - const skeleton = skeletons[ child.skeleton ]; +const uniformArray = ( values, nodeType ) => nodeObject( new UniformArrayNode( values, nodeType ) ); - if ( skeleton === undefined ) { +// - console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton ); +const uniforms = ( values, nodeType ) => { // @deprecated, r168 - } else { + console.warn( 'TSL.UniformArrayNode: uniforms() has been renamed to uniformArray().' ); + return nodeObject( new UniformArrayNode( values, nodeType ) ); - child.bind( skeleton, child.bindMatrix ); +}; - } +class ReferenceElementNode extends ArrayElementNode { - } + static get type() { - } ); + return 'ReferenceElementNode'; } - bindLightTargets( object ) { - - object.traverse( function ( child ) { + constructor( referenceNode, indexNode ) { - if ( child.isDirectionalLight || child.isSpotLight ) { + super( referenceNode, indexNode ); - const uuid = child.target; + this.referenceNode = referenceNode; - const target = object.getObjectByProperty( 'uuid', uuid ); + this.isReferenceElementNode = true; - if ( target !== undefined ) { + } - child.target = target; + getNodeType() { - } else { + return this.referenceNode.uniformType; - child.target = new Object3D(); + } - } + generate( builder ) { - } + const snippet = super.generate( builder ); + const arrayType = this.referenceNode.getNodeType(); + const elementType = this.getNodeType(); - } ); + return builder.format( snippet, arrayType, elementType ); } } -const TEXTURE_MAPPING = { - UVMapping: UVMapping, - CubeReflectionMapping: CubeReflectionMapping, - CubeRefractionMapping: CubeRefractionMapping, - EquirectangularReflectionMapping: EquirectangularReflectionMapping, - EquirectangularRefractionMapping: EquirectangularRefractionMapping, - CubeUVReflectionMapping: CubeUVReflectionMapping -}; +// TODO: Extends this from ReferenceBaseNode +class ReferenceNode extends Node { -const TEXTURE_WRAPPING = { - RepeatWrapping: RepeatWrapping, - ClampToEdgeWrapping: ClampToEdgeWrapping, - MirroredRepeatWrapping: MirroredRepeatWrapping -}; + static get type() { -const TEXTURE_FILTER = { - NearestFilter: NearestFilter, - NearestMipmapNearestFilter: NearestMipmapNearestFilter, - NearestMipmapLinearFilter: NearestMipmapLinearFilter, - LinearFilter: LinearFilter, - LinearMipmapNearestFilter: LinearMipmapNearestFilter, - LinearMipmapLinearFilter: LinearMipmapLinearFilter -}; + return 'ReferenceNode'; -class ImageBitmapLoader extends Loader { + } - constructor( manager ) { + constructor( property, uniformType, object = null, count = null ) { - super( manager ); + super(); - this.isImageBitmapLoader = true; + this.property = property; + this.uniformType = uniformType; + this.object = object; + this.count = count; - if ( typeof createImageBitmap === 'undefined' ) { + this.properties = property.split( '.' ); + this.reference = object; + this.node = null; + this.group = null; + this.name = null; - console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); + this.updateType = NodeUpdateType.OBJECT; - } + } - if ( typeof fetch === 'undefined' ) { + element( indexNode ) { - console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); + return nodeObject( new ReferenceElementNode( this, nodeObject( indexNode ) ) ); - } + } - this.options = { premultiplyAlpha: 'none' }; + setGroup( group ) { + + this.group = group; + + return this; } - setOptions( options ) { + label( name ) { - this.options = options; + this.name = name; return this; } - load( url, onLoad, onProgress, onError ) { + setNodeType( uniformType ) { - if ( url === undefined ) url = ''; + let node = null; - if ( this.path !== undefined ) url = this.path + url; + if ( this.count !== null ) { - url = this.manager.resolveURL( url ); + node = buffer( null, uniformType, this.count ); - const scope = this; + } else if ( Array.isArray( this.getValueFromReference() ) ) { - const cached = Cache.get( url ); + node = uniformArray( null, uniformType ); - if ( cached !== undefined ) { + } else if ( uniformType === 'texture' ) { - scope.manager.itemStart( url ); + node = texture( null ); - // If cached is a promise, wait for it to resolve - if ( cached.then ) { + } else if ( uniformType === 'cubeTexture' ) { - cached.then( imageBitmap => { + node = cubeTexture( null ); - if ( onLoad ) onLoad( imageBitmap ); + } else { - scope.manager.itemEnd( url ); + node = uniform( null, uniformType ); - } ).catch( e => { + } - if ( onError ) onError( e ); + if ( this.group !== null ) { - } ); - return; + node.setGroup( this.group ); - } + } - // If cached is not a promise (i.e., it's already an imageBitmap) - setTimeout( function () { + if ( this.name !== null ) node.label( this.name ); - if ( onLoad ) onLoad( cached ); + this.node = node.getSelf(); - scope.manager.itemEnd( url ); + } - }, 0 ); + getNodeType( builder ) { - return cached; + if ( this.node === null ) { + + this.updateReference( builder ); + this.updateValue(); } - const fetchOptions = {}; - fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include'; - fetchOptions.headers = this.requestHeader; + return this.node.getNodeType( builder ); - const promise = fetch( url, fetchOptions ).then( function ( res ) { + } - return res.blob(); + getValueFromReference( object = this.reference ) { - } ).then( function ( blob ) { + const { properties } = this; - return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) ); + let value = object[ properties[ 0 ] ]; - } ).then( function ( imageBitmap ) { + for ( let i = 1; i < properties.length; i ++ ) { - Cache.add( url, imageBitmap ); + value = value[ properties[ i ] ]; - if ( onLoad ) onLoad( imageBitmap ); + } - scope.manager.itemEnd( url ); + return value; - return imageBitmap; + } - } ).catch( function ( e ) { + updateReference( state ) { - if ( onError ) onError( e ); + this.reference = this.object !== null ? this.object : state.object; - Cache.remove( url ); + return this.reference; - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); + } - } ); + setup() { - Cache.add( url, promise ); - scope.manager.itemStart( url ); + this.updateValue(); + + return this.node; } -} + update( /*frame*/ ) { -let _context; + this.updateValue(); -class AudioContext { + } - static getContext() { + updateValue() { - if ( _context === undefined ) { + if ( this.node === null ) this.setNodeType( this.uniformType ); - _context = new ( window.AudioContext || window.webkitAudioContext )(); + const value = this.getValueFromReference(); - } + if ( Array.isArray( value ) ) { - return _context; + this.node.array = value; - } + } else { - static setContext( value ) { + this.node.value = value; - _context = value; + } } } -class AudioLoader extends Loader { +const reference = ( name, type, object ) => nodeObject( new ReferenceNode( name, type, object ) ); +const referenceBuffer = ( name, type, count, object ) => nodeObject( new ReferenceNode( name, type, object, count ) ); - constructor( manager ) { +class MaterialReferenceNode extends ReferenceNode { - super( manager ); + static get type() { - } + return 'MaterialReferenceNode'; - load( url, onLoad, onProgress, onError ) { + } - const scope = this; + constructor( property, inputType, material = null ) { - const loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( buffer ) { + super( property, inputType, material ); - try { + this.material = material; - // Create a copy of the buffer. The `decodeAudioData` method - // detaches the buffer when complete, preventing reuse. - const bufferCopy = buffer.slice( 0 ); + //this.updateType = NodeUpdateType.RENDER; - const context = AudioContext.getContext(); - context.decodeAudioData( bufferCopy, function ( audioBuffer ) { + this.isMaterialReferenceNode = true; - onLoad( audioBuffer ); + } - } ).catch( handleError ); + /*setNodeType( node ) { - } catch ( e ) { + super.setNodeType( node ); - handleError( e ); + this.node.groupNode = renderGroup; - } + }*/ - }, onProgress, onError ); + updateReference( state ) { - function handleError( e ) { + this.reference = this.material !== null ? this.material : state.material; - if ( onError ) { + return this.reference; - onError( e ); + } - } else { +} - console.error( e ); +const materialReference = ( name, type, material ) => nodeObject( new MaterialReferenceNode( name, type, material ) ); - } +const tangentGeometry = /*@__PURE__*/ Fn( ( builder ) => { - scope.manager.itemError( url ); + if ( builder.geometry.hasAttribute( 'tangent' ) === false ) { - } + builder.geometry.computeTangents(); } -} + return attribute( 'tangent', 'vec4' ); -const _eyeRight = /*@__PURE__*/ new Matrix4(); -const _eyeLeft = /*@__PURE__*/ new Matrix4(); -const _projectionMatrix = /*@__PURE__*/ new Matrix4(); +} )(); -class StereoCamera { +const tangentLocal = /*@__PURE__*/ tangentGeometry.xyz.toVar( 'tangentLocal' ); +const tangentView = /*@__PURE__*/ modelViewMatrix.mul( vec4( tangentLocal, 0 ) ).xyz.varying( 'v_tangentView' ).normalize().toVar( 'tangentView' ); +const tangentWorld = /*@__PURE__*/ tangentView.transformDirection( cameraViewMatrix ).varying( 'v_tangentWorld' ).normalize().toVar( 'tangentWorld' ); +const transformedTangentView = /*@__PURE__*/ tangentView.toVar( 'transformedTangentView' ); +const transformedTangentWorld = /*@__PURE__*/ transformedTangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedTangentWorld' ); - constructor() { +const getBitangent = ( crossNormalTangent ) => crossNormalTangent.mul( tangentGeometry.w ).xyz; - this.type = 'StereoCamera'; +const bitangentGeometry = /*@__PURE__*/ varying( getBitangent( normalGeometry.cross( tangentGeometry ) ), 'v_bitangentGeometry' ).normalize().toVar( 'bitangentGeometry' ); +const bitangentLocal = /*@__PURE__*/ varying( getBitangent( normalLocal.cross( tangentLocal ) ), 'v_bitangentLocal' ).normalize().toVar( 'bitangentLocal' ); +const bitangentView = /*@__PURE__*/ varying( getBitangent( normalView.cross( tangentView ) ), 'v_bitangentView' ).normalize().toVar( 'bitangentView' ); +const bitangentWorld = /*@__PURE__*/ varying( getBitangent( normalWorld.cross( tangentWorld ) ), 'v_bitangentWorld' ).normalize().toVar( 'bitangentWorld' ); +const transformedBitangentView = /*@__PURE__*/ getBitangent( transformedNormalView.cross( transformedTangentView ) ).normalize().toVar( 'transformedBitangentView' ); +const transformedBitangentWorld = /*@__PURE__*/ transformedBitangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedBitangentWorld' ); - this.aspect = 1; +const TBNViewMatrix = /*@__PURE__*/ mat3( tangentView, bitangentView, normalView ); - this.eyeSep = 0.064; +const parallaxDirection = /*@__PURE__*/ positionViewDirection.mul( TBNViewMatrix )/*.normalize()*/; +const parallaxUV = ( uv, scale ) => uv.sub( parallaxDirection.mul( scale ) ); - this.cameraL = new PerspectiveCamera(); - this.cameraL.layers.enable( 1 ); - this.cameraL.matrixAutoUpdate = false; +const transformedBentNormalView = /*@__PURE__*/ ( () => { - this.cameraR = new PerspectiveCamera(); - this.cameraR.layers.enable( 2 ); - this.cameraR.matrixAutoUpdate = false; + // https://google.github.io/filament/Filament.md.html#lighting/imagebasedlights/anisotropy - this._cache = { - focus: null, - fov: null, - aspect: null, - near: null, - far: null, - zoom: null, - eyeSep: null - }; + let bentNormal = anisotropyB.cross( positionViewDirection ); + bentNormal = bentNormal.cross( anisotropyB ).normalize(); + bentNormal = mix( bentNormal, transformedNormalView, anisotropy.mul( roughness.oneMinus() ).oneMinus().pow2().pow2() ).normalize(); - } + return bentNormal; - update( camera ) { - const cache = this._cache; +} )(); - const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov || - cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near || - cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep; +// Normal Mapping Without Precomputed Tangents +// http://www.thetenthplanet.de/archives/1180 - if ( needsUpdate ) { +const perturbNormal2Arb = /*@__PURE__*/ Fn( ( inputs ) => { - cache.focus = camera.focus; - cache.fov = camera.fov; - cache.aspect = camera.aspect * this.aspect; - cache.near = camera.near; - cache.far = camera.far; - cache.zoom = camera.zoom; - cache.eyeSep = this.eyeSep; + const { eye_pos, surf_norm, mapN, uv } = inputs; - // Off-axis stereoscopic effect based on - // http://paulbourke.net/stereographics/stereorender/ + const q0 = eye_pos.dFdx(); + const q1 = eye_pos.dFdy(); + const st0 = uv.dFdx(); + const st1 = uv.dFdy(); - _projectionMatrix.copy( camera.projectionMatrix ); - const eyeSepHalf = cache.eyeSep / 2; - const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus; - const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom; - let xmin, xmax; + const N = surf_norm; // normalized - // translate xOffset + const q1perp = q1.cross( N ); + const q0perp = N.cross( q0 ); - _eyeLeft.elements[ 12 ] = - eyeSepHalf; - _eyeRight.elements[ 12 ] = eyeSepHalf; + const T = q1perp.mul( st0.x ).add( q0perp.mul( st1.x ) ); + const B = q1perp.mul( st0.y ).add( q0perp.mul( st1.y ) ); - // for left eye + const det = T.dot( T ).max( B.dot( B ) ); + const scale = faceDirection.mul( det.inverseSqrt() ); - xmin = - ymax * cache.aspect + eyeSepOnProjection; - xmax = ymax * cache.aspect + eyeSepOnProjection; + return add( T.mul( mapN.x, scale ), B.mul( mapN.y, scale ), N.mul( mapN.z ) ).normalize(); - _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); - _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); +} ); - this.cameraL.projectionMatrix.copy( _projectionMatrix ); +class NormalMapNode extends TempNode { - // for right eye + static get type() { - xmin = - ymax * cache.aspect - eyeSepOnProjection; - xmax = ymax * cache.aspect - eyeSepOnProjection; + return 'NormalMapNode'; - _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); - _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); + } - this.cameraR.projectionMatrix.copy( _projectionMatrix ); + constructor( node, scaleNode = null ) { - } + super( 'vec3' ); - this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft ); - this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight ); + this.node = node; + this.scaleNode = scaleNode; + + this.normalMapType = TangentSpaceNormalMap; } -} + setup( builder ) { -class ArrayCamera extends PerspectiveCamera { + const { normalMapType, scaleNode } = this; - constructor( array = [] ) { + let normalMap = this.node.mul( 2.0 ).sub( 1.0 ); - super(); + if ( scaleNode !== null ) { - this.isArrayCamera = true; + normalMap = vec3( normalMap.xy.mul( scaleNode ), normalMap.z ); - this.cameras = array; + } - } + let outputNode = null; -} + if ( normalMapType === ObjectSpaceNormalMap ) { -class Clock { + outputNode = transformNormalToView( normalMap ); - constructor( autoStart = true ) { + } else if ( normalMapType === TangentSpaceNormalMap ) { - this.autoStart = autoStart; + const tangent = builder.hasGeometryAttribute( 'tangent' ); - this.startTime = 0; - this.oldTime = 0; - this.elapsedTime = 0; + if ( tangent === true ) { - this.running = false; + outputNode = TBNViewMatrix.mul( normalMap ).normalize(); - } + } else { - start() { + outputNode = perturbNormal2Arb( { + eye_pos: positionView, + surf_norm: normalView, + mapN: normalMap, + uv: uv() + } ); - this.startTime = now(); + } - this.oldTime = this.startTime; - this.elapsedTime = 0; - this.running = true; + } + + return outputNode; } - stop() { +} - this.getElapsedTime(); - this.running = false; - this.autoStart = false; +const normalMap = /*@__PURE__*/ nodeProxy( NormalMapNode ); - } +// Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen +// https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf - getElapsedTime() { +const dHdxy_fwd = Fn( ( { textureNode, bumpScale } ) => { - this.getDelta(); - return this.elapsedTime; + // It's used to preserve the same TextureNode instance + const sampleTexture = ( callback ) => textureNode.cache().context( { getUV: ( texNode ) => callback( texNode.uvNode || uv() ), forceUVContext: true } ); - } + const Hll = float( sampleTexture( ( uvNode ) => uvNode ) ); - getDelta() { + return vec2( + float( sampleTexture( ( uvNode ) => uvNode.add( uvNode.dFdx() ) ) ).sub( Hll ), + float( sampleTexture( ( uvNode ) => uvNode.add( uvNode.dFdy() ) ) ).sub( Hll ) + ).mul( bumpScale ); - let diff = 0; +} ); - if ( this.autoStart && ! this.running ) { +// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2) - this.start(); - return 0; +const perturbNormalArb = Fn( ( inputs ) => { - } + const { surf_pos, surf_norm, dHdxy } = inputs; - if ( this.running ) { + // normalize is done to ensure that the bump map looks the same regardless of the texture's scale + const vSigmaX = surf_pos.dFdx().normalize(); + const vSigmaY = surf_pos.dFdy().normalize(); + const vN = surf_norm; // normalized - const newTime = now(); + const R1 = vSigmaY.cross( vN ); + const R2 = vN.cross( vSigmaX ); - diff = ( newTime - this.oldTime ) / 1000; - this.oldTime = newTime; + const fDet = vSigmaX.dot( R1 ).mul( faceDirection ); - this.elapsedTime += diff; + const vGrad = fDet.sign().mul( dHdxy.x.mul( R1 ).add( dHdxy.y.mul( R2 ) ) ); - } + return fDet.abs().mul( surf_norm ).sub( vGrad ).normalize(); - return diff; +} ); - } +class BumpMapNode extends TempNode { -} + static get type() { -function now() { + return 'BumpMapNode'; - return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 + } -} + constructor( textureNode, scaleNode = null ) { -const _position$1 = /*@__PURE__*/ new Vector3(); -const _quaternion$1 = /*@__PURE__*/ new Quaternion(); -const _scale$1 = /*@__PURE__*/ new Vector3(); -const _orientation$1 = /*@__PURE__*/ new Vector3(); + super( 'vec3' ); -class AudioListener extends Object3D { + this.textureNode = textureNode; + this.scaleNode = scaleNode; - constructor() { + } - super(); + setup() { - this.type = 'AudioListener'; + const bumpScale = this.scaleNode !== null ? this.scaleNode : 1; + const dHdxy = dHdxy_fwd( { textureNode: this.textureNode, bumpScale } ); - this.context = AudioContext.getContext(); + return perturbNormalArb( { + surf_pos: positionView, + surf_norm: normalView, + dHdxy + } ); - this.gain = this.context.createGain(); - this.gain.connect( this.context.destination ); + } - this.filter = null; +} - this.timeDelta = 0; +const bumpMap = /*@__PURE__*/ nodeProxy( BumpMapNode ); - // private +const _propertyCache = new Map(); - this._clock = new Clock(); +class MaterialNode extends Node { + + static get type() { + + return 'MaterialNode'; } - getInput() { + constructor( scope ) { - return this.gain; + super(); - } + this.scope = scope; - removeFilter() { + } - if ( this.filter !== null ) { + getCache( property, type ) { - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); - this.gain.connect( this.context.destination ); - this.filter = null; + let node = _propertyCache.get( property ); - } + if ( node === undefined ) { - return this; + node = materialReference( property, type ); - } + _propertyCache.set( property, node ); - getFilter() { + } - return this.filter; + return node; } - setFilter( value ) { + getFloat( property ) { - if ( this.filter !== null ) { + return this.getCache( property, 'float' ); - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); + } - } else { + getColor( property ) { - this.gain.disconnect( this.context.destination ); + return this.getCache( property, 'color' ); - } + } - this.filter = value; - this.gain.connect( this.filter ); - this.filter.connect( this.context.destination ); + getTexture( property ) { - return this; + return this.getCache( property === 'map' ? 'map' : property + 'Map', 'texture' ); } - getMasterVolume() { + setup( builder ) { - return this.gain.gain.value; + const material = builder.context.material; + const scope = this.scope; - } + let node = null; - setMasterVolume( value ) { + if ( scope === MaterialNode.COLOR ) { - this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); + const colorNode = material.color !== undefined ? this.getColor( scope ) : vec3(); - return this; + if ( material.map && material.map.isTexture === true ) { - } + node = colorNode.mul( this.getTexture( 'map' ) ); - updateMatrixWorld( force ) { + } else { - super.updateMatrixWorld( force ); + node = colorNode; - const listener = this.context.listener; - const up = this.up; + } - this.timeDelta = this._clock.getDelta(); + } else if ( scope === MaterialNode.OPACITY ) { - this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 ); + const opacityNode = this.getFloat( scope ); - _orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 ); + if ( material.alphaMap && material.alphaMap.isTexture === true ) { - if ( listener.positionX ) { + node = opacityNode.mul( this.getTexture( 'alpha' ) ); - // code path for Chrome (see #14393) + } else { - const endTime = this.context.currentTime + this.timeDelta; + node = opacityNode; - listener.positionX.linearRampToValueAtTime( _position$1.x, endTime ); - listener.positionY.linearRampToValueAtTime( _position$1.y, endTime ); - listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime ); - listener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime ); - listener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime ); - listener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime ); - listener.upX.linearRampToValueAtTime( up.x, endTime ); - listener.upY.linearRampToValueAtTime( up.y, endTime ); - listener.upZ.linearRampToValueAtTime( up.z, endTime ); + } - } else { + } else if ( scope === MaterialNode.SPECULAR_STRENGTH ) { - listener.setPosition( _position$1.x, _position$1.y, _position$1.z ); - listener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z ); + if ( material.specularMap && material.specularMap.isTexture === true ) { - } + node = this.getTexture( 'specular' ).r; - } + } else { -} + node = float( 1 ); -class Audio extends Object3D { + } - constructor( listener ) { + } else if ( scope === MaterialNode.SPECULAR_INTENSITY ) { - super(); + const specularIntensity = this.getFloat( scope ); - this.type = 'Audio'; + if ( material.specularMap ) { - this.listener = listener; - this.context = listener.context; + node = specularIntensity.mul( this.getTexture( scope ).a ); - this.gain = this.context.createGain(); - this.gain.connect( listener.getInput() ); + } else { - this.autoplay = false; + node = specularIntensity; - this.buffer = null; - this.detune = 0; - this.loop = false; - this.loopStart = 0; - this.loopEnd = 0; - this.offset = 0; - this.duration = undefined; - this.playbackRate = 1; - this.isPlaying = false; - this.hasPlaybackControl = true; - this.source = null; - this.sourceType = 'empty'; + } - this._startedAt = 0; - this._progress = 0; - this._connected = false; + } else if ( scope === MaterialNode.SPECULAR_COLOR ) { - this.filters = []; + const specularColorNode = this.getColor( scope ); - } + if ( material.specularColorMap && material.specularColorMap.isTexture === true ) { - getOutput() { + node = specularColorNode.mul( this.getTexture( scope ).rgb ); - return this.gain; + } else { - } + node = specularColorNode; - setNodeSource( audioNode ) { + } - this.hasPlaybackControl = false; - this.sourceType = 'audioNode'; - this.source = audioNode; - this.connect(); + } else if ( scope === MaterialNode.ROUGHNESS ) { // TODO: cleanup similar branches - return this; + const roughnessNode = this.getFloat( scope ); - } + if ( material.roughnessMap && material.roughnessMap.isTexture === true ) { - setMediaElementSource( mediaElement ) { + node = roughnessNode.mul( this.getTexture( scope ).g ); - this.hasPlaybackControl = false; - this.sourceType = 'mediaNode'; - this.source = this.context.createMediaElementSource( mediaElement ); - this.connect(); + } else { - return this; + node = roughnessNode; - } + } - setMediaStreamSource( mediaStream ) { + } else if ( scope === MaterialNode.METALNESS ) { - this.hasPlaybackControl = false; - this.sourceType = 'mediaStreamNode'; - this.source = this.context.createMediaStreamSource( mediaStream ); - this.connect(); + const metalnessNode = this.getFloat( scope ); - return this; + if ( material.metalnessMap && material.metalnessMap.isTexture === true ) { - } + node = metalnessNode.mul( this.getTexture( scope ).b ); - setBuffer( audioBuffer ) { + } else { - this.buffer = audioBuffer; - this.sourceType = 'buffer'; + node = metalnessNode; - if ( this.autoplay ) this.play(); + } - return this; + } else if ( scope === MaterialNode.EMISSIVE ) { - } + const emissiveIntensityNode = this.getFloat( 'emissiveIntensity' ); + const emissiveNode = this.getColor( scope ).mul( emissiveIntensityNode ); - play( delay = 0 ) { + if ( material.emissiveMap && material.emissiveMap.isTexture === true ) { - if ( this.isPlaying === true ) { + node = emissiveNode.mul( this.getTexture( scope ) ); - console.warn( 'THREE.Audio: Audio is already playing.' ); - return; + } else { - } + node = emissiveNode; - if ( this.hasPlaybackControl === false ) { + } - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + } else if ( scope === MaterialNode.NORMAL ) { - } + if ( material.normalMap ) { - this._startedAt = this.context.currentTime + delay; + node = normalMap( this.getTexture( 'normal' ), this.getCache( 'normalScale', 'vec2' ) ); + node.normalMapType = material.normalMapType; - const source = this.context.createBufferSource(); - source.buffer = this.buffer; - source.loop = this.loop; - source.loopStart = this.loopStart; - source.loopEnd = this.loopEnd; - source.onended = this.onEnded.bind( this ); - source.start( this._startedAt, this._progress + this.offset, this.duration ); + } else if ( material.bumpMap ) { - this.isPlaying = true; + node = bumpMap( this.getTexture( 'bump' ).r, this.getFloat( 'bumpScale' ) ); - this.source = source; + } else { - this.setDetune( this.detune ); - this.setPlaybackRate( this.playbackRate ); + node = normalView; - return this.connect(); + } - } + } else if ( scope === MaterialNode.CLEARCOAT ) { - pause() { + const clearcoatNode = this.getFloat( scope ); - if ( this.hasPlaybackControl === false ) { + if ( material.clearcoatMap && material.clearcoatMap.isTexture === true ) { - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + node = clearcoatNode.mul( this.getTexture( scope ).r ); - } + } else { - if ( this.isPlaying === true ) { + node = clearcoatNode; - // update current progress + } - this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate; + } else if ( scope === MaterialNode.CLEARCOAT_ROUGHNESS ) { - if ( this.loop === true ) { + const clearcoatRoughnessNode = this.getFloat( scope ); - // ensure _progress does not exceed duration with looped audios + if ( material.clearcoatRoughnessMap && material.clearcoatRoughnessMap.isTexture === true ) { - this._progress = this._progress % ( this.duration || this.buffer.duration ); + node = clearcoatRoughnessNode.mul( this.getTexture( scope ).r ); - } + } else { - this.source.stop(); - this.source.onended = null; + node = clearcoatRoughnessNode; - this.isPlaying = false; + } - } + } else if ( scope === MaterialNode.CLEARCOAT_NORMAL ) { - return this; + if ( material.clearcoatNormalMap ) { - } + node = normalMap( this.getTexture( scope ), this.getCache( scope + 'Scale', 'vec2' ) ); - stop() { + } else { - if ( this.hasPlaybackControl === false ) { + node = normalView; - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + } - } + } else if ( scope === MaterialNode.SHEEN ) { - this._progress = 0; + const sheenNode = this.getColor( 'sheenColor' ).mul( this.getFloat( 'sheen' ) ); // Move this mul() to CPU - if ( this.source !== null ) { + if ( material.sheenColorMap && material.sheenColorMap.isTexture === true ) { - this.source.stop(); - this.source.onended = null; + node = sheenNode.mul( this.getTexture( 'sheenColor' ).rgb ); - } + } else { - this.isPlaying = false; + node = sheenNode; - return this; + } - } + } else if ( scope === MaterialNode.SHEEN_ROUGHNESS ) { - connect() { + const sheenRoughnessNode = this.getFloat( scope ); - if ( this.filters.length > 0 ) { + if ( material.sheenRoughnessMap && material.sheenRoughnessMap.isTexture === true ) { - this.source.connect( this.filters[ 0 ] ); + node = sheenRoughnessNode.mul( this.getTexture( scope ).a ); - for ( let i = 1, l = this.filters.length; i < l; i ++ ) { + } else { - this.filters[ i - 1 ].connect( this.filters[ i ] ); + node = sheenRoughnessNode; } - this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); + node = node.clamp( 0.07, 1.0 ); - } else { + } else if ( scope === MaterialNode.ANISOTROPY ) { - this.source.connect( this.getOutput() ); + if ( material.anisotropyMap && material.anisotropyMap.isTexture === true ) { - } + const anisotropyPolar = this.getTexture( scope ); + const anisotropyMat = mat2( materialAnisotropyVector.x, materialAnisotropyVector.y, materialAnisotropyVector.y.negate(), materialAnisotropyVector.x ); - this._connected = true; + node = anisotropyMat.mul( anisotropyPolar.rg.mul( 2.0 ).sub( vec2( 1.0 ) ).normalize().mul( anisotropyPolar.b ) ); - return this; + } else { - } + node = materialAnisotropyVector; - disconnect() { + } - if ( this._connected === false ) { + } else if ( scope === MaterialNode.IRIDESCENCE_THICKNESS ) { - return; + const iridescenceThicknessMaximum = reference( '1', 'float', material.iridescenceThicknessRange ); - } + if ( material.iridescenceThicknessMap ) { - if ( this.filters.length > 0 ) { + const iridescenceThicknessMinimum = reference( '0', 'float', material.iridescenceThicknessRange ); - this.source.disconnect( this.filters[ 0 ] ); + node = iridescenceThicknessMaximum.sub( iridescenceThicknessMinimum ).mul( this.getTexture( scope ).g ).add( iridescenceThicknessMinimum ); - for ( let i = 1, l = this.filters.length; i < l; i ++ ) { + } else { - this.filters[ i - 1 ].disconnect( this.filters[ i ] ); + node = iridescenceThicknessMaximum; } - this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); + } else if ( scope === MaterialNode.TRANSMISSION ) { - } else { + const transmissionNode = this.getFloat( scope ); - this.source.disconnect( this.getOutput() ); + if ( material.transmissionMap ) { - } + node = transmissionNode.mul( this.getTexture( scope ).r ); - this._connected = false; + } else { - return this; + node = transmissionNode; - } + } - getFilters() { + } else if ( scope === MaterialNode.THICKNESS ) { - return this.filters; + const thicknessNode = this.getFloat( scope ); - } + if ( material.thicknessMap ) { - setFilters( value ) { + node = thicknessNode.mul( this.getTexture( scope ).g ); - if ( ! value ) value = []; + } else { - if ( this._connected === true ) { + node = thicknessNode; - this.disconnect(); - this.filters = value.slice(); - this.connect(); + } - } else { + } else if ( scope === MaterialNode.IOR ) { - this.filters = value.slice(); + node = this.getFloat( scope ); - } + } else if ( scope === MaterialNode.LIGHT_MAP ) { - return this; + node = this.getTexture( scope ).rgb.mul( this.getFloat( 'lightMapIntensity' ) ); - } + } else if ( scope === MaterialNode.AO_MAP ) { - setDetune( value ) { + node = this.getTexture( scope ).r.sub( 1.0 ).mul( this.getFloat( 'aoMapIntensity' ) ).add( 1.0 ); - this.detune = value; + } else { - if ( this.isPlaying === true && this.source.detune !== undefined ) { + const outputType = this.getNodeType( builder ); - this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 ); + node = this.getCache( scope, outputType ); } - return this; + return node; } - getDetune() { - - return this.detune; +} - } - - getFilter() { +MaterialNode.ALPHA_TEST = 'alphaTest'; +MaterialNode.COLOR = 'color'; +MaterialNode.OPACITY = 'opacity'; +MaterialNode.SHININESS = 'shininess'; +MaterialNode.SPECULAR = 'specular'; +MaterialNode.SPECULAR_STRENGTH = 'specularStrength'; +MaterialNode.SPECULAR_INTENSITY = 'specularIntensity'; +MaterialNode.SPECULAR_COLOR = 'specularColor'; +MaterialNode.REFLECTIVITY = 'reflectivity'; +MaterialNode.ROUGHNESS = 'roughness'; +MaterialNode.METALNESS = 'metalness'; +MaterialNode.NORMAL = 'normal'; +MaterialNode.CLEARCOAT = 'clearcoat'; +MaterialNode.CLEARCOAT_ROUGHNESS = 'clearcoatRoughness'; +MaterialNode.CLEARCOAT_NORMAL = 'clearcoatNormal'; +MaterialNode.EMISSIVE = 'emissive'; +MaterialNode.ROTATION = 'rotation'; +MaterialNode.SHEEN = 'sheen'; +MaterialNode.SHEEN_ROUGHNESS = 'sheenRoughness'; +MaterialNode.ANISOTROPY = 'anisotropy'; +MaterialNode.IRIDESCENCE = 'iridescence'; +MaterialNode.IRIDESCENCE_IOR = 'iridescenceIOR'; +MaterialNode.IRIDESCENCE_THICKNESS = 'iridescenceThickness'; +MaterialNode.IOR = 'ior'; +MaterialNode.TRANSMISSION = 'transmission'; +MaterialNode.THICKNESS = 'thickness'; +MaterialNode.ATTENUATION_DISTANCE = 'attenuationDistance'; +MaterialNode.ATTENUATION_COLOR = 'attenuationColor'; +MaterialNode.LINE_SCALE = 'scale'; +MaterialNode.LINE_DASH_SIZE = 'dashSize'; +MaterialNode.LINE_GAP_SIZE = 'gapSize'; +MaterialNode.LINE_WIDTH = 'linewidth'; +MaterialNode.LINE_DASH_OFFSET = 'dashOffset'; +MaterialNode.POINT_WIDTH = 'pointWidth'; +MaterialNode.DISPERSION = 'dispersion'; +MaterialNode.LIGHT_MAP = 'light'; +MaterialNode.AO_MAP = 'ao'; - return this.getFilters()[ 0 ]; +const materialAlphaTest = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ALPHA_TEST ); +const materialColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.COLOR ); +const materialShininess = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHININESS ); +const materialEmissive = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.EMISSIVE ); +const materialOpacity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.OPACITY ); +const materialSpecular = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR ); - } +const materialSpecularIntensity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_INTENSITY ); +const materialSpecularColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_COLOR ); - setFilter( filter ) { +const materialSpecularStrength = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_STRENGTH ); +const materialReflectivity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.REFLECTIVITY ); +const materialRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ROUGHNESS ); +const materialMetalness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.METALNESS ); +const materialNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.NORMAL ).context( { getUV: null } ); +const materialClearcoat = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT ); +const materialClearcoatRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_ROUGHNESS ); +const materialClearcoatNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_NORMAL ).context( { getUV: null } ); +const materialRotation = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ROTATION ); +const materialSheen = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHEEN ); +const materialSheenRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHEEN_ROUGHNESS ); +const materialAnisotropy = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ANISOTROPY ); +const materialIridescence = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE ); +const materialIridescenceIOR = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_IOR ); +const materialIridescenceThickness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_THICKNESS ); +const materialTransmission = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.TRANSMISSION ); +const materialThickness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.THICKNESS ); +const materialIOR = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IOR ); +const materialAttenuationDistance = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_DISTANCE ); +const materialAttenuationColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_COLOR ); +const materialLineScale = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_SCALE ); +const materialLineDashSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_SIZE ); +const materialLineGapSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_GAP_SIZE ); +const materialLineWidth = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_WIDTH ); +const materialLineDashOffset = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_OFFSET ); +const materialPointWidth = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.POINT_WIDTH ); +const materialDispersion = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.DISPERSION ); +const materialLightMap = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LIGHT_MAP ); +const materialAOMap = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.AO_MAP ); +const materialAnisotropyVector = /*@__PURE__*/ uniform( new Vector2() ).onReference( function ( frame ) { - return this.setFilters( filter ? [ filter ] : [] ); + return frame.material; - } +} ).onRenderUpdate( function ( { material } ) { - setPlaybackRate( value ) { + this.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) ); - if ( this.hasPlaybackControl === false ) { +} ); - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; +class ModelViewProjectionNode extends TempNode { - } + static get type() { - this.playbackRate = value; + return 'ModelViewProjectionNode'; - if ( this.isPlaying === true ) { + } - this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 ); + constructor( positionNode = null ) { - } + super( 'vec4' ); - return this; + this.positionNode = positionNode; } - getPlaybackRate() { + setup( builder ) { - return this.playbackRate; + if ( builder.shaderStage === 'fragment' ) { - } + return varying( builder.context.mvp ); - onEnded() { + } - this.isPlaying = false; + const position = this.positionNode || positionLocal; + const viewMatrix = builder.renderer.nodes.modelViewMatrix || modelViewMatrix; + + return cameraProjectionMatrix.mul( viewMatrix ).mul( position ); } - getLoop() { +} - if ( this.hasPlaybackControl === false ) { +const modelViewProjection = /*@__PURE__*/ nodeProxy( ModelViewProjectionNode ); - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return false; +class IndexNode extends Node { - } + static get type() { - return this.loop; + return 'IndexNode'; } - setLoop( value ) { + constructor( scope ) { - if ( this.hasPlaybackControl === false ) { + super( 'uint' ); - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + this.scope = scope; - } + this.isInstanceIndexNode = true; - this.loop = value; + } - if ( this.isPlaying === true ) { + generate( builder ) { - this.source.loop = this.loop; + const nodeType = this.getNodeType( builder ); + const scope = this.scope; - } + let propertyName; - return this; + if ( scope === IndexNode.VERTEX ) { - } + // The index of a vertex within a mesh. + propertyName = builder.getVertexIndex(); - setLoopStart( value ) { + } else if ( scope === IndexNode.INSTANCE ) { - this.loopStart = value; + // The index of either a mesh instance or an invocation of a compute shader. + propertyName = builder.getInstanceIndex(); - return this; + } else if ( scope === IndexNode.DRAW ) { - } + // The index of a draw call. + propertyName = builder.getDrawIndex(); - setLoopEnd( value ) { + } else if ( scope === IndexNode.INVOCATION_LOCAL ) { - this.loopEnd = value; + // The index of a compute invocation within the scope of a workgroup load. + propertyName = builder.getInvocationLocalIndex(); - return this; + } else if ( scope === IndexNode.INVOCATION_SUBGROUP ) { - } + // The index of a compute invocation within the scope of a subgroup. + propertyName = builder.getInvocationSubgroupIndex(); - getVolume() { + } else if ( scope === IndexNode.SUBGROUP ) { - return this.gain.gain.value; + // The index of the subgroup the current compute invocation belongs to. + propertyName = builder.getSubgroupIndex(); - } + } else { - setVolume( value ) { + throw new Error( 'THREE.IndexNode: Unknown scope: ' + scope ); - this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); + } - return this; + let output; - } + if ( builder.shaderStage === 'vertex' || builder.shaderStage === 'compute' ) { -} + output = propertyName; -const _position = /*@__PURE__*/ new Vector3(); -const _quaternion = /*@__PURE__*/ new Quaternion(); -const _scale = /*@__PURE__*/ new Vector3(); -const _orientation = /*@__PURE__*/ new Vector3(); + } else { -class PositionalAudio extends Audio { + const nodeVarying = varying( this ); - constructor( listener ) { + output = nodeVarying.build( builder, nodeType ); - super( listener ); + } - this.panner = this.context.createPanner(); - this.panner.panningModel = 'HRTF'; - this.panner.connect( this.gain ); + return output; } - connect() { - - super.connect(); +} - this.panner.connect( this.gain ); +IndexNode.VERTEX = 'vertex'; +IndexNode.INSTANCE = 'instance'; +IndexNode.SUBGROUP = 'subgroup'; +IndexNode.INVOCATION_LOCAL = 'invocationLocal'; +IndexNode.INVOCATION_SUBGROUP = 'invocationSubgroup'; +IndexNode.DRAW = 'draw'; - } +const vertexIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.VERTEX ); +const instanceIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INSTANCE ); +const subgroupIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.SUBGROUP ); +const invocationSubgroupIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INVOCATION_SUBGROUP ); +const invocationLocalIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INVOCATION_LOCAL ); +const drawIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.DRAW ); - disconnect() { +class InstanceNode extends Node { - super.disconnect(); + static get type() { - this.panner.disconnect( this.gain ); + return 'InstanceNode'; } - getOutput() { - - return this.panner; - - } + constructor( instanceMesh ) { - getRefDistance() { + super( 'void' ); - return this.panner.refDistance; + this.instanceMesh = instanceMesh; - } + this.instanceMatrixNode = null; - setRefDistance( value ) { + this.instanceColorNode = null; - this.panner.refDistance = value; + this.updateType = NodeUpdateType.FRAME; - return this; + this.buffer = null; + this.bufferColor = null; } - getRolloffFactor() { - - return this.panner.rolloffFactor; + setup( builder ) { - } + let instanceMatrixNode = this.instanceMatrixNode; + let instanceColorNode = this.instanceColorNode; - setRolloffFactor( value ) { + const instanceMesh = this.instanceMesh; - this.panner.rolloffFactor = value; + if ( instanceMatrixNode === null ) { - return this; + const instanceAttribute = instanceMesh.instanceMatrix; - } + // Both WebGPU and WebGL backends have UBO max limited to 64kb. Matrix count number bigger than 1000 ( 16 * 4 * 1000 = 64kb ) will fallback to attribute. - getDistanceModel() { + if ( instanceMesh.count <= 1000 ) { - return this.panner.distanceModel; + instanceMatrixNode = buffer( instanceAttribute.array, 'mat4', Math.max( instanceMesh.count, 1 ) ).element( instanceIndex ); - } + } else { - setDistanceModel( value ) { + const buffer = new InstancedInterleavedBuffer( instanceAttribute.array, 16, 1 ); - this.panner.distanceModel = value; + this.buffer = buffer; - return this; + const bufferFn = instanceAttribute.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute; - } + const instanceBuffers = [ + // F.Signature -> bufferAttribute( array, type, stride, offset ) + bufferFn( buffer, 'vec4', 16, 0 ), + bufferFn( buffer, 'vec4', 16, 4 ), + bufferFn( buffer, 'vec4', 16, 8 ), + bufferFn( buffer, 'vec4', 16, 12 ) + ]; - getMaxDistance() { + instanceMatrixNode = mat4( ...instanceBuffers ); - return this.panner.maxDistance; + } - } + this.instanceMatrixNode = instanceMatrixNode; - setMaxDistance( value ) { + } - this.panner.maxDistance = value; + const instanceColorAttribute = instanceMesh.instanceColor; - return this; + if ( instanceColorAttribute && instanceColorNode === null ) { - } + const buffer = new InstancedBufferAttribute( instanceColorAttribute.array, 3 ); - setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) { + const bufferFn = instanceColorAttribute.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute; - this.panner.coneInnerAngle = coneInnerAngle; - this.panner.coneOuterAngle = coneOuterAngle; - this.panner.coneOuterGain = coneOuterGain; + this.bufferColor = buffer; - return this; + instanceColorNode = vec3( bufferFn( buffer, 'vec3', 3, 0 ) ); - } + this.instanceColorNode = instanceColorNode; - updateMatrixWorld( force ) { + } - super.updateMatrixWorld( force ); + // POSITION - if ( this.hasPlaybackControl === true && this.isPlaying === false ) return; + const instancePosition = instanceMatrixNode.mul( positionLocal ).xyz; + positionLocal.assign( instancePosition ); - this.matrixWorld.decompose( _position, _quaternion, _scale ); + // NORMAL - _orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion ); + if ( builder.hasGeometryAttribute( 'normal' ) ) { - const panner = this.panner; + const instanceNormal = transformNormal( normalLocal, instanceMatrixNode ); - if ( panner.positionX ) { + // ASSIGNS - // code path for Chrome and Firefox (see #14393) + normalLocal.assign( instanceNormal ); - const endTime = this.context.currentTime + this.listener.timeDelta; + } - panner.positionX.linearRampToValueAtTime( _position.x, endTime ); - panner.positionY.linearRampToValueAtTime( _position.y, endTime ); - panner.positionZ.linearRampToValueAtTime( _position.z, endTime ); - panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime ); - panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime ); - panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime ); + // COLOR - } else { + if ( this.instanceColorNode !== null ) { - panner.setPosition( _position.x, _position.y, _position.z ); - panner.setOrientation( _orientation.x, _orientation.y, _orientation.z ); + varyingProperty( 'vec3', 'vInstanceColor' ).assign( this.instanceColorNode ); } } -} + update( /*frame*/ ) { -class AudioAnalyser { + if ( this.instanceMesh.instanceMatrix.usage !== DynamicDrawUsage && this.buffer != null && this.instanceMesh.instanceMatrix.version !== this.buffer.version ) { - constructor( audio, fftSize = 2048 ) { + this.buffer.version = this.instanceMesh.instanceMatrix.version; - this.analyser = audio.context.createAnalyser(); - this.analyser.fftSize = fftSize; + } - this.data = new Uint8Array( this.analyser.frequencyBinCount ); + if ( this.instanceMesh.instanceColor && this.instanceMesh.instanceColor.usage !== DynamicDrawUsage && this.bufferColor != null && this.instanceMesh.instanceColor.version !== this.bufferColor.version ) { - audio.getOutput().connect( this.analyser ); + this.bufferColor.version = this.instanceMesh.instanceColor.version; + + } } +} + +const instance = /*@__PURE__*/ nodeProxy( InstanceNode ); - getFrequencyData() { +class BatchNode extends Node { - this.analyser.getByteFrequencyData( this.data ); + static get type() { - return this.data; + return 'BatchNode'; } - getAverageFrequency() { - - let value = 0; - const data = this.getFrequencyData(); + constructor( batchMesh ) { - for ( let i = 0; i < data.length; i ++ ) { + super( 'void' ); - value += data[ i ]; + this.batchMesh = batchMesh; - } - return value / data.length; + this.batchingIdNode = null; } -} - -class PropertyMixer { + setup( builder ) { - constructor( binding, typeName, valueSize ) { + // POSITION - this.binding = binding; - this.valueSize = valueSize; + if ( this.batchingIdNode === null ) { - let mixFunction, - mixFunctionAdditive, - setIdentity; + if ( builder.getDrawIndex() === null ) { - // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ] - // - // interpolators can use .buffer as their .result - // the data then goes to 'incoming' - // - // 'accu0' and 'accu1' are used frame-interleaved for - // the cumulative result and are compared to detect - // changes - // - // 'orig' stores the original state of the property - // - // 'add' is used for additive cumulative results - // - // 'work' is optional and is only present for quaternion types. It is used - // to store intermediate quaternion multiplication results + this.batchingIdNode = instanceIndex; - switch ( typeName ) { + } else { - case 'quaternion': - mixFunction = this._slerp; - mixFunctionAdditive = this._slerpAdditive; - setIdentity = this._setAdditiveIdentityQuaternion; + this.batchingIdNode = drawIndex; - this.buffer = new Float64Array( valueSize * 6 ); - this._workIndex = 5; - break; + } - case 'string': - case 'bool': - mixFunction = this._select; + } - // Use the regular mix function and for additive on these types, - // additive is not relevant for non-numeric types - mixFunctionAdditive = this._select; + const getIndirectIndex = Fn( ( [ id ] ) => { - setIdentity = this._setAdditiveIdentityOther; + const size = textureSize( textureLoad( this.batchMesh._indirectTexture ), 0 ); + const x = int( id ).modInt( int( size ) ); + const y = int( id ).div( int( size ) ); + return textureLoad( this.batchMesh._indirectTexture, ivec2( x, y ) ).x; - this.buffer = new Array( valueSize * 5 ); - break; + } ).setLayout( { + name: 'getIndirectIndex', + type: 'uint', + inputs: [ + { name: 'id', type: 'int' } + ] + } ); - default: - mixFunction = this._lerp; - mixFunctionAdditive = this._lerpAdditive; - setIdentity = this._setAdditiveIdentityNumeric; + const indirectId = getIndirectIndex( int( this.batchingIdNode ) ); - this.buffer = new Float64Array( valueSize * 5 ); + const matricesTexture = this.batchMesh._matricesTexture; - } + const size = textureSize( textureLoad( matricesTexture ), 0 ); + const j = float( indirectId ).mul( 4 ).toInt().toVar(); - this._mixBufferRegion = mixFunction; - this._mixBufferRegionAdditive = mixFunctionAdditive; - this._setIdentity = setIdentity; - this._origIndex = 3; - this._addIndex = 4; + const x = j.modInt( size ); + const y = j.div( int( size ) ); + const batchingMatrix = mat4( + textureLoad( matricesTexture, ivec2( x, y ) ), + textureLoad( matricesTexture, ivec2( x.add( 1 ), y ) ), + textureLoad( matricesTexture, ivec2( x.add( 2 ), y ) ), + textureLoad( matricesTexture, ivec2( x.add( 3 ), y ) ) + ); - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; - this.useCount = 0; - this.referenceCount = 0; + const colorsTexture = this.batchMesh._colorsTexture; - } + if ( colorsTexture !== null ) { - // accumulate data in the 'incoming' region into 'accu' - accumulate( accuIndex, weight ) { + const getBatchingColor = Fn( ( [ id ] ) => { - // note: happily accumulating nothing when weight = 0, the caller knows - // the weight and shouldn't have made the call in the first place + const size = textureSize( textureLoad( colorsTexture ), 0 ).x; + const j = id; + const x = j.modInt( size ); + const y = j.div( size ); + return textureLoad( colorsTexture, ivec2( x, y ) ).rgb; - const buffer = this.buffer, - stride = this.valueSize, - offset = accuIndex * stride + stride; + } ).setLayout( { + name: 'getBatchingColor', + type: 'vec3', + inputs: [ + { name: 'id', type: 'int' } + ] + } ); - let currentWeight = this.cumulativeWeight; + const color = getBatchingColor( indirectId ); - if ( currentWeight === 0 ) { + varyingProperty( 'vec3', 'vBatchColor' ).assign( color ); - // accuN := incoming * weight + } - for ( let i = 0; i !== stride; ++ i ) { + const bm = mat3( batchingMatrix ); - buffer[ offset + i ] = buffer[ i ]; + positionLocal.assign( batchingMatrix.mul( positionLocal ) ); - } + const transformedNormal = normalLocal.div( vec3( bm[ 0 ].dot( bm[ 0 ] ), bm[ 1 ].dot( bm[ 1 ] ), bm[ 2 ].dot( bm[ 2 ] ) ) ); - currentWeight = weight; + const batchingNormal = bm.mul( transformedNormal ).xyz; - } else { + normalLocal.assign( batchingNormal ); - // accuN := accuN + incoming * weight + if ( builder.hasGeometryAttribute( 'tangent' ) ) { - currentWeight += weight; - const mix = weight / currentWeight; - this._mixBufferRegion( buffer, offset, 0, mix, stride ); + tangentLocal.mulAssign( bm ); } - this.cumulativeWeight = currentWeight; - } - // accumulate data in the 'incoming' region into 'add' - accumulateAdditive( weight ) { - - const buffer = this.buffer, - stride = this.valueSize, - offset = stride * this._addIndex; - - if ( this.cumulativeWeightAdditive === 0 ) { +} - // add = identity +const batch = /*@__PURE__*/ nodeProxy( BatchNode ); - this._setIdentity(); +const _frameId = new WeakMap(); - } +class SkinningNode extends Node { - // add := add + incoming * weight + static get type() { - this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride ); - this.cumulativeWeightAdditive += weight; + return 'SkinningNode'; } - // apply the state of 'accu' to the binding when accus differ - apply( accuIndex ) { + constructor( skinnedMesh, useReference = false ) { - const stride = this.valueSize, - buffer = this.buffer, - offset = accuIndex * stride + stride, + super( 'void' ); - weight = this.cumulativeWeight, - weightAdditive = this.cumulativeWeightAdditive, + this.skinnedMesh = skinnedMesh; + this.useReference = useReference; - binding = this.binding; - - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; - - if ( weight < 1 ) { + this.updateType = NodeUpdateType.OBJECT; - // accuN := accuN + original * ( 1 - cumulativeWeight ) + // - const originalValueOffset = stride * this._origIndex; + this.skinIndexNode = attribute( 'skinIndex', 'uvec4' ); + this.skinWeightNode = attribute( 'skinWeight', 'vec4' ); - this._mixBufferRegion( - buffer, offset, originalValueOffset, 1 - weight, stride ); + let bindMatrixNode, bindMatrixInverseNode, boneMatricesNode; - } + if ( useReference ) { - if ( weightAdditive > 0 ) { + bindMatrixNode = reference( 'bindMatrix', 'mat4' ); + bindMatrixInverseNode = reference( 'bindMatrixInverse', 'mat4' ); + boneMatricesNode = referenceBuffer( 'skeleton.boneMatrices', 'mat4', skinnedMesh.skeleton.bones.length ); - // accuN := accuN + additive accuN + } else { - this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride ); + bindMatrixNode = uniform( skinnedMesh.bindMatrix, 'mat4' ); + bindMatrixInverseNode = uniform( skinnedMesh.bindMatrixInverse, 'mat4' ); + boneMatricesNode = buffer( skinnedMesh.skeleton.boneMatrices, 'mat4', skinnedMesh.skeleton.bones.length ); } - for ( let i = stride, e = stride + stride; i !== e; ++ i ) { + this.bindMatrixNode = bindMatrixNode; + this.bindMatrixInverseNode = bindMatrixInverseNode; + this.boneMatricesNode = boneMatricesNode; + this.previousBoneMatricesNode = null; - if ( buffer[ i ] !== buffer[ i + stride ] ) { + } - // value has changed -> update scene graph + getSkinnedPosition( boneMatrices = this.boneMatricesNode, position = positionLocal ) { - binding.setValue( buffer, offset ); - break; + const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; - } + const boneMatX = boneMatrices.element( skinIndexNode.x ); + const boneMatY = boneMatrices.element( skinIndexNode.y ); + const boneMatZ = boneMatrices.element( skinIndexNode.z ); + const boneMatW = boneMatrices.element( skinIndexNode.w ); - } + // POSITION - } + const skinVertex = bindMatrixNode.mul( position ); - // remember the state of the bound property and copy it to both accus - saveOriginalState() { + const skinned = add( + boneMatX.mul( skinWeightNode.x ).mul( skinVertex ), + boneMatY.mul( skinWeightNode.y ).mul( skinVertex ), + boneMatZ.mul( skinWeightNode.z ).mul( skinVertex ), + boneMatW.mul( skinWeightNode.w ).mul( skinVertex ) + ); - const binding = this.binding; + return bindMatrixInverseNode.mul( skinned ).xyz; - const buffer = this.buffer, - stride = this.valueSize, + } - originalValueOffset = stride * this._origIndex; + getSkinnedNormal( boneMatrices = this.boneMatricesNode, normal = normalLocal ) { - binding.getValue( buffer, originalValueOffset ); + const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; - // accu[0..1] := orig -- initially detect changes against the original - for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) { + const boneMatX = boneMatrices.element( skinIndexNode.x ); + const boneMatY = boneMatrices.element( skinIndexNode.y ); + const boneMatZ = boneMatrices.element( skinIndexNode.z ); + const boneMatW = boneMatrices.element( skinIndexNode.w ); - buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; + // NORMAL - } + let skinMatrix = add( + skinWeightNode.x.mul( boneMatX ), + skinWeightNode.y.mul( boneMatY ), + skinWeightNode.z.mul( boneMatZ ), + skinWeightNode.w.mul( boneMatW ) + ); - // Add to identity for additive - this._setIdentity(); + skinMatrix = bindMatrixInverseNode.mul( skinMatrix ).mul( bindMatrixNode ); - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; + return skinMatrix.transformDirection( normal ).xyz; } - // apply the state previously taken via 'saveOriginalState' to the binding - restoreOriginalState() { - - const originalValueOffset = this.valueSize * 3; - this.binding.setValue( this.buffer, originalValueOffset ); - - } + getPreviousSkinnedPosition( builder ) { - _setAdditiveIdentityNumeric() { + const skinnedMesh = builder.object; - const startIndex = this._addIndex * this.valueSize; - const endIndex = startIndex + this.valueSize; + if ( this.previousBoneMatricesNode === null ) { - for ( let i = startIndex; i < endIndex; i ++ ) { + skinnedMesh.skeleton.previousBoneMatrices = new Float32Array( skinnedMesh.skeleton.boneMatrices ); - this.buffer[ i ] = 0; + this.previousBoneMatricesNode = referenceBuffer( 'skeleton.previousBoneMatrices', 'mat4', skinnedMesh.skeleton.bones.length ); } + return this.getSkinnedPosition( this.previousBoneMatricesNode, positionPrevious ); + } - _setAdditiveIdentityQuaternion() { + needsPreviousBoneMatrices( builder ) { - this._setAdditiveIdentityNumeric(); - this.buffer[ this._addIndex * this.valueSize + 3 ] = 1; + const mrt = builder.renderer.getMRT(); - } + return mrt && mrt.has( 'velocity' ); - _setAdditiveIdentityOther() { + } - const startIndex = this._origIndex * this.valueSize; - const targetIndex = this._addIndex * this.valueSize; + setup( builder ) { - for ( let i = 0; i < this.valueSize; i ++ ) { + if ( this.needsPreviousBoneMatrices( builder ) ) { - this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ]; + positionPrevious.assign( this.getPreviousSkinnedPosition( builder ) ); } - } + const skinPosition = this.getSkinnedPosition(); - // mix functions + positionLocal.assign( skinPosition ); - _select( buffer, dstOffset, srcOffset, t, stride ) { + if ( builder.hasGeometryAttribute( 'normal' ) ) { - if ( t >= 0.5 ) { + const skinNormal = this.getSkinnedNormal(); - for ( let i = 0; i !== stride; ++ i ) { + normalLocal.assign( skinNormal ); - buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; + if ( builder.hasGeometryAttribute( 'tangent' ) ) { + + tangentLocal.assign( skinNormal ); } @@ -43850,11292 +43751,11058 @@ class PropertyMixer { } - _slerp( buffer, dstOffset, srcOffset, t ) { - - Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); - - } - - _slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { + generate( builder, output ) { - const workOffset = this._workIndex * stride; + if ( output !== 'void' ) { - // Store result in intermediate buffer offset - Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset ); + return positionLocal.build( builder, output ); - // Slerp to the intermediate result - Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t ); + } } - _lerp( buffer, dstOffset, srcOffset, t, stride ) { + update( frame ) { - const s = 1 - t; + const object = this.useReference ? frame.object : this.skinnedMesh; + const skeleton = object.skeleton; - for ( let i = 0; i !== stride; ++ i ) { + if ( _frameId.get( skeleton ) === frame.frameId ) return; - const j = dstOffset + i; + _frameId.set( skeleton, frame.frameId ); - buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; + if ( this.previousBoneMatricesNode !== null ) skeleton.previousBoneMatrices.set( skeleton.boneMatrices ); - } + skeleton.update(); } - _lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { +} - for ( let i = 0; i !== stride; ++ i ) { +const skinning = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh ) ); +const skinningReference = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh, true ) ); - const j = dstOffset + i; +class LoopNode extends Node { - buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t; + static get type() { - } + return 'LoopNode'; } -} - -// Characters [].:/ are reserved for track binding syntax. -const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; -const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' ); + constructor( params = [] ) { -// Attempts to allow node names from any language. ES5's `\w` regexp matches -// only latin characters, and the unicode \p{L} is not yet supported. So -// instead, we exclude reserved characters and match everything else. -const _wordChar = '[^' + _RESERVED_CHARS_RE + ']'; -const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; + super(); -// Parent directories, delimited by '/' or ':'. Currently unused, but must -// be matched to parse the rest of the track name. -const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar ); + this.params = params; -// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. -const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot ); + } -// Object on target node, and accessor. May not contain reserved -// characters. Accessor may contain any character except closing bracket. -const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar ); + getVarName( index ) { -// Property and accessor. May not contain reserved characters. Accessor may -// contain any non-bracket characters. -const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar ); + return String.fromCharCode( 'i'.charCodeAt() + index ); -const _trackRe = new RegExp( '' - + '^' - + _directoryRe - + _nodeRe - + _objectRe - + _propertyRe - + '$' -); + } -const _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ]; + getProperties( builder ) { -class Composite { + const properties = builder.getNodeProperties( this ); - constructor( targetGroup, path, optionalParsedPath ) { + if ( properties.stackNode !== undefined ) return properties; - const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); + // - this._targetGroup = targetGroup; - this._bindings = targetGroup.subscribe_( path, parsedPath ); + const inputs = {}; - } + for ( let i = 0, l = this.params.length - 1; i < l; i ++ ) { - getValue( array, offset ) { + const param = this.params[ i ]; - this.bind(); // bind all binding + const name = ( param.isNode !== true && param.name ) || this.getVarName( i ); + const type = ( param.isNode !== true && param.type ) || 'int'; - const firstValidIndex = this._targetGroup.nCachedObjects_, - binding = this._bindings[ firstValidIndex ]; + inputs[ name ] = expression( name, type ); - // and only call .getValue on the first - if ( binding !== undefined ) binding.getValue( array, offset ); + } - } + const stack = builder.addStack(); // TODO: cache() it - setValue( array, offset ) { + properties.returnsNode = this.params[ this.params.length - 1 ]( inputs, stack, builder ); + properties.stackNode = stack; - const bindings = this._bindings; + builder.removeStack(); - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { + return properties; - bindings[ i ].setValue( array, offset ); + } - } + getNodeType( builder ) { - } + const { returnsNode } = this.getProperties( builder ); - bind() { + return returnsNode ? returnsNode.getNodeType( builder ) : 'void'; - const bindings = this._bindings; + } - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { + setup( builder ) { - bindings[ i ].bind(); + // setup properties - } + this.getProperties( builder ); } - unbind() { - - const bindings = this._bindings; + generate( builder ) { - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { + const properties = this.getProperties( builder ); - bindings[ i ].unbind(); + const params = this.params; + const stackNode = properties.stackNode; - } + for ( let i = 0, l = params.length - 1; i < l; i ++ ) { - } + const param = params[ i ]; -} + let start = null, end = null, name = null, type = null, condition = null, update = null; -// Note: This class uses a State pattern on a per-method basis: -// 'bind' sets 'this.getValue' / 'setValue' and shadows the -// prototype version of these methods with one that represents -// the bound state. When the property is not found, the methods -// become no-ops. -class PropertyBinding { + if ( param.isNode ) { - constructor( rootNode, path, parsedPath ) { + type = 'int'; + name = this.getVarName( i ); + start = '0'; + end = param.build( builder, type ); + condition = '<'; - this.path = path; - this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); + } else { - this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ); + type = param.type || 'int'; + name = param.name || this.getVarName( i ); + start = param.start; + end = param.end; + condition = param.condition; + update = param.update; - this.rootNode = rootNode; + if ( typeof start === 'number' ) start = start.toString(); + else if ( start && start.isNode ) start = start.build( builder, type ); - // initial state of these methods that calls 'bind' - this.getValue = this._getValue_unbound; - this.setValue = this._setValue_unbound; + if ( typeof end === 'number' ) end = end.toString(); + else if ( end && end.isNode ) end = end.build( builder, type ); - } + if ( start !== undefined && end === undefined ) { + start = start + ' - 1'; + end = '0'; + condition = '>='; - static create( root, path, parsedPath ) { + } else if ( end !== undefined && start === undefined ) { - if ( ! ( root && root.isAnimationObjectGroup ) ) { + start = '0'; + condition = '<'; - return new PropertyBinding( root, path, parsedPath ); + } - } else { + if ( condition === undefined ) { - return new PropertyBinding.Composite( root, path, parsedPath ); + if ( Number( start ) > Number( end ) ) { - } + condition = '>='; - } + } else { - /** - * Replaces spaces with underscores and removes unsupported characters from - * node names, to ensure compatibility with parseTrackName(). - * - * @param {string} name Node name to be sanitized. - * @return {string} - */ - static sanitizeNodeName( name ) { + condition = '<'; - return name.replace( /\s/g, '_' ).replace( _reservedRe, '' ); + } - } + } - static parseTrackName( trackName ) { + } - const matches = _trackRe.exec( trackName ); + const internalParam = { start, end, condition }; - if ( matches === null ) { + // - throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); + const startSnippet = internalParam.start; + const endSnippet = internalParam.end; - } + let declarationSnippet = ''; + let conditionalSnippet = ''; + let updateSnippet = ''; - const results = { - // directoryName: matches[ 1 ], // (tschw) currently unused - nodeName: matches[ 2 ], - objectName: matches[ 3 ], - objectIndex: matches[ 4 ], - propertyName: matches[ 5 ], // required - propertyIndex: matches[ 6 ] - }; + if ( ! update ) { - const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); + if ( type === 'int' || type === 'uint' ) { - if ( lastDot !== undefined && lastDot !== - 1 ) { + if ( condition.includes( '<' ) ) update = '++'; + else update = '--'; - const objectName = results.nodeName.substring( lastDot + 1 ); + } else { - // Object names must be checked against an allowlist. Otherwise, there - // is no way to parse 'foo.bar.baz': 'baz' must be a property, but - // 'bar' could be the objectName, or part of a nodeName (which can - // include '.' characters). - if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) { + if ( condition.includes( '<' ) ) update = '+= 1.'; + else update = '-= 1.'; - results.nodeName = results.nodeName.substring( 0, lastDot ); - results.objectName = objectName; + } } - } + declarationSnippet += builder.getVar( type, name ) + ' = ' + startSnippet; - if ( results.propertyName === null || results.propertyName.length === 0 ) { + conditionalSnippet += name + ' ' + condition + ' ' + endSnippet; + updateSnippet += name + ' ' + update; - throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); + const forSnippet = `for ( ${ declarationSnippet }; ${ conditionalSnippet }; ${ updateSnippet } )`; + + builder.addFlowCode( ( i === 0 ? '\n' : '' ) + builder.tab + forSnippet + ' {\n\n' ).addFlowTab(); } - return results; + const stackSnippet = stackNode.build( builder, 'void' ); - } + const returnsSnippet = properties.returnsNode ? properties.returnsNode.build( builder ) : ''; - static findNode( root, nodeName ) { + builder.removeFlowTab().addFlowCode( '\n' + builder.tab + stackSnippet ); - if ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { + for ( let i = 0, l = this.params.length - 1; i < l; i ++ ) { - return root; + builder.addFlowCode( ( i === 0 ? '' : builder.tab ) + '}\n\n' ).removeFlowTab(); } - // search into skeleton bones. - if ( root.skeleton ) { - - const bone = root.skeleton.getBoneByName( nodeName ); + builder.addFlowTab(); - if ( bone !== undefined ) { + return returnsSnippet; - return bone; + } - } +} - } +const Loop = ( ...params ) => nodeObject( new LoopNode( nodeArray( params, 'int' ) ) ).append(); +const Continue = () => expression( 'continue' ).append(); +const Break = () => expression( 'break' ).append(); - // search into node subtree. - if ( root.children ) { +// - const searchNodeSubtree = function ( children ) { +const loop = ( ...params ) => { // @deprecated, r168 - for ( let i = 0; i < children.length; i ++ ) { + console.warn( 'TSL.LoopNode: loop() has been renamed to Loop().' ); + return Loop( ...params ); - const childNode = children[ i ]; +}; - if ( childNode.name === nodeName || childNode.uuid === nodeName ) { +const _morphTextures = /*@__PURE__*/ new WeakMap(); +const _morphVec4 = /*@__PURE__*/ new Vector4(); - return childNode; +const getMorph = /*@__PURE__*/ Fn( ( { bufferMap, influence, stride, width, depth, offset } ) => { - } + const texelIndex = int( vertexIndex ).mul( stride ).add( offset ); - const result = searchNodeSubtree( childNode.children ); + const y = texelIndex.div( width ); + const x = texelIndex.sub( y.mul( width ) ); - if ( result ) return result; + const bufferAttrib = textureLoad( bufferMap, ivec2( x, y ) ).depth( depth ); - } + return bufferAttrib.mul( influence ); - return null; +} ); - }; +function getEntry( geometry ) { - const subTreeNode = searchNodeSubtree( root.children ); + const hasMorphPosition = geometry.morphAttributes.position !== undefined; + const hasMorphNormals = geometry.morphAttributes.normal !== undefined; + const hasMorphColors = geometry.morphAttributes.color !== undefined; - if ( subTreeNode ) { + // instead of using attributes, the WebGL 2 code path encodes morph targets + // into an array of data textures. Each layer represents a single morph target. - return subTreeNode; + const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; + const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - } + let entry = _morphTextures.get( geometry ); - } + if ( entry === undefined || entry.count !== morphTargetsCount ) { - return null; + if ( entry !== undefined ) entry.texture.dispose(); - } + const morphTargets = geometry.morphAttributes.position || []; + const morphNormals = geometry.morphAttributes.normal || []; + const morphColors = geometry.morphAttributes.color || []; - // these are used to "bind" a nonexistent property - _getValue_unavailable() {} - _setValue_unavailable() {} + let vertexDataCount = 0; - // Getters + if ( hasMorphPosition === true ) vertexDataCount = 1; + if ( hasMorphNormals === true ) vertexDataCount = 2; + if ( hasMorphColors === true ) vertexDataCount = 3; - _getValue_direct( buffer, offset ) { + let width = geometry.attributes.position.count * vertexDataCount; + let height = 1; - buffer[ offset ] = this.targetObject[ this.propertyName ]; + const maxTextureSize = 4096; // @TODO: Use 'capabilities.maxTextureSize' - } + if ( width > maxTextureSize ) { - _getValue_array( buffer, offset ) { + height = Math.ceil( width / maxTextureSize ); + width = maxTextureSize; - const source = this.resolvedProperty; + } - for ( let i = 0, n = source.length; i !== n; ++ i ) { + const buffer = new Float32Array( width * height * 4 * morphTargetsCount ); - buffer[ offset ++ ] = source[ i ]; + const bufferTexture = new DataArrayTexture( buffer, width, height, morphTargetsCount ); + bufferTexture.type = FloatType; + bufferTexture.needsUpdate = true; - } + // fill buffer - } + const vertexDataStride = vertexDataCount * 4; - _getValue_arrayElement( buffer, offset ) { + for ( let i = 0; i < morphTargetsCount; i ++ ) { - buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; + const morphTarget = morphTargets[ i ]; + const morphNormal = morphNormals[ i ]; + const morphColor = morphColors[ i ]; - } + const offset = width * height * 4 * i; - _getValue_toArray( buffer, offset ) { + for ( let j = 0; j < morphTarget.count; j ++ ) { - this.resolvedProperty.toArray( buffer, offset ); + const stride = j * vertexDataStride; - } + if ( hasMorphPosition === true ) { - // Direct + _morphVec4.fromBufferAttribute( morphTarget, j ); - _setValue_direct( buffer, offset ) { + buffer[ offset + stride + 0 ] = _morphVec4.x; + buffer[ offset + stride + 1 ] = _morphVec4.y; + buffer[ offset + stride + 2 ] = _morphVec4.z; + buffer[ offset + stride + 3 ] = 0; - this.targetObject[ this.propertyName ] = buffer[ offset ]; + } - } + if ( hasMorphNormals === true ) { - _setValue_direct_setNeedsUpdate( buffer, offset ) { + _morphVec4.fromBufferAttribute( morphNormal, j ); - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; - - } - - _setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { - - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; + buffer[ offset + stride + 4 ] = _morphVec4.x; + buffer[ offset + stride + 5 ] = _morphVec4.y; + buffer[ offset + stride + 6 ] = _morphVec4.z; + buffer[ offset + stride + 7 ] = 0; - } + } - // EntireArray + if ( hasMorphColors === true ) { - _setValue_array( buffer, offset ) { + _morphVec4.fromBufferAttribute( morphColor, j ); - const dest = this.resolvedProperty; + buffer[ offset + stride + 8 ] = _morphVec4.x; + buffer[ offset + stride + 9 ] = _morphVec4.y; + buffer[ offset + stride + 10 ] = _morphVec4.z; + buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? _morphVec4.w : 1; - for ( let i = 0, n = dest.length; i !== n; ++ i ) { + } - dest[ i ] = buffer[ offset ++ ]; + } } - } + entry = { + count: morphTargetsCount, + texture: bufferTexture, + stride: vertexDataCount, + size: new Vector2( width, height ) + }; - _setValue_array_setNeedsUpdate( buffer, offset ) { + _morphTextures.set( geometry, entry ); - const dest = this.resolvedProperty; + function disposeTexture() { - for ( let i = 0, n = dest.length; i !== n; ++ i ) { + bufferTexture.dispose(); - dest[ i ] = buffer[ offset ++ ]; + _morphTextures.delete( geometry ); + + geometry.removeEventListener( 'dispose', disposeTexture ); } - this.targetObject.needsUpdate = true; + geometry.addEventListener( 'dispose', disposeTexture ); } - _setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { + return entry; - const dest = this.resolvedProperty; +} - for ( let i = 0, n = dest.length; i !== n; ++ i ) { - dest[ i ] = buffer[ offset ++ ]; +class MorphNode extends Node { - } + static get type() { - this.targetObject.matrixWorldNeedsUpdate = true; + return 'MorphNode'; } - // ArrayElement - - _setValue_arrayElement( buffer, offset ) { - - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + constructor( mesh ) { - } + super( 'void' ); - _setValue_arrayElement_setNeedsUpdate( buffer, offset ) { + this.mesh = mesh; + this.morphBaseInfluence = uniform( 1 ); - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; + this.updateType = NodeUpdateType.OBJECT; } - _setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { + setup( builder ) { - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; + const { geometry } = builder; - } + const hasMorphPosition = geometry.morphAttributes.position !== undefined; + const hasMorphNormals = geometry.hasAttribute( 'normal' ) && geometry.morphAttributes.normal !== undefined; - // HasToFromArray + const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; + const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - _setValue_fromArray( buffer, offset ) { + // nodes - this.resolvedProperty.fromArray( buffer, offset ); + const { texture: bufferMap, stride, size } = getEntry( geometry ); - } + if ( hasMorphPosition === true ) positionLocal.mulAssign( this.morphBaseInfluence ); + if ( hasMorphNormals === true ) normalLocal.mulAssign( this.morphBaseInfluence ); - _setValue_fromArray_setNeedsUpdate( buffer, offset ) { + const width = int( size.width ); - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.needsUpdate = true; + Loop( morphTargetsCount, ( { i } ) => { - } + const influence = float( 0 ).toVar(); - _setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { + if ( this.mesh.count > 1 && ( this.mesh.morphTexture !== null && this.mesh.morphTexture !== undefined ) ) { - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.matrixWorldNeedsUpdate = true; + influence.assign( textureLoad( this.mesh.morphTexture, ivec2( int( i ).add( 1 ), int( instanceIndex ) ) ).r ); - } + } else { - _getValue_unbound( targetArray, offset ) { + influence.assign( reference( 'morphTargetInfluences', 'float' ).element( i ).toVar() ); - this.bind(); - this.getValue( targetArray, offset ); + } - } + if ( hasMorphPosition === true ) { - _setValue_unbound( sourceArray, offset ) { + positionLocal.addAssign( getMorph( { + bufferMap, + influence, + stride, + width, + depth: i, + offset: int( 0 ) + } ) ); - this.bind(); - this.setValue( sourceArray, offset ); + } - } + if ( hasMorphNormals === true ) { - // create getter / setter pair for a property in the scene graph - bind() { + normalLocal.addAssign( getMorph( { + bufferMap, + influence, + stride, + width, + depth: i, + offset: int( 1 ) + } ) ); - let targetObject = this.node; - const parsedPath = this.parsedPath; + } - const objectName = parsedPath.objectName; - const propertyName = parsedPath.propertyName; - let propertyIndex = parsedPath.propertyIndex; + } ); - if ( ! targetObject ) { + } - targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ); + update() { - this.node = targetObject; + const morphBaseInfluence = this.morphBaseInfluence; - } + if ( this.mesh.geometry.morphTargetsRelative ) { - // set fail state so we can just 'return' on error - this.getValue = this._getValue_unavailable; - this.setValue = this._setValue_unavailable; + morphBaseInfluence.value = 1; - // ensure there is a value node - if ( ! targetObject ) { + } else { - console.warn( 'THREE.PropertyBinding: No target node found for track: ' + this.path + '.' ); - return; + morphBaseInfluence.value = 1 - this.mesh.morphTargetInfluences.reduce( ( a, b ) => a + b, 0 ); } - if ( objectName ) { + } - let objectIndex = parsedPath.objectIndex; +} - // special cases were we need to reach deeper into the hierarchy to get the face materials.... - switch ( objectName ) { +const morphReference = /*@__PURE__*/ nodeProxy( MorphNode ); - case 'materials': +const sortLights = ( lights ) => { - if ( ! targetObject.material ) { + return lights.sort( ( a, b ) => a.id - b.id ); - console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); - return; +}; - } +const getLightNodeById = ( id, lightNodes ) => { - if ( ! targetObject.material.materials ) { + for ( const lightNode of lightNodes ) { - console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); - return; + if ( lightNode.isAnalyticLightNode && lightNode.light.id === id ) { - } + return lightNode; - targetObject = targetObject.material.materials; + } - break; + } - case 'bones': + return null; - if ( ! targetObject.skeleton ) { +}; - console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); - return; +const _lightsNodeRef = /*@__PURE__*/ new WeakMap(); - } +class LightsNode extends Node { - // potential future optimization: skip this if propertyIndex is already an integer - // and convert the integer string to a true integer. + static get type() { - targetObject = targetObject.skeleton.bones; + return 'LightsNode'; - // support resolving morphTarget names into indices. - for ( let i = 0; i < targetObject.length; i ++ ) { + } - if ( targetObject[ i ].name === objectIndex ) { + constructor( lights = [] ) { - objectIndex = i; - break; + super( 'vec3' ); - } + this.totalDiffuseNode = vec3().toVar( 'totalDiffuse' ); + this.totalSpecularNode = vec3().toVar( 'totalSpecular' ); - } + this.outgoingLightNode = vec3().toVar( 'outgoingLight' ); - break; + this._lights = lights; - case 'map': + this._lightNodes = null; + this._lightNodesHash = null; - if ( 'map' in targetObject ) { + this.global = true; - targetObject = targetObject.map; - break; + } - } + getHash( builder ) { - if ( ! targetObject.material ) { + if ( this._lightNodesHash === null ) { - console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); - return; + if ( this._lightNodes === null ) this.setupLightsNode( builder ); - } + const hash = []; - if ( ! targetObject.material.map ) { + for ( const lightNode of this._lightNodes ) { - console.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this ); - return; + hash.push( lightNode.getHash() ); - } + } - targetObject = targetObject.material.map; - break; + this._lightNodesHash = 'lights-' + hash.join( ',' ); - default: + } - if ( targetObject[ objectName ] === undefined ) { + return this._lightNodesHash; - console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); - return; + } - } + analyze( builder ) { - targetObject = targetObject[ objectName ]; + const properties = builder.getDataFromNode( this ); - } + for ( const node of properties.nodes ) { + node.build( builder ); - if ( objectIndex !== undefined ) { + } - if ( targetObject[ objectIndex ] === undefined ) { + } - console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); - return; + setupLightsNode( builder ) { - } + const lightNodes = []; - targetObject = targetObject[ objectIndex ]; + const previousLightNodes = this._lightNodes; - } + const lights = sortLights( this._lights ); + const nodeLibrary = builder.renderer.nodes.library; - } + for ( const light of lights ) { - // resolve property - const nodeProperty = targetObject[ propertyName ]; + if ( light.isNode ) { - if ( nodeProperty === undefined ) { + lightNodes.push( nodeObject( light ) ); - const nodeName = parsedPath.nodeName; + } else { - console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + - '.' + propertyName + ' but it wasn\'t found.', targetObject ); - return; + let lightNode = null; - } + if ( previousLightNodes !== null ) { - // determine versioning scheme - let versioning = this.Versioning.None; + lightNode = getLightNodeById( light.id, previousLightNodes ); // resuse existing light node - this.targetObject = targetObject; + } - if ( targetObject.needsUpdate !== undefined ) { // material + if ( lightNode === null ) { - versioning = this.Versioning.NeedsUpdate; + const lightNodeClass = nodeLibrary.getLightNodeClass( light.constructor ); - } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform + if ( lightNodeClass === null ) { - versioning = this.Versioning.MatrixWorldNeedsUpdate; + console.warn( `LightsNode.setupNodeLights: Light node not found for ${ light.constructor.name }` ); + continue; - } + } - // determine how the property gets bound - let bindingType = this.BindingType.Direct; + let lightNode = null; - if ( propertyIndex !== undefined ) { + if ( ! _lightsNodeRef.has( light ) ) { - // access a sub element of the property array (only primitives are supported right now) + lightNode = new lightNodeClass( light ); + _lightsNodeRef.set( light, lightNode ); - if ( propertyName === 'morphTargetInfluences' ) { + } else { - // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. + lightNode = _lightsNodeRef.get( light ); - // support resolving morphTarget names into indices. - if ( ! targetObject.geometry ) { + } - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); - return; + lightNodes.push( lightNode ); } - if ( ! targetObject.geometry.morphAttributes ) { + } - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); - return; + } - } + this._lightNodes = lightNodes; - if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) { + } - propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ]; + setup( builder ) { - } + if ( this._lightNodes === null ) this.setupLightsNode( builder ); - } + const context = builder.context; + const lightingModel = context.lightingModel; - bindingType = this.BindingType.ArrayElement; + let outgoingLightNode = this.outgoingLightNode; - this.resolvedProperty = nodeProperty; - this.propertyIndex = propertyIndex; + if ( lightingModel ) { - } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { + const { _lightNodes, totalDiffuseNode, totalSpecularNode } = this; - // must use copy for Object3D.Euler/Quaternion + context.outgoingLight = outgoingLightNode; - bindingType = this.BindingType.HasFromToArray; + const stack = builder.addStack(); - this.resolvedProperty = nodeProperty; + // - } else if ( Array.isArray( nodeProperty ) ) { + const properties = builder.getDataFromNode( this ); + properties.nodes = stack.nodes; - bindingType = this.BindingType.EntireArray; + // - this.resolvedProperty = nodeProperty; + lightingModel.start( context, stack, builder ); - } else { + // lights - this.propertyName = propertyName; + for ( const lightNode of _lightNodes ) { - } + lightNode.build( builder ); - // select getter / setter - this.getValue = this.GetterByBindingType[ bindingType ]; - this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; + } - } + // - unbind() { + lightingModel.indirect( context, stack, builder ); - this.node = null; + // - // back to the prototype version of getValue / setValue - // note: avoiding to mutate the shape of 'this' via 'delete' - this.getValue = this._getValue_unbound; - this.setValue = this._setValue_unbound; + const { backdrop, backdropAlpha } = context; + const { directDiffuse, directSpecular, indirectDiffuse, indirectSpecular } = context.reflectedLight; - } + let totalDiffuse = directDiffuse.add( indirectDiffuse ); -} + if ( backdrop !== null ) { -PropertyBinding.Composite = Composite; + if ( backdropAlpha !== null ) { -PropertyBinding.prototype.BindingType = { - Direct: 0, - EntireArray: 1, - ArrayElement: 2, - HasFromToArray: 3 -}; + totalDiffuse = vec3( backdropAlpha.mix( totalDiffuse, backdrop ) ); -PropertyBinding.prototype.Versioning = { - None: 0, - NeedsUpdate: 1, - MatrixWorldNeedsUpdate: 2 -}; + } else { -PropertyBinding.prototype.GetterByBindingType = [ + totalDiffuse = vec3( backdrop ); - PropertyBinding.prototype._getValue_direct, - PropertyBinding.prototype._getValue_array, - PropertyBinding.prototype._getValue_arrayElement, - PropertyBinding.prototype._getValue_toArray, + } -]; + context.material.transparent = true; -PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [ + } - [ - // Direct - PropertyBinding.prototype._setValue_direct, - PropertyBinding.prototype._setValue_direct_setNeedsUpdate, - PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate, + totalDiffuseNode.assign( totalDiffuse ); + totalSpecularNode.assign( directSpecular.add( indirectSpecular ) ); - ], [ + outgoingLightNode.assign( totalDiffuseNode.add( totalSpecularNode ) ); - // EntireArray + // - PropertyBinding.prototype._setValue_array, - PropertyBinding.prototype._setValue_array_setNeedsUpdate, - PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate, + lightingModel.finish( context, stack, builder ); - ], [ + // - // ArrayElement - PropertyBinding.prototype._setValue_arrayElement, - PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate, - PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate, + outgoingLightNode = outgoingLightNode.bypass( builder.removeStack() ); - ], [ + } - // HasToFromArray - PropertyBinding.prototype._setValue_fromArray, - PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate, - PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate, + return outgoingLightNode; - ] + } -]; + setLights( lights ) { -/** - * - * A group of objects that receives a shared animation state. - * - * Usage: - * - * - Add objects you would otherwise pass as 'root' to the - * constructor or the .clipAction method of AnimationMixer. - * - * - Instead pass this object as 'root'. - * - * - You can also add and remove objects later when the mixer - * is running. - * - * Note: - * - * Objects of this class appear as one object to the mixer, - * so cache control of the individual objects must be done - * on the group. - * - * Limitation: - * - * - The animated properties must be compatible among the - * all objects in the group. - * - * - A single property can either be controlled through a - * target group or directly, but not both. - */ + this._lights = lights; -class AnimationObjectGroup { + this._lightNodes = null; + this._lightNodesHash = null; - constructor() { + return this; - this.isAnimationObjectGroup = true; + } - this.uuid = generateUUID(); + getLights() { - // cached objects followed by the active ones - this._objects = Array.prototype.slice.call( arguments ); + return this._lights; - this.nCachedObjects_ = 0; // threshold - // note: read by PropertyBinding.Composite + } - const indices = {}; - this._indicesByUUID = indices; // for bookkeeping +} - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { +const lights = /*@__PURE__*/ nodeProxy( LightsNode ); - indices[ arguments[ i ].uuid ] = i; +class LightingNode extends Node { - } + static get type() { - this._paths = []; // inside: string - this._parsedPaths = []; // inside: { we don't care, here } - this._bindings = []; // inside: Array< PropertyBinding > - this._bindingsIndicesByPath = {}; // inside: indices in these arrays + return 'LightingNode'; - const scope = this; + } - this.stats = { + constructor() { - objects: { - get total() { + super( 'vec3' ); - return scope._objects.length; + this.isLightingNode = true; - }, - get inUse() { + } - return this.total - scope.nCachedObjects_; + generate( /*builder*/ ) { - } - }, - get bindingsPerObject() { + console.warn( 'Abstract function.' ); - return scope._bindings.length; + } - } +} - }; +class AONode extends LightingNode { + + static get type() { + + return 'AONode'; } - add() { + constructor( aoNode = null ) { - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - nBindings = bindings.length; - - let knownObject = undefined, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_; - - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - - const object = arguments[ i ], - uuid = object.uuid; - let index = indicesByUUID[ uuid ]; - - if ( index === undefined ) { - - // unknown object -> add it to the ACTIVE region - - index = nObjects ++; - indicesByUUID[ uuid ] = index; - objects.push( object ); - - // accounting is done, now do the same for all bindings + super(); - for ( let j = 0, m = nBindings; j !== m; ++ j ) { + this.aoNode = aoNode; - bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); + } - } + setup( builder ) { - } else if ( index < nCachedObjects ) { + builder.context.ambientOcclusion.mulAssign( this.aoNode ); - knownObject = objects[ index ]; + } - // move existing object to the ACTIVE region +} - const firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ]; +class LightingContextNode extends ContextNode { - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; + static get type() { - indicesByUUID[ uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = object; + return 'LightingContextNode'; - // accounting is done, now do the same for all bindings + } - for ( let j = 0, m = nBindings; j !== m; ++ j ) { + constructor( node, lightingModel = null, backdropNode = null, backdropAlphaNode = null ) { - const bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ]; + super( node ); - let binding = bindingsForPath[ index ]; + this.lightingModel = lightingModel; + this.backdropNode = backdropNode; + this.backdropAlphaNode = backdropAlphaNode; - bindingsForPath[ index ] = lastCached; + this._value = null; - if ( binding === undefined ) { + } - // since we do not bother to create new bindings - // for objects that are cached, the binding may - // or may not exist + getContext() { - binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ); + const { backdropNode, backdropAlphaNode } = this; - } + const directDiffuse = vec3().toVar( 'directDiffuse' ), + directSpecular = vec3().toVar( 'directSpecular' ), + indirectDiffuse = vec3().toVar( 'indirectDiffuse' ), + indirectSpecular = vec3().toVar( 'indirectSpecular' ); - bindingsForPath[ firstActiveIndex ] = binding; + const reflectedLight = { + directDiffuse, + directSpecular, + indirectDiffuse, + indirectSpecular + }; - } + const context = { + radiance: vec3().toVar( 'radiance' ), + irradiance: vec3().toVar( 'irradiance' ), + iblIrradiance: vec3().toVar( 'iblIrradiance' ), + ambientOcclusion: float( 1 ).toVar( 'ambientOcclusion' ), + reflectedLight, + backdrop: backdropNode, + backdropAlpha: backdropAlphaNode + }; - } else if ( objects[ index ] !== knownObject ) { + return context; - console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' + - 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); + } - } // else the object is already where we want it to be + setup( builder ) { - } // for arguments + this.value = this._value || ( this._value = this.getContext() ); + this.value.lightingModel = this.lightingModel || builder.context.lightingModel; - this.nCachedObjects_ = nCachedObjects; + return super.setup( builder ); } - remove() { +} - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; +const lightingContext = /*@__PURE__*/ nodeProxy( LightingContextNode ); - let nCachedObjects = this.nCachedObjects_; +class IrradianceNode extends LightingNode { - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { + static get type() { - const object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; + return 'IrradianceNode'; - if ( index !== undefined && index >= nCachedObjects ) { + } - // move existing object into the CACHED region + constructor( node ) { - const lastCachedIndex = nCachedObjects ++, - firstActiveObject = objects[ lastCachedIndex ]; + super(); - indicesByUUID[ firstActiveObject.uuid ] = index; - objects[ index ] = firstActiveObject; + this.node = node; - indicesByUUID[ uuid ] = lastCachedIndex; - objects[ lastCachedIndex ] = object; + } - // accounting is done, now do the same for all bindings + setup( builder ) { - for ( let j = 0, m = nBindings; j !== m; ++ j ) { + builder.context.irradiance.addAssign( this.node ); - const bindingsForPath = bindings[ j ], - firstActive = bindingsForPath[ lastCachedIndex ], - binding = bindingsForPath[ index ]; + } - bindingsForPath[ index ] = firstActive; - bindingsForPath[ lastCachedIndex ] = binding; +} - } +let screenSizeVec, viewportVec; - } +class ScreenNode extends Node { - } // for arguments + static get type() { - this.nCachedObjects_ = nCachedObjects; + return 'ScreenNode'; } - // remove & forget - uncache() { - - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; + constructor( scope ) { - let nCachedObjects = this.nCachedObjects_, - nObjects = objects.length; + super(); - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { + this.scope = scope; - const object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; + this.isViewportNode = true; - if ( index !== undefined ) { + } - delete indicesByUUID[ uuid ]; + getNodeType() { - if ( index < nCachedObjects ) { + if ( this.scope === ScreenNode.VIEWPORT ) return 'vec4'; + else return 'vec2'; - // object is cached, shrink the CACHED region + } - const firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ], - lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; + getUpdateType() { - // last cached object takes this object's place - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; + let updateType = NodeUpdateType.NONE; - // last object goes to the activated slot and pop - indicesByUUID[ lastObject.uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = lastObject; - objects.pop(); + if ( this.scope === ScreenNode.SIZE || this.scope === ScreenNode.VIEWPORT ) { - // accounting is done, now do the same for all bindings + updateType = NodeUpdateType.RENDER; - for ( let j = 0, m = nBindings; j !== m; ++ j ) { + } - const bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ], - last = bindingsForPath[ lastIndex ]; + this.updateType = updateType; - bindingsForPath[ index ] = lastCached; - bindingsForPath[ firstActiveIndex ] = last; - bindingsForPath.pop(); + return updateType; - } + } - } else { + update( { renderer } ) { - // object is active, just swap with the last and pop + const renderTarget = renderer.getRenderTarget(); - const lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; + if ( this.scope === ScreenNode.VIEWPORT ) { - if ( lastIndex > 0 ) { + if ( renderTarget !== null ) { - indicesByUUID[ lastObject.uuid ] = index; + viewportVec.copy( renderTarget.viewport ); - } + } else { - objects[ index ] = lastObject; - objects.pop(); + renderer.getViewport( viewportVec ); - // accounting is done, now do the same for all bindings + viewportVec.multiplyScalar( renderer.getPixelRatio() ); - for ( let j = 0, m = nBindings; j !== m; ++ j ) { + } - const bindingsForPath = bindings[ j ]; + } else { - bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; - bindingsForPath.pop(); + if ( renderTarget !== null ) { - } + screenSizeVec.width = renderTarget.width; + screenSizeVec.height = renderTarget.height; - } // cached or active + } else { - } // if object is known + renderer.getDrawingBufferSize( screenSizeVec ); - } // for arguments + } - this.nCachedObjects_ = nCachedObjects; + } } - // Internal interface used by befriended PropertyBinding.Composite: - - subscribe_( path, parsedPath ) { - - // returns an array of bindings for the given path that is changed - // according to the contained objects in the group + setup( /*builder*/ ) { - const indicesByPath = this._bindingsIndicesByPath; - let index = indicesByPath[ path ]; - const bindings = this._bindings; + const scope = this.scope; - if ( index !== undefined ) return bindings[ index ]; + let output = null; - const paths = this._paths, - parsedPaths = this._parsedPaths, - objects = this._objects, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_, - bindingsForPath = new Array( nObjects ); + if ( scope === ScreenNode.SIZE ) { - index = bindings.length; + output = uniform( screenSizeVec || ( screenSizeVec = new Vector2() ) ); - indicesByPath[ path ] = index; + } else if ( scope === ScreenNode.VIEWPORT ) { - paths.push( path ); - parsedPaths.push( parsedPath ); - bindings.push( bindingsForPath ); + output = uniform( viewportVec || ( viewportVec = new Vector4() ) ); - for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) { + } else { - const object = objects[ i ]; - bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); + output = vec2( screenCoordinate.div( screenSize ) ); } - return bindingsForPath; + return output; } - unsubscribe_( path ) { + generate( builder ) { - // tells the group to forget about a property path and no longer - // update the array previously obtained with 'subscribe_' + if ( this.scope === ScreenNode.COORDINATE ) { - const indicesByPath = this._bindingsIndicesByPath, - index = indicesByPath[ path ]; + let coord = builder.getFragCoord(); - if ( index !== undefined ) { + if ( builder.isFlipY() ) { - const paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - lastBindingsIndex = bindings.length - 1, - lastBindings = bindings[ lastBindingsIndex ], - lastBindingsPath = path[ lastBindingsIndex ]; + // follow webgpu standards - indicesByPath[ lastBindingsPath ] = index; + const size = builder.getNodeProperties( screenSize ).outputNode.build( builder ); - bindings[ index ] = lastBindings; - bindings.pop(); + coord = `${ builder.getType( 'vec2' ) }( ${ coord }.x, ${ size }.y - ${ coord }.y )`; - parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; - parsedPaths.pop(); + } - paths[ index ] = paths[ lastBindingsIndex ]; - paths.pop(); + return coord; } + return super.generate( builder ); + } } -class AnimationAction { +ScreenNode.COORDINATE = 'coordinate'; +ScreenNode.VIEWPORT = 'viewport'; +ScreenNode.SIZE = 'size'; +ScreenNode.UV = 'uv'; - constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) { +// Screen - this._mixer = mixer; - this._clip = clip; - this._localRoot = localRoot; - this.blendMode = blendMode; +const screenUV = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.UV ); +const screenSize = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.SIZE ); +const screenCoordinate = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.COORDINATE ); - const tracks = clip.tracks, - nTracks = tracks.length, - interpolants = new Array( nTracks ); +// Viewport - const interpolantSettings = { - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding - }; +const viewport = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.VIEWPORT ); +const viewportSize = viewport.zw; +const viewportCoordinate = /*@__PURE__*/ screenCoordinate.sub( viewport.xy ); +const viewportUV = /*@__PURE__*/ viewportCoordinate.div( viewportSize ); - for ( let i = 0; i !== nTracks; ++ i ) { +// Deprecated - const interpolant = tracks[ i ].createInterpolant( null ); - interpolants[ i ] = interpolant; - interpolant.settings = interpolantSettings; +const viewportResolution = /*@__PURE__*/ ( Fn( () => { // @deprecated, r169 - } + console.warn( 'TSL.ViewportNode: "viewportResolution" is deprecated. Use "screenSize" instead.' ); - this._interpolantSettings = interpolantSettings; + return screenSize; - this._interpolants = interpolants; // bound by the mixer +}, 'vec2' ).once() )(); - // inside: PropertyMixer (managed by the mixer) - this._propertyBindings = new Array( nTracks ); +const viewportTopLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 - this._cacheIndex = null; // for the memory manager - this._byClipCacheIndex = null; // for the memory manager + console.warn( 'TSL.ViewportNode: "viewportTopLeft" is deprecated. Use "screenUV" instead.' ); - this._timeScaleInterpolant = null; - this._weightInterpolant = null; + return screenUV; - this.loop = LoopRepeat; - this._loopCount = - 1; +}, 'vec2' ).once() )(); - // global mixer time when the action is to be started - // it's set back to 'null' upon start of the action - this._startTime = null; +const viewportBottomLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 - // scaled local time of the action - // gets clamped or wrapped to 0..clip.duration according to loop - this.time = 0; + console.warn( 'TSL.ViewportNode: "viewportBottomLeft" is deprecated. Use "screenUV.flipY()" instead.' ); - this.timeScale = 1; - this._effectiveTimeScale = 1; + return screenUV.flipY(); - this.weight = 1; - this._effectiveWeight = 1; +}, 'vec2' ).once() )(); - this.repetitions = Infinity; // no. of repetitions when looping +const _size$a = /*@__PURE__*/ new Vector2(); - this.paused = false; // true -> zero effective time scale - this.enabled = true; // false -> zero effective weight +class ViewportTextureNode extends TextureNode { - this.clampWhenFinished = false;// keep feeding the last frame? + static get type() { - this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate - this.zeroSlopeAtEnd = true;// clips for start, loop and end + return 'ViewportTextureNode'; } - // State & Scheduling + constructor( uvNode = screenUV, levelNode = null, framebufferTexture = null ) { - play() { + if ( framebufferTexture === null ) { - this._mixer._activateAction( this ); + framebufferTexture = new FramebufferTexture(); + framebufferTexture.minFilter = LinearMipmapLinearFilter; - return this; + } - } + super( framebufferTexture, uvNode, levelNode ); - stop() { + this.generateMipmaps = false; - this._mixer._deactivateAction( this ); + this.isOutputTextureNode = true; - return this.reset(); + this.updateBeforeType = NodeUpdateType.FRAME; } - reset() { + updateBefore( frame ) { - this.paused = false; - this.enabled = true; + const renderer = frame.renderer; + renderer.getDrawingBufferSize( _size$a ); - this.time = 0; // restart clip - this._loopCount = - 1;// forget previous loops - this._startTime = null;// forget scheduling + // - return this.stopFading().stopWarping(); + const framebufferTexture = this.value; - } + if ( framebufferTexture.image.width !== _size$a.width || framebufferTexture.image.height !== _size$a.height ) { - isRunning() { + framebufferTexture.image.width = _size$a.width; + framebufferTexture.image.height = _size$a.height; + framebufferTexture.needsUpdate = true; - return this.enabled && ! this.paused && this.timeScale !== 0 && - this._startTime === null && this._mixer._isActiveAction( this ); + } - } + // - // return true when play has been called - isScheduled() { + const currentGenerateMipmaps = framebufferTexture.generateMipmaps; + framebufferTexture.generateMipmaps = this.generateMipmaps; - return this._mixer._isActiveAction( this ); + renderer.copyFramebufferToTexture( framebufferTexture ); + + framebufferTexture.generateMipmaps = currentGenerateMipmaps; } - startAt( time ) { + clone() { - this._startTime = time; + const viewportTextureNode = new this.constructor( this.uvNode, this.levelNode, this.value ); + viewportTextureNode.generateMipmaps = this.generateMipmaps; - return this; + return viewportTextureNode; } - setLoop( mode, repetitions ) { +} - this.loop = mode; - this.repetitions = repetitions; +const viewportTexture = /*@__PURE__*/ nodeProxy( ViewportTextureNode ); +const viewportMipTexture = /*@__PURE__*/ nodeProxy( ViewportTextureNode, null, null, { generateMipmaps: true } ); - return this; +let sharedDepthbuffer = null; + +class ViewportDepthTextureNode extends ViewportTextureNode { + + static get type() { + + return 'ViewportDepthTextureNode'; } - // Weight + constructor( uvNode = screenUV, levelNode = null ) { - // set the weight stopping any scheduled fading - // although .enabled = false yields an effective weight of zero, this - // method does *not* change .enabled, because it would be confusing - setEffectiveWeight( weight ) { + if ( sharedDepthbuffer === null ) { - this.weight = weight; + sharedDepthbuffer = new DepthTexture(); - // note: same logic as when updated at runtime - this._effectiveWeight = this.enabled ? weight : 0; + } - return this.stopFading(); + super( uvNode, levelNode, sharedDepthbuffer ); } - // return the weight considering fading and .enabled - getEffectiveWeight() { +} - return this._effectiveWeight; +const viewportDepthTexture = /*@__PURE__*/ nodeProxy( ViewportDepthTextureNode ); - } +class ViewportDepthNode extends Node { - fadeIn( duration ) { + static get type() { - return this._scheduleFading( duration, 0, 1 ); + return 'ViewportDepthNode'; } - fadeOut( duration ) { + constructor( scope, valueNode = null ) { - return this._scheduleFading( duration, 1, 0 ); + super( 'float' ); - } + this.scope = scope; + this.valueNode = valueNode; - crossFadeFrom( fadeOutAction, duration, warp ) { + this.isViewportDepthNode = true; - fadeOutAction.fadeOut( duration ); - this.fadeIn( duration ); + } - if ( warp ) { + generate( builder ) { - const fadeInDuration = this._clip.duration, - fadeOutDuration = fadeOutAction._clip.duration, + const { scope } = this; - startEndRatio = fadeOutDuration / fadeInDuration, - endStartRatio = fadeInDuration / fadeOutDuration; + if ( scope === ViewportDepthNode.DEPTH_BASE ) { - fadeOutAction.warp( 1.0, startEndRatio, duration ); - this.warp( endStartRatio, 1.0, duration ); + return builder.getFragDepth(); } - return this; + return super.generate( builder ); } - crossFadeTo( fadeInAction, duration, warp ) { + setup( { camera } ) { - return fadeInAction.crossFadeFrom( this, duration, warp ); + const { scope } = this; + const value = this.valueNode; - } + let node = null; - stopFading() { + if ( scope === ViewportDepthNode.DEPTH_BASE ) { - const weightInterpolant = this._weightInterpolant; + if ( value !== null ) { - if ( weightInterpolant !== null ) { + node = depthBase().assign( value ); - this._weightInterpolant = null; - this._mixer._takeBackControlInterpolant( weightInterpolant ); + } - } + } else if ( scope === ViewportDepthNode.DEPTH ) { - return this; + if ( camera.isPerspectiveCamera ) { - } + node = viewZToPerspectiveDepth( positionView.z, cameraNear, cameraFar ); - // Time Scale Control + } else { - // set the time scale stopping any scheduled warping - // although .paused = true yields an effective time scale of zero, this - // method does *not* change .paused, because it would be confusing - setEffectiveTimeScale( timeScale ) { + node = viewZToOrthographicDepth( positionView.z, cameraNear, cameraFar ); - this.timeScale = timeScale; - this._effectiveTimeScale = this.paused ? 0 : timeScale; + } - return this.stopWarping(); + } else if ( scope === ViewportDepthNode.LINEAR_DEPTH ) { - } + if ( value !== null ) { - // return the time scale considering warping and .paused - getEffectiveTimeScale() { + if ( camera.isPerspectiveCamera ) { - return this._effectiveTimeScale; + const viewZ = perspectiveDepthToViewZ( value, cameraNear, cameraFar ); - } + node = viewZToOrthographicDepth( viewZ, cameraNear, cameraFar ); - setDuration( duration ) { + } else { - this.timeScale = this._clip.duration / duration; + node = value; - return this.stopWarping(); + } - } + } else { - syncWith( action ) { + node = viewZToOrthographicDepth( positionView.z, cameraNear, cameraFar ); - this.time = action.time; - this.timeScale = action.timeScale; + } - return this.stopWarping(); + } + + return node; } - halt( duration ) { +} - return this.warp( this._effectiveTimeScale, 0, duration ); +ViewportDepthNode.DEPTH_BASE = 'depthBase'; +ViewportDepthNode.DEPTH = 'depth'; +ViewportDepthNode.LINEAR_DEPTH = 'linearDepth'; - } +// NOTE: viewZ, the z-coordinate in camera space, is negative for points in front of the camera - warp( startTimeScale, endTimeScale, duration ) { +// -near maps to 0; -far maps to 1 +const viewZToOrthographicDepth = ( viewZ, near, far ) => viewZ.add( near ).div( near.sub( far ) ); - const mixer = this._mixer, - now = mixer.time, - timeScale = this.timeScale; +// maps orthographic depth in [ 0, 1 ] to viewZ +const orthographicDepthToViewZ = ( depth, near, far ) => near.sub( far ).mul( depth ).sub( near ); - let interpolant = this._timeScaleInterpolant; +// NOTE: https://twitter.com/gonnavis/status/1377183786949959682 - if ( interpolant === null ) { +// -near maps to 0; -far maps to 1 +const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ ).mul( far ).div( far.sub( near ).mul( viewZ ) ); - interpolant = mixer._lendControlInterpolant(); - this._timeScaleInterpolant = interpolant; +// maps perspective depth in [ 0, 1 ] to viewZ +const perspectiveDepthToViewZ = ( depth, near, far ) => near.mul( far ).div( far.sub( near ).mul( depth ).sub( far ) ); - } +const depthBase = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.DEPTH_BASE ); - const times = interpolant.parameterPositions, - values = interpolant.sampleValues; +const depth = /*@__PURE__*/ nodeImmutable( ViewportDepthNode, ViewportDepthNode.DEPTH ); +const linearDepth = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.LINEAR_DEPTH ); +const viewportLinearDepth = /*@__PURE__*/ linearDepth( viewportDepthTexture() ); - times[ 0 ] = now; - times[ 1 ] = now + duration; +depth.assign = ( value ) => depthBase( value ); - values[ 0 ] = startTimeScale / timeScale; - values[ 1 ] = endTimeScale / timeScale; +class ClippingNode extends Node { - return this; + static get type() { + + return 'ClippingNode'; } - stopWarping() { + constructor( scope = ClippingNode.DEFAULT ) { - const timeScaleInterpolant = this._timeScaleInterpolant; + super(); - if ( timeScaleInterpolant !== null ) { + this.scope = scope; - this._timeScaleInterpolant = null; - this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); + } - } + setup( builder ) { - return this; + super.setup( builder ); - } + const clippingContext = builder.clippingContext; + const { localClipIntersection, localClippingCount, globalClippingCount } = clippingContext; - // Object Accessors + const numClippingPlanes = globalClippingCount + localClippingCount; + const numUnionClippingPlanes = localClipIntersection ? numClippingPlanes - localClippingCount : numClippingPlanes; - getMixer() { + if ( this.scope === ClippingNode.ALPHA_TO_COVERAGE ) { - return this._mixer; + return this.setupAlphaToCoverage( clippingContext.planes, numClippingPlanes, numUnionClippingPlanes ); - } + } else { - getClip() { + return this.setupDefault( clippingContext.planes, numClippingPlanes, numUnionClippingPlanes ); - return this._clip; + } } - getRoot() { + setupAlphaToCoverage( planes, numClippingPlanes, numUnionClippingPlanes ) { - return this._localRoot || this._mixer._root; + return Fn( () => { - } + const clippingPlanes = uniformArray( planes ); - // Interna + const distanceToPlane = property( 'float', 'distanceToPlane' ); + const distanceGradient = property( 'float', 'distanceToGradient' ); - _update( time, deltaTime, timeDirection, accuIndex ) { + const clipOpacity = property( 'float', 'clipOpacity' ); - // called by the mixer + clipOpacity.assign( 1 ); - if ( ! this.enabled ) { + let plane; - // call ._updateWeight() to update ._effectiveWeight + Loop( numUnionClippingPlanes, ( { i } ) => { - this._updateWeight( time ); - return; + plane = clippingPlanes.element( i ); - } + distanceToPlane.assign( positionView.dot( plane.xyz ).negate().add( plane.w ) ); + distanceGradient.assign( distanceToPlane.fwidth().div( 2.0 ) ); - const startTime = this._startTime; + clipOpacity.mulAssign( smoothstep( distanceGradient.negate(), distanceGradient, distanceToPlane ) ); - if ( startTime !== null ) { + clipOpacity.equal( 0.0 ).discard(); - // check for scheduled start of action + } ); - const timeRunning = ( time - startTime ) * timeDirection; - if ( timeRunning < 0 || timeDirection === 0 ) { + if ( numUnionClippingPlanes < numClippingPlanes ) { - deltaTime = 0; + const unionClipOpacity = property( 'float', 'unionclipOpacity' ); - } else { + unionClipOpacity.assign( 1 ); + Loop( { start: numUnionClippingPlanes, end: numClippingPlanes }, ( { i } ) => { - this._startTime = null; // unschedule - deltaTime = timeDirection * timeRunning; + plane = clippingPlanes.element( i ); + + distanceToPlane.assign( positionView.dot( plane.xyz ).negate().add( plane.w ) ); + distanceGradient.assign( distanceToPlane.fwidth().div( 2.0 ) ); + + unionClipOpacity.mulAssign( smoothstep( distanceGradient.negate(), distanceGradient, distanceToPlane ).oneMinus() ); + + } ); + + clipOpacity.mulAssign( unionClipOpacity.oneMinus() ); } - } + diffuseColor.a.mulAssign( clipOpacity ); - // apply time scale and advance time + diffuseColor.a.equal( 0.0 ).discard(); - deltaTime *= this._updateTimeScale( time ); - const clipTime = this._updateTime( deltaTime ); + } )(); - // note: _updateTime may disable the action resulting in - // an effective weight of 0 + } - const weight = this._updateWeight( time ); + setupDefault( planes, numClippingPlanes, numUnionClippingPlanes ) { - if ( weight > 0 ) { + return Fn( () => { - const interpolants = this._interpolants; - const propertyMixers = this._propertyBindings; + const clippingPlanes = uniformArray( planes ); - switch ( this.blendMode ) { + let plane; - case AdditiveAnimationBlendMode: + Loop( numUnionClippingPlanes, ( { i } ) => { - for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { + plane = clippingPlanes.element( i ); + positionView.dot( plane.xyz ).greaterThan( plane.w ).discard(); - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulateAdditive( weight ); + } ); - } + if ( numUnionClippingPlanes < numClippingPlanes ) { - break; + const clipped = property( 'bool', 'clipped' ); - case NormalAnimationBlendMode: - default: + clipped.assign( true ); - for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { + Loop( { start: numUnionClippingPlanes, end: numClippingPlanes }, ( { i } ) => { - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulate( accuIndex, weight ); + plane = clippingPlanes.element( i ); + clipped.assign( positionView.dot( plane.xyz ).greaterThan( plane.w ).and( clipped ) ); - } + } ); + + clipped.discard(); } - } + } )(); } - _updateWeight( time ) { - - let weight = 0; +} - if ( this.enabled ) { +ClippingNode.ALPHA_TO_COVERAGE = 'alphaToCoverage'; +ClippingNode.DEFAULT = 'default'; - weight = this.weight; - const interpolant = this._weightInterpolant; +const clipping = () => nodeObject( new ClippingNode() ); - if ( interpolant !== null ) { +const clippingAlpha = () => nodeObject( new ClippingNode( ClippingNode.ALPHA_TO_COVERAGE ) ); - const interpolantValue = interpolant.evaluate( time )[ 0 ]; +class NodeMaterial extends Material { - weight *= interpolantValue; + static get type() { - if ( time > interpolant.parameterPositions[ 1 ] ) { + return 'NodeMaterial'; - this.stopFading(); + } - if ( interpolantValue === 0 ) { + constructor() { - // faded out, disable - this.enabled = false; + super(); - } + this.isNodeMaterial = true; - } + this.type = this.constructor.type; - } + this.forceSinglePass = false; - } + this.fog = true; + this.lights = false; - this._effectiveWeight = weight; - return weight; + this.lightsNode = null; + this.envNode = null; + this.aoNode = null; - } + this.colorNode = null; + this.normalNode = null; + this.opacityNode = null; + this.backdropNode = null; + this.backdropAlphaNode = null; + this.alphaTestNode = null; - _updateTimeScale( time ) { + this.positionNode = null; - let timeScale = 0; + this.depthNode = null; + this.shadowNode = null; + this.shadowPositionNode = null; - if ( ! this.paused ) { + this.outputNode = null; + this.mrtNode = null; - timeScale = this.timeScale; + this.fragmentNode = null; + this.vertexNode = null; - const interpolant = this._timeScaleInterpolant; + } - if ( interpolant !== null ) { + customProgramCacheKey() { - const interpolantValue = interpolant.evaluate( time )[ 0 ]; + return this.type + getCacheKey$1( this ); - timeScale *= interpolantValue; + } - if ( time > interpolant.parameterPositions[ 1 ] ) { + build( builder ) { - this.stopWarping(); + this.setup( builder ); - if ( timeScale === 0 ) { + } - // motion has halted, pause - this.paused = true; + setupObserver( builder ) { - } else { + return new NodeMaterialObserver( builder ); - // warp done - apply final time scale - this.timeScale = timeScale; + } - } + setup( builder ) { - } + builder.context.setupNormal = () => this.setupNormal( builder ); - } + // < VERTEX STAGE > - } + builder.addStack(); - this._effectiveTimeScale = timeScale; - return timeScale; + builder.stack.outputNode = this.vertexNode || this.setupPosition( builder ); - } + builder.addFlow( 'vertex', builder.removeStack() ); - _updateTime( deltaTime ) { + // < FRAGMENT STAGE > - const duration = this._clip.duration; - const loop = this.loop; + builder.addStack(); - let time = this.time + deltaTime; - let loopCount = this._loopCount; + let resultNode; - const pingPong = ( loop === LoopPingPong ); + const clippingNode = this.setupClipping( builder ); - if ( deltaTime === 0 ) { + if ( this.depthWrite === true ) this.setupDepth( builder ); - if ( loopCount === - 1 ) return time; + if ( this.fragmentNode === null ) { - return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time; + this.setupDiffuseColor( builder ); + this.setupVariants( builder ); - } + const outgoingLightNode = this.setupLighting( builder ); - if ( loop === LoopOnce ) { + if ( clippingNode !== null ) builder.stack.add( clippingNode ); - if ( loopCount === - 1 ) { + // force unsigned floats - useful for RenderTargets - // just started + const basicOutput = vec4( outgoingLightNode, diffuseColor.a ).max( 0 ); - this._loopCount = 0; - this._setEndings( true, true, false ); + resultNode = this.setupOutput( builder, basicOutput ); - } + // OUTPUT NODE - handle_stop: { + output.assign( resultNode ); - if ( time >= duration ) { + // - time = duration; + if ( this.outputNode !== null ) resultNode = this.outputNode; - } else if ( time < 0 ) { + // MRT - time = 0; + const renderTarget = builder.renderer.getRenderTarget(); - } else { + if ( renderTarget !== null ) { - this.time = time; + const mrt = builder.renderer.getMRT(); + const materialMRT = this.mrtNode; - break handle_stop; + if ( mrt !== null ) { - } + resultNode = mrt; - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; + if ( materialMRT !== null ) { - this.time = time; + resultNode = mrt.merge( materialMRT ); - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime < 0 ? - 1 : 1 - } ); + } - } + } else if ( materialMRT !== null ) { - } else { // repetitive Repeat or PingPong + resultNode = materialMRT; - if ( loopCount === - 1 ) { + } - // just started + } - if ( deltaTime >= 0 ) { + } else { - loopCount = 0; + let fragmentNode = this.fragmentNode; - this._setEndings( true, this.repetitions === 0, pingPong ); + if ( fragmentNode.isOutputStructNode !== true ) { - } else { + fragmentNode = vec4( fragmentNode ); - // when looping in reverse direction, the initial - // transition through zero counts as a repetition, - // so leave loopCount at -1 + } - this._setEndings( this.repetitions === 0, true, pingPong ); + resultNode = this.setupOutput( builder, fragmentNode ); - } + } - } + builder.stack.outputNode = resultNode; - if ( time >= duration || time < 0 ) { + builder.addFlow( 'fragment', builder.removeStack() ); - // wrap around + // < MONITOR > - const loopDelta = Math.floor( time / duration ); // signed - time -= duration * loopDelta; + builder.monitor = this.setupObserver( builder ); - loopCount += Math.abs( loopDelta ); + } - const pending = this.repetitions - loopCount; + setupClipping( builder ) { - if ( pending <= 0 ) { + if ( builder.clippingContext === null ) return null; - // have to stop (switch state, clamp time, fire event) + const { globalClippingCount, localClippingCount } = builder.clippingContext; - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; + let result = null; - time = deltaTime > 0 ? duration : 0; + if ( globalClippingCount || localClippingCount ) { - this.time = time; + const samples = builder.renderer.samples; - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime > 0 ? 1 : - 1 - } ); + if ( this.alphaToCoverage && samples > 1 ) { - } else { + // to be added to flow when the color/alpha value has been determined + result = clippingAlpha(); - // keep running + } else { - if ( pending === 1 ) { + builder.stack.add( clipping() ); - // entering the last round + } - const atStart = deltaTime < 0; - this._setEndings( atStart, ! atStart, pingPong ); + } - } else { + return result; - this._setEndings( false, false, pingPong ); + } - } + setupDepth( builder ) { - this._loopCount = loopCount; + const { renderer } = builder; - this.time = time; + // Depth - this._mixer.dispatchEvent( { - type: 'loop', action: this, loopDelta: loopDelta - } ); + let depthNode = this.depthNode; - } + if ( depthNode === null ) { - } else { + const mrt = renderer.getMRT(); - this.time = time; + if ( mrt && mrt.has( 'depth' ) ) { - } + depthNode = mrt.get( 'depth' ); - if ( pingPong && ( loopCount & 1 ) === 1 ) { + } else if ( renderer.logarithmicDepthBuffer === true ) { - // invert time for the "pong round" + const fragDepth = modelViewProjection().w.add( 1 ); - return duration - time; + depthNode = fragDepth.log2().mul( cameraLogDepth ).mul( 0.5 ); } } - return time; + if ( depthNode !== null ) { + + depth.assign( depthNode ).append(); + + } } - _setEndings( atStart, atEnd, pingPong ) { + setupPosition( builder ) { - const settings = this._interpolantSettings; + const { object } = builder; + const geometry = object.geometry; - if ( pingPong ) { + builder.addStack(); - settings.endingStart = ZeroSlopeEnding; - settings.endingEnd = ZeroSlopeEnding; + // Vertex - } else { + if ( geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color ) { - // assuming for LoopOnce atStart == atEnd == true + morphReference( object ).append(); - if ( atStart ) { + } - settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; + if ( object.isSkinnedMesh === true ) { - } else { + skinningReference( object ).append(); - settings.endingStart = WrapAroundEnding; + } - } + if ( this.displacementMap ) { - if ( atEnd ) { + const displacementMap = materialReference( 'displacementMap', 'texture' ); + const displacementScale = materialReference( 'displacementScale', 'float' ); + const displacementBias = materialReference( 'displacementBias', 'float' ); - settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; + positionLocal.addAssign( normalLocal.normalize().mul( ( displacementMap.x.mul( displacementScale ).add( displacementBias ) ) ) ); - } else { + } - settings.endingEnd = WrapAroundEnding; + if ( object.isBatchedMesh ) { - } + batch( object ).append(); } - } + if ( ( object.instanceMatrix && object.instanceMatrix.isInstancedBufferAttribute === true ) ) { - _scheduleFading( duration, weightNow, weightThen ) { + instance( object ).append(); - const mixer = this._mixer, now = mixer.time; - let interpolant = this._weightInterpolant; + } - if ( interpolant === null ) { + if ( this.positionNode !== null ) { - interpolant = mixer._lendControlInterpolant(); - this._weightInterpolant = interpolant; + positionLocal.assign( this.positionNode ); } - const times = interpolant.parameterPositions, - values = interpolant.sampleValues; + const mvp = modelViewProjection(); - times[ 0 ] = now; - values[ 0 ] = weightNow; - times[ 1 ] = now + duration; - values[ 1 ] = weightThen; + builder.context.vertex = builder.removeStack(); + builder.context.mvp = mvp; - return this; + return mvp; } -} + setupDiffuseColor( { object, geometry } ) { -const _controlInterpolantsResultBuffer = new Float32Array( 1 ); + let colorNode = this.colorNode ? vec4( this.colorNode ) : materialColor; + // VERTEX COLORS -class AnimationMixer extends EventDispatcher { + if ( this.vertexColors === true && geometry.hasAttribute( 'color' ) ) { - constructor( root ) { + colorNode = vec4( colorNode.xyz.mul( attribute( 'color', 'vec3' ) ), colorNode.a ); - super(); + } - this._root = root; - this._initMemoryManager(); - this._accuIndex = 0; - this.time = 0; - this.timeScale = 1.0; + // Instanced colors - } + if ( object.instanceColor ) { - _bindAction( action, prototypeAction ) { + const instanceColor = varyingProperty( 'vec3', 'vInstanceColor' ); - const root = action._localRoot || this._root, - tracks = action._clip.tracks, - nTracks = tracks.length, - bindings = action._propertyBindings, - interpolants = action._interpolants, - rootUuid = root.uuid, - bindingsByRoot = this._bindingsByRootAndName; + colorNode = instanceColor.mul( colorNode ); - let bindingsByName = bindingsByRoot[ rootUuid ]; + } - if ( bindingsByName === undefined ) { + if ( object.isBatchedMesh && object._colorsTexture ) { - bindingsByName = {}; - bindingsByRoot[ rootUuid ] = bindingsByName; + const batchColor = varyingProperty( 'vec3', 'vBatchColor' ); + + colorNode = batchColor.mul( colorNode ); } - for ( let i = 0; i !== nTracks; ++ i ) { - const track = tracks[ i ], - trackName = track.name; + // COLOR - let binding = bindingsByName[ trackName ]; + diffuseColor.assign( colorNode ); - if ( binding !== undefined ) { + // OPACITY - ++ binding.referenceCount; - bindings[ i ] = binding; + const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity; + diffuseColor.a.assign( diffuseColor.a.mul( opacityNode ) ); - } else { + // ALPHA TEST - binding = bindings[ i ]; + if ( this.alphaTestNode !== null || this.alphaTest > 0 ) { - if ( binding !== undefined ) { - - // existing binding, make sure the cache knows - - if ( binding._cacheIndex === null ) { + const alphaTestNode = this.alphaTestNode !== null ? float( this.alphaTestNode ) : materialAlphaTest; - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); + diffuseColor.a.lessThanEqual( alphaTestNode ).discard(); - } + } - continue; + if ( this.transparent === false && this.blending === NormalBlending && this.alphaToCoverage === false ) { - } + diffuseColor.a.assign( 1.0 ); - const path = prototypeAction && prototypeAction. - _propertyBindings[ i ].binding.parsedPath; + } - binding = new PropertyMixer( - PropertyBinding.create( root, trackName, path ), - track.ValueTypeName, track.getValueSize() ); + } - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); + setupVariants( /*builder*/ ) { - bindings[ i ] = binding; + // Interface function. - } + } - interpolants[ i ].resultBuffer = binding.buffer; + setupOutgoingLight() { - } + return ( this.lights === true ) ? vec3( 0 ) : diffuseColor.rgb; } - _activateAction( action ) { + setupNormal() { - if ( ! this._isActiveAction( action ) ) { + return this.normalNode ? vec3( this.normalNode ) : materialNormal; - if ( action._cacheIndex === null ) { + } - // this action has been forgotten by the cache, but the user - // appears to be still using it -> rebind + setupEnvironment( /*builder*/ ) { - const rootUuid = ( action._localRoot || this._root ).uuid, - clipUuid = action._clip.uuid, - actionsForClip = this._actionsByClip[ clipUuid ]; + let node = null; - this._bindAction( action, - actionsForClip && actionsForClip.knownActions[ 0 ] ); + if ( this.envNode ) { - this._addInactiveAction( action, clipUuid, rootUuid ); + node = this.envNode; - } + } else if ( this.envMap ) { - const bindings = action._propertyBindings; + node = this.envMap.isCubeTexture ? materialReference( 'envMap', 'cubeTexture' ) : materialReference( 'envMap', 'texture' ); - // increment reference counts / sort out state - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { + } - const binding = bindings[ i ]; + return node; - if ( binding.useCount ++ === 0 ) { + } - this._lendBinding( binding ); - binding.saveOriginalState(); + setupLightMap( builder ) { - } + let node = null; - } + if ( builder.material.lightMap ) { - this._lendAction( action ); + node = new IrradianceNode( materialLightMap ); } + return node; + } - _deactivateAction( action ) { + setupLights( builder ) { - if ( this._isActiveAction( action ) ) { + const materialLightsNode = []; - const bindings = action._propertyBindings; + // - // decrement reference counts / sort out state - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { + const envNode = this.setupEnvironment( builder ); - const binding = bindings[ i ]; + if ( envNode && envNode.isLightingNode ) { - if ( -- binding.useCount === 0 ) { + materialLightsNode.push( envNode ); - binding.restoreOriginalState(); - this._takeBackBinding( binding ); + } - } + const lightMapNode = this.setupLightMap( builder ); - } + if ( lightMapNode && lightMapNode.isLightingNode ) { - this._takeBackAction( action ); + materialLightsNode.push( lightMapNode ); } - } + if ( this.aoNode !== null || builder.material.aoMap ) { - // Memory manager + const aoNode = this.aoNode !== null ? this.aoNode : materialAOMap; - _initMemoryManager() { + materialLightsNode.push( new AONode( aoNode ) ); - this._actions = []; // 'nActiveActions' followed by inactive ones - this._nActiveActions = 0; + } - this._actionsByClip = {}; - // inside: - // { - // knownActions: Array< AnimationAction > - used as prototypes - // actionByRoot: AnimationAction - lookup - // } + let lightsN = this.lightsNode || builder.lightsNode; + if ( materialLightsNode.length > 0 ) { - this._bindings = []; // 'nActiveBindings' followed by inactive ones - this._nActiveBindings = 0; + lightsN = lights( [ ...lightsN.getLights(), ...materialLightsNode ] ); - this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > + } + return lightsN; - this._controlInterpolants = []; // same game as above - this._nActiveControlInterpolants = 0; + } - const scope = this; + setupLightingModel( /*builder*/ ) { - this.stats = { + // Interface function. - actions: { - get total() { + } - return scope._actions.length; + setupLighting( builder ) { - }, - get inUse() { + const { material } = builder; + const { backdropNode, backdropAlphaNode, emissiveNode } = this; - return scope._nActiveActions; + // OUTGOING LIGHT - } - }, - bindings: { - get total() { + const lights = this.lights === true || this.lightsNode !== null; - return scope._bindings.length; + const lightsNode = lights ? this.setupLights( builder ) : null; - }, - get inUse() { + let outgoingLightNode = this.setupOutgoingLight( builder ); - return scope._nActiveBindings; + if ( lightsNode && lightsNode.getScope().getLights().length > 0 ) { - } - }, - controlInterpolants: { - get total() { + const lightingModel = this.setupLightingModel( builder ); - return scope._controlInterpolants.length; + outgoingLightNode = lightingContext( lightsNode, lightingModel, backdropNode, backdropAlphaNode ); - }, - get inUse() { + } else if ( backdropNode !== null ) { - return scope._nActiveControlInterpolants; + outgoingLightNode = vec3( backdropAlphaNode !== null ? mix( outgoingLightNode, backdropNode, backdropAlphaNode ) : backdropNode ); - } - } + } - }; + // EMISSIVE - } + if ( ( emissiveNode && emissiveNode.isNode === true ) || ( material.emissive && material.emissive.isColor === true ) ) { - // Memory management for AnimationAction objects + emissive.assign( vec3( emissiveNode ? emissiveNode : materialEmissive ) ); - _isActiveAction( action ) { + outgoingLightNode = outgoingLightNode.add( emissive ); - const index = action._cacheIndex; - return index !== null && index < this._nActiveActions; + } - } + return outgoingLightNode; - _addInactiveAction( action, clipUuid, rootUuid ) { + } - const actions = this._actions, - actionsByClip = this._actionsByClip; + setupOutput( builder, outputNode ) { - let actionsForClip = actionsByClip[ clipUuid ]; + // FOG - if ( actionsForClip === undefined ) { + if ( this.fog === true ) { - actionsForClip = { + const fogNode = builder.fogNode; - knownActions: [ action ], - actionByRoot: {} + if ( fogNode ) outputNode = vec4( fogNode.mix( outputNode.rgb, fogNode.colorNode ), outputNode.a ); - }; + } - action._byClipCacheIndex = 0; + return outputNode; - actionsByClip[ clipUuid ] = actionsForClip; + } - } else { + setDefaultValues( material ) { - const knownActions = actionsForClip.knownActions; + // This approach is to reuse the native refreshUniforms* + // and turn available the use of features like transmission and environment in core - action._byClipCacheIndex = knownActions.length; - knownActions.push( action ); + for ( const property in material ) { - } + const value = material[ property ]; - action._cacheIndex = actions.length; - actions.push( action ); + if ( this[ property ] === undefined ) { - actionsForClip.actionByRoot[ rootUuid ] = action; + this[ property ] = value; - } + if ( value && value.clone ) this[ property ] = value.clone(); - _removeInactiveAction( action ) { + } - const actions = this._actions, - lastInactiveAction = actions[ actions.length - 1 ], - cacheIndex = action._cacheIndex; + } - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); + const descriptors = Object.getOwnPropertyDescriptors( material.constructor.prototype ); - action._cacheIndex = null; + for ( const key in descriptors ) { + if ( Object.getOwnPropertyDescriptor( this.constructor.prototype, key ) === undefined && + descriptors[ key ].get !== undefined ) { - const clipUuid = action._clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ], - knownActionsForClip = actionsForClip.knownActions, + Object.defineProperty( this.constructor.prototype, key, descriptors[ key ] ); - lastKnownAction = - knownActionsForClip[ knownActionsForClip.length - 1 ], + } - byClipCacheIndex = action._byClipCacheIndex; + } - lastKnownAction._byClipCacheIndex = byClipCacheIndex; - knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; - knownActionsForClip.pop(); + } - action._byClipCacheIndex = null; + toJSON( meta ) { + const isRoot = ( meta === undefined || typeof meta === 'string' ); - const actionByRoot = actionsForClip.actionByRoot, - rootUuid = ( action._localRoot || this._root ).uuid; + if ( isRoot ) { - delete actionByRoot[ rootUuid ]; + meta = { + textures: {}, + images: {}, + nodes: {} + }; - if ( knownActionsForClip.length === 0 ) { + } - delete actionsByClip[ clipUuid ]; + const data = Material.prototype.toJSON.call( this, meta ); + const nodeChildren = getNodeChildren( this ); - } + data.inputNodes = {}; - this._removeInactiveBindingsForAction( action ); + for ( const { property, childNode } of nodeChildren ) { - } + data.inputNodes[ property ] = childNode.toJSON( meta ).uuid; - _removeInactiveBindingsForAction( action ) { + } - const bindings = action._propertyBindings; + // TODO: Copied from Object3D.toJSON - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { + function extractFromCache( cache ) { - const binding = bindings[ i ]; + const values = []; - if ( -- binding.referenceCount === 0 ) { + for ( const key in cache ) { - this._removeInactiveBinding( binding ); + const data = cache[ key ]; + delete data.metadata; + values.push( data ); } + return values; + } - } + if ( isRoot ) { - _lendAction( action ) { + const textures = extractFromCache( meta.textures ); + const images = extractFromCache( meta.images ); + const nodes = extractFromCache( meta.nodes ); - // [ active actions | inactive actions ] - // [ active actions >| inactive actions ] - // s a - // <-swap-> - // a s + if ( textures.length > 0 ) data.textures = textures; + if ( images.length > 0 ) data.images = images; + if ( nodes.length > 0 ) data.nodes = nodes; - const actions = this._actions, - prevIndex = action._cacheIndex, + } - lastActiveIndex = this._nActiveActions ++, + return data; - firstInactiveAction = actions[ lastActiveIndex ]; + } - action._cacheIndex = lastActiveIndex; - actions[ lastActiveIndex ] = action; + copy( source ) { - firstInactiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = firstInactiveAction; + this.lightsNode = source.lightsNode; + this.envNode = source.envNode; - } + this.colorNode = source.colorNode; + this.normalNode = source.normalNode; + this.opacityNode = source.opacityNode; + this.backdropNode = source.backdropNode; + this.backdropAlphaNode = source.backdropAlphaNode; + this.alphaTestNode = source.alphaTestNode; - _takeBackAction( action ) { + this.positionNode = source.positionNode; - // [ active actions | inactive actions ] - // [ active actions |< inactive actions ] - // a s - // <-swap-> - // s a + this.depthNode = source.depthNode; + this.shadowNode = source.shadowNode; + this.shadowPositionNode = source.shadowPositionNode; - const actions = this._actions, - prevIndex = action._cacheIndex, + this.outputNode = source.outputNode; + this.mrtNode = source.mrtNode; - firstInactiveIndex = -- this._nActiveActions, + this.fragmentNode = source.fragmentNode; + this.vertexNode = source.vertexNode; - lastActiveAction = actions[ firstInactiveIndex ]; + return super.copy( source ); - action._cacheIndex = firstInactiveIndex; - actions[ firstInactiveIndex ] = action; + } - lastActiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = lastActiveAction; +} - } +const _defaultValues$e = /*@__PURE__*/ new PointsMaterial(); - // Memory management for PropertyMixer objects +class InstancedPointsNodeMaterial extends NodeMaterial { - _addInactiveBinding( binding, rootUuid, trackName ) { + static get type() { - const bindingsByRoot = this._bindingsByRootAndName, - bindings = this._bindings; + return 'InstancedPointsNodeMaterial'; - let bindingByName = bindingsByRoot[ rootUuid ]; + } - if ( bindingByName === undefined ) { + constructor( params = {} ) { - bindingByName = {}; - bindingsByRoot[ rootUuid ] = bindingByName; + super(); - } + this.lights = false; - bindingByName[ trackName ] = binding; + this.useAlphaToCoverage = true; - binding._cacheIndex = bindings.length; - bindings.push( binding ); + this.useColor = params.vertexColors; - } + this.pointWidth = 1; - _removeInactiveBinding( binding ) { + this.pointColorNode = null; - const bindings = this._bindings, - propBinding = binding.binding, - rootUuid = propBinding.rootNode.uuid, - trackName = propBinding.path, - bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ], + this.pointWidthNode = null; - lastInactiveBinding = bindings[ bindings.length - 1 ], - cacheIndex = binding._cacheIndex; + this.setDefaultValues( _defaultValues$e ); - lastInactiveBinding._cacheIndex = cacheIndex; - bindings[ cacheIndex ] = lastInactiveBinding; - bindings.pop(); + this.setValues( params ); - delete bindingByName[ trackName ]; + } - if ( Object.keys( bindingByName ).length === 0 ) { + setup( builder ) { - delete bindingsByRoot[ rootUuid ]; + this.setupShaders( builder ); - } + super.setup( builder ); } - _lendBinding( binding ) { + setupShaders( { renderer } ) { - const bindings = this._bindings, - prevIndex = binding._cacheIndex, + const useAlphaToCoverage = this.alphaToCoverage; + const useColor = this.useColor; - lastActiveIndex = this._nActiveBindings ++, + this.vertexNode = Fn( () => { - firstInactiveBinding = bindings[ lastActiveIndex ]; + const instancePosition = attribute( 'instancePosition' ).xyz; - binding._cacheIndex = lastActiveIndex; - bindings[ lastActiveIndex ] = binding; + // camera space + const mvPos = vec4( modelViewMatrix.mul( vec4( instancePosition, 1.0 ) ) ); - firstInactiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = firstInactiveBinding; + const aspect = viewport.z.div( viewport.w ); - } + // clip space + const clipPos = cameraProjectionMatrix.mul( mvPos ); - _takeBackBinding( binding ) { + // offset in ndc space + const offset = positionGeometry.xy.toVar(); - const bindings = this._bindings, - prevIndex = binding._cacheIndex, + offset.mulAssign( this.pointWidthNode ? this.pointWidthNode : materialPointWidth ); - firstInactiveIndex = -- this._nActiveBindings, + offset.assign( offset.div( viewport.z ) ); + offset.y.assign( offset.y.mul( aspect ) ); - lastActiveBinding = bindings[ firstInactiveIndex ]; + // back to clip space + offset.assign( offset.mul( clipPos.w ) ); - binding._cacheIndex = firstInactiveIndex; - bindings[ firstInactiveIndex ] = binding; + //clipPos.xy += offset; + clipPos.addAssign( vec4( offset, 0, 0 ) ); - lastActiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = lastActiveBinding; + return clipPos; - } + } )(); + this.fragmentNode = Fn( () => { - // Memory management of Interpolants for weight and time scale + const alpha = float( 1 ).toVar(); - _lendControlInterpolant() { + const len2 = lengthSq( uv().mul( 2 ).sub( 1 ) ); - const interpolants = this._controlInterpolants, - lastActiveIndex = this._nActiveControlInterpolants ++; + if ( useAlphaToCoverage && renderer.samples > 1 ) { - let interpolant = interpolants[ lastActiveIndex ]; + const dlen = float( len2.fwidth() ).toVar(); - if ( interpolant === undefined ) { + alpha.assign( smoothstep( dlen.oneMinus(), dlen.add( 1 ), len2 ).oneMinus() ); - interpolant = new LinearInterpolant( - new Float32Array( 2 ), new Float32Array( 2 ), - 1, _controlInterpolantsResultBuffer ); + } else { - interpolant.__cacheIndex = lastActiveIndex; - interpolants[ lastActiveIndex ] = interpolant; + len2.greaterThan( 1.0 ).discard(); - } + } - return interpolant; + let pointColorNode; - } + if ( this.pointColorNode ) { - _takeBackControlInterpolant( interpolant ) { + pointColorNode = this.pointColorNode; - const interpolants = this._controlInterpolants, - prevIndex = interpolant.__cacheIndex, + } else { - firstInactiveIndex = -- this._nActiveControlInterpolants, + if ( useColor ) { - lastActiveInterpolant = interpolants[ firstInactiveIndex ]; + const instanceColor = attribute( 'instanceColor' ); - interpolant.__cacheIndex = firstInactiveIndex; - interpolants[ firstInactiveIndex ] = interpolant; + pointColorNode = instanceColor.mul( materialColor ); - lastActiveInterpolant.__cacheIndex = prevIndex; - interpolants[ prevIndex ] = lastActiveInterpolant; + } else { - } + pointColorNode = materialColor; - // return an action for a clip optionally using a custom root target - // object (this method allocates a lot of dynamic memory in case a - // previously unknown clip/root combination is specified) - clipAction( clip, optionalRoot, blendMode ) { + } - const root = optionalRoot || this._root, - rootUuid = root.uuid; + } - let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip; + alpha.mulAssign( materialOpacity ); - const clipUuid = clipObject !== null ? clipObject.uuid : clip; + return vec4( pointColorNode, alpha ); - const actionsForClip = this._actionsByClip[ clipUuid ]; - let prototypeAction = null; + } )(); - if ( blendMode === undefined ) { + } - if ( clipObject !== null ) { + get alphaToCoverage() { - blendMode = clipObject.blendMode; + return this.useAlphaToCoverage; - } else { + } - blendMode = NormalAnimationBlendMode; + set alphaToCoverage( value ) { - } + if ( this.useAlphaToCoverage !== value ) { + + this.useAlphaToCoverage = value; + this.needsUpdate = true; } - if ( actionsForClip !== undefined ) { + } - const existingAction = actionsForClip.actionByRoot[ rootUuid ]; +} - if ( existingAction !== undefined && existingAction.blendMode === blendMode ) { +const _defaultValues$d = /*@__PURE__*/ new LineBasicMaterial(); - return existingAction; +class LineBasicNodeMaterial extends NodeMaterial { - } + static get type() { - // we know the clip, so we don't have to parse all - // the bindings again but can just copy - prototypeAction = actionsForClip.knownActions[ 0 ]; + return 'LineBasicNodeMaterial'; - // also, take the clip from the prototype action - if ( clipObject === null ) - clipObject = prototypeAction._clip; + } - } + constructor( parameters ) { - // clip must be known when specified via string - if ( clipObject === null ) return null; + super(); - // allocate all resources required to run it - const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode ); + this.isLineBasicNodeMaterial = true; - this._bindAction( newAction, prototypeAction ); + this.lights = false; - // and make the action known to the memory manager - this._addInactiveAction( newAction, clipUuid, rootUuid ); + this.setDefaultValues( _defaultValues$d ); - return newAction; + this.setValues( parameters ); } - // get an existing action - existingAction( clip, optionalRoot ) { - - const root = optionalRoot || this._root, - rootUuid = root.uuid, - - clipObject = typeof clip === 'string' ? - AnimationClip.findByName( root, clip ) : clip, - - clipUuid = clipObject ? clipObject.uuid : clip, - - actionsForClip = this._actionsByClip[ clipUuid ]; +} - if ( actionsForClip !== undefined ) { +const _defaultValues$c = /*@__PURE__*/ new LineDashedMaterial(); - return actionsForClip.actionByRoot[ rootUuid ] || null; +class LineDashedNodeMaterial extends NodeMaterial { - } + static get type() { - return null; + return 'LineDashedNodeMaterial'; } - // deactivates all previously scheduled actions - stopAllAction() { + constructor( parameters ) { - const actions = this._actions, - nActions = this._nActiveActions; + super(); - for ( let i = nActions - 1; i >= 0; -- i ) { + this.isLineDashedNodeMaterial = true; - actions[ i ].stop(); + this.lights = false; - } + this.setDefaultValues( _defaultValues$c ); - return this; + this.offsetNode = null; + this.dashScaleNode = null; + this.dashSizeNode = null; + this.gapSizeNode = null; - } + this.setValues( parameters ); - // advance the time and update apply the animation - update( deltaTime ) { + } - deltaTime *= this.timeScale; + setupVariants() { - const actions = this._actions, - nActions = this._nActiveActions, + const offsetNode = this.offsetNode; + const dashScaleNode = this.dashScaleNode ? float( this.dashScaleNode ) : materialLineScale; + const dashSizeNode = this.dashSizeNode ? float( this.dashSizeNode ) : materialLineDashSize; + const gapSizeNode = this.dashSizeNode ? float( this.dashGapNode ) : materialLineGapSize; - time = this.time += deltaTime, - timeDirection = Math.sign( deltaTime ), + dashSize.assign( dashSizeNode ); + gapSize.assign( gapSizeNode ); - accuIndex = this._accuIndex ^= 1; + const vLineDistance = varying( attribute( 'lineDistance' ).mul( dashScaleNode ) ); + const vLineDistanceOffset = offsetNode ? vLineDistance.add( offsetNode ) : vLineDistance; - // run active actions + vLineDistanceOffset.mod( dashSize.add( gapSize ) ).greaterThan( dashSize ).discard(); - for ( let i = 0; i !== nActions; ++ i ) { + } - const action = actions[ i ]; +} - action._update( time, deltaTime, timeDirection, accuIndex ); +const _defaultValues$b = /*@__PURE__*/ new LineDashedMaterial(); - } +class Line2NodeMaterial extends NodeMaterial { - // update scene graph + static get type() { - const bindings = this._bindings, - nBindings = this._nActiveBindings; + return 'Line2NodeMaterial'; - for ( let i = 0; i !== nBindings; ++ i ) { + } - bindings[ i ].apply( accuIndex ); + constructor( params = {} ) { - } + super(); - return this; + this.lights = false; - } + this.setDefaultValues( _defaultValues$b ); - // Allows you to seek to a specific time in an animation. - setTime( timeInSeconds ) { + this.useAlphaToCoverage = true; + this.useColor = params.vertexColors; + this.useDash = params.dashed; + this.useWorldUnits = false; - this.time = 0; // Zero out time attribute for AnimationMixer object; - for ( let i = 0; i < this._actions.length; i ++ ) { + this.dashOffset = 0; + this.lineWidth = 1; - this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects. + this.lineColorNode = null; - } + this.offsetNode = null; + this.dashScaleNode = null; + this.dashSizeNode = null; + this.gapSizeNode = null; - return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object. + this.setValues( params ); } - // return this mixer's root target object - getRoot() { + setup( builder ) { - return this._root; + this.setupShaders( builder ); + + super.setup( builder ); } - // free all resources specific to a particular clip - uncacheClip( clip ) { + setupShaders( { renderer } ) { - const actions = this._actions, - clipUuid = clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ]; + const useAlphaToCoverage = this.alphaToCoverage; + const useColor = this.useColor; + const useDash = this.dashed; + const useWorldUnits = this.worldUnits; - if ( actionsForClip !== undefined ) { + const trimSegment = Fn( ( { start, end } ) => { - // note: just calling _removeInactiveAction would mess up the - // iteration state and also require updating the state we can - // just throw away + const a = cameraProjectionMatrix.element( 2 ).element( 2 ); // 3nd entry in 3th column + const b = cameraProjectionMatrix.element( 3 ).element( 2 ); // 3nd entry in 4th column + const nearEstimate = b.mul( - 0.5 ).div( a ); - const actionsToRemove = actionsForClip.knownActions; + const alpha = nearEstimate.sub( start.z ).div( end.z.sub( start.z ) ); - for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) { + return vec4( mix( start.xyz, end.xyz, alpha ), end.w ); - const action = actionsToRemove[ i ]; + } ).setLayout( { + name: 'trimSegment', + type: 'vec4', + inputs: [ + { name: 'start', type: 'vec4' }, + { name: 'end', type: 'vec4' } + ] + } ); - this._deactivateAction( action ); + this.vertexNode = Fn( () => { - const cacheIndex = action._cacheIndex, - lastInactiveAction = actions[ actions.length - 1 ]; + const instanceStart = attribute( 'instanceStart' ); + const instanceEnd = attribute( 'instanceEnd' ); - action._cacheIndex = null; - action._byClipCacheIndex = null; + // camera space - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); + const start = vec4( modelViewMatrix.mul( vec4( instanceStart, 1.0 ) ) ).toVar( 'start' ); + const end = vec4( modelViewMatrix.mul( vec4( instanceEnd, 1.0 ) ) ).toVar( 'end' ); - this._removeInactiveBindingsForAction( action ); + if ( useWorldUnits ) { + + varyingProperty( 'vec3', 'worldStart' ).assign( start.xyz ); + varyingProperty( 'vec3', 'worldEnd' ).assign( end.xyz ); } - delete actionsByClip[ clipUuid ]; + const aspect = viewport.z.div( viewport.w ); - } + // special case for perspective projection, and segments that terminate either in, or behind, the camera plane + // clearly the gpu firmware has a way of addressing this issue when projecting into ndc space + // but we need to perform ndc-space calculations in the shader, so we must address this issue directly + // perhaps there is a more elegant solution -- WestLangley - } + const perspective = cameraProjectionMatrix.element( 2 ).element( 3 ).equal( - 1.0 ); // 4th entry in the 3rd column - // free all resources specific to a particular root target object - uncacheRoot( root ) { + If( perspective, () => { - const rootUuid = root.uuid, - actionsByClip = this._actionsByClip; + If( start.z.lessThan( 0.0 ).and( end.z.greaterThan( 0.0 ) ), () => { - for ( const clipUuid in actionsByClip ) { + end.assign( trimSegment( { start: start, end: end } ) ); - const actionByRoot = actionsByClip[ clipUuid ].actionByRoot, - action = actionByRoot[ rootUuid ]; + } ).ElseIf( end.z.lessThan( 0.0 ).and( start.z.greaterThanEqual( 0.0 ) ), () => { - if ( action !== undefined ) { + start.assign( trimSegment( { start: end, end: start } ) ); - this._deactivateAction( action ); - this._removeInactiveAction( action ); + } ); - } + } ); - } + // clip space + const clipStart = cameraProjectionMatrix.mul( start ); + const clipEnd = cameraProjectionMatrix.mul( end ); - const bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ]; + // ndc space + const ndcStart = clipStart.xyz.div( clipStart.w ); + const ndcEnd = clipEnd.xyz.div( clipEnd.w ); - if ( bindingByName !== undefined ) { + // direction + const dir = ndcEnd.xy.sub( ndcStart.xy ).toVar(); - for ( const trackName in bindingByName ) { + // account for clip-space aspect ratio + dir.x.assign( dir.x.mul( aspect ) ); + dir.assign( dir.normalize() ); - const binding = bindingByName[ trackName ]; - binding.restoreOriginalState(); - this._removeInactiveBinding( binding ); + const clip = vec4().toVar(); - } + if ( useWorldUnits ) { - } + // get the offset direction as perpendicular to the view vector - } + const worldDir = end.xyz.sub( start.xyz ).normalize(); + const tmpFwd = mix( start.xyz, end.xyz, 0.5 ).normalize(); + const worldUp = worldDir.cross( tmpFwd ).normalize(); + const worldFwd = worldDir.cross( worldUp ); - // remove a targeted clip from the cache - uncacheAction( clip, optionalRoot ) { + const worldPos = varyingProperty( 'vec4', 'worldPos' ); - const action = this.existingAction( clip, optionalRoot ); + worldPos.assign( positionGeometry.y.lessThan( 0.5 ).select( start, end ) ); - if ( action !== null ) { + // height offset + const hw = materialLineWidth.mul( 0.5 ); + worldPos.addAssign( vec4( positionGeometry.x.lessThan( 0.0 ).select( worldUp.mul( hw ), worldUp.mul( hw ).negate() ), 0 ) ); - this._deactivateAction( action ); - this._removeInactiveAction( action ); + // don't extend the line if we're rendering dashes because we + // won't be rendering the endcaps + if ( ! useDash ) { - } + // cap extension + worldPos.addAssign( vec4( positionGeometry.y.lessThan( 0.5 ).select( worldDir.mul( hw ).negate(), worldDir.mul( hw ) ), 0 ) ); - } + // add width to the box + worldPos.addAssign( vec4( worldFwd.mul( hw ), 0 ) ); -} + // endcaps + If( positionGeometry.y.greaterThan( 1.0 ).or( positionGeometry.y.lessThan( 0.0 ) ), () => { -let Uniform$1 = class Uniform { + worldPos.subAssign( vec4( worldFwd.mul( 2.0 ).mul( hw ), 0 ) ); - constructor( value ) { + } ); - this.value = value; + } - } + // project the worldpos + clip.assign( cameraProjectionMatrix.mul( worldPos ) ); - clone() { + // shift the depth of the projected points so the line + // segments overlap neatly + const clipPose = vec3().toVar(); - return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); + clipPose.assign( positionGeometry.y.lessThan( 0.5 ).select( ndcStart, ndcEnd ) ); + clip.z.assign( clipPose.z.mul( clip.w ) ); - } + } else { -}; + const offset = vec2( dir.y, dir.x.negate() ).toVar( 'offset' ); -let _id$8 = 0; + // undo aspect ratio adjustment + dir.x.assign( dir.x.div( aspect ) ); + offset.x.assign( offset.x.div( aspect ) ); -let UniformsGroup$1 = class UniformsGroup extends EventDispatcher { + // sign flip + offset.assign( positionGeometry.x.lessThan( 0.0 ).select( offset.negate(), offset ) ); - constructor() { + // endcaps + If( positionGeometry.y.lessThan( 0.0 ), () => { - super(); + offset.assign( offset.sub( dir ) ); - this.isUniformsGroup = true; + } ).ElseIf( positionGeometry.y.greaterThan( 1.0 ), () => { - Object.defineProperty( this, 'id', { value: _id$8 ++ } ); + offset.assign( offset.add( dir ) ); - this.name = ''; + } ); - this.usage = StaticDrawUsage; - this.uniforms = []; + // adjust for linewidth + offset.assign( offset.mul( materialLineWidth ) ); - } + // adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ... + offset.assign( offset.div( viewport.w ) ); - add( uniform ) { + // select end + clip.assign( positionGeometry.y.lessThan( 0.5 ).select( clipStart, clipEnd ) ); - this.uniforms.push( uniform ); + // back to clip space + offset.assign( offset.mul( clip.w ) ); - return this; + clip.assign( clip.add( vec4( offset, 0, 0 ) ) ); - } + } - remove( uniform ) { + return clip; - const index = this.uniforms.indexOf( uniform ); + } )(); - if ( index !== - 1 ) this.uniforms.splice( index, 1 ); + const closestLineToLine = Fn( ( { p1, p2, p3, p4 } ) => { - return this; + const p13 = p1.sub( p3 ); + const p43 = p4.sub( p3 ); - } + const p21 = p2.sub( p1 ); - setName( name ) { + const d1343 = p13.dot( p43 ); + const d4321 = p43.dot( p21 ); + const d1321 = p13.dot( p21 ); + const d4343 = p43.dot( p43 ); + const d2121 = p21.dot( p21 ); - this.name = name; + const denom = d2121.mul( d4343 ).sub( d4321.mul( d4321 ) ); + const numer = d1343.mul( d4321 ).sub( d1321.mul( d4343 ) ); - return this; + const mua = numer.div( denom ).clamp(); + const mub = d1343.add( d4321.mul( mua ) ).div( d4343 ).clamp(); - } + return vec2( mua, mub ); - setUsage( value ) { + } ); - this.usage = value; + this.fragmentNode = Fn( () => { - return this; + const vUv = uv(); - } + if ( useDash ) { - dispose() { + const offsetNode = this.offsetNode ? float( this.offsetNodeNode ) : materialLineDashOffset; + const dashScaleNode = this.dashScaleNode ? float( this.dashScaleNode ) : materialLineScale; + const dashSizeNode = this.dashSizeNode ? float( this.dashSizeNode ) : materialLineDashSize; + const gapSizeNode = this.dashSizeNode ? float( this.dashGapNode ) : materialLineGapSize; - this.dispatchEvent( { type: 'dispose' } ); + dashSize.assign( dashSizeNode ); + gapSize.assign( gapSizeNode ); - return this; + const instanceDistanceStart = attribute( 'instanceDistanceStart' ); + const instanceDistanceEnd = attribute( 'instanceDistanceEnd' ); - } + const lineDistance = positionGeometry.y.lessThan( 0.5 ).select( dashScaleNode.mul( instanceDistanceStart ), materialLineScale.mul( instanceDistanceEnd ) ); - copy( source ) { + const vLineDistance = varying( lineDistance.add( materialLineDashOffset ) ); + const vLineDistanceOffset = offsetNode ? vLineDistance.add( offsetNode ) : vLineDistance; - this.name = source.name; - this.usage = source.usage; + vUv.y.lessThan( - 1.0 ).or( vUv.y.greaterThan( 1.0 ) ).discard(); // discard endcaps + vLineDistanceOffset.mod( dashSize.add( gapSize ) ).greaterThan( dashSize ).discard(); // todo - FIX - const uniformsSource = source.uniforms; + } - this.uniforms.length = 0; + const alpha = float( 1 ).toVar( 'alpha' ); - for ( let i = 0, l = uniformsSource.length; i < l; i ++ ) { + if ( useWorldUnits ) { - const uniforms = Array.isArray( uniformsSource[ i ] ) ? uniformsSource[ i ] : [ uniformsSource[ i ] ]; + const worldStart = varyingProperty( 'vec3', 'worldStart' ); + const worldEnd = varyingProperty( 'vec3', 'worldEnd' ); - for ( let j = 0; j < uniforms.length; j ++ ) { + // Find the closest points on the view ray and the line segment + const rayEnd = varyingProperty( 'vec4', 'worldPos' ).xyz.normalize().mul( 1e5 ); + const lineDir = worldEnd.sub( worldStart ); + const params = closestLineToLine( { p1: worldStart, p2: worldEnd, p3: vec3( 0.0, 0.0, 0.0 ), p4: rayEnd } ); - this.uniforms.push( uniforms[ j ].clone() ); + const p1 = worldStart.add( lineDir.mul( params.x ) ); + const p2 = rayEnd.mul( params.y ); + const delta = p1.sub( p2 ); + const len = delta.length(); + const norm = len.div( materialLineWidth ); - } + if ( ! useDash ) { - } + if ( useAlphaToCoverage && renderer.samples > 1 ) { - return this; + const dnorm = norm.fwidth(); + alpha.assign( smoothstep( dnorm.negate().add( 0.5 ), dnorm.add( 0.5 ), norm ).oneMinus() ); - } + } else { - clone() { + norm.greaterThan( 0.5 ).discard(); - return new this.constructor().copy( this ); + } - } + } -}; + } else { -class GLBufferAttribute { + // round endcaps - constructor( buffer, type, itemSize, elementSize, count ) { + if ( useAlphaToCoverage && renderer.samples > 1 ) { - this.isGLBufferAttribute = true; + const a = vUv.x; + const b = vUv.y.greaterThan( 0.0 ).select( vUv.y.sub( 1.0 ), vUv.y.add( 1.0 ) ); - this.name = ''; + const len2 = a.mul( a ).add( b.mul( b ) ); - this.buffer = buffer; - this.type = type; - this.itemSize = itemSize; - this.elementSize = elementSize; - this.count = count; + const dlen = float( len2.fwidth() ).toVar( 'dlen' ); - this.version = 0; + If( vUv.y.abs().greaterThan( 1.0 ), () => { - } + alpha.assign( smoothstep( dlen.oneMinus(), dlen.add( 1 ), len2 ).oneMinus() ); - set needsUpdate( value ) { + } ); - if ( value === true ) this.version ++; + } else { - } + If( vUv.y.abs().greaterThan( 1.0 ), () => { - setBuffer( buffer ) { + const a = vUv.x; + const b = vUv.y.greaterThan( 0.0 ).select( vUv.y.sub( 1.0 ), vUv.y.add( 1.0 ) ); + const len2 = a.mul( a ).add( b.mul( b ) ); - this.buffer = buffer; + len2.greaterThan( 1.0 ).discard(); - return this; + } ); - } + } - setType( type, elementSize ) { + } - this.type = type; - this.elementSize = elementSize; + let lineColorNode; - return this; + if ( this.lineColorNode ) { - } + lineColorNode = this.lineColorNode; - setItemSize( itemSize ) { + } else { - this.itemSize = itemSize; + if ( useColor ) { - return this; + const instanceColorStart = attribute( 'instanceColorStart' ); + const instanceColorEnd = attribute( 'instanceColorEnd' ); - } + const instanceColor = positionGeometry.y.lessThan( 0.5 ).select( instanceColorStart, instanceColorEnd ); - setCount( count ) { + lineColorNode = instanceColor.mul( materialColor ); - this.count = count; + } else { - return this; + lineColorNode = materialColor; - } + } -} + } -const _matrix = /*@__PURE__*/ new Matrix4(); + return vec4( lineColorNode, alpha ); -class Raycaster { + } )(); - constructor( origin, direction, near = 0, far = Infinity ) { + } - this.ray = new Ray( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) - this.near = near; - this.far = far; - this.camera = null; - this.layers = new Layers(); + get worldUnits() { - this.params = { - Mesh: {}, - Line: { threshold: 1 }, - LOD: {}, - Points: { threshold: 1 }, - Sprite: {} - }; + return this.useWorldUnits; } - set( origin, direction ) { + set worldUnits( value ) { - // direction is assumed to be normalized (for accurate distance calculations) + if ( this.useWorldUnits !== value ) { - this.ray.set( origin, direction ); + this.useWorldUnits = value; + this.needsUpdate = true; + + } } - setFromCamera( coords, camera ) { - if ( camera.isPerspectiveCamera ) { + get dashed() { - this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); - this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); - this.camera = camera; + return this.useDash; - } else if ( camera.isOrthographicCamera ) { + } - this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera - this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); - this.camera = camera; + set dashed( value ) { - } else { + if ( this.useDash !== value ) { - console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type ); + this.useDash = value; + this.needsUpdate = true; } } - setFromXRController( controller ) { - - _matrix.identity().extractRotation( controller.matrixWorld ); - this.ray.origin.setFromMatrixPosition( controller.matrixWorld ); - this.ray.direction.set( 0, 0, - 1 ).applyMatrix4( _matrix ); + get alphaToCoverage() { - return this; + return this.useAlphaToCoverage; } - intersectObject( object, recursive = true, intersects = [] ) { + set alphaToCoverage( value ) { - intersect( object, this, intersects, recursive ); + if ( this.useAlphaToCoverage !== value ) { - intersects.sort( ascSort ); + this.useAlphaToCoverage = value; + this.needsUpdate = true; - return intersects; + } } - intersectObjects( objects, recursive = true, intersects = [] ) { +} - for ( let i = 0, l = objects.length; i < l; i ++ ) { +const directionToColor = ( node ) => nodeObject( node ).mul( 0.5 ).add( 0.5 ); +const colorToDirection = ( node ) => nodeObject( node ).mul( 2.0 ).sub( 1 ); - intersect( objects[ i ], this, intersects, recursive ); +const _defaultValues$a = /*@__PURE__*/ new MeshNormalMaterial(); - } +class MeshNormalNodeMaterial extends NodeMaterial { - intersects.sort( ascSort ); + static get type() { - return intersects; + return 'MeshNormalNodeMaterial'; } -} - -function ascSort( a, b ) { - - return a.distance - b.distance; - -} + constructor( parameters ) { -function intersect( object, raycaster, intersects, recursive ) { + super(); - let propagate = true; + this.lights = false; - if ( object.layers.test( raycaster.layers ) ) { + this.isMeshNormalNodeMaterial = true; - const result = object.raycast( raycaster, intersects ); + this.setDefaultValues( _defaultValues$a ); - if ( result === false ) propagate = false; + this.setValues( parameters ); } - if ( propagate === true && recursive === true ) { - - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { + setupDiffuseColor() { - intersect( children[ i ], raycaster, intersects, true ); + const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity; - } + diffuseColor.assign( vec4( directionToColor( transformedNormalView ), opacityNode ) ); } } -/** - * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system - * - * phi (the polar angle) is measured from the positive y-axis. The positive y-axis is up. - * theta (the azimuthal angle) is measured from the positive z-axis. - */ -class Spherical { - - constructor( radius = 1, phi = 0, theta = 0 ) { +class EquirectUVNode extends TempNode { - this.radius = radius; - this.phi = phi; // polar angle - this.theta = theta; // azimuthal angle + static get type() { - return this; + return 'EquirectUVNode'; } - set( radius, phi, theta ) { + constructor( dirNode = positionWorldDirection ) { - this.radius = radius; - this.phi = phi; - this.theta = theta; + super( 'vec2' ); - return this; + this.dirNode = dirNode; } - copy( other ) { + setup() { - this.radius = other.radius; - this.phi = other.phi; - this.theta = other.theta; + const dir = this.dirNode; - return this; + const u = dir.z.atan2( dir.x ).mul( 1 / ( Math.PI * 2 ) ).add( 0.5 ); + const v = dir.y.clamp( - 1.0, 1.0 ).asin().mul( 1 / Math.PI ).add( 0.5 ); + + return vec2( u, v ); } - // restrict phi to be between EPS and PI-EPS - makeSafe() { +} - const EPS = 0.000001; - this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); +const equirectUV = /*@__PURE__*/ nodeProxy( EquirectUVNode ); - return this; +// @TODO: Consider rename WebGLCubeRenderTarget to just CubeRenderTarget - } +class CubeRenderTarget extends WebGLCubeRenderTarget { - setFromVector3( v ) { + constructor( size = 1, options = {} ) { - return this.setFromCartesianCoords( v.x, v.y, v.z ); + super( size, options ); + + this.isCubeRenderTarget = true; } - setFromCartesianCoords( x, y, z ) { + fromEquirectangularTexture( renderer, texture$1 ) { - this.radius = Math.sqrt( x * x + y * y + z * z ); + const currentMinFilter = texture$1.minFilter; + const currentGenerateMipmaps = texture$1.generateMipmaps; - if ( this.radius === 0 ) { + texture$1.generateMipmaps = true; - this.theta = 0; - this.phi = 0; + this.texture.type = texture$1.type; + this.texture.colorSpace = texture$1.colorSpace; - } else { + this.texture.generateMipmaps = texture$1.generateMipmaps; + this.texture.minFilter = texture$1.minFilter; + this.texture.magFilter = texture$1.magFilter; - this.theta = Math.atan2( x, z ); - this.phi = Math.acos( clamp$1( y / this.radius, - 1, 1 ) ); + const geometry = new BoxGeometry( 5, 5, 5 ); - } + const uvNode = equirectUV( positionWorldDirection ); - return this; + const material = new NodeMaterial(); + material.colorNode = texture( texture$1, uvNode, 0 ); + material.side = BackSide; + material.blending = NoBlending; - } + const mesh = new Mesh( geometry, material ); - clone() { + const scene = new Scene(); + scene.add( mesh ); - return new this.constructor().copy( this ); + // Avoid blurred poles + if ( texture$1.minFilter === LinearMipmapLinearFilter ) texture$1.minFilter = LinearFilter; - } + const camera = new CubeCamera( 1, 10, this ); -} + const currentMRT = renderer.getMRT(); + renderer.setMRT( null ); -/** - * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system - */ + camera.update( renderer, scene ); -class Cylindrical { + renderer.setMRT( currentMRT ); - constructor( radius = 1, theta = 0, y = 0 ) { + texture$1.minFilter = currentMinFilter; + texture$1.currentGenerateMipmaps = currentGenerateMipmaps; - this.radius = radius; // distance from the origin to a point in the x-z plane - this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis - this.y = y; // height above the x-z plane + mesh.geometry.dispose(); + mesh.material.dispose(); return this; } - set( radius, theta, y ) { - - this.radius = radius; - this.theta = theta; - this.y = y; - - return this; +} - } +const _cache$1 = new WeakMap(); - copy( other ) { +class CubeMapNode extends TempNode { - this.radius = other.radius; - this.theta = other.theta; - this.y = other.y; + static get type() { - return this; + return 'CubeMapNode'; } - setFromVector3( v ) { + constructor( envNode ) { - return this.setFromCartesianCoords( v.x, v.y, v.z ); + super( 'vec3' ); - } + this.envNode = envNode; - setFromCartesianCoords( x, y, z ) { + this._cubeTexture = null; + this._cubeTextureNode = cubeTexture(); - this.radius = Math.sqrt( x * x + z * z ); - this.theta = Math.atan2( x, z ); - this.y = y; + const defaultTexture = new CubeTexture(); + defaultTexture.isRenderTargetTexture = true; - return this; + this._defaultTexture = defaultTexture; + + this.updateBeforeType = NodeUpdateType.RENDER; } - clone() { + updateBefore( frame ) { - return new this.constructor().copy( this ); + const { renderer, material } = frame; - } + const envNode = this.envNode; -} + if ( envNode.isTextureNode || envNode.isMaterialReferenceNode ) { -class Matrix2 { + const texture = ( envNode.isTextureNode ) ? envNode.value : material[ envNode.property ]; - constructor( n11, n12, n21, n22 ) { + if ( texture && texture.isTexture ) { - Matrix2.prototype.isMatrix2 = true; + const mapping = texture.mapping; - this.elements = [ - 1, 0, - 0, 1, - ]; + if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) { - if ( n11 !== undefined ) { + // check for converted cubemap map - this.set( n11, n12, n21, n22 ); + if ( _cache$1.has( texture ) ) { - } + const cubeMap = _cache$1.get( texture ); - } + mapTextureMapping( cubeMap, texture.mapping ); + this._cubeTexture = cubeMap; - identity() { + } else { - this.set( - 1, 0, - 0, 1, - ); + // create cube map from equirectangular map - return this; + const image = texture.image; - } + if ( isEquirectangularMapReady$1( image ) ) { - fromArray( array, offset = 0 ) { + const renderTarget = new CubeRenderTarget( image.height ); + renderTarget.fromEquirectangularTexture( renderer, texture ); - for ( let i = 0; i < 4; i ++ ) { + mapTextureMapping( renderTarget.texture, texture.mapping ); + this._cubeTexture = renderTarget.texture; - this.elements[ i ] = array[ i + offset ]; + _cache$1.set( texture, renderTarget.texture ); - } + texture.addEventListener( 'dispose', onTextureDispose ); - return this; + } else { - } + // default cube texture as fallback when equirectangular texture is not yet loaded - set( n11, n12, n21, n22 ) { + this._cubeTexture = this._defaultTexture; - const te = this.elements; + } - te[ 0 ] = n11; te[ 2 ] = n12; - te[ 1 ] = n21; te[ 3 ] = n22; + } - return this; + // - } + this._cubeTextureNode.value = this._cubeTexture; -} + } else { -const _vector$4 = /*@__PURE__*/ new Vector2(); + // envNode already refers to a cube map -class Box2 { + this._cubeTextureNode = this.envNode; - constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) { + } - this.isBox2 = true; + } - this.min = min; - this.max = max; + } } - set( min, max ) { + setup( builder ) { - this.min.copy( min ); - this.max.copy( max ); + this.updateBefore( builder ); - return this; + return this._cubeTextureNode; } - setFromPoints( points ) { - - this.makeEmpty(); +} - for ( let i = 0, il = points.length; i < il; i ++ ) { +function isEquirectangularMapReady$1( image ) { - this.expandByPoint( points[ i ] ); + if ( image === null || image === undefined ) return false; - } + return image.height > 0; - return this; +} - } +function onTextureDispose( event ) { - setFromCenterAndSize( center, size ) { + const texture = event.target; - const halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 ); - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); + texture.removeEventListener( 'dispose', onTextureDispose ); - return this; + const renderTarget = _cache$1.get( texture ); - } + if ( renderTarget !== undefined ) { - clone() { + _cache$1.delete( texture ); - return new this.constructor().copy( this ); + renderTarget.dispose(); } - copy( box ) { - - this.min.copy( box.min ); - this.max.copy( box.max ); +} - return this; +function mapTextureMapping( texture, mapping ) { - } + if ( mapping === EquirectangularReflectionMapping ) { - makeEmpty() { + texture.mapping = CubeReflectionMapping; - this.min.x = this.min.y = + Infinity; - this.max.x = this.max.y = - Infinity; + } else if ( mapping === EquirectangularRefractionMapping ) { - return this; + texture.mapping = CubeRefractionMapping; } - isEmpty() { - - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes +} - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); +const cubeMapNode = /*@__PURE__*/ nodeProxy( CubeMapNode ); - } +class BasicEnvironmentNode extends LightingNode { - getCenter( target ) { + static get type() { - return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + return 'BasicEnvironmentNode'; } - getSize( target ) { + constructor( envNode = null ) { - return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); + super(); + + this.envNode = envNode; } - expandByPoint( point ) { + setup( builder ) { - this.min.min( point ); - this.max.max( point ); + // environment property is used in the finish() method of BasicLightingModel - return this; + builder.context.environment = cubeMapNode( this.envNode ); } - expandByVector( vector ) { +} - this.min.sub( vector ); - this.max.add( vector ); +class BasicLightMapNode extends LightingNode { - return this; + static get type() { + + return 'BasicLightMapNode'; } - expandByScalar( scalar ) { + constructor( lightMapNode = null ) { - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); + super(); - return this; + this.lightMapNode = lightMapNode; } - containsPoint( point ) { + setup( builder ) { - return point.x >= this.min.x && point.x <= this.max.x && - point.y >= this.min.y && point.y <= this.max.y; + // irradianceLightMap property is used in the indirectDiffuse() method of BasicLightingModel + + const RECIPROCAL_PI = float( 1 / Math.PI ); + + builder.context.irradianceLightMap = this.lightMapNode.mul( RECIPROCAL_PI ); } - containsBox( box ) { +} - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y; +class LightingModel { - } + start( /*input, stack, builder*/ ) { } - getParameter( point, target ) { + finish( /*input, stack, builder*/ ) { } - // This can potentially have a divide by zero if the box - // has a size dimension of 0. + direct( /*input, stack, builder*/ ) { } - return target.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ) - ); + directRectArea( /*input, stack, builder*/ ) {} - } + indirect( /*input, stack, builder*/ ) { } - intersectsBox( box ) { + ambientOcclusion( /*input, stack, builder*/ ) { } - // using 4 splitting planes to rule out intersections +} - return box.max.x >= this.min.x && box.min.x <= this.max.x && - box.max.y >= this.min.y && box.min.y <= this.max.y; +class BasicLightingModel extends LightingModel { + + constructor() { + + super(); } - clampPoint( point, target ) { + indirect( context, stack, builder ) { - return target.copy( point ).clamp( this.min, this.max ); + const ambientOcclusion = context.ambientOcclusion; + const reflectedLight = context.reflectedLight; + const irradianceLightMap = builder.context.irradianceLightMap; - } + reflectedLight.indirectDiffuse.assign( vec4( 0.0 ) ); - distanceToPoint( point ) { + // accumulation (baked indirect lighting only) - return this.clampPoint( point, _vector$4 ).distanceTo( point ); + if ( irradianceLightMap ) { - } + reflectedLight.indirectDiffuse.addAssign( irradianceLightMap ); - intersect( box ) { + } else { - this.min.max( box.min ); - this.max.min( box.max ); + reflectedLight.indirectDiffuse.addAssign( vec4( 1.0, 1.0, 1.0, 0.0 ) ); - if ( this.isEmpty() ) this.makeEmpty(); + } - return this; + // modulation + + reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion ); + + reflectedLight.indirectDiffuse.mulAssign( diffuseColor.rgb ); } - union( box ) { + finish( context, stack, builder ) { - this.min.min( box.min ); - this.max.max( box.max ); + const material = builder.material; + const outgoingLight = context.outgoingLight; + const envNode = builder.context.environment; - return this; + if ( envNode ) { - } + switch ( material.combine ) { - translate( offset ) { + case MultiplyOperation: + outgoingLight.rgb.assign( mix( outgoingLight.rgb, outgoingLight.rgb.mul( envNode.rgb ), materialSpecularStrength.mul( materialReflectivity ) ) ); + break; - this.min.add( offset ); - this.max.add( offset ); + case MixOperation: + outgoingLight.rgb.assign( mix( outgoingLight.rgb, envNode.rgb, materialSpecularStrength.mul( materialReflectivity ) ) ); + break; - return this; + case AddOperation: + outgoingLight.rgb.addAssign( envNode.rgb.mul( materialSpecularStrength.mul( materialReflectivity ) ) ); + break; - } + default: + console.warn( 'THREE.BasicLightingModel: Unsupported .combine value:', material.combine ); + break; - equals( box ) { + } - return box.min.equals( this.min ) && box.max.equals( this.max ); + } } } -const _startP = /*@__PURE__*/ new Vector3(); -const _startEnd = /*@__PURE__*/ new Vector3(); +const _defaultValues$9 = /*@__PURE__*/ new MeshBasicMaterial(); -class Line3 { +class MeshBasicNodeMaterial extends NodeMaterial { - constructor( start = new Vector3(), end = new Vector3() ) { + static get type() { - this.start = start; - this.end = end; + return 'MeshBasicNodeMaterial'; } - set( start, end ) { - - this.start.copy( start ); - this.end.copy( end ); + constructor( parameters ) { - return this; + super(); - } + this.isMeshBasicNodeMaterial = true; - copy( line ) { + this.lights = true; - this.start.copy( line.start ); - this.end.copy( line.end ); + this.setDefaultValues( _defaultValues$9 ); - return this; + this.setValues( parameters ); } - getCenter( target ) { + setupNormal() { - return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); + return normalView; // see #28839 } - delta( target ) { + setupEnvironment( builder ) { - return target.subVectors( this.end, this.start ); + const envNode = super.setupEnvironment( builder ); + + return envNode ? new BasicEnvironmentNode( envNode ) : null; } - distanceSq() { + setupLightMap( builder ) { - return this.start.distanceToSquared( this.end ); + let node = null; - } + if ( builder.material.lightMap ) { - distance() { + node = new BasicLightMapNode( materialLightMap ); - return this.start.distanceTo( this.end ); + } + + return node; } - at( t, target ) { + setupOutgoingLight() { - return this.delta( target ).multiplyScalar( t ).add( this.start ); + return diffuseColor.rgb; } - closestPointToPointParameter( point, clampToLine ) { + setupLightingModel() { - _startP.subVectors( point, this.start ); - _startEnd.subVectors( this.end, this.start ); + return new BasicLightingModel(); - const startEnd2 = _startEnd.dot( _startEnd ); - const startEnd_startP = _startEnd.dot( _startP ); + } - let t = startEnd_startP / startEnd2; +} - if ( clampToLine ) { +const F_Schlick = /*@__PURE__*/ Fn( ( { f0, f90, dotVH } ) => { - t = clamp$1( t, 0, 1 ); + // Original approximation by Christophe Schlick '94 + // float fresnel = pow( 1.0 - dotVH, 5.0 ); - } + // Optimized variant (presented by Epic at SIGGRAPH '13) + // https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf + const fresnel = dotVH.mul( - 5.55473 ).sub( 6.98316 ).mul( dotVH ).exp2(); - return t; + return f0.mul( fresnel.oneMinus() ).add( f90.mul( fresnel ) ); - } +} ); // validated - closestPointToPoint( point, clampToLine, target ) { +const BRDF_Lambert = /*@__PURE__*/ Fn( ( inputs ) => { - const t = this.closestPointToPointParameter( point, clampToLine ); + return inputs.diffuseColor.mul( 1 / Math.PI ); // punctual light - return this.delta( target ).multiplyScalar( t ).add( this.start ); +} ); // validated - } +const G_BlinnPhong_Implicit = () => float( 0.25 ); - applyMatrix4( matrix ) { +const D_BlinnPhong = /*@__PURE__*/ Fn( ( { dotNH } ) => { - this.start.applyMatrix4( matrix ); - this.end.applyMatrix4( matrix ); - - return this; - - } - - equals( line ) { + return shininess.mul( float( 0.5 ) ).add( 1.0 ).mul( float( 1 / Math.PI ) ).mul( dotNH.pow( shininess ) ); - return line.start.equals( this.start ) && line.end.equals( this.end ); +} ); - } +const BRDF_BlinnPhong = /*@__PURE__*/ Fn( ( { lightDirection } ) => { - clone() { + const halfDir = lightDirection.add( positionViewDirection ).normalize(); - return new this.constructor().copy( this ); + const dotNH = transformedNormalView.dot( halfDir ).clamp(); + const dotVH = positionViewDirection.dot( halfDir ).clamp(); - } + const F = F_Schlick( { f0: specularColor, f90: 1.0, dotVH } ); + const G = G_BlinnPhong_Implicit(); + const D = D_BlinnPhong( { dotNH } ); -} + return F.mul( G ).mul( D ); -const _vector$3 = /*@__PURE__*/ new Vector3(); +} ); -class SpotLightHelper extends Object3D { +class PhongLightingModel extends BasicLightingModel { - constructor( light, color ) { + constructor( specular = true ) { super(); - this.light = light; - - this.matrixAutoUpdate = false; - - this.color = color; + this.specular = specular; - this.type = 'SpotLightHelper'; + } - const geometry = new BufferGeometry(); + direct( { lightDirection, lightColor, reflectedLight } ) { - const positions = [ - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 1, 0, 1, - 0, 0, 0, - 1, 0, 1, - 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, - 1, 1 - ]; + const dotNL = transformedNormalView.dot( lightDirection ).clamp(); + const irradiance = dotNL.mul( lightColor ); - for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { + reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) ); - const p1 = ( i / l ) * Math.PI * 2; - const p2 = ( j / l ) * Math.PI * 2; + if ( this.specular === true ) { - positions.push( - Math.cos( p1 ), Math.sin( p1 ), 1, - Math.cos( p2 ), Math.sin( p2 ), 1 - ); + reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_BlinnPhong( { lightDirection } ) ).mul( materialSpecularStrength ) ); } - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + } - const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); + indirect( { ambientOcclusion, irradiance, reflectedLight } ) { - this.cone = new LineSegments( geometry, material ); - this.add( this.cone ); + reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) ); - this.update(); + reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion ); } - dispose() { - - this.cone.geometry.dispose(); - this.cone.material.dispose(); - - } +} - update() { +const _defaultValues$8 = /*@__PURE__*/ new MeshLambertMaterial(); - this.light.updateWorldMatrix( true, false ); - this.light.target.updateWorldMatrix( true, false ); +class MeshLambertNodeMaterial extends NodeMaterial { - // update the local matrix based on the parent and light target transforms - if ( this.parent ) { + static get type() { - this.parent.updateWorldMatrix( true ); + return 'MeshLambertNodeMaterial'; - this.matrix - .copy( this.parent.matrixWorld ) - .invert() - .multiply( this.light.matrixWorld ); + } - } else { + constructor( parameters ) { - this.matrix.copy( this.light.matrixWorld ); + super(); - } + this.isMeshLambertNodeMaterial = true; - this.matrixWorld.copy( this.light.matrixWorld ); + this.lights = true; - const coneLength = this.light.distance ? this.light.distance : 1000; - const coneWidth = coneLength * Math.tan( this.light.angle ); + this.setDefaultValues( _defaultValues$8 ); - this.cone.scale.set( coneWidth, coneWidth, coneLength ); + this.setValues( parameters ); - _vector$3.setFromMatrixPosition( this.light.target.matrixWorld ); + } - this.cone.lookAt( _vector$3 ); + setupEnvironment( builder ) { - if ( this.color !== undefined ) { + const envNode = super.setupEnvironment( builder ); - this.cone.material.color.set( this.color ); + return envNode ? new BasicEnvironmentNode( envNode ) : null; - } else { + } - this.cone.material.color.copy( this.light.color ); + setupLightingModel( /*builder*/ ) { - } + return new PhongLightingModel( false ); // ( specular ) -> force lambert } } -const _vector$2 = /*@__PURE__*/ new Vector3(); -const _boneMatrix = /*@__PURE__*/ new Matrix4(); -const _matrixWorldInv = /*@__PURE__*/ new Matrix4(); - - -class SkeletonHelper extends LineSegments { - - constructor( object ) { - - const bones = getBoneList( object ); - - const geometry = new BufferGeometry(); - - const vertices = []; - const colors = []; - - const color1 = new Color( 0, 0, 1 ); - const color2 = new Color( 0, 1, 0 ); - - for ( let i = 0; i < bones.length; i ++ ) { - - const bone = bones[ i ]; +const _defaultValues$7 = /*@__PURE__*/ new MeshPhongMaterial(); - if ( bone.parent && bone.parent.isBone ) { +class MeshPhongNodeMaterial extends NodeMaterial { - vertices.push( 0, 0, 0 ); - vertices.push( 0, 0, 0 ); - colors.push( color1.r, color1.g, color1.b ); - colors.push( color2.r, color2.g, color2.b ); + static get type() { - } + return 'MeshPhongNodeMaterial'; - } + } - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + constructor( parameters ) { - const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } ); + super(); - super( geometry, material ); + this.isMeshPhongNodeMaterial = true; - this.isSkeletonHelper = true; + this.lights = true; - this.type = 'SkeletonHelper'; + this.shininessNode = null; + this.specularNode = null; - this.root = object; - this.bones = bones; + this.setDefaultValues( _defaultValues$7 ); - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; + this.setValues( parameters ); } - updateMatrixWorld( force ) { + setupEnvironment( builder ) { - const bones = this.bones; + const envNode = super.setupEnvironment( builder ); - const geometry = this.geometry; - const position = geometry.getAttribute( 'position' ); + return envNode ? new BasicEnvironmentNode( envNode ) : null; - _matrixWorldInv.copy( this.root.matrixWorld ).invert(); + } - for ( let i = 0, j = 0; i < bones.length; i ++ ) { + setupLightingModel( /*builder*/ ) { - const bone = bones[ i ]; + return new PhongLightingModel(); - if ( bone.parent && bone.parent.isBone ) { + } - _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld ); - _vector$2.setFromMatrixPosition( _boneMatrix ); - position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z ); + setupVariants() { - _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld ); - _vector$2.setFromMatrixPosition( _boneMatrix ); - position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z ); + // SHININESS - j += 2; + const shininessNode = ( this.shininessNode ? float( this.shininessNode ) : materialShininess ).max( 1e-4 ); // to prevent pow( 0.0, 0.0 ) - } + shininess.assign( shininessNode ); - } + // SPECULAR COLOR - geometry.getAttribute( 'position' ).needsUpdate = true; + const specularNode = this.specularNode || materialSpecular; - super.updateMatrixWorld( force ); + specularColor.assign( specularNode ); } - dispose() { + copy( source ) { - this.geometry.dispose(); - this.material.dispose(); + this.shininessNode = source.shininessNode; + this.specularNode = source.specularNode; + + return super.copy( source ); } } +const getGeometryRoughness = /*@__PURE__*/ Fn( () => { -function getBoneList( object ) { - - const boneList = []; + const dxy = normalView.dFdx().abs().max( normalView.dFdy().abs() ); + const geometryRoughness = dxy.x.max( dxy.y ).max( dxy.z ); - if ( object.isBone === true ) { + return geometryRoughness; - boneList.push( object ); +} ); - } +const getRoughness = /*@__PURE__*/ Fn( ( inputs ) => { - for ( let i = 0; i < object.children.length; i ++ ) { + const { roughness } = inputs; - boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); + const geometryRoughness = getGeometryRoughness(); - } + let roughnessFactor = roughness.max( 0.0525 ); // 0.0525 corresponds to the base mip of a 256 cubemap. + roughnessFactor = roughnessFactor.add( geometryRoughness ); + roughnessFactor = roughnessFactor.min( 1.0 ); - return boneList; + return roughnessFactor; -} +} ); -class PointLightHelper extends Mesh { +// Moving Frostbite to Physically Based Rendering 3.0 - page 12, listing 2 +// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf +const V_GGX_SmithCorrelated = /*@__PURE__*/ Fn( ( { alpha, dotNL, dotNV } ) => { - constructor( light, sphereSize, color ) { + const a2 = alpha.pow2(); - const geometry = new SphereGeometry( sphereSize, 4, 2 ); - const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); + const gv = dotNL.mul( a2.add( a2.oneMinus().mul( dotNV.pow2() ) ).sqrt() ); + const gl = dotNV.mul( a2.add( a2.oneMinus().mul( dotNL.pow2() ) ).sqrt() ); - super( geometry, material ); + return div( 0.5, gv.add( gl ).max( EPSILON ) ); - this.light = light; +} ).setLayout( { + name: 'V_GGX_SmithCorrelated', + type: 'float', + inputs: [ + { name: 'alpha', type: 'float' }, + { name: 'dotNL', type: 'float' }, + { name: 'dotNV', type: 'float' } + ] +} ); // validated - this.color = color; +// https://google.github.io/filament/Filament.md.html#materialsystem/anisotropicmodel/anisotropicspecularbrdf - this.type = 'PointLightHelper'; +const V_GGX_SmithCorrelated_Anisotropic = /*@__PURE__*/ Fn( ( { alphaT, alphaB, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL } ) => { - this.matrix = this.light.matrixWorld; - this.matrixAutoUpdate = false; + const gv = dotNL.mul( vec3( alphaT.mul( dotTV ), alphaB.mul( dotBV ), dotNV ).length() ); + const gl = dotNV.mul( vec3( alphaT.mul( dotTL ), alphaB.mul( dotBL ), dotNL ).length() ); + const v = div( 0.5, gv.add( gl ) ); - this.update(); + return v.saturate(); +} ).setLayout( { + name: 'V_GGX_SmithCorrelated_Anisotropic', + type: 'float', + inputs: [ + { name: 'alphaT', type: 'float', qualifier: 'in' }, + { name: 'alphaB', type: 'float', qualifier: 'in' }, + { name: 'dotTV', type: 'float', qualifier: 'in' }, + { name: 'dotBV', type: 'float', qualifier: 'in' }, + { name: 'dotTL', type: 'float', qualifier: 'in' }, + { name: 'dotBL', type: 'float', qualifier: 'in' }, + { name: 'dotNV', type: 'float', qualifier: 'in' }, + { name: 'dotNL', type: 'float', qualifier: 'in' } + ] +} ); - /* - // TODO: delete this comment? - const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); - const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); +// Microfacet Models for Refraction through Rough Surfaces - equation (33) +// http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html +// alpha is "roughness squared" in Disney’s reparameterization +const D_GGX = /*@__PURE__*/ Fn( ( { alpha, dotNH } ) => { - this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); - this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); + const a2 = alpha.pow2(); - const d = light.distance; + const denom = dotNH.pow2().mul( a2.oneMinus() ).oneMinus(); // avoid alpha = 0 with dotNH = 1 - if ( d === 0.0 ) { + return a2.div( denom.pow2() ).mul( 1 / Math.PI ); - this.lightDistance.visible = false; +} ).setLayout( { + name: 'D_GGX', + type: 'float', + inputs: [ + { name: 'alpha', type: 'float' }, + { name: 'dotNH', type: 'float' } + ] +} ); // validated - } else { +const RECIPROCAL_PI = /*@__PURE__*/ float( 1 / Math.PI ); - this.lightDistance.scale.set( d, d, d ); +// https://google.github.io/filament/Filament.md.html#materialsystem/anisotropicmodel/anisotropicspecularbrdf - } +const D_GGX_Anisotropic = /*@__PURE__*/ Fn( ( { alphaT, alphaB, dotNH, dotTH, dotBH } ) => { - this.add( this.lightDistance ); - */ + const a2 = alphaT.mul( alphaB ); + const v = vec3( alphaB.mul( dotTH ), alphaT.mul( dotBH ), a2.mul( dotNH ) ); + const v2 = v.dot( v ); + const w2 = a2.div( v2 ); - } + return RECIPROCAL_PI.mul( a2.mul( w2.pow2() ) ); - dispose() { +} ).setLayout( { + name: 'D_GGX_Anisotropic', + type: 'float', + inputs: [ + { name: 'alphaT', type: 'float', qualifier: 'in' }, + { name: 'alphaB', type: 'float', qualifier: 'in' }, + { name: 'dotNH', type: 'float', qualifier: 'in' }, + { name: 'dotTH', type: 'float', qualifier: 'in' }, + { name: 'dotBH', type: 'float', qualifier: 'in' } + ] +} ); - this.geometry.dispose(); - this.material.dispose(); +// GGX Distribution, Schlick Fresnel, GGX_SmithCorrelated Visibility +const BRDF_GGX = /*@__PURE__*/ Fn( ( inputs ) => { - } + const { lightDirection, f0, f90, roughness, f, USE_IRIDESCENCE, USE_ANISOTROPY } = inputs; - update() { + const normalView = inputs.normalView || transformedNormalView; - this.light.updateWorldMatrix( true, false ); + const alpha = roughness.pow2(); // UE4's roughness - if ( this.color !== undefined ) { + const halfDir = lightDirection.add( positionViewDirection ).normalize(); - this.material.color.set( this.color ); + const dotNL = normalView.dot( lightDirection ).clamp(); + const dotNV = normalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV + const dotNH = normalView.dot( halfDir ).clamp(); + const dotVH = positionViewDirection.dot( halfDir ).clamp(); - } else { + let F = F_Schlick( { f0, f90, dotVH } ); + let V, D; - this.material.color.copy( this.light.color ); + if ( defined( USE_IRIDESCENCE ) ) { - } + F = iridescence.mix( F, f ); - /* - const d = this.light.distance; + } - if ( d === 0.0 ) { + if ( defined( USE_ANISOTROPY ) ) { - this.lightDistance.visible = false; + const dotTL = anisotropyT.dot( lightDirection ); + const dotTV = anisotropyT.dot( positionViewDirection ); + const dotTH = anisotropyT.dot( halfDir ); + const dotBL = anisotropyB.dot( lightDirection ); + const dotBV = anisotropyB.dot( positionViewDirection ); + const dotBH = anisotropyB.dot( halfDir ); - } else { + V = V_GGX_SmithCorrelated_Anisotropic( { alphaT, alphaB: alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL } ); + D = D_GGX_Anisotropic( { alphaT, alphaB: alpha, dotNH, dotTH, dotBH } ); - this.lightDistance.visible = true; - this.lightDistance.scale.set( d, d, d ); + } else { - } - */ + V = V_GGX_SmithCorrelated( { alpha, dotNL, dotNV } ); + D = D_GGX( { alpha, dotNH } ); } -} + return F.mul( V ).mul( D ); -const _vector$1 = /*@__PURE__*/ new Vector3(); -const _color1 = /*@__PURE__*/ new Color(); -const _color2 = /*@__PURE__*/ new Color(); +} ); // validated -class HemisphereLightHelper extends Object3D { +// Analytical approximation of the DFG LUT, one half of the +// split-sum approximation used in indirect specular lighting. +// via 'environmentBRDF' from "Physically Based Shading on Mobile" +// https://www.unrealengine.com/blog/physically-based-shading-on-mobile +const DFGApprox = /*@__PURE__*/ Fn( ( { roughness, dotNV } ) => { - constructor( light, size, color ) { + const c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 ); - super(); + const c1 = vec4( 1, 0.0425, 1.04, - 0.04 ); - this.light = light; + const r = roughness.mul( c0 ).add( c1 ); - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + const a004 = r.x.mul( r.x ).min( dotNV.mul( - 9.28 ).exp2() ).mul( r.x ).add( r.y ); - this.color = color; + const fab = vec2( - 1.04, 1.04 ).mul( a004 ).add( r.zw ); - this.type = 'HemisphereLightHelper'; + return fab; - const geometry = new OctahedronGeometry( size ); - geometry.rotateY( Math.PI * 0.5 ); +} ).setLayout( { + name: 'DFGApprox', + type: 'vec2', + inputs: [ + { name: 'roughness', type: 'float' }, + { name: 'dotNV', type: 'vec3' } + ] +} ); - this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); - if ( this.color === undefined ) this.material.vertexColors = true; +const EnvironmentBRDF = /*@__PURE__*/ Fn( ( inputs ) => { - const position = geometry.getAttribute( 'position' ); - const colors = new Float32Array( position.count * 3 ); + const { dotNV, specularColor, specularF90, roughness } = inputs; - geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) ); + const fab = DFGApprox( { dotNV, roughness } ); + return specularColor.mul( fab.x ).add( specularF90.mul( fab.y ) ); - this.add( new Mesh( geometry, this.material ) ); +} ); - this.update(); +const Schlick_to_F0 = /*@__PURE__*/ Fn( ( { f, f90, dotVH } ) => { - } + const x = dotVH.oneMinus().saturate(); + const x2 = x.mul( x ); + const x5 = x.mul( x2, x2 ).clamp( 0, .9999 ); - dispose() { + return f.sub( vec3( f90 ).mul( x5 ) ).div( x5.oneMinus() ); - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); +} ).setLayout( { + name: 'Schlick_to_F0', + type: 'vec3', + inputs: [ + { name: 'f', type: 'vec3' }, + { name: 'f90', type: 'float' }, + { name: 'dotVH', type: 'float' } + ] +} ); - } +// https://github.com/google/filament/blob/master/shaders/src/brdf.fs +const D_Charlie = /*@__PURE__*/ Fn( ( { roughness, dotNH } ) => { - update() { + const alpha = roughness.pow2(); - const mesh = this.children[ 0 ]; + // Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF" + const invAlpha = float( 1.0 ).div( alpha ); + const cos2h = dotNH.pow2(); + const sin2h = cos2h.oneMinus().max( 0.0078125 ); // 2^(-14/2), so sin2h^2 > 0 in fp16 - if ( this.color !== undefined ) { + return float( 2.0 ).add( invAlpha ).mul( sin2h.pow( invAlpha.mul( 0.5 ) ) ).div( 2.0 * Math.PI ); - this.material.color.set( this.color ); +} ).setLayout( { + name: 'D_Charlie', + type: 'float', + inputs: [ + { name: 'roughness', type: 'float' }, + { name: 'dotNH', type: 'float' } + ] +} ); - } else { +// https://github.com/google/filament/blob/master/shaders/src/brdf.fs +const V_Neubelt = /*@__PURE__*/ Fn( ( { dotNV, dotNL } ) => { - const colors = mesh.geometry.getAttribute( 'color' ); + // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886" + return float( 1.0 ).div( float( 4.0 ).mul( dotNL.add( dotNV ).sub( dotNL.mul( dotNV ) ) ) ); - _color1.copy( this.light.color ); - _color2.copy( this.light.groundColor ); +} ).setLayout( { + name: 'V_Neubelt', + type: 'float', + inputs: [ + { name: 'dotNV', type: 'float' }, + { name: 'dotNL', type: 'float' } + ] +} ); - for ( let i = 0, l = colors.count; i < l; i ++ ) { +const BRDF_Sheen = /*@__PURE__*/ Fn( ( { lightDirection } ) => { - const color = ( i < ( l / 2 ) ) ? _color1 : _color2; + const halfDir = lightDirection.add( positionViewDirection ).normalize(); - colors.setXYZ( i, color.r, color.g, color.b ); + const dotNL = transformedNormalView.dot( lightDirection ).clamp(); + const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); + const dotNH = transformedNormalView.dot( halfDir ).clamp(); - } + const D = D_Charlie( { roughness: sheenRoughness, dotNH } ); + const V = V_Neubelt( { dotNV, dotNL } ); - colors.needsUpdate = true; + return sheen.mul( D ).mul( V ); - } +} ); - this.light.updateWorldMatrix( true, false ); +// Rect Area Light - mesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() ); +// Real-Time Polygonal-Light Shading with Linearly Transformed Cosines +// by Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt +// code: https://github.com/selfshadow/ltc_code/ - } +const LTC_Uv = /*@__PURE__*/ Fn( ( { N, V, roughness } ) => { -} + const LUT_SIZE = 64.0; + const LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE; + const LUT_BIAS = 0.5 / LUT_SIZE; -class GridHelper extends LineSegments { + const dotNV = N.dot( V ).saturate(); - constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) { + // texture parameterized by sqrt( GGX alpha ) and sqrt( 1 - cos( theta ) ) + const uv = vec2( roughness, dotNV.oneMinus().sqrt() ); - color1 = new Color( color1 ); - color2 = new Color( color2 ); + uv.assign( uv.mul( LUT_SCALE ).add( LUT_BIAS ) ); - const center = divisions / 2; - const step = size / divisions; - const halfSize = size / 2; - - const vertices = [], colors = []; - - for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { + return uv; - vertices.push( - halfSize, 0, k, halfSize, 0, k ); - vertices.push( k, 0, - halfSize, k, 0, halfSize ); +} ).setLayout( { + name: 'LTC_Uv', + type: 'vec2', + inputs: [ + { name: 'N', type: 'vec3' }, + { name: 'V', type: 'vec3' }, + { name: 'roughness', type: 'float' } + ] +} ); - const color = i === center ? color1 : color2; +const LTC_ClippedSphereFormFactor = /*@__PURE__*/ Fn( ( { f } ) => { - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; + // Real-Time Area Lighting: a Journey from Research to Production (p.102) + // An approximation of the form factor of a horizon-clipped rectangle. - } + const l = f.length(); - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + return max$1( l.mul( l ).add( f.z ).div( l.add( 1.0 ) ), 0 ); - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); +} ).setLayout( { + name: 'LTC_ClippedSphereFormFactor', + type: 'float', + inputs: [ + { name: 'f', type: 'vec3' } + ] +} ); - super( geometry, material ); +const LTC_EdgeVectorFormFactor = /*@__PURE__*/ Fn( ( { v1, v2 } ) => { - this.type = 'GridHelper'; + const x = v1.dot( v2 ); + const y = x.abs().toVar(); - } + // rational polynomial approximation to theta / sin( theta ) / 2PI + const a = y.mul( 0.0145206 ).add( 0.4965155 ).mul( y ).add( 0.8543985 ).toVar(); + const b = y.add( 4.1616724 ).mul( y ).add( 3.4175940 ).toVar(); + const v = a.div( b ); - dispose() { + const theta_sintheta = x.greaterThan( 0.0 ).select( v, max$1( x.mul( x ).oneMinus(), 1e-7 ).inverseSqrt().mul( 0.5 ).sub( v ) ); - this.geometry.dispose(); - this.material.dispose(); + return v1.cross( v2 ).mul( theta_sintheta ); - } +} ).setLayout( { + name: 'LTC_EdgeVectorFormFactor', + type: 'vec3', + inputs: [ + { name: 'v1', type: 'vec3' }, + { name: 'v2', type: 'vec3' } + ] +} ); -} +const LTC_Evaluate = /*@__PURE__*/ Fn( ( { N, V, P, mInv, p0, p1, p2, p3 } ) => { -class PolarGridHelper extends LineSegments { + // bail if point is on back side of plane of light + // assumes ccw winding order of light vertices + const v1 = p1.sub( p0 ).toVar(); + const v2 = p3.sub( p0 ).toVar(); - constructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) { + const lightNormal = v1.cross( v2 ); + const result = vec3().toVar(); - color1 = new Color( color1 ); - color2 = new Color( color2 ); + If( lightNormal.dot( P.sub( p0 ) ).greaterThanEqual( 0.0 ), () => { - const vertices = []; - const colors = []; + // construct orthonormal basis around N + const T1 = V.sub( N.mul( V.dot( N ) ) ).normalize(); + const T2 = N.cross( T1 ).negate(); // negated from paper; possibly due to a different handedness of world coordinate system - // create the sectors + // compute transform + const mat = mInv.mul( mat3( T1, T2, N ).transpose() ).toVar(); - if ( sectors > 1 ) { + // transform rect + // & project rect onto sphere + const coords0 = mat.mul( p0.sub( P ) ).normalize().toVar(); + const coords1 = mat.mul( p1.sub( P ) ).normalize().toVar(); + const coords2 = mat.mul( p2.sub( P ) ).normalize().toVar(); + const coords3 = mat.mul( p3.sub( P ) ).normalize().toVar(); - for ( let i = 0; i < sectors; i ++ ) { + // calculate vector form factor + const vectorFormFactor = vec3( 0 ).toVar(); + vectorFormFactor.addAssign( LTC_EdgeVectorFormFactor( { v1: coords0, v2: coords1 } ) ); + vectorFormFactor.addAssign( LTC_EdgeVectorFormFactor( { v1: coords1, v2: coords2 } ) ); + vectorFormFactor.addAssign( LTC_EdgeVectorFormFactor( { v1: coords2, v2: coords3 } ) ); + vectorFormFactor.addAssign( LTC_EdgeVectorFormFactor( { v1: coords3, v2: coords0 } ) ); - const v = ( i / sectors ) * ( Math.PI * 2 ); + // adjust for horizon clipping + result.assign( vec3( LTC_ClippedSphereFormFactor( { f: vectorFormFactor } ) ) ); - const x = Math.sin( v ) * radius; - const z = Math.cos( v ) * radius; + } ); - vertices.push( 0, 0, 0 ); - vertices.push( x, 0, z ); + return result; - const color = ( i & 1 ) ? color1 : color2; +} ).setLayout( { + name: 'LTC_Evaluate', + type: 'vec3', + inputs: [ + { name: 'N', type: 'vec3' }, + { name: 'V', type: 'vec3' }, + { name: 'P', type: 'vec3' }, + { name: 'mInv', type: 'mat3' }, + { name: 'p0', type: 'vec3' }, + { name: 'p1', type: 'vec3' }, + { name: 'p2', type: 'vec3' }, + { name: 'p3', type: 'vec3' } + ] +} ); - colors.push( color.r, color.g, color.b ); - colors.push( color.r, color.g, color.b ); +// Mipped Bicubic Texture Filtering by N8 +// https://www.shadertoy.com/view/Dl2SDW - } +const bC = 1.0 / 6.0; - } +const w0 = ( a ) => mul( bC, mul( a, mul( a, a.negate().add( 3.0 ) ).sub( 3.0 ) ).add( 1.0 ) ); - // create the rings +const w1 = ( a ) => mul( bC, mul( a, mul( a, mul( 3.0, a ).sub( 6.0 ) ) ).add( 4.0 ) ); - for ( let i = 0; i < rings; i ++ ) { +const w2 = ( a ) => mul( bC, mul( a, mul( a, mul( - 3.0, a ).add( 3.0 ) ).add( 3.0 ) ).add( 1.0 ) ); - const color = ( i & 1 ) ? color1 : color2; +const w3 = ( a ) => mul( bC, pow( a, 3 ) ); - const r = radius - ( radius / rings * i ); +const g0 = ( a ) => w0( a ).add( w1( a ) ); - for ( let j = 0; j < divisions; j ++ ) { +const g1 = ( a ) => w2( a ).add( w3( a ) ); - // first vertex +// h0 and h1 are the two offset functions +const h0 = ( a ) => add( - 1.0, w1( a ).div( w0( a ).add( w1( a ) ) ) ); - let v = ( j / divisions ) * ( Math.PI * 2 ); +const h1 = ( a ) => add( 1.0, w3( a ).div( w2( a ).add( w3( a ) ) ) ); - let x = Math.sin( v ) * r; - let z = Math.cos( v ) * r; +const bicubic = ( textureNode, texelSize, lod ) => { - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); + const uv = textureNode.uvNode; + const uvScaled = mul( uv, texelSize.zw ).add( 0.5 ); - // second vertex + const iuv = floor( uvScaled ); + const fuv = fract( uvScaled ); - v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); + const g0x = g0( fuv.x ); + const g1x = g1( fuv.x ); + const h0x = h0( fuv.x ); + const h1x = h1( fuv.x ); + const h0y = h0( fuv.y ); + const h1y = h1( fuv.y ); - x = Math.sin( v ) * r; - z = Math.cos( v ) * r; + const p0 = vec2( iuv.x.add( h0x ), iuv.y.add( h0y ) ).sub( 0.5 ).mul( texelSize.xy ); + const p1 = vec2( iuv.x.add( h1x ), iuv.y.add( h0y ) ).sub( 0.5 ).mul( texelSize.xy ); + const p2 = vec2( iuv.x.add( h0x ), iuv.y.add( h1y ) ).sub( 0.5 ).mul( texelSize.xy ); + const p3 = vec2( iuv.x.add( h1x ), iuv.y.add( h1y ) ).sub( 0.5 ).mul( texelSize.xy ); - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); + const a = g0( fuv.y ).mul( add( g0x.mul( textureNode.uv( p0 ).level( lod ) ), g1x.mul( textureNode.uv( p1 ).level( lod ) ) ) ); + const b = g1( fuv.y ).mul( add( g0x.mul( textureNode.uv( p2 ).level( lod ) ), g1x.mul( textureNode.uv( p3 ).level( lod ) ) ) ); - } + return a.add( b ); - } +}; - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); +const textureBicubic = /*@__PURE__*/ Fn( ( [ textureNode, lodNode = float( 3 ) ] ) => { - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); + const fLodSize = vec2( textureNode.size( int( lodNode ) ) ); + const cLodSize = vec2( textureNode.size( int( lodNode.add( 1.0 ) ) ) ); + const fLodSizeInv = div( 1.0, fLodSize ); + const cLodSizeInv = div( 1.0, cLodSize ); + const fSample = bicubic( textureNode, vec4( fLodSizeInv, fLodSize ), floor( lodNode ) ); + const cSample = bicubic( textureNode, vec4( cLodSizeInv, cLodSize ), ceil( lodNode ) ); - super( geometry, material ); + return fract( lodNode ).mix( fSample, cSample ); - this.type = 'PolarGridHelper'; +} ); - } +// +// Transmission +// - dispose() { +const getVolumeTransmissionRay = /*@__PURE__*/ Fn( ( [ n, v, thickness, ior, modelMatrix ] ) => { - this.geometry.dispose(); - this.material.dispose(); + // Direction of refracted light. + const refractionVector = vec3( refract( v.negate(), normalize( n ), div( 1.0, ior ) ) ); - } + // Compute rotation-independant scaling of the model matrix. + const modelScale = vec3( + length( modelMatrix[ 0 ].xyz ), + length( modelMatrix[ 1 ].xyz ), + length( modelMatrix[ 2 ].xyz ) + ); -} + // The thickness is specified in local space. + return normalize( refractionVector ).mul( thickness.mul( modelScale ) ); -const _v1 = /*@__PURE__*/ new Vector3(); -const _v2 = /*@__PURE__*/ new Vector3(); -const _v3 = /*@__PURE__*/ new Vector3(); +} ).setLayout( { + name: 'getVolumeTransmissionRay', + type: 'vec3', + inputs: [ + { name: 'n', type: 'vec3' }, + { name: 'v', type: 'vec3' }, + { name: 'thickness', type: 'float' }, + { name: 'ior', type: 'float' }, + { name: 'modelMatrix', type: 'mat4' } + ] +} ); -class DirectionalLightHelper extends Object3D { +const applyIorToRoughness = /*@__PURE__*/ Fn( ( [ roughness, ior ] ) => { - constructor( light, size, color ) { + // Scale roughness with IOR so that an IOR of 1.0 results in no microfacet refraction and + // an IOR of 1.5 results in the default amount of microfacet refraction. + return roughness.mul( clamp( ior.mul( 2.0 ).sub( 2.0 ), 0.0, 1.0 ) ); - super(); +} ).setLayout( { + name: 'applyIorToRoughness', + type: 'float', + inputs: [ + { name: 'roughness', type: 'float' }, + { name: 'ior', type: 'float' } + ] +} ); - this.light = light; +const singleViewportMipTexture = /*@__PURE__*/ viewportMipTexture(); - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; +const getTransmissionSample = /*@__PURE__*/ Fn( ( [ fragCoord, roughness, ior ] ) => { - this.color = color; + const transmissionSample = singleViewportMipTexture.uv( fragCoord ); + //const transmissionSample = viewportMipTexture( fragCoord ); - this.type = 'DirectionalLightHelper'; + const lod = log2( float( screenSize.x ) ).mul( applyIorToRoughness( roughness, ior ) ); - if ( size === undefined ) size = 1; + return textureBicubic( transmissionSample, lod ); - let geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( [ - - size, size, 0, - size, size, 0, - size, - size, 0, - - size, - size, 0, - - size, size, 0 - ], 3 ) ); +} ); - const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); +const volumeAttenuation = /*@__PURE__*/ Fn( ( [ transmissionDistance, attenuationColor, attenuationDistance ] ) => { - this.lightPlane = new Line( geometry, material ); - this.add( this.lightPlane ); + If( attenuationDistance.notEqual( 0 ), () => { - geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); + // Compute light attenuation using Beer's law. + const attenuationCoefficient = log( attenuationColor ).negate().div( attenuationDistance ); + const transmittance = exp( attenuationCoefficient.negate().mul( transmissionDistance ) ); - this.targetLine = new Line( geometry, material ); - this.add( this.targetLine ); + return transmittance; - this.update(); + } ); - } + // Attenuation distance is +∞, i.e. the transmitted color is not attenuated at all. + return vec3( 1.0 ); - dispose() { +} ).setLayout( { + name: 'volumeAttenuation', + type: 'vec3', + inputs: [ + { name: 'transmissionDistance', type: 'float' }, + { name: 'attenuationColor', type: 'vec3' }, + { name: 'attenuationDistance', type: 'float' } + ] +} ); - this.lightPlane.geometry.dispose(); - this.lightPlane.material.dispose(); - this.targetLine.geometry.dispose(); - this.targetLine.material.dispose(); +const getIBLVolumeRefraction = /*@__PURE__*/ Fn( ( [ n, v, roughness, diffuseColor, specularColor, specularF90, position, modelMatrix, viewMatrix, projMatrix, ior, thickness, attenuationColor, attenuationDistance, dispersion ] ) => { - } + let transmittedLight, transmittance; - update() { + if ( dispersion ) { - this.light.updateWorldMatrix( true, false ); - this.light.target.updateWorldMatrix( true, false ); + transmittedLight = vec4().toVar(); + transmittance = vec3().toVar(); - _v1.setFromMatrixPosition( this.light.matrixWorld ); - _v2.setFromMatrixPosition( this.light.target.matrixWorld ); - _v3.subVectors( _v2, _v1 ); + const halfSpread = ior.sub( 1.0 ).mul( dispersion.mul( 0.025 ) ); + const iors = vec3( ior.sub( halfSpread ), ior, ior.add( halfSpread ) ); - this.lightPlane.lookAt( _v2 ); + Loop( { start: 0, end: 3 }, ( { i } ) => { - if ( this.color !== undefined ) { + const ior = iors.element( i ); - this.lightPlane.material.color.set( this.color ); - this.targetLine.material.color.set( this.color ); + const transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix ); + const refractedRayExit = position.add( transmissionRay ); - } else { + // Project refracted vector on the framebuffer, while mapping to normalized device coordinates. + const ndcPos = projMatrix.mul( viewMatrix.mul( vec4( refractedRayExit, 1.0 ) ) ); + const refractionCoords = vec2( ndcPos.xy.div( ndcPos.w ) ).toVar(); + refractionCoords.addAssign( 1.0 ); + refractionCoords.divAssign( 2.0 ); + refractionCoords.assign( vec2( refractionCoords.x, refractionCoords.y.oneMinus() ) ); // webgpu - this.lightPlane.material.color.copy( this.light.color ); - this.targetLine.material.color.copy( this.light.color ); + // Sample framebuffer to get pixel the refracted ray hits. + const transmissionSample = getTransmissionSample( refractionCoords, roughness, ior ); - } + transmittedLight.element( i ).assign( transmissionSample.element( i ) ); + transmittedLight.a.addAssign( transmissionSample.a ); - this.targetLine.lookAt( _v2 ); - this.targetLine.scale.z = _v3.length(); + transmittance.element( i ).assign( diffuseColor.element( i ).mul( volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ).element( i ) ) ); - } + } ); -} + transmittedLight.a.divAssign( 3.0 ); -const _vector = /*@__PURE__*/ new Vector3(); -const _camera$1 = /*@__PURE__*/ new Camera(); + } else { -/** - * - shows frustum, line of sight and up of the camera - * - suitable for fast updates - * - based on frustum visualization in lightgl.js shadowmap example - * https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html - */ + const transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix ); + const refractedRayExit = position.add( transmissionRay ); -class CameraHelper extends LineSegments { + // Project refracted vector on the framebuffer, while mapping to normalized device coordinates. + const ndcPos = projMatrix.mul( viewMatrix.mul( vec4( refractedRayExit, 1.0 ) ) ); + const refractionCoords = vec2( ndcPos.xy.div( ndcPos.w ) ).toVar(); + refractionCoords.addAssign( 1.0 ); + refractionCoords.divAssign( 2.0 ); + refractionCoords.assign( vec2( refractionCoords.x, refractionCoords.y.oneMinus() ) ); // webgpu - constructor( camera ) { + // Sample framebuffer to get pixel the refracted ray hits. + transmittedLight = getTransmissionSample( refractionCoords, roughness, ior ); + transmittance = diffuseColor.mul( volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ) ); - const geometry = new BufferGeometry(); - const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } ); + } - const vertices = []; - const colors = []; + const attenuatedColor = transmittance.rgb.mul( transmittedLight.rgb ); + const dotNV = n.dot( v ).clamp(); - const pointMap = {}; + // Get the specular component. + const F = vec3( EnvironmentBRDF( { // n, v, specularColor, specularF90, roughness + dotNV, + specularColor, + specularF90, + roughness + } ) ); - // near + // As less light is transmitted, the opacity should be increased. This simple approximation does a decent job + // of modulating a CSS background, and has no effect when the buffer is opaque, due to a solid object or clear color. + const transmittanceFactor = transmittance.r.add( transmittance.g, transmittance.b ).div( 3.0 ); - addLine( 'n1', 'n2' ); - addLine( 'n2', 'n4' ); - addLine( 'n4', 'n3' ); - addLine( 'n3', 'n1' ); + return vec4( F.oneMinus().mul( attenuatedColor ), transmittedLight.a.oneMinus().mul( transmittanceFactor ).oneMinus() ); - // far +} ); - addLine( 'f1', 'f2' ); - addLine( 'f2', 'f4' ); - addLine( 'f4', 'f3' ); - addLine( 'f3', 'f1' ); +// +// Iridescence +// - // sides +// XYZ to linear-sRGB color space +const XYZ_TO_REC709 = /*@__PURE__*/ mat3( + 3.2404542, - 0.9692660, 0.0556434, + - 1.5371385, 1.8760108, - 0.2040259, + - 0.4985314, 0.0415560, 1.0572252 +); - addLine( 'n1', 'f1' ); - addLine( 'n2', 'f2' ); - addLine( 'n3', 'f3' ); - addLine( 'n4', 'f4' ); +// Assume air interface for top +// Note: We don't handle the case fresnel0 == 1 +const Fresnel0ToIor = ( fresnel0 ) => { - // cone + const sqrtF0 = fresnel0.sqrt(); + return vec3( 1.0 ).add( sqrtF0 ).div( vec3( 1.0 ).sub( sqrtF0 ) ); - addLine( 'p', 'n1' ); - addLine( 'p', 'n2' ); - addLine( 'p', 'n3' ); - addLine( 'p', 'n4' ); +}; - // up +// ior is a value between 1.0 and 3.0. 1.0 is air interface +const IorToFresnel0 = ( transmittedIor, incidentIor ) => { - addLine( 'u1', 'u2' ); - addLine( 'u2', 'u3' ); - addLine( 'u3', 'u1' ); + return transmittedIor.sub( incidentIor ).div( transmittedIor.add( incidentIor ) ).pow2(); - // target +}; - addLine( 'c', 't' ); - addLine( 'p', 'c' ); +// Fresnel equations for dielectric/dielectric interfaces. +// Ref: https://belcour.github.io/blog/research/2017/05/01/brdf-thin-film.html +// Evaluation XYZ sensitivity curves in Fourier space +const evalSensitivity = ( OPD, shift ) => { - // cross + const phase = OPD.mul( 2.0 * Math.PI * 1.0e-9 ); + const val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 ); + const pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 ); + const VAR = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 ); - addLine( 'cn1', 'cn2' ); - addLine( 'cn3', 'cn4' ); + const x = float( 9.7470e-14 * Math.sqrt( 2.0 * Math.PI * 4.5282e+09 ) ).mul( phase.mul( 2.2399e+06 ).add( shift.x ).cos() ).mul( phase.pow2().mul( - 4.5282e+09 ).exp() ); - addLine( 'cf1', 'cf2' ); - addLine( 'cf3', 'cf4' ); + let xyz = val.mul( VAR.mul( 2.0 * Math.PI ).sqrt() ).mul( pos.mul( phase ).add( shift ).cos() ).mul( phase.pow2().negate().mul( VAR ).exp() ); + xyz = vec3( xyz.x.add( x ), xyz.y, xyz.z ).div( 1.0685e-7 ); - function addLine( a, b ) { + const rgb = XYZ_TO_REC709.mul( xyz ); - addPoint( a ); - addPoint( b ); + return rgb; - } +}; - function addPoint( id ) { +const evalIridescence = /*@__PURE__*/ Fn( ( { outsideIOR, eta2, cosTheta1, thinFilmThickness, baseF0 } ) => { - vertices.push( 0, 0, 0 ); - colors.push( 0, 0, 0 ); + // Force iridescenceIOR -> outsideIOR when thinFilmThickness -> 0.0 + const iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) ); + // Evaluate the cosTheta on the base layer (Snell law) + const sinTheta2Sq = outsideIOR.div( iridescenceIOR ).pow2().mul( float( 1 ).sub( cosTheta1.pow2() ) ); - if ( pointMap[ id ] === undefined ) { + // Handle TIR: + const cosTheta2Sq = float( 1 ).sub( sinTheta2Sq ); + /*if ( cosTheta2Sq < 0.0 ) { - pointMap[ id ] = []; + return vec3( 1.0 ); - } + }*/ - pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); + const cosTheta2 = cosTheta2Sq.sqrt(); - } + // First interface + const R0 = IorToFresnel0( iridescenceIOR, outsideIOR ); + const R12 = F_Schlick( { f0: R0, f90: 1.0, dotVH: cosTheta1 } ); + //const R21 = R12; + const T121 = R12.oneMinus(); + const phi12 = iridescenceIOR.lessThan( outsideIOR ).select( Math.PI, 0.0 ); + const phi21 = float( Math.PI ).sub( phi12 ); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + // Second interface + const baseIOR = Fresnel0ToIor( baseF0.clamp( 0.0, 0.9999 ) ); // guard against 1.0 + const R1 = IorToFresnel0( baseIOR, iridescenceIOR.toVec3() ); + const R23 = F_Schlick( { f0: R1, f90: 1.0, dotVH: cosTheta2 } ); + const phi23 = vec3( + baseIOR.x.lessThan( iridescenceIOR ).select( Math.PI, 0.0 ), + baseIOR.y.lessThan( iridescenceIOR ).select( Math.PI, 0.0 ), + baseIOR.z.lessThan( iridescenceIOR ).select( Math.PI, 0.0 ) + ); - super( geometry, material ); + // Phase shift + const OPD = iridescenceIOR.mul( thinFilmThickness, cosTheta2, 2.0 ); + const phi = vec3( phi21 ).add( phi23 ); - this.type = 'CameraHelper'; + // Compound terms + const R123 = R12.mul( R23 ).clamp( 1e-5, 0.9999 ); + const r123 = R123.sqrt(); + const Rs = T121.pow2().mul( R23 ).div( vec3( 1.0 ).sub( R123 ) ); - this.camera = camera; - if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); + // Reflectance term for m = 0 (DC term amplitude) + const C0 = R12.add( Rs ); + let I = C0; - this.matrix = camera.matrixWorld; - this.matrixAutoUpdate = false; + // Reflectance term for m > 0 (pairs of diracs) + let Cm = Rs.sub( T121 ); + for ( let m = 1; m <= 2; ++ m ) { - this.pointMap = pointMap; + Cm = Cm.mul( r123 ); + const Sm = evalSensitivity( float( m ).mul( OPD ), float( m ).mul( phi ) ).mul( 2.0 ); + I = I.add( Cm.mul( Sm ) ); - this.update(); + } - // colors + // Since out of gamut colors might be produced, negative color values are clamped to 0. + return I.max( vec3( 0.0 ) ); - const colorFrustum = new Color( 0xffaa00 ); - const colorCone = new Color( 0xff0000 ); - const colorUp = new Color( 0x00aaff ); - const colorTarget = new Color( 0xffffff ); - const colorCross = new Color( 0x333333 ); - - this.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross ); - - } +} ).setLayout( { + name: 'evalIridescence', + type: 'vec3', + inputs: [ + { name: 'outsideIOR', type: 'float' }, + { name: 'eta2', type: 'float' }, + { name: 'cosTheta1', type: 'float' }, + { name: 'thinFilmThickness', type: 'float' }, + { name: 'baseF0', type: 'vec3' } + ] +} ); - setColors( frustum, cone, up, target, cross ) { +// +// Sheen +// - const geometry = this.geometry; +// This is a curve-fit approxmation to the "Charlie sheen" BRDF integrated over the hemisphere from +// Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF". The analysis can be found +// in the Sheen section of https://drive.google.com/file/d/1T0D1VSyR4AllqIJTQAraEIzjlb5h4FKH/view?usp=sharing +const IBLSheenBRDF = /*@__PURE__*/ Fn( ( { normal, viewDir, roughness } ) => { - const colorAttribute = geometry.getAttribute( 'color' ); + const dotNV = normal.dot( viewDir ).saturate(); - // near + const r2 = roughness.pow2(); - colorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2 - colorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4 - colorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3 - colorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1 + const a = select( + roughness.lessThan( 0.25 ), + float( - 339.2 ).mul( r2 ).add( float( 161.4 ).mul( roughness ) ).sub( 25.9 ), + float( - 8.48 ).mul( r2 ).add( float( 14.3 ).mul( roughness ) ).sub( 9.95 ) + ); - // far + const b = select( + roughness.lessThan( 0.25 ), + float( 44.0 ).mul( r2 ).sub( float( 23.7 ).mul( roughness ) ).add( 3.26 ), + float( 1.97 ).mul( r2 ).sub( float( 3.27 ).mul( roughness ) ).add( 0.72 ) + ); - colorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2 - colorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4 - colorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3 - colorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1 + const DG = select( roughness.lessThan( 0.25 ), 0.0, float( 0.1 ).mul( roughness ).sub( 0.025 ) ).add( a.mul( dotNV ).add( b ).exp() ); - // sides + return DG.mul( 1.0 / Math.PI ).saturate(); - colorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1 - colorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2 - colorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3 - colorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4 +} ); - // cone +const clearcoatF0 = vec3( 0.04 ); +const clearcoatF90 = float( 1 ); - colorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1 - colorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2 - colorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3 - colorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4 +// - // up +class PhysicalLightingModel extends LightingModel { - colorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2 - colorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3 - colorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1 + constructor( clearcoat = false, sheen = false, iridescence = false, anisotropy = false, transmission = false, dispersion = false ) { - // target + super(); - colorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t - colorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c + this.clearcoat = clearcoat; + this.sheen = sheen; + this.iridescence = iridescence; + this.anisotropy = anisotropy; + this.transmission = transmission; + this.dispersion = dispersion; - // cross + this.clearcoatRadiance = null; + this.clearcoatSpecularDirect = null; + this.clearcoatSpecularIndirect = null; + this.sheenSpecularDirect = null; + this.sheenSpecularIndirect = null; + this.iridescenceFresnel = null; + this.iridescenceF0 = null; - colorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2 - colorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4 + } - colorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2 - colorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4 + start( context ) { - colorAttribute.needsUpdate = true; + if ( this.clearcoat === true ) { - } + this.clearcoatRadiance = vec3().toVar( 'clearcoatRadiance' ); + this.clearcoatSpecularDirect = vec3().toVar( 'clearcoatSpecularDirect' ); + this.clearcoatSpecularIndirect = vec3().toVar( 'clearcoatSpecularIndirect' ); - update() { + } - const geometry = this.geometry; - const pointMap = this.pointMap; + if ( this.sheen === true ) { - const w = 1, h = 1; + this.sheenSpecularDirect = vec3().toVar( 'sheenSpecularDirect' ); + this.sheenSpecularIndirect = vec3().toVar( 'sheenSpecularIndirect' ); - // we need just camera projection matrix inverse - // world matrix must be identity + } - _camera$1.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); + if ( this.iridescence === true ) { - // center / target + const dotNVi = transformedNormalView.dot( positionViewDirection ).clamp(); - setPoint( 'c', pointMap, geometry, _camera$1, 0, 0, - 1 ); - setPoint( 't', pointMap, geometry, _camera$1, 0, 0, 1 ); + this.iridescenceFresnel = evalIridescence( { + outsideIOR: float( 1.0 ), + eta2: iridescenceIOR, + cosTheta1: dotNVi, + thinFilmThickness: iridescenceThickness, + baseF0: specularColor + } ); - // near + this.iridescenceF0 = Schlick_to_F0( { f: this.iridescenceFresnel, f90: 1.0, dotVH: dotNVi } ); - setPoint( 'n1', pointMap, geometry, _camera$1, - w, - h, - 1 ); - setPoint( 'n2', pointMap, geometry, _camera$1, w, - h, - 1 ); - setPoint( 'n3', pointMap, geometry, _camera$1, - w, h, - 1 ); - setPoint( 'n4', pointMap, geometry, _camera$1, w, h, - 1 ); + } - // far + if ( this.transmission === true ) { - setPoint( 'f1', pointMap, geometry, _camera$1, - w, - h, 1 ); - setPoint( 'f2', pointMap, geometry, _camera$1, w, - h, 1 ); - setPoint( 'f3', pointMap, geometry, _camera$1, - w, h, 1 ); - setPoint( 'f4', pointMap, geometry, _camera$1, w, h, 1 ); + const position = positionWorld; + const v = cameraPosition.sub( positionWorld ).normalize(); // TODO: Create Node for this, same issue in MaterialX + const n = transformedNormalWorld; - // up + context.backdrop = getIBLVolumeRefraction( + n, + v, + roughness, + diffuseColor, + specularColor, + specularF90, // specularF90 + position, // positionWorld + modelWorldMatrix, // modelMatrix + cameraViewMatrix, // viewMatrix + cameraProjectionMatrix, // projMatrix + ior, + thickness, + attenuationColor, + attenuationDistance, + this.dispersion ? dispersion : null + ); - setPoint( 'u1', pointMap, geometry, _camera$1, w * 0.7, h * 1.1, - 1 ); - setPoint( 'u2', pointMap, geometry, _camera$1, - w * 0.7, h * 1.1, - 1 ); - setPoint( 'u3', pointMap, geometry, _camera$1, 0, h * 2, - 1 ); + context.backdropAlpha = transmission; - // cross + diffuseColor.a.mulAssign( mix( 1, context.backdrop.a, transmission ) ); - setPoint( 'cf1', pointMap, geometry, _camera$1, - w, 0, 1 ); - setPoint( 'cf2', pointMap, geometry, _camera$1, w, 0, 1 ); - setPoint( 'cf3', pointMap, geometry, _camera$1, 0, - h, 1 ); - setPoint( 'cf4', pointMap, geometry, _camera$1, 0, h, 1 ); + } - setPoint( 'cn1', pointMap, geometry, _camera$1, - w, 0, - 1 ); - setPoint( 'cn2', pointMap, geometry, _camera$1, w, 0, - 1 ); - setPoint( 'cn3', pointMap, geometry, _camera$1, 0, - h, - 1 ); - setPoint( 'cn4', pointMap, geometry, _camera$1, 0, h, - 1 ); + } - geometry.getAttribute( 'position' ).needsUpdate = true; + // Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting" + // Approximates multiscattering in order to preserve energy. + // http://www.jcgt.org/published/0008/01/03/ - } + computeMultiscattering( singleScatter, multiScatter, specularF90 ) { - dispose() { + const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV - this.geometry.dispose(); - this.material.dispose(); + const fab = DFGApprox( { roughness, dotNV } ); - } + const Fr = this.iridescenceF0 ? iridescence.mix( specularColor, this.iridescenceF0 ) : specularColor; -} + const FssEss = Fr.mul( fab.x ).add( specularF90.mul( fab.y ) ); + const Ess = fab.x.add( fab.y ); + const Ems = Ess.oneMinus(); -function setPoint( point, pointMap, geometry, camera, x, y, z ) { + const Favg = specularColor.add( specularColor.oneMinus().mul( 0.047619 ) ); // 1/21 + const Fms = FssEss.mul( Favg ).div( Ems.mul( Favg ).oneMinus() ); - _vector.set( x, y, z ).unproject( camera ); + singleScatter.addAssign( FssEss ); + multiScatter.addAssign( Fms.mul( Ems ) ); - const points = pointMap[ point ]; + } - if ( points !== undefined ) { + direct( { lightDirection, lightColor, reflectedLight } ) { - const position = geometry.getAttribute( 'position' ); + const dotNL = transformedNormalView.dot( lightDirection ).clamp(); + const irradiance = dotNL.mul( lightColor ); - for ( let i = 0, l = points.length; i < l; i ++ ) { + if ( this.sheen === true ) { - position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z ); + this.sheenSpecularDirect.addAssign( irradiance.mul( BRDF_Sheen( { lightDirection } ) ) ); } - } + if ( this.clearcoat === true ) { -} + const dotNLcc = transformedClearcoatNormalView.dot( lightDirection ).clamp(); + const ccIrradiance = dotNLcc.mul( lightColor ); -const _box = /*@__PURE__*/ new Box3(); + this.clearcoatSpecularDirect.addAssign( ccIrradiance.mul( BRDF_GGX( { lightDirection, f0: clearcoatF0, f90: clearcoatF90, roughness: clearcoatRoughness, normalView: transformedClearcoatNormalView } ) ) ); -class BoxHelper extends LineSegments { + } - constructor( object, color = 0xffff00 ) { + reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) ); - const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); - const positions = new Float32Array( 8 * 3 ); + reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_GGX( { lightDirection, f0: specularColor, f90: 1, roughness, iridescence: this.iridescence, f: this.iridescenceFresnel, USE_IRIDESCENCE: this.iridescence, USE_ANISOTROPY: this.anisotropy } ) ) ); - const geometry = new BufferGeometry(); - geometry.setIndex( new BufferAttribute( indices, 1 ) ); - geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) ); + } - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + directRectArea( { lightColor, lightPosition, halfWidth, halfHeight, reflectedLight, ltc_1, ltc_2 } ) { - this.object = object; - this.type = 'BoxHelper'; + const p0 = lightPosition.add( halfWidth ).sub( halfHeight ); // counterclockwise; light shines in local neg z direction + const p1 = lightPosition.sub( halfWidth ).sub( halfHeight ); + const p2 = lightPosition.sub( halfWidth ).add( halfHeight ); + const p3 = lightPosition.add( halfWidth ).add( halfHeight ); - this.matrixAutoUpdate = false; + const N = transformedNormalView; + const V = positionViewDirection; + const P = positionView.toVar(); - this.update(); + const uv = LTC_Uv( { N, V, roughness } ); - } + const t1 = ltc_1.uv( uv ).toVar(); + const t2 = ltc_2.uv( uv ).toVar(); - update( object ) { + const mInv = mat3( + vec3( t1.x, 0, t1.y ), + vec3( 0, 1, 0 ), + vec3( t1.z, 0, t1.w ) + ).toVar(); - if ( object !== undefined ) { + // LTC Fresnel Approximation by Stephen Hill + // http://blog.selfshadow.com/publications/s2016-advances/s2016_ltc_fresnel.pdf + const fresnel = specularColor.mul( t2.x ).add( specularColor.oneMinus().mul( t2.y ) ).toVar(); - console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); + reflectedLight.directSpecular.addAssign( lightColor.mul( fresnel ).mul( LTC_Evaluate( { N, V, P, mInv, p0, p1, p2, p3 } ) ) ); - } + reflectedLight.directDiffuse.addAssign( lightColor.mul( diffuseColor ).mul( LTC_Evaluate( { N, V, P, mInv: mat3( 1, 0, 0, 0, 1, 0, 0, 0, 1 ), p0, p1, p2, p3 } ) ) ); - if ( this.object !== undefined ) { + } - _box.setFromObject( this.object ); + indirect( context, stack, builder ) { - } + this.indirectDiffuse( context, stack, builder ); + this.indirectSpecular( context, stack, builder ); + this.ambientOcclusion( context, stack, builder ); - if ( _box.isEmpty() ) return; + } - const min = _box.min; - const max = _box.max; + indirectDiffuse( { irradiance, reflectedLight } ) { - /* - 5____4 - 1/___0/| - | 6__|_7 - 2/___3/ + reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) ); - 0: max.x, max.y, max.z - 1: min.x, max.y, max.z - 2: min.x, min.y, max.z - 3: max.x, min.y, max.z - 4: max.x, max.y, min.z - 5: min.x, max.y, min.z - 6: min.x, min.y, min.z - 7: max.x, min.y, min.z - */ + } - const position = this.geometry.attributes.position; - const array = position.array; + indirectSpecular( { radiance, iblIrradiance, reflectedLight } ) { - array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; - array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; - array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; - array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; - array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; - array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; - array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; - array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; + if ( this.sheen === true ) { - position.needsUpdate = true; + this.sheenSpecularIndirect.addAssign( iblIrradiance.mul( + sheen, + IBLSheenBRDF( { + normal: transformedNormalView, + viewDir: positionViewDirection, + roughness: sheenRoughness + } ) + ) ); - this.geometry.computeBoundingSphere(); + } - } + if ( this.clearcoat === true ) { - setFromObject( object ) { + const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp(); - this.object = object; - this.update(); + const clearcoatEnv = EnvironmentBRDF( { + dotNV: dotNVcc, + specularColor: clearcoatF0, + specularF90: clearcoatF90, + roughness: clearcoatRoughness + } ); - return this; + this.clearcoatSpecularIndirect.addAssign( this.clearcoatRadiance.mul( clearcoatEnv ) ); - } + } - copy( source, recursive ) { + // Both indirect specular and indirect diffuse light accumulate here - super.copy( source, recursive ); + const singleScattering = vec3().toVar( 'singleScattering' ); + const multiScattering = vec3().toVar( 'multiScattering' ); + const cosineWeightedIrradiance = iblIrradiance.mul( 1 / Math.PI ); - this.object = source.object; + this.computeMultiscattering( singleScattering, multiScattering, specularF90 ); - return this; + const totalScattering = singleScattering.add( multiScattering ); - } + const diffuse = diffuseColor.mul( totalScattering.r.max( totalScattering.g ).max( totalScattering.b ).oneMinus() ); - dispose() { + reflectedLight.indirectSpecular.addAssign( radiance.mul( singleScattering ) ); + reflectedLight.indirectSpecular.addAssign( multiScattering.mul( cosineWeightedIrradiance ) ); - this.geometry.dispose(); - this.material.dispose(); + reflectedLight.indirectDiffuse.addAssign( diffuse.mul( cosineWeightedIrradiance ) ); } -} - -class Box3Helper extends LineSegments { + ambientOcclusion( { ambientOcclusion, reflectedLight } ) { - constructor( box, color = 0xffff00 ) { + const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV - const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); + const aoNV = dotNV.add( ambientOcclusion ); + const aoExp = roughness.mul( - 16.0 ).oneMinus().negate().exp2(); - const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ]; + const aoNode = ambientOcclusion.sub( aoNV.pow( aoExp ).oneMinus() ).clamp(); - const geometry = new BufferGeometry(); + if ( this.clearcoat === true ) { - geometry.setIndex( new BufferAttribute( indices, 1 ) ); + this.clearcoatSpecularIndirect.mulAssign( ambientOcclusion ); - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + } - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + if ( this.sheen === true ) { - this.box = box; + this.sheenSpecularIndirect.mulAssign( ambientOcclusion ); - this.type = 'Box3Helper'; + } - this.geometry.computeBoundingSphere(); + reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion ); + reflectedLight.indirectSpecular.mulAssign( aoNode ); } - updateMatrixWorld( force ) { + finish( context ) { - const box = this.box; + const { outgoingLight } = context; - if ( box.isEmpty() ) return; + if ( this.clearcoat === true ) { - box.getCenter( this.position ); + const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp(); - box.getSize( this.scale ); + const Fcc = F_Schlick( { + dotVH: dotNVcc, + f0: clearcoatF0, + f90: clearcoatF90 + } ); - this.scale.multiplyScalar( 0.5 ); + const clearcoatLight = outgoingLight.mul( clearcoat.mul( Fcc ).oneMinus() ).add( this.clearcoatSpecularDirect.add( this.clearcoatSpecularIndirect ).mul( clearcoat ) ); - super.updateMatrixWorld( force ); + outgoingLight.assign( clearcoatLight ); - } + } - dispose() { + if ( this.sheen === true ) { - this.geometry.dispose(); - this.material.dispose(); + const sheenEnergyComp = sheen.r.max( sheen.g ).max( sheen.b ).mul( 0.157 ).oneMinus(); + const sheenLight = outgoingLight.mul( sheenEnergyComp ).add( this.sheenSpecularDirect, this.sheenSpecularIndirect ); + + outgoingLight.assign( sheenLight ); + + } } } -class PlaneHelper extends Line { +// These defines must match with PMREMGenerator - constructor( plane, size = 1, hex = 0xffff00 ) { +const cubeUV_r0 = /*@__PURE__*/ float( 1.0 ); +const cubeUV_m0 = /*@__PURE__*/ float( - 2.0 ); +const cubeUV_r1 = /*@__PURE__*/ float( 0.8 ); +const cubeUV_m1 = /*@__PURE__*/ float( - 1.0 ); +const cubeUV_r4 = /*@__PURE__*/ float( 0.4 ); +const cubeUV_m4 = /*@__PURE__*/ float( 2.0 ); +const cubeUV_r5 = /*@__PURE__*/ float( 0.305 ); +const cubeUV_m5 = /*@__PURE__*/ float( 3.0 ); +const cubeUV_r6 = /*@__PURE__*/ float( 0.21 ); +const cubeUV_m6 = /*@__PURE__*/ float( 4.0 ); - const color = hex; +const cubeUV_minMipLevel = /*@__PURE__*/ float( 4.0 ); +const cubeUV_minTileSize = /*@__PURE__*/ float( 16.0 ); - const positions = [ 1, - 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, - 1, 0, 1, 1, 0 ]; +// These shader functions convert between the UV coordinates of a single face of +// a cubemap, the 0-5 integer index of a cube face, and the direction vector for +// sampling a textureCube (not generally normalized ). - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - geometry.computeBoundingSphere(); +const getFace = /*@__PURE__*/ Fn( ( [ direction ] ) => { - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + const absDirection = vec3( abs( direction ) ).toVar(); + const face = float( - 1.0 ).toVar(); - this.type = 'PlaneHelper'; + If( absDirection.x.greaterThan( absDirection.z ), () => { - this.plane = plane; + If( absDirection.x.greaterThan( absDirection.y ), () => { - this.size = size; + face.assign( select( direction.x.greaterThan( 0.0 ), 0.0, 3.0 ) ); - const positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ]; + } ).Else( () => { - const geometry2 = new BufferGeometry(); - geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); - geometry2.computeBoundingSphere(); + face.assign( select( direction.y.greaterThan( 0.0 ), 1.0, 4.0 ) ); - this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) ); + } ); - } + } ).Else( () => { - updateMatrixWorld( force ) { + If( absDirection.z.greaterThan( absDirection.y ), () => { - this.position.set( 0, 0, 0 ); + face.assign( select( direction.z.greaterThan( 0.0 ), 2.0, 5.0 ) ); - this.scale.set( 0.5 * this.size, 0.5 * this.size, 1 ); + } ).Else( () => { - this.lookAt( this.plane.normal ); + face.assign( select( direction.y.greaterThan( 0.0 ), 1.0, 4.0 ) ); - this.translateZ( - this.plane.constant ); + } ); - super.updateMatrixWorld( force ); + } ); - } + return face; - dispose() { +} ).setLayout( { + name: 'getFace', + type: 'float', + inputs: [ + { name: 'direction', type: 'vec3' } + ] +} ); - this.geometry.dispose(); - this.material.dispose(); - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); +// RH coordinate system; PMREM face-indexing convention +const getUV = /*@__PURE__*/ Fn( ( [ direction, face ] ) => { - } + const uv = vec2().toVar(); -} + If( face.equal( 0.0 ), () => { -const _axis = /*@__PURE__*/ new Vector3(); -let _lineGeometry, _coneGeometry; + uv.assign( vec2( direction.z, direction.y ).div( abs( direction.x ) ) ); // pos x -class ArrowHelper extends Object3D { + } ).ElseIf( face.equal( 1.0 ), () => { - // dir is assumed to be normalized + uv.assign( vec2( direction.x.negate(), direction.z.negate() ).div( abs( direction.y ) ) ); // pos y - constructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) { + } ).ElseIf( face.equal( 2.0 ), () => { - super(); + uv.assign( vec2( direction.x.negate(), direction.y ).div( abs( direction.z ) ) ); // pos z - this.type = 'ArrowHelper'; + } ).ElseIf( face.equal( 3.0 ), () => { - if ( _lineGeometry === undefined ) { + uv.assign( vec2( direction.z.negate(), direction.y ).div( abs( direction.x ) ) ); // neg x - _lineGeometry = new BufferGeometry(); - _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); + } ).ElseIf( face.equal( 4.0 ), () => { - _coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 ); - _coneGeometry.translate( 0, - 0.5, 0 ); + uv.assign( vec2( direction.x.negate(), direction.z ).div( abs( direction.y ) ) ); // neg y - } + } ).Else( () => { - this.position.copy( origin ); + uv.assign( vec2( direction.x, direction.y ).div( abs( direction.z ) ) ); // neg z - this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - this.line.matrixAutoUpdate = false; - this.add( this.line ); + } ); - this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) ); - this.cone.matrixAutoUpdate = false; - this.add( this.cone ); + return mul( 0.5, uv.add( 1.0 ) ); - this.setDirection( dir ); - this.setLength( length, headLength, headWidth ); - - } +} ).setLayout( { + name: 'getUV', + type: 'vec2', + inputs: [ + { name: 'direction', type: 'vec3' }, + { name: 'face', type: 'float' } + ] +} ); - setDirection( dir ) { +const roughnessToMip = /*@__PURE__*/ Fn( ( [ roughness ] ) => { - // dir is assumed to be normalized + const mip = float( 0.0 ).toVar(); - if ( dir.y > 0.99999 ) { + If( roughness.greaterThanEqual( cubeUV_r1 ), () => { - this.quaternion.set( 0, 0, 0, 1 ); + mip.assign( cubeUV_r0.sub( roughness ).mul( cubeUV_m1.sub( cubeUV_m0 ) ).div( cubeUV_r0.sub( cubeUV_r1 ) ).add( cubeUV_m0 ) ); - } else if ( dir.y < - 0.99999 ) { + } ).ElseIf( roughness.greaterThanEqual( cubeUV_r4 ), () => { - this.quaternion.set( 1, 0, 0, 0 ); + mip.assign( cubeUV_r1.sub( roughness ).mul( cubeUV_m4.sub( cubeUV_m1 ) ).div( cubeUV_r1.sub( cubeUV_r4 ) ).add( cubeUV_m1 ) ); - } else { + } ).ElseIf( roughness.greaterThanEqual( cubeUV_r5 ), () => { - _axis.set( dir.z, 0, - dir.x ).normalize(); + mip.assign( cubeUV_r4.sub( roughness ).mul( cubeUV_m5.sub( cubeUV_m4 ) ).div( cubeUV_r4.sub( cubeUV_r5 ) ).add( cubeUV_m4 ) ); - const radians = Math.acos( dir.y ); + } ).ElseIf( roughness.greaterThanEqual( cubeUV_r6 ), () => { - this.quaternion.setFromAxisAngle( _axis, radians ); + mip.assign( cubeUV_r5.sub( roughness ).mul( cubeUV_m6.sub( cubeUV_m5 ) ).div( cubeUV_r5.sub( cubeUV_r6 ) ).add( cubeUV_m5 ) ); - } + } ).Else( () => { - } + mip.assign( float( - 2.0 ).mul( log2( mul( 1.16, roughness ) ) ) ); // 1.16 = 1.79^0.25 - setLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) { + } ); - this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458 - this.line.updateMatrix(); + return mip; - this.cone.scale.set( headWidth, headLength, headWidth ); - this.cone.position.y = length; - this.cone.updateMatrix(); +} ).setLayout( { + name: 'roughnessToMip', + type: 'float', + inputs: [ + { name: 'roughness', type: 'float' } + ] +} ); - } +// RH coordinate system; PMREM face-indexing convention +const getDirection = /*@__PURE__*/ Fn( ( [ uv_immutable, face ] ) => { - setColor( color ) { + const uv = uv_immutable.toVar(); + uv.assign( mul( 2.0, uv ).sub( 1.0 ) ); + const direction = vec3( uv, 1.0 ).toVar(); - this.line.material.color.set( color ); - this.cone.material.color.set( color ); + If( face.equal( 0.0 ), () => { - } + direction.assign( direction.zyx ); // ( 1, v, u ) pos x - copy( source ) { + } ).ElseIf( face.equal( 1.0 ), () => { - super.copy( source, false ); + direction.assign( direction.xzy ); + direction.xz.mulAssign( - 1.0 ); // ( -u, 1, -v ) pos y - this.line.copy( source.line ); - this.cone.copy( source.cone ); + } ).ElseIf( face.equal( 2.0 ), () => { - return this; + direction.x.mulAssign( - 1.0 ); // ( -u, v, 1 ) pos z - } + } ).ElseIf( face.equal( 3.0 ), () => { - dispose() { + direction.assign( direction.zyx ); + direction.xz.mulAssign( - 1.0 ); // ( -1, v, -u ) neg x - this.line.geometry.dispose(); - this.line.material.dispose(); - this.cone.geometry.dispose(); - this.cone.material.dispose(); + } ).ElseIf( face.equal( 4.0 ), () => { - } + direction.assign( direction.xzy ); + direction.xy.mulAssign( - 1.0 ); // ( -u, -1, v ) neg y -} + } ).ElseIf( face.equal( 5.0 ), () => { -class AxesHelper extends LineSegments { + direction.z.mulAssign( - 1.0 ); // ( u, v, -1 ) neg zS - constructor( size = 1 ) { + } ); - const vertices = [ - 0, 0, 0, size, 0, 0, - 0, 0, 0, 0, size, 0, - 0, 0, 0, 0, 0, size - ]; + return direction; - const colors = [ - 1, 0, 0, 1, 0.6, 0, - 0, 1, 0, 0.6, 1, 0, - 0, 0, 1, 0, 0.6, 1 - ]; +} ).setLayout( { + name: 'getDirection', + type: 'vec3', + inputs: [ + { name: 'uv', type: 'vec2' }, + { name: 'face', type: 'float' } + ] +} ); - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); +// - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); +const textureCubeUV = /*@__PURE__*/ Fn( ( [ envMap, sampleDir_immutable, roughness_immutable, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ] ) => { - super( geometry, material ); + const roughness = float( roughness_immutable ); + const sampleDir = vec3( sampleDir_immutable ); - this.type = 'AxesHelper'; + const mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP ); + const mipF = fract( mip ); + const mipInt = floor( mip ); + const color0 = vec3( bilinearCubeUV( envMap, sampleDir, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ) ).toVar(); - } + If( mipF.notEqual( 0.0 ), () => { - setColors( xAxisColor, yAxisColor, zAxisColor ) { + const color1 = vec3( bilinearCubeUV( envMap, sampleDir, mipInt.add( 1.0 ), CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ) ).toVar(); - const color = new Color(); - const array = this.geometry.attributes.color.array; + color0.assign( mix( color0, color1, mipF ) ); - color.set( xAxisColor ); - color.toArray( array, 0 ); - color.toArray( array, 3 ); + } ); - color.set( yAxisColor ); - color.toArray( array, 6 ); - color.toArray( array, 9 ); + return color0; - color.set( zAxisColor ); - color.toArray( array, 12 ); - color.toArray( array, 15 ); +} ); - this.geometry.attributes.color.needsUpdate = true; +const bilinearCubeUV = /*@__PURE__*/ Fn( ( [ envMap, direction_immutable, mipInt_immutable, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ] ) => { - return this; + const mipInt = float( mipInt_immutable ).toVar(); + const direction = vec3( direction_immutable ); + const face = float( getFace( direction ) ).toVar(); + const filterInt = float( max$1( cubeUV_minMipLevel.sub( mipInt ), 0.0 ) ).toVar(); + mipInt.assign( max$1( mipInt, cubeUV_minMipLevel ) ); + const faceSize = float( exp2( mipInt ) ).toVar(); + const uv = vec2( getUV( direction, face ).mul( faceSize.sub( 2.0 ) ).add( 1.0 ) ).toVar(); - } + If( face.greaterThan( 2.0 ), () => { - dispose() { + uv.y.addAssign( faceSize ); + face.subAssign( 3.0 ); - this.geometry.dispose(); - this.material.dispose(); + } ); - } + uv.x.addAssign( face.mul( faceSize ) ); + uv.x.addAssign( filterInt.mul( mul( 3.0, cubeUV_minTileSize ) ) ); + uv.y.addAssign( mul( 4.0, exp2( CUBEUV_MAX_MIP ).sub( faceSize ) ) ); + uv.x.mulAssign( CUBEUV_TEXEL_WIDTH ); + uv.y.mulAssign( CUBEUV_TEXEL_HEIGHT ); -} + return envMap.uv( uv ).grad( vec2(), vec2() ); // disable anisotropic filtering -class ShapePath { +} ); - constructor() { +const getSample = /*@__PURE__*/ Fn( ( { envMap, mipInt, outputDirection, theta, axis, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) => { - this.type = 'ShapePath'; + const cosTheta = cos( theta ); - this.color = new Color(); + // Rodrigues' axis-angle rotation + const sampleDirection = outputDirection.mul( cosTheta ) + .add( axis.cross( outputDirection ).mul( sin( theta ) ) ) + .add( axis.mul( axis.dot( outputDirection ).mul( cosTheta.oneMinus() ) ) ); - this.subPaths = []; - this.currentPath = null; + return bilinearCubeUV( envMap, sampleDirection, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ); - } +} ); - moveTo( x, y ) { +const blur = /*@__PURE__*/ Fn( ( { n, latitudinal, poleAxis, outputDirection, weights, samples, dTheta, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) => { - this.currentPath = new Path(); - this.subPaths.push( this.currentPath ); - this.currentPath.moveTo( x, y ); + const axis = vec3( select( latitudinal, poleAxis, cross( poleAxis, outputDirection ) ) ).toVar(); - return this; + If( all( axis.equals( vec3( 0.0 ) ) ), () => { - } + axis.assign( vec3( outputDirection.z, 0.0, outputDirection.x.negate() ) ); - lineTo( x, y ) { + } ); - this.currentPath.lineTo( x, y ); + axis.assign( normalize( axis ) ); - return this; + const gl_FragColor = vec3().toVar(); + gl_FragColor.addAssign( weights.element( int( 0 ) ).mul( getSample( { theta: 0.0, axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) ) ); - } + Loop( { start: int( 1 ), end: n }, ( { i } ) => { - quadraticCurveTo( aCPx, aCPy, aX, aY ) { + If( i.greaterThanEqual( samples ), () => { - this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); + Break(); - return this; + } ); - } + const theta = float( dTheta.mul( float( i ) ) ).toVar(); + gl_FragColor.addAssign( weights.element( i ).mul( getSample( { theta: theta.mul( - 1.0 ), axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) ) ); + gl_FragColor.addAssign( weights.element( i ).mul( getSample( { theta, axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) ) ); - bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { + } ); - this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); + return vec4( gl_FragColor, 1 ); - return this; +} ); - } +let _generator = null; - splineThru( pts ) { +const _cache = new WeakMap(); - this.currentPath.splineThru( pts ); +function _generateCubeUVSize( imageHeight ) { - return this; + const maxMip = Math.log2( imageHeight ) - 2; - } + const texelHeight = 1.0 / imageHeight; - toShapes( isCCW ) { + const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) ); - function toShapesNoHoles( inSubpaths ) { + return { texelWidth, texelHeight, maxMip }; - const shapes = []; +} - for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) { +function _getPMREMFromTexture( texture ) { - const tmpPath = inSubpaths[ i ]; + let cacheTexture = _cache.get( texture ); - const tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; + const pmremVersion = cacheTexture !== undefined ? cacheTexture.pmremVersion : - 1; - shapes.push( tmpShape ); + if ( pmremVersion !== texture.pmremVersion ) { - } + const image = texture.image; - return shapes; + if ( texture.isCubeTexture ) { - } + if ( isCubeMapReady( image ) ) { - function isPointInsidePolygon( inPt, inPolygon ) { + cacheTexture = _generator.fromCubemap( texture, cacheTexture ); - const polyLen = inPolygon.length; + } else { - // inPt on polygon contour => immediate success or - // toggling of inside/outside at every single! intersection point of an edge - // with the horizontal line through inPt, left of inPt - // not counting lowerY endpoints of edges and whole edges on that line - let inside = false; - for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { + return null; - let edgeLowPt = inPolygon[ p ]; - let edgeHighPt = inPolygon[ q ]; + } - let edgeDx = edgeHighPt.x - edgeLowPt.x; - let edgeDy = edgeHighPt.y - edgeLowPt.y; - if ( Math.abs( edgeDy ) > Number.EPSILON ) { + } else { - // not parallel - if ( edgeDy < 0 ) { + if ( isEquirectangularMapReady( image ) ) { - edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; - edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; + cacheTexture = _generator.fromEquirectangular( texture, cacheTexture ); - } + } else { - if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; + return null; - if ( inPt.y === edgeLowPt.y ) { + } - if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? - // continue; // no intersection or edgeLowPt => doesn't count !!! + } - } else { + cacheTexture.pmremVersion = texture.pmremVersion; - const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); - if ( perpEdge === 0 ) return true; // inPt is on contour ? - if ( perpEdge < 0 ) continue; - inside = ! inside; // true intersection left of inPt + _cache.set( texture, cacheTexture ); - } + } - } else { + return cacheTexture.texture; - // parallel or collinear - if ( inPt.y !== edgeLowPt.y ) continue; // parallel - // edge lies on the same horizontal line as inPt - if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || - ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! - // continue; +} - } +class PMREMNode extends TempNode { - } + static get type() { - return inside; + return 'PMREMNode'; - } + } - const isClockWise = ShapeUtils.isClockWise; + constructor( value, uvNode = null, levelNode = null ) { - const subPaths = this.subPaths; - if ( subPaths.length === 0 ) return []; + super( 'vec3' ); - let solid, tmpPath, tmpShape; - const shapes = []; + this._value = value; + this._pmrem = null; - if ( subPaths.length === 1 ) { + this.uvNode = uvNode; + this.levelNode = levelNode; - tmpPath = subPaths[ 0 ]; - tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; - shapes.push( tmpShape ); - return shapes; + this._generator = null; - } + const defaultTexture = new Texture(); + defaultTexture.isRenderTargetTexture = true; - let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); - holesFirst = isCCW ? ! holesFirst : holesFirst; + this._texture = texture( defaultTexture ); - // console.log("Holes first", holesFirst); + this._width = uniform( 0 ); + this._height = uniform( 0 ); + this._maxMip = uniform( 0 ); - const betterShapeHoles = []; - const newShapes = []; - let newShapeHoles = []; - let mainIdx = 0; - let tmpPoints; + this.updateBeforeType = NodeUpdateType.RENDER; - newShapes[ mainIdx ] = undefined; - newShapeHoles[ mainIdx ] = []; + } - for ( let i = 0, l = subPaths.length; i < l; i ++ ) { + set value( value ) { - tmpPath = subPaths[ i ]; - tmpPoints = tmpPath.getPoints(); - solid = isClockWise( tmpPoints ); - solid = isCCW ? ! solid : solid; + this._value = value; + this._pmrem = null; - if ( solid ) { + } - if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; + get value() { - newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; - newShapes[ mainIdx ].s.curves = tmpPath.curves; + return this._value; - if ( holesFirst ) mainIdx ++; - newShapeHoles[ mainIdx ] = []; + } - //console.log('cw', i); + updateFromTexture( texture ) { - } else { + const cubeUVSize = _generateCubeUVSize( texture.image.height ); - newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); + this._texture.value = texture; + this._width.value = cubeUVSize.texelWidth; + this._height.value = cubeUVSize.texelHeight; + this._maxMip.value = cubeUVSize.maxMip; - //console.log('ccw', i); + } - } + updateBefore() { - } + let pmrem = this._pmrem; - // only Holes? -> probably all Shapes with wrong orientation - if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); + const pmremVersion = pmrem ? pmrem.pmremVersion : - 1; + const texture = this._value; + if ( pmremVersion !== texture.pmremVersion ) { - if ( newShapes.length > 1 ) { + if ( texture.isPMREMTexture === true ) { - let ambiguous = false; - let toChange = 0; + pmrem = texture; - for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + } else { - betterShapeHoles[ sIdx ] = []; + pmrem = _getPMREMFromTexture( texture ); } - for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - - const sho = newShapeHoles[ sIdx ]; + if ( pmrem !== null ) { - for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) { + this._pmrem = pmrem; - const ho = sho[ hIdx ]; - let hole_unassigned = true; + this.updateFromTexture( pmrem ); - for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { + } - if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { + } - if ( sIdx !== s2Idx ) toChange ++; + } - if ( hole_unassigned ) { + setup( builder ) { - hole_unassigned = false; - betterShapeHoles[ s2Idx ].push( ho ); + if ( _generator === null ) { - } else { + _generator = builder.createPMREMGenerator(); - ambiguous = true; + } - } + // - } + this.updateBefore( builder ); - } + // - if ( hole_unassigned ) { + let uvNode = this.uvNode; - betterShapeHoles[ sIdx ].push( ho ); + if ( uvNode === null && builder.context.getUV ) { - } + uvNode = builder.context.getUV( this ); - } + } - } + // - if ( toChange > 0 && ambiguous === false ) { + const texture = this.value; - newShapeHoles = betterShapeHoles; + if ( builder.renderer.coordinateSystem === WebGLCoordinateSystem && texture.isPMREMTexture !== true && texture.isRenderTargetTexture === true ) { - } + uvNode = vec3( uvNode.x.negate(), uvNode.yz ); } - let tmpHoles; - - for ( let i = 0, il = newShapes.length; i < il; i ++ ) { - - tmpShape = newShapes[ i ].s; - shapes.push( tmpShape ); - tmpHoles = newShapeHoles[ i ]; + // - for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) { + let levelNode = this.levelNode; - tmpShape.holes.push( tmpHoles[ j ].h ); + if ( levelNode === null && builder.context.getTextureLevel ) { - } + levelNode = builder.context.getTextureLevel( this ); } - //console.log("shape", shapes); + // - return shapes; + return textureCubeUV( this._texture, uvNode, levelNode, this._width, this._height, this._maxMip ); } } -class Controls extends EventDispatcher { +function isCubeMapReady( image ) { - constructor( object, domElement ) { + if ( image === null || image === undefined ) return false; - super(); + let count = 0; + const length = 6; - this.object = object; - this.domElement = domElement; + for ( let i = 0; i < length; i ++ ) { - this.enabled = true; + if ( image[ i ] !== undefined ) count ++; - this.state = - 1; + } - this.keys = {}; - this.mouseButtons = { LEFT: null, MIDDLE: null, RIGHT: null }; - this.touches = { ONE: null, TWO: null }; + return count === length; - } - connect() {} +} - disconnect() {} +function isEquirectangularMapReady( image ) { - dispose() {} + if ( image === null || image === undefined ) return false; - update( /* delta */ ) {} + return image.height > 0; } -class WebGLMultipleRenderTargets extends WebGLRenderTarget { // @deprecated, r162 +const pmremTexture = /*@__PURE__*/ nodeProxy( PMREMNode ); - constructor( width = 1, height = 1, count = 1, options = {} ) { +const _envNodeCache = new WeakMap(); - console.warn( 'THREE.WebGLMultipleRenderTargets has been deprecated and will be removed in r172. Use THREE.WebGLRenderTarget and set the "count" parameter to enable MRT.' ); +class EnvironmentNode extends LightingNode { - super( width, height, { ...options, count } ); + static get type() { - this.isWebGLMultipleRenderTargets = true; + return 'EnvironmentNode'; } - get texture() { + constructor( envNode = null ) { - return this.textures; + super(); + + this.envNode = envNode; } -} + setup( builder ) { -class Animation { + const { material } = builder; - constructor( nodes, info ) { + let envNode = this.envNode; - this.nodes = nodes; - this.info = info; + if ( envNode.isTextureNode || envNode.isMaterialReferenceNode ) { - this.animationLoop = null; - this.requestId = null; + const value = ( envNode.isTextureNode ) ? envNode.value : material[ envNode.property ]; - this._init(); + let cacheEnvNode = _envNodeCache.get( value ); - } + if ( cacheEnvNode === undefined ) { - _init() { - - const update = ( time, frame ) => { + cacheEnvNode = pmremTexture( value ); - this.requestId = self.requestAnimationFrame( update ); + _envNodeCache.set( value, cacheEnvNode ); - if ( this.info.autoReset === true ) this.info.reset(); + } - this.nodes.nodeFrame.update(); + envNode = cacheEnvNode; - this.info.frame = this.nodes.nodeFrame.frameId; + } - if ( this.animationLoop !== null ) this.animationLoop( time, frame ); + // - }; + const envMap = material.envMap; + const intensity = envMap ? reference( 'envMapIntensity', 'float', builder.material ) : reference( 'environmentIntensity', 'float', builder.scene ); // @TODO: Add materialEnvIntensity in MaterialNode - update(); + const useAnisotropy = material.useAnisotropy === true || material.anisotropy > 0; + const radianceNormalView = useAnisotropy ? transformedBentNormalView : transformedNormalView; - } + const radiance = envNode.context( createRadianceContext( roughness, radianceNormalView ) ).mul( intensity ); + const irradiance = envNode.context( createIrradianceContext( transformedNormalWorld ) ).mul( Math.PI ).mul( intensity ); - dispose() { + const isolateRadiance = cache( radiance ); + const isolateIrradiance = cache( irradiance ); - self.cancelAnimationFrame( this.requestId ); - this.requestId = null; + // - } + builder.context.radiance.addAssign( isolateRadiance ); - setAnimationLoop( callback ) { + builder.context.iblIrradiance.addAssign( isolateIrradiance ); - this.animationLoop = callback; + // - } + const clearcoatRadiance = builder.context.lightingModel.clearcoatRadiance; -} + if ( clearcoatRadiance ) { -class ChainMap { + const clearcoatRadianceContext = envNode.context( createRadianceContext( clearcoatRoughness, transformedClearcoatNormalView ) ).mul( intensity ); + const isolateClearcoatRadiance = cache( clearcoatRadianceContext ); - constructor() { + clearcoatRadiance.addAssign( isolateClearcoatRadiance ); - this.weakMap = new WeakMap(); + } } - get( keys ) { +} - let map = this.weakMap; +const createRadianceContext = ( roughnessNode, normalViewNode ) => { - for ( let i = 0; i < keys.length; i ++ ) { + let reflectVec = null; - map = map.get( keys[ i ] ); + return { + getUV: () => { - if ( map === undefined ) return undefined; + if ( reflectVec === null ) { - } + reflectVec = positionViewDirection.negate().reflect( normalViewNode ); - return map.get( keys[ keys.length - 1 ] ); + // Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane. + reflectVec = roughnessNode.mul( roughnessNode ).mix( reflectVec, normalViewNode ).normalize(); - } + reflectVec = reflectVec.transformDirection( cameraViewMatrix ); - set( keys, value ) { + } - let map = this.weakMap; + return reflectVec; - for ( let i = 0; i < keys.length; i ++ ) { + }, + getTextureLevel: () => { - const key = keys[ i ]; + return roughnessNode; - if ( map.has( key ) === false ) map.set( key, new WeakMap() ); + } + }; - map = map.get( key ); +}; - } +const createIrradianceContext = ( normalWorldNode ) => { - return map.set( keys[ keys.length - 1 ], value ); + return { + getUV: () => { - } + return normalWorldNode; - delete( keys ) { + }, + getTextureLevel: () => { - let map = this.weakMap; + return float( 1.0 ); - for ( let i = 0; i < keys.length; i ++ ) { + } + }; - map = map.get( keys[ i ] ); +}; - if ( map === undefined ) return false; +const _defaultValues$6 = /*@__PURE__*/ new MeshStandardMaterial(); - } +class MeshStandardNodeMaterial extends NodeMaterial { - return map.delete( keys[ keys.length - 1 ] ); + static get type() { - } + return 'MeshStandardNodeMaterial'; -} + } -const _plane = /*@__PURE__*/ new Plane(); + constructor( parameters ) { -class ClippingContext { + super(); - constructor() { + this.isMeshStandardNodeMaterial = true; - this.version = 0; + this.lights = true; - this.globalClippingCount = 0; + this.emissiveNode = null; - this.localClippingCount = 0; - this.localClippingEnabled = false; - this.localClipIntersection = false; + this.metalnessNode = null; + this.roughnessNode = null; - this.planes = []; + this.setDefaultValues( _defaultValues$6 ); - this.parentVersion = 0; - this.viewNormalMatrix = new Matrix3(); - this.cacheKey = ''; + this.setValues( parameters ); } - projectPlanes( source, offset ) { + setupEnvironment( builder ) { - const l = source.length; - const planes = this.planes; + let envNode = super.setupEnvironment( builder ); - for ( let i = 0; i < l; i ++ ) { + if ( envNode === null && builder.environmentNode ) { - _plane.copy( source[ i ] ).applyMatrix4( this.viewMatrix, this.viewNormalMatrix ); + envNode = builder.environmentNode; - const v = planes[ offset + i ]; - const normal = _plane.normal; + } - v.x = - normal.x; - v.y = - normal.y; - v.z = - normal.z; - v.w = _plane.constant; + return envNode ? new EnvironmentNode( envNode ) : null; - } + } + + setupLightingModel( /*builder*/ ) { + + return new PhysicalLightingModel(); } - updateGlobal( renderer, camera ) { + setupSpecular() { - const rendererClippingPlanes = renderer.clippingPlanes; - this.viewMatrix = camera.matrixWorldInverse; + const specularColorNode = mix( vec3( 0.04 ), diffuseColor.rgb, metalness ); - this.viewNormalMatrix.getNormalMatrix( this.viewMatrix ); + specularColor.assign( specularColorNode ); + specularF90.assign( 1.0 ); - let update = false; + } - if ( Array.isArray( rendererClippingPlanes ) && rendererClippingPlanes.length !== 0 ) { + setupVariants() { - const l = rendererClippingPlanes.length; + // METALNESS - if ( l !== this.globalClippingCount ) { + const metalnessNode = this.metalnessNode ? float( this.metalnessNode ) : materialMetalness; - const planes = []; + metalness.assign( metalnessNode ); - for ( let i = 0; i < l; i ++ ) { + // ROUGHNESS - planes.push( new Vector4() ); + let roughnessNode = this.roughnessNode ? float( this.roughnessNode ) : materialRoughness; + roughnessNode = getRoughness( { roughness: roughnessNode } ); - } + roughness.assign( roughnessNode ); - this.globalClippingCount = l; - this.planes = planes; + // SPECULAR COLOR - update = true; + this.setupSpecular(); - } + // DIFFUSE COLOR - this.projectPlanes( rendererClippingPlanes, 0 ); + diffuseColor.assign( vec4( diffuseColor.rgb.mul( metalnessNode.oneMinus() ), diffuseColor.a ) ); - } else if ( this.globalClippingCount !== 0 ) { + } - this.globalClippingCount = 0; - this.planes = []; - update = true; + copy( source ) { - } + this.emissiveNode = source.emissiveNode; - if ( renderer.localClippingEnabled !== this.localClippingEnabled ) { + this.metalnessNode = source.metalnessNode; + this.roughnessNode = source.roughnessNode; - this.localClippingEnabled = renderer.localClippingEnabled; - update = true; + return super.copy( source ); - } + } - if ( update ) { +} - this.version ++; - this.cacheKey = `${ this.globalClippingCount }:${ this.localClippingEnabled === undefined ? false : this.localClippingEnabled }:`; +const _defaultValues$5 = /*@__PURE__*/ new MeshPhysicalMaterial(); - } +class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { + + static get type() { + + return 'MeshPhysicalNodeMaterial'; } - update( parent, material ) { + constructor( parameters ) { - let update = false; + super(); - if ( this !== parent && parent.version !== this.parentVersion ) { + this.isMeshPhysicalNodeMaterial = true; - this.globalClippingCount = material.isShadowNodeMaterial ? 0 : parent.globalClippingCount; - this.localClippingEnabled = parent.localClippingEnabled; - this.planes = Array.from( parent.planes ); - this.parentVersion = parent.version; - this.viewMatrix = parent.viewMatrix; - this.viewNormalMatrix = parent.viewNormalMatrix; + this.clearcoatNode = null; + this.clearcoatRoughnessNode = null; + this.clearcoatNormalNode = null; - update = true; + this.sheenNode = null; + this.sheenRoughnessNode = null; - } + this.iridescenceNode = null; + this.iridescenceIORNode = null; + this.iridescenceThicknessNode = null; - if ( this.localClippingEnabled ) { + this.specularIntensityNode = null; + this.specularColorNode = null; - const localClippingPlanes = material.clippingPlanes; + this.iorNode = null; + this.transmissionNode = null; + this.thicknessNode = null; + this.attenuationDistanceNode = null; + this.attenuationColorNode = null; + this.dispersionNode = null; - if ( ( Array.isArray( localClippingPlanes ) && localClippingPlanes.length !== 0 ) ) { + this.anisotropyNode = null; - const l = localClippingPlanes.length; - const planes = this.planes; - const offset = this.globalClippingCount; + this.setDefaultValues( _defaultValues$5 ); - if ( update || l !== this.localClippingCount ) { + this.setValues( parameters ); - planes.length = offset + l; + } - for ( let i = 0; i < l; i ++ ) { + get useClearcoat() { - planes[ offset + i ] = new Vector4(); + return this.clearcoat > 0 || this.clearcoatNode !== null; - } + } - this.localClippingCount = l; - update = true; + get useIridescence() { - } + return this.iridescence > 0 || this.iridescenceNode !== null; - this.projectPlanes( localClippingPlanes, offset ); + } + get useSheen() { - } else if ( this.localClippingCount !== 0 ) { + return this.sheen > 0 || this.sheenNode !== null; - this.localClippingCount = 0; - update = true; + } - } + get useAnisotropy() { - if ( this.localClipIntersection !== material.clipIntersection ) { + return this.anisotropy > 0 || this.anisotropyNode !== null; - this.localClipIntersection = material.clipIntersection; - update = true; + } - } + get useTransmission() { - } + return this.transmission > 0 || this.transmissionNode !== null; - if ( update ) { + } - this.version += parent.version; - this.cacheKey = parent.cacheKey + `:${ this.localClippingCount }:${ this.localClipIntersection === undefined ? false : this.localClipIntersection }`; + get useDispersion() { - } + return this.dispersion > 0 || this.dispersionNode !== null; } -} - -let _id$7 = 0; + setupSpecular() { -function getKeys( obj ) { + const iorNode = this.iorNode ? float( this.iorNode ) : materialIOR; - const keys = Object.keys( obj ); + ior.assign( iorNode ); + specularColor.assign( mix( min$1( pow2( ior.sub( 1.0 ).div( ior.add( 1.0 ) ) ).mul( materialSpecularColor ), vec3( 1.0 ) ).mul( materialSpecularIntensity ), diffuseColor.rgb, metalness ) ); + specularF90.assign( mix( materialSpecularIntensity, 1.0, metalness ) ); - let proto = Object.getPrototypeOf( obj ); + } - while ( proto ) { + setupLightingModel( /*builder*/ ) { - const descriptors = Object.getOwnPropertyDescriptors( proto ); + return new PhysicalLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion ); - for ( const key in descriptors ) { + } - if ( descriptors[ key ] !== undefined ) { + setupVariants( builder ) { - const descriptor = descriptors[ key ]; + super.setupVariants( builder ); - if ( descriptor && typeof descriptor.get === 'function' ) { + // CLEARCOAT - keys.push( key ); + if ( this.useClearcoat ) { - } + const clearcoatNode = this.clearcoatNode ? float( this.clearcoatNode ) : materialClearcoat; + const clearcoatRoughnessNode = this.clearcoatRoughnessNode ? float( this.clearcoatRoughnessNode ) : materialClearcoatRoughness; - } + clearcoat.assign( clearcoatNode ); + clearcoatRoughness.assign( getRoughness( { roughness: clearcoatRoughnessNode } ) ); } - proto = Object.getPrototypeOf( proto ); + // SHEEN - } + if ( this.useSheen ) { - return keys; + const sheenNode = this.sheenNode ? vec3( this.sheenNode ) : materialSheen; + const sheenRoughnessNode = this.sheenRoughnessNode ? float( this.sheenRoughnessNode ) : materialSheenRoughness; -} + sheen.assign( sheenNode ); + sheenRoughness.assign( sheenRoughnessNode ); -class RenderObject { + } - constructor( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext ) { + // IRIDESCENCE - this._nodes = nodes; - this._geometries = geometries; + if ( this.useIridescence ) { - this.id = _id$7 ++; + const iridescenceNode = this.iridescenceNode ? float( this.iridescenceNode ) : materialIridescence; + const iridescenceIORNode = this.iridescenceIORNode ? float( this.iridescenceIORNode ) : materialIridescenceIOR; + const iridescenceThicknessNode = this.iridescenceThicknessNode ? float( this.iridescenceThicknessNode ) : materialIridescenceThickness; - this.renderer = renderer; - this.object = object; - this.material = material; - this.scene = scene; - this.camera = camera; - this.lightsNode = lightsNode; - this.context = renderContext; + iridescence.assign( iridescenceNode ); + iridescenceIOR.assign( iridescenceIORNode ); + iridescenceThickness.assign( iridescenceThicknessNode ); - this.geometry = object.geometry; - this.version = material.version; + } - this.drawRange = null; + // ANISOTROPY - this.attributes = null; - this.pipeline = null; - this.vertexBuffers = null; + if ( this.useAnisotropy ) { - this.updateClipping( renderContext.clippingContext ); + const anisotropyV = ( this.anisotropyNode ? vec2( this.anisotropyNode ) : materialAnisotropy ).toVar(); - this.clippingContextVersion = this.clippingContext.version; + anisotropy.assign( anisotropyV.length() ); - this.initialNodesCacheKey = this.getDynamicCacheKey(); - this.initialCacheKey = this.getCacheKey(); + If( anisotropy.equal( 0.0 ), () => { - this._nodeBuilderState = null; - this._bindings = null; + anisotropyV.assign( vec2( 1.0, 0.0 ) ); - this.onDispose = null; + } ).Else( () => { - this.isRenderObject = true; + anisotropyV.divAssign( vec2( anisotropy ) ); + anisotropy.assign( anisotropy.saturate() ); - this.onMaterialDispose = () => { + } ); - this.dispose(); + // Roughness along the anisotropy bitangent is the material roughness, while the tangent roughness increases with anisotropy. + alphaT.assign( anisotropy.pow2().mix( roughness.pow2(), 1.0 ) ); - }; + anisotropyT.assign( TBNViewMatrix[ 0 ].mul( anisotropyV.x ).add( TBNViewMatrix[ 1 ].mul( anisotropyV.y ) ) ); + anisotropyB.assign( TBNViewMatrix[ 1 ].mul( anisotropyV.x ).sub( TBNViewMatrix[ 0 ].mul( anisotropyV.y ) ) ); - this.material.addEventListener( 'dispose', this.onMaterialDispose ); + } - } + // TRANSMISSION - updateClipping( parent ) { + if ( this.useTransmission ) { - const material = this.material; + const transmissionNode = this.transmissionNode ? float( this.transmissionNode ) : materialTransmission; + const thicknessNode = this.thicknessNode ? float( this.thicknessNode ) : materialThickness; + const attenuationDistanceNode = this.attenuationDistanceNode ? float( this.attenuationDistanceNode ) : materialAttenuationDistance; + const attenuationColorNode = this.attenuationColorNode ? vec3( this.attenuationColorNode ) : materialAttenuationColor; - let clippingContext = this.clippingContext; + transmission.assign( transmissionNode ); + thickness.assign( thicknessNode ); + attenuationDistance.assign( attenuationDistanceNode ); + attenuationColor.assign( attenuationColorNode ); - if ( Array.isArray( material.clippingPlanes ) ) { + if ( this.useDispersion ) { - if ( clippingContext === parent || ! clippingContext ) { + const dispersionNode = this.dispersionNode ? float( this.dispersionNode ) : materialDispersion; - clippingContext = new ClippingContext(); - this.clippingContext = clippingContext; + dispersion.assign( dispersionNode ); } - clippingContext.update( parent, material ); + } - } else if ( this.clippingContext !== parent ) { + } - this.clippingContext = parent; + setupClearcoatNormal() { - } + return this.clearcoatNormalNode ? vec3( this.clearcoatNormalNode ) : materialClearcoatNormal; } - get clippingNeedsUpdate() { - - if ( this.clippingContext.version === this.clippingContextVersion ) return false; + setup( builder ) { - this.clippingContextVersion = this.clippingContext.version; + builder.context.setupClearcoatNormal = () => this.setupClearcoatNormal( builder ); - return true; + super.setup( builder ); } - getNodeBuilderState() { + copy( source ) { - return this._nodeBuilderState || ( this._nodeBuilderState = this._nodes.getForRender( this ) ); + this.clearcoatNode = source.clearcoatNode; + this.clearcoatRoughnessNode = source.clearcoatRoughnessNode; + this.clearcoatNormalNode = source.clearcoatNormalNode; - } + this.sheenNode = source.sheenNode; + this.sheenRoughnessNode = source.sheenRoughnessNode; - getBindings() { + this.iridescenceNode = source.iridescenceNode; + this.iridescenceIORNode = source.iridescenceIORNode; + this.iridescenceThicknessNode = source.iridescenceThicknessNode; - return this._bindings || ( this._bindings = this.getNodeBuilderState().createBindings() ); + this.specularIntensityNode = source.specularIntensityNode; + this.specularColorNode = source.specularColorNode; - } + this.transmissionNode = source.transmissionNode; + this.thicknessNode = source.thicknessNode; + this.attenuationDistanceNode = source.attenuationDistanceNode; + this.attenuationColorNode = source.attenuationColorNode; + this.dispersionNode = source.dispersionNode; - getIndex() { + this.anisotropyNode = source.anisotropyNode; - return this._geometries.getIndex( this ); + return super.copy( source ); } - getChainArray() { +} - return [ this.object, this.material, this.context, this.lightsNode ]; +class SSSLightingModel extends PhysicalLightingModel { - } + constructor( useClearcoat, useSheen, useIridescence, useSSS ) { - getAttributes() { + super( useClearcoat, useSheen, useIridescence ); - if ( this.attributes !== null ) return this.attributes; + this.useSSS = useSSS; - const nodeAttributes = this.getNodeBuilderState().nodeAttributes; - const geometry = this.geometry; + } - const attributes = []; - const vertexBuffers = new Set(); + direct( { lightDirection, lightColor, reflectedLight }, stack, builder ) { - for ( const nodeAttribute of nodeAttributes ) { + if ( this.useSSS === true ) { - const attribute = nodeAttribute.node && nodeAttribute.node.attribute ? nodeAttribute.node.attribute : geometry.getAttribute( nodeAttribute.name ); + const material = builder.material; - if ( attribute === undefined ) continue; + const { thicknessColorNode, thicknessDistortionNode, thicknessAmbientNode, thicknessAttenuationNode, thicknessPowerNode, thicknessScaleNode } = material; - attributes.push( attribute ); + const scatteringHalf = lightDirection.add( transformedNormalView.mul( thicknessDistortionNode ) ).normalize(); + const scatteringDot = float( positionViewDirection.dot( scatteringHalf.negate() ).saturate().pow( thicknessPowerNode ).mul( thicknessScaleNode ) ); + const scatteringIllu = vec3( scatteringDot.add( thicknessAmbientNode ).mul( thicknessColorNode ) ); - const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute; - vertexBuffers.add( bufferAttribute ); + reflectedLight.directDiffuse.addAssign( scatteringIllu.mul( thicknessAttenuationNode.mul( lightColor ) ) ); } - this.attributes = attributes; - this.vertexBuffers = Array.from( vertexBuffers.values() ); - - return attributes; + super.direct( { lightDirection, lightColor, reflectedLight }, stack, builder ); } - getVertexBuffers() { - - if ( this.vertexBuffers === null ) this.getAttributes(); +} - return this.vertexBuffers; +class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial { - } + static get type() { - getMaterialCacheKey() { + return 'MeshSSSNodeMaterial'; - const { object, material } = this; + } - let cacheKey = material.customProgramCacheKey(); + constructor( parameters ) { - for ( const property of getKeys( material ) ) { + super( parameters ); - if ( /^(is[A-Z]|_)|^(visible|version|uuid|name|opacity|userData)$/.test( property ) ) continue; + this.thicknessColorNode = null; + this.thicknessDistortionNode = float( 0.1 ); + this.thicknessAmbientNode = float( 0.0 ); + this.thicknessAttenuationNode = float( .1 ); + this.thicknessPowerNode = float( 2.0 ); + this.thicknessScaleNode = float( 10.0 ); - const value = material[ property ]; + } - let valueKey; + get useSSS() { - if ( value !== null ) { + return this.thicknessColorNode !== null; - // some material values require a formatting + } - const type = typeof value; + setupLightingModel( /*builder*/ ) { - if ( type === 'number' ) { + return new SSSLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useSSS ); - valueKey = value !== 0 ? '1' : '0'; // Convert to on/off, important for clearcoat, transmission, etc + } - } else if ( type === 'object' ) { + copy( source ) { - valueKey = '{'; + this.thicknessColorNode = source.thicknessColorNode; + this.thicknessDistortionNode = source.thicknessDistortionNode; + this.thicknessAmbientNode = source.thicknessAmbientNode; + this.thicknessAttenuationNode = source.thicknessAttenuationNode; + this.thicknessPowerNode = source.thicknessPowerNode; + this.thicknessScaleNode = source.thicknessScaleNode; - if ( value.isTexture ) { + return super.copy( source ); - valueKey += value.mapping; + } - } +} - valueKey += '}'; +const getGradientIrradiance = /*@__PURE__*/ Fn( ( { normal, lightDirection, builder } ) => { - } else { + // dotNL will be from -1.0 to 1.0 + const dotNL = normal.dot( lightDirection ); + const coord = vec2( dotNL.mul( 0.5 ).add( 0.5 ), 0.0 ); - valueKey = String( value ); + if ( builder.material.gradientMap ) { - } + const gradientMap = materialReference( 'gradientMap', 'texture' ).context( { getUV: () => coord } ); - } else { + return vec3( gradientMap.r ); - valueKey = String( value ); + } else { - } + const fw = coord.fwidth().mul( 0.5 ); - cacheKey += /*property + ':' +*/ valueKey + ','; + return mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( float( 0.7 ).sub( fw.x ), float( 0.7 ).add( fw.x ), coord.x ) ); - } + } - cacheKey += this.clippingContext.cacheKey + ','; +} ); - if ( object.skeleton ) { +class ToonLightingModel extends LightingModel { - cacheKey += object.skeleton.bones.length + ','; + direct( { lightDirection, lightColor, reflectedLight }, stack, builder ) { - } + const irradiance = getGradientIrradiance( { normal: normalGeometry, lightDirection, builder } ).mul( lightColor ); - if ( object.morphTargetInfluences ) { + reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) ); - cacheKey += object.morphTargetInfluences.length + ','; + } - } + indirect( { ambientOcclusion, irradiance, reflectedLight } ) { - if ( object.isBatchedMesh ) { + reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) ); - cacheKey += object._matricesTexture.uuid + ','; + reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion ); - if ( object._colorsTexture !== null ) { + } - cacheKey += object._colorsTexture.uuid + ','; +} - } +const _defaultValues$4 = /*@__PURE__*/ new MeshToonMaterial(); - } +class MeshToonNodeMaterial extends NodeMaterial { - if ( object.count > 1 ) { + static get type() { - cacheKey += object.count + ',' + object.uuid + ','; + return 'MeshToonNodeMaterial'; - } + } - return cacheKey; + constructor( parameters ) { + + super(); + + this.isMeshToonNodeMaterial = true; + + this.lights = true; + + this.setDefaultValues( _defaultValues$4 ); + + this.setValues( parameters ); } - get needsUpdate() { + setupLightingModel( /*builder*/ ) { - return this.initialNodesCacheKey !== this.getDynamicCacheKey() || this.clippingNeedsUpdate; + return new ToonLightingModel(); } - getDynamicCacheKey() { +} - // Environment Nodes Cache Key +class MatcapUVNode extends TempNode { + + static get type() { - return this.object.receiveShadow + ',' + this._nodes.getCacheKey( this.scene, this.lightsNode ); + return 'MatcapUVNode'; } - getCacheKey() { + constructor() { - return this.getMaterialCacheKey() + ',' + this.getDynamicCacheKey(); + super( 'vec2' ); } - dispose() { + setup() { - this.material.removeEventListener( 'dispose', this.onMaterialDispose ); + const x = vec3( positionViewDirection.z, 0, positionViewDirection.x.negate() ).normalize(); + const y = positionViewDirection.cross( x ); - this.onDispose(); + return vec2( x.dot( transformedNormalView ), y.dot( transformedNormalView ) ).mul( 0.495 ).add( 0.5 ); // 0.495 to remove artifacts caused by undersized matcap disks } } -class RenderObjects { - - constructor( renderer, nodes, geometries, pipelines, bindings, info ) { +const matcapUV = /*@__PURE__*/ nodeImmutable( MatcapUVNode ); - this.renderer = renderer; - this.nodes = nodes; - this.geometries = geometries; - this.pipelines = pipelines; - this.bindings = bindings; - this.info = info; +const _defaultValues$3 = /*@__PURE__*/ new MeshMatcapMaterial(); - this.chainMaps = {}; +class MeshMatcapNodeMaterial extends NodeMaterial { - } + static get type() { - get( object, material, scene, camera, lightsNode, renderContext, passId ) { + return 'MeshMatcapNodeMaterial'; - const chainMap = this.getChainMap( passId ); - const chainArray = [ object, material, renderContext, lightsNode ]; + } - let renderObject = chainMap.get( chainArray ); + constructor( parameters ) { - if ( renderObject === undefined ) { + super(); - renderObject = this.createRenderObject( this.nodes, this.geometries, this.renderer, object, material, scene, camera, lightsNode, renderContext, passId ); + this.lights = false; - chainMap.set( chainArray, renderObject ); + this.isMeshMatcapNodeMaterial = true; - } else { + this.setDefaultValues( _defaultValues$3 ); - renderObject.updateClipping( renderContext.clippingContext ); + this.setValues( parameters ); - if ( renderObject.version !== material.version || renderObject.needsUpdate ) { + } - if ( renderObject.initialCacheKey !== renderObject.getCacheKey() ) { + setupVariants( builder ) { - renderObject.dispose(); + const uv = matcapUV; - renderObject = this.get( object, material, scene, camera, lightsNode, renderContext, passId ); + let matcapColor; - } else { + if ( builder.material.matcap ) { - renderObject.version = material.version; + matcapColor = materialReference( 'matcap', 'texture' ).context( { getUV: () => uv } ); - } + } else { - } + matcapColor = vec3( mix( 0.2, 0.8, uv.y ) ); // default if matcap is missing } - return renderObject; + diffuseColor.rgb.mulAssign( matcapColor.rgb ); } - getChainMap( passId = 'default' ) { +} - return this.chainMaps[ passId ] || ( this.chainMaps[ passId ] = new ChainMap() ); +const _defaultValues$2 = /*@__PURE__*/ new PointsMaterial(); - } +class PointsNodeMaterial extends NodeMaterial { - dispose() { + static get type() { - this.chainMaps = {}; + return 'PointsNodeMaterial'; } - createRenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, passId ) { - - const chainMap = this.getChainMap( passId ); + constructor( parameters ) { - const renderObject = new RenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext ); + super(); - renderObject.onDispose = () => { + this.isPointsNodeMaterial = true; - this.pipelines.delete( renderObject ); - this.bindings.delete( renderObject ); - this.nodes.delete( renderObject ); + this.lights = false; + this.transparent = true; - chainMap.delete( renderObject.getChainArray() ); + this.sizeNode = null; - }; + this.setDefaultValues( _defaultValues$2 ); - return renderObject; + this.setValues( parameters ); } + copy( source ) { -} + this.sizeNode = source.sizeNode; -class DataMap { + return super.copy( source ); - constructor() { + } - this.data = new WeakMap(); +} - } +class RotateNode extends TempNode { - get( object ) { + static get type() { - let map = this.data.get( object ); + return 'RotateNode'; - if ( map === undefined ) { + } - map = {}; - this.data.set( object, map ); + constructor( positionNode, rotationNode ) { - } + super(); - return map; + this.positionNode = positionNode; + this.rotationNode = rotationNode; } - delete( object ) { + getNodeType( builder ) { - let map; + return this.positionNode.getNodeType( builder ); - if ( this.data.has( object ) ) { + } - map = this.data.get( object ); + setup( builder ) { - this.data.delete( object ); + const { rotationNode, positionNode } = this; - } + const nodeType = this.getNodeType( builder ); - return map; + if ( nodeType === 'vec2' ) { - } + const cosAngle = rotationNode.cos(); + const sinAngle = rotationNode.sin(); - has( object ) { + const rotationMatrix = mat2( + cosAngle, sinAngle, + sinAngle.negate(), cosAngle + ); - return this.data.has( object ); + return rotationMatrix.mul( positionNode ); - } + } else { - dispose() { + const rotation = rotationNode; + const rotationXMatrix = mat4( vec4( 1.0, 0.0, 0.0, 0.0 ), vec4( 0.0, cos( rotation.x ), sin( rotation.x ).negate(), 0.0 ), vec4( 0.0, sin( rotation.x ), cos( rotation.x ), 0.0 ), vec4( 0.0, 0.0, 0.0, 1.0 ) ); + const rotationYMatrix = mat4( vec4( cos( rotation.y ), 0.0, sin( rotation.y ), 0.0 ), vec4( 0.0, 1.0, 0.0, 0.0 ), vec4( sin( rotation.y ).negate(), 0.0, cos( rotation.y ), 0.0 ), vec4( 0.0, 0.0, 0.0, 1.0 ) ); + const rotationZMatrix = mat4( vec4( cos( rotation.z ), sin( rotation.z ).negate(), 0.0, 0.0 ), vec4( sin( rotation.z ), cos( rotation.z ), 0.0, 0.0 ), vec4( 0.0, 0.0, 1.0, 0.0 ), vec4( 0.0, 0.0, 0.0, 1.0 ) ); - this.data = new WeakMap(); + return rotationXMatrix.mul( rotationYMatrix ).mul( rotationZMatrix ).mul( vec4( positionNode, 1.0 ) ).xyz; + + } } } -const AttributeType = { - VERTEX: 1, - INDEX: 2, - STORAGE: 4 -}; +const rotate = /*@__PURE__*/ nodeProxy( RotateNode ); -// size of a chunk in bytes (STD140 layout) +const _defaultValues$1 = /*@__PURE__*/ new SpriteMaterial(); -const GPU_CHUNK_BYTES = 16; +class SpriteNodeMaterial extends NodeMaterial { -// @TODO: Move to src/constants.js + static get type() { -const BlendColorFactor = 211; -const OneMinusBlendColorFactor = 212; + return 'SpriteNodeMaterial'; -class Attributes extends DataMap { + } - constructor( backend ) { + constructor( parameters ) { super(); - this.backend = backend; - - } - - delete( attribute ) { - - const attributeData = super.delete( attribute ); + this.isSpriteNodeMaterial = true; - if ( attributeData !== undefined ) { + this.lights = false; + this._useSizeAttenuation = true; - this.backend.destroyAttribute( attribute ); + this.positionNode = null; + this.rotationNode = null; + this.scaleNode = null; - } + this.setDefaultValues( _defaultValues$1 ); - return attributeData; + this.setValues( parameters ); } - update( attribute, type ) { + setupPosition( { object, camera, context } ) { - const data = this.get( attribute ); + const sizeAttenuation = this.sizeAttenuation; - if ( data.version === undefined ) { + // < VERTEX STAGE > - if ( type === AttributeType.VERTEX ) { + const { positionNode, rotationNode, scaleNode } = this; - this.backend.createAttribute( attribute ); + const vertex = positionLocal; - } else if ( type === AttributeType.INDEX ) { + let mvPosition = modelViewMatrix.mul( vec3( positionNode || 0 ) ); - this.backend.createIndexAttribute( attribute ); + let scale = vec2( modelWorldMatrix[ 0 ].xyz.length(), modelWorldMatrix[ 1 ].xyz.length() ); - } else if ( type === AttributeType.STORAGE ) { + if ( scaleNode !== null ) { - this.backend.createStorageAttribute( attribute ); + scale = scale.mul( scaleNode ); - } + } - data.version = this._getBufferAttribute( attribute ).version; - } else { + if ( ! sizeAttenuation && camera.isPerspectiveCamera ) { - const bufferAttribute = this._getBufferAttribute( attribute ); + scale = scale.mul( mvPosition.z.negate() ); - if ( data.version < bufferAttribute.version || bufferAttribute.usage === DynamicDrawUsage ) { + } - this.backend.updateAttribute( attribute ); + let alignedPosition = vertex.xy; - data.version = bufferAttribute.version; + if ( object.center && object.center.isVector2 === true ) { - } + const center = reference$1( 'center', 'vec2' ); + + alignedPosition = alignedPosition.sub( center.sub( 0.5 ) ); } - } + alignedPosition = alignedPosition.mul( scale ); - _getBufferAttribute( attribute ) { + const rotation = float( rotationNode || materialRotation ); - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; + const rotatedPosition = rotate( alignedPosition, rotation ); - return attribute; + mvPosition = vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw ); - } + const modelViewProjection = cameraProjectionMatrix.mul( mvPosition ); -} + context.vertex = vertex; -function arrayNeedsUint32( array ) { + return modelViewProjection; - // assumes larger values usually on last + } - for ( let i = array.length - 1; i >= 0; -- i ) { + copy( source ) { - if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 + this.positionNode = source.positionNode; + this.rotationNode = source.rotationNode; + this.scaleNode = source.scaleNode; + + return super.copy( source ); } - return false; + get sizeAttenuation() { -} + return this._useSizeAttenuation; -function getWireframeVersion( geometry ) { + } - return ( geometry.index !== null ) ? geometry.index.version : geometry.attributes.position.version; + set sizeAttenuation( value ) { -} + if ( this._useSizeAttenuation !== value ) { -function getWireframeIndex( geometry ) { + this._useSizeAttenuation = value; + this.needsUpdate = true; - const indices = []; + } - const geometryIndex = geometry.index; - const geometryPosition = geometry.attributes.position; + } - if ( geometryIndex !== null ) { +} - const array = geometryIndex.array; +class ShadowMaskModel extends LightingModel { - for ( let i = 0, l = array.length; i < l; i += 3 ) { + constructor() { - const a = array[ i + 0 ]; - const b = array[ i + 1 ]; - const c = array[ i + 2 ]; + super(); - indices.push( a, b, b, c, c, a ); + this.shadowNode = float( 1 ).toVar( 'shadowMask' ); - } + } - } else { + direct( { shadowMask } ) { - const array = geometryPosition.array; + this.shadowNode.mulAssign( shadowMask ); - for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { + } - const a = i + 0; - const b = i + 1; - const c = i + 2; + finish( context ) { - indices.push( a, b, b, c, c, a ); + diffuseColor.a.mulAssign( this.shadowNode.oneMinus() ); - } + context.outgoingLight.rgb.assign( diffuseColor.rgb ); // TODO: Optimize LightsNode to avoid this assignment } - const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); - attribute.version = getWireframeVersion( geometry ); - - return attribute; - } -class Geometries extends DataMap { +const _defaultValues = /*@__PURE__*/ new ShadowMaterial(); - constructor( attributes, info ) { +class ShadowNodeMaterial extends NodeMaterial { - super(); + static get type() { - this.attributes = attributes; - this.info = info; + return 'ShadowNodeMaterial'; - this.wireframes = new WeakMap(); + } - this.attributeCall = new WeakMap(); + constructor( parameters ) { - } + super(); - has( renderObject ) { + this.isShadowNodeMaterial = true; - const geometry = renderObject.geometry; + this.lights = true; - return super.has( geometry ) && this.get( geometry ).initialized === true; + this.setDefaultValues( _defaultValues ); - } + this.setValues( parameters ); - updateForRender( renderObject ) { + } - if ( this.has( renderObject ) === false ) this.initGeometry( renderObject ); + setupLightingModel( /*builder*/ ) { - this.updateAttributes( renderObject ); + return new ShadowMaskModel(); } - initGeometry( renderObject ) { +} - const geometry = renderObject.geometry; - const geometryData = this.get( geometry ); +const normal = Fn( ( { texture, uv } ) => { - geometryData.initialized = true; + const epsilon = 0.0001; - this.info.memory.geometries ++; + const ret = vec3().toVar(); - const onDispose = () => { + If( uv.x.lessThan( epsilon ), () => { - this.info.memory.geometries --; + ret.assign( vec3( 1, 0, 0 ) ); - const index = geometry.index; - const geometryAttributes = renderObject.getAttributes(); + } ).ElseIf( uv.y.lessThan( epsilon ), () => { - if ( index !== null ) { + ret.assign( vec3( 0, 1, 0 ) ); - this.attributes.delete( index ); + } ).ElseIf( uv.z.lessThan( epsilon ), () => { - } + ret.assign( vec3( 0, 0, 1 ) ); - for ( const geometryAttribute of geometryAttributes ) { + } ).ElseIf( uv.x.greaterThan( 1 - epsilon ), () => { - this.attributes.delete( geometryAttribute ); + ret.assign( vec3( - 1, 0, 0 ) ); - } + } ).ElseIf( uv.y.greaterThan( 1 - epsilon ), () => { - const wireframeAttribute = this.wireframes.get( geometry ); + ret.assign( vec3( 0, - 1, 0 ) ); - if ( wireframeAttribute !== undefined ) { + } ).ElseIf( uv.z.greaterThan( 1 - epsilon ), () => { - this.attributes.delete( wireframeAttribute ); + ret.assign( vec3( 0, 0, - 1 ) ); - } + } ).Else( () => { - geometry.removeEventListener( 'dispose', onDispose ); + const step = 0.01; - }; + const x = texture.uv( uv.add( vec3( - step, 0.0, 0.0 ) ) ).r.sub( texture.uv( uv.add( vec3( step, 0.0, 0.0 ) ) ).r ); + const y = texture.uv( uv.add( vec3( 0.0, - step, 0.0 ) ) ).r.sub( texture.uv( uv.add( vec3( 0.0, step, 0.0 ) ) ).r ); + const z = texture.uv( uv.add( vec3( 0.0, 0.0, - step ) ) ).r.sub( texture.uv( uv.add( vec3( 0.0, 0.0, step ) ) ).r ); - geometry.addEventListener( 'dispose', onDispose ); + ret.assign( vec3( x, y, z ) ); - } + } ); - updateAttributes( renderObject ) { + return ret.normalize(); - const attributes = renderObject.getAttributes(); +} ); - for ( const attribute of attributes ) { - if ( attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute ) { +class Texture3DNode extends TextureNode { - this.updateAttribute( attribute, AttributeType.STORAGE ); + static get type() { - } else { + return 'Texture3DNode'; - this.updateAttribute( attribute, AttributeType.VERTEX ); + } - } + constructor( value, uvNode = null, levelNode = null ) { - } + super( value, uvNode, levelNode ); - const index = this.getIndex( renderObject ); + this.isTexture3DNode = true; - if ( index !== null ) { + } - this.updateAttribute( index, AttributeType.INDEX ); + getInputType( /*builder*/ ) { - } + return 'texture3D'; } - updateAttribute( attribute, type ) { + getDefaultUV() { - const callId = this.info.render.calls; + return vec3( 0.5, 0.5, 0.5 ); - if ( ! attribute.isInterleavedBufferAttribute ) { + } - if ( this.attributeCall.get( attribute ) !== callId ) { + setUpdateMatrix( /*updateMatrix*/ ) { } // Ignore .updateMatrix for 3d TextureNode - this.attributes.update( attribute, type ); + setupUV( builder, uvNode ) { - this.attributeCall.set( attribute, callId ); + return uvNode; - } + } - } else { + generateUV( builder, uvNode ) { - if ( this.attributeCall.get( attribute ) === undefined ) { + return uvNode.build( builder, 'vec3' ); - this.attributes.update( attribute, type ); + } - this.attributeCall.set( attribute, callId ); + normal( uvNode ) { - } else if ( this.attributeCall.get( attribute.data ) !== callId ) { + return normal( { texture: this, uv: uvNode } ); - this.attributes.update( attribute, type ); + } - this.attributeCall.set( attribute.data, callId ); +} - this.attributeCall.set( attribute, callId ); +const texture3D = /*@__PURE__*/ nodeProxy( Texture3DNode ); - } +class VolumeNodeMaterial extends NodeMaterial { - } + static get type() { - } + return 'VolumeNodeMaterial'; - getIndex( renderObject ) { + } - const { geometry, material } = renderObject; + constructor( params = {} ) { - let index = geometry.index; + super(); - if ( material.wireframe === true ) { + this.lights = false; + this.isVolumeNodeMaterial = true; + this.testNode = null; - const wireframes = this.wireframes; + this.setValues( params ); - let wireframeAttribute = wireframes.get( geometry ); + } - if ( wireframeAttribute === undefined ) { + setup( builder ) { - wireframeAttribute = getWireframeIndex( geometry ); + const map = texture3D( this.map, null, 0 ); - wireframes.set( geometry, wireframeAttribute ); + const hitBox = Fn( ( { orig, dir } ) => { - } else if ( wireframeAttribute.version !== getWireframeVersion( geometry ) ) { + const box_min = vec3( - 0.5 ); + const box_max = vec3( 0.5 ); - this.attributes.delete( wireframeAttribute ); + const inv_dir = dir.reciprocal(); - wireframeAttribute = getWireframeIndex( geometry ); + const tmin_tmp = box_min.sub( orig ).mul( inv_dir ); + const tmax_tmp = box_max.sub( orig ).mul( inv_dir ); - wireframes.set( geometry, wireframeAttribute ); + const tmin = min$1( tmin_tmp, tmax_tmp ); + const tmax = max$1( tmin_tmp, tmax_tmp ); - } + const t0 = max$1( tmin.x, max$1( tmin.y, tmin.z ) ); + const t1 = min$1( tmax.x, min$1( tmax.y, tmax.z ) ); - index = wireframeAttribute; + return vec2( t0, t1 ); - } + } ); - return index; + this.fragmentNode = Fn( () => { - } + const vOrigin = varying( vec3( modelWorldMatrixInverse.mul( vec4( cameraPosition, 1.0 ) ) ) ); + const vDirection = varying( positionGeometry.sub( vOrigin ) ); -} + const rayDir = vDirection.normalize(); + const bounds = vec2( hitBox( { orig: vOrigin, dir: rayDir } ) ).toVar(); -class Info { + bounds.x.greaterThan( bounds.y ).discard(); - constructor() { + bounds.assign( vec2( max$1( bounds.x, 0.0 ), bounds.y ) ); - this.autoReset = true; + const p = vec3( vOrigin.add( bounds.x.mul( rayDir ) ) ).toVar(); + const inc = vec3( rayDir.abs().reciprocal() ).toVar(); + const delta = float( min$1( inc.x, min$1( inc.y, inc.z ) ) ).toVar( 'delta' ); // used 'delta' name in loop - this.frame = 0; - this.calls = 0; + delta.divAssign( materialReference( 'steps', 'float' ) ); - this.render = { - calls: 0, - frameCalls: 0, - drawCalls: 0, - triangles: 0, - points: 0, - lines: 0, - timestamp: 0, - previousFrameCalls: 0, - timestampCalls: 0 - }; + const ac = vec4( materialReference( 'base', 'color' ), 0.0 ).toVar(); - this.compute = { - calls: 0, - frameCalls: 0, - timestamp: 0, - previousFrameCalls: 0, - timestampCalls: 0 - }; + Loop( { type: 'float', start: bounds.x, end: bounds.y, update: '+= delta' }, () => { - this.memory = { - geometries: 0, - textures: 0 - }; + const d = property( 'float', 'd' ).assign( map.uv( p.add( 0.5 ) ).r ); - } + if ( this.testNode !== null ) { - update( object, count, instanceCount ) { + this.testNode( { map: map, mapValue: d, probe: p, finalColor: ac } ).append(); - this.render.drawCalls ++; + } else { - if ( object.isMesh || object.isSprite ) { + // default to show surface of mesh + ac.a.assign( 1 ); + Break(); - this.render.triangles += instanceCount * ( count / 3 ); + } - } else if ( object.isPoints ) { + p.addAssign( rayDir.mul( delta ) ); - this.render.points += instanceCount * count; + } ); - } else if ( object.isLineSegments ) { + ac.a.equal( 0 ).discard(); - this.render.lines += instanceCount * ( count / 2 ); + return vec4( ac ); - } else if ( object.isLine ) { + } )(); - this.render.lines += instanceCount * ( count - 1 ); + super.setup( builder ); - } else { + } - console.error( 'THREE.WebGPUInfo: Unknown object type.' ); +} - } +class Animation { + + constructor( nodes, info ) { + + this.nodes = nodes; + this.info = info; + + this.animationLoop = null; + this.requestId = null; + + this._init(); } - updateTimestamp( type, time ) { + _init() { - if ( this[ type ].timestampCalls === 0 ) { + const update = ( time, frame ) => { - this[ type ].timestamp = 0; + this.requestId = self.requestAnimationFrame( update ); - } + if ( this.info.autoReset === true ) this.info.reset(); + this.nodes.nodeFrame.update(); - this[ type ].timestamp += time; + this.info.frame = this.nodes.nodeFrame.frameId; - this[ type ].timestampCalls ++; + if ( this.animationLoop !== null ) this.animationLoop( time, frame ); + }; - if ( this[ type ].timestampCalls >= this[ type ].previousFrameCalls ) { + update(); - this[ type ].timestampCalls = 0; + } - } + dispose() { + self.cancelAnimationFrame( this.requestId ); + this.requestId = null; } - reset() { + setAnimationLoop( callback ) { - const previousRenderFrameCalls = this.render.frameCalls; - this.render.previousFrameCalls = previousRenderFrameCalls; + this.animationLoop = callback; - const previousComputeFrameCalls = this.compute.frameCalls; - this.compute.previousFrameCalls = previousComputeFrameCalls; + } +} - this.render.drawCalls = 0; - this.render.frameCalls = 0; - this.compute.frameCalls = 0; +class ChainMap { - this.render.triangles = 0; - this.render.points = 0; - this.render.lines = 0; + constructor() { + this.weakMap = new WeakMap(); } - dispose() { - - this.reset(); + get( keys ) { - this.calls = 0; + let map = this.weakMap; - this.render.calls = 0; - this.compute.calls = 0; + for ( let i = 0; i < keys.length; i ++ ) { - this.render.timestamp = 0; - this.compute.timestamp = 0; - this.memory.geometries = 0; - this.memory.textures = 0; + map = map.get( keys[ i ] ); - } + if ( map === undefined ) return undefined; -} + } -class Pipeline { + return map.get( keys[ keys.length - 1 ] ); - constructor( cacheKey ) { + } - this.cacheKey = cacheKey; + set( keys, value ) { - this.usedTimes = 0; + let map = this.weakMap; - } + for ( let i = 0; i < keys.length; i ++ ) { -} + const key = keys[ i ]; -class RenderPipeline extends Pipeline { + if ( map.has( key ) === false ) map.set( key, new WeakMap() ); - constructor( cacheKey, vertexProgram, fragmentProgram ) { + map = map.get( key ); - super( cacheKey ); + } - this.vertexProgram = vertexProgram; - this.fragmentProgram = fragmentProgram; + return map.set( keys[ keys.length - 1 ], value ); } -} + delete( keys ) { -class ComputePipeline extends Pipeline { + let map = this.weakMap; - constructor( cacheKey, computeProgram ) { + for ( let i = 0; i < keys.length; i ++ ) { - super( cacheKey ); + map = map.get( keys[ i ] ); - this.computeProgram = computeProgram; + if ( map === undefined ) return false; - this.isComputePipeline = true; + } + + return map.delete( keys[ keys.length - 1 ] ); } } -let _id$6 = 0; +const _plane = /*@__PURE__*/ new Plane(); -class ProgrammableStage { +class ClippingContext { - constructor( code, type, transforms = null, attributes = null ) { + constructor() { - this.id = _id$6 ++; + this.version = 0; - this.code = code; - this.stage = type; - this.transforms = transforms; - this.attributes = attributes; + this.globalClippingCount = 0; - this.usedTimes = 0; + this.localClippingCount = 0; + this.localClippingEnabled = false; + this.localClipIntersection = false; + + this.planes = []; + + this.parentVersion = 0; + this.viewNormalMatrix = new Matrix3(); + this.cacheKey = 0; } -} + projectPlanes( source, offset ) { -class Pipelines extends DataMap { + const l = source.length; + const planes = this.planes; - constructor( backend, nodes ) { + for ( let i = 0; i < l; i ++ ) { - super(); + _plane.copy( source[ i ] ).applyMatrix4( this.viewMatrix, this.viewNormalMatrix ); - this.backend = backend; - this.nodes = nodes; + const v = planes[ offset + i ]; + const normal = _plane.normal; - this.bindings = null; // set by the bindings + v.x = - normal.x; + v.y = - normal.y; + v.z = - normal.z; + v.w = _plane.constant; - this.caches = new Map(); - this.programs = { - vertex: new Map(), - fragment: new Map(), - compute: new Map() - }; + } } - getForCompute( computeNode, bindings ) { + updateGlobal( renderer, camera ) { - const { backend } = this; + const rendererClippingPlanes = renderer.clippingPlanes; + this.viewMatrix = camera.matrixWorldInverse; - const data = this.get( computeNode ); + this.viewNormalMatrix.getNormalMatrix( this.viewMatrix ); - if ( this._needsComputeUpdate( computeNode ) ) { + let update = false; - const previousPipeline = data.pipeline; + if ( Array.isArray( rendererClippingPlanes ) && rendererClippingPlanes.length !== 0 ) { - if ( previousPipeline ) { + const l = rendererClippingPlanes.length; - previousPipeline.usedTimes --; - previousPipeline.computeProgram.usedTimes --; + if ( l !== this.globalClippingCount ) { - } + const planes = []; - // get shader + for ( let i = 0; i < l; i ++ ) { - const nodeBuilderState = this.nodes.getForCompute( computeNode ); + planes.push( new Vector4() ); - // programmable stage + } - let stageCompute = this.programs.compute.get( nodeBuilderState.computeShader ); + this.globalClippingCount = l; + this.planes = planes; - if ( stageCompute === undefined ) { + update = true; - if ( previousPipeline && previousPipeline.computeProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.computeProgram ); + } - stageCompute = new ProgrammableStage( nodeBuilderState.computeShader, 'compute', nodeBuilderState.transforms, nodeBuilderState.nodeAttributes ); - this.programs.compute.set( nodeBuilderState.computeShader, stageCompute ); + this.projectPlanes( rendererClippingPlanes, 0 ); - backend.createProgram( stageCompute ); + } else if ( this.globalClippingCount !== 0 ) { - } + this.globalClippingCount = 0; + this.planes = []; + update = true; - // determine compute pipeline + } - const cacheKey = this._getComputeCacheKey( computeNode, stageCompute ); + if ( renderer.localClippingEnabled !== this.localClippingEnabled ) { - let pipeline = this.caches.get( cacheKey ); + this.localClippingEnabled = renderer.localClippingEnabled; + update = true; - if ( pipeline === undefined ) { + } - if ( previousPipeline && previousPipeline.usedTimes === 0 ) this._releasePipeline( previousPipeline ); + if ( update ) { - pipeline = this._getComputePipeline( computeNode, stageCompute, cacheKey, bindings ); + this.version ++; + this.cacheKey = hash$1( this.globalClippingCount, this.localClippingEnabled === true ? 1 : 0 ); - } + } - // keep track of all used times + } - pipeline.usedTimes ++; - stageCompute.usedTimes ++; + update( parent, material ) { - // + let update = false; - data.version = computeNode.version; - data.pipeline = pipeline; + if ( this !== parent && parent.version !== this.parentVersion ) { + + this.globalClippingCount = material.isShadowNodeMaterial ? 0 : parent.globalClippingCount; + this.localClippingEnabled = parent.localClippingEnabled; + this.planes = Array.from( parent.planes ); + this.parentVersion = parent.version; + this.viewMatrix = parent.viewMatrix; + this.viewNormalMatrix = parent.viewNormalMatrix; + + update = true; } - return data.pipeline; + if ( this.localClippingEnabled ) { - } + const localClippingPlanes = material.clippingPlanes; - getForRender( renderObject, promises = null ) { + if ( ( Array.isArray( localClippingPlanes ) && localClippingPlanes.length !== 0 ) ) { - const { backend } = this; + const l = localClippingPlanes.length; + const planes = this.planes; + const offset = this.globalClippingCount; - const data = this.get( renderObject ); + if ( update || l !== this.localClippingCount ) { - if ( this._needsRenderUpdate( renderObject ) ) { + planes.length = offset + l; - const previousPipeline = data.pipeline; + for ( let i = 0; i < l; i ++ ) { - if ( previousPipeline ) { + planes[ offset + i ] = new Vector4(); - previousPipeline.usedTimes --; - previousPipeline.vertexProgram.usedTimes --; - previousPipeline.fragmentProgram.usedTimes --; + } - } + this.localClippingCount = l; + update = true; - // get shader + } - const nodeBuilderState = renderObject.getNodeBuilderState(); + this.projectPlanes( localClippingPlanes, offset ); - // programmable stages - let stageVertex = this.programs.vertex.get( nodeBuilderState.vertexShader ); + } else if ( this.localClippingCount !== 0 ) { - if ( stageVertex === undefined ) { + this.localClippingCount = 0; + update = true; - if ( previousPipeline && previousPipeline.vertexProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.vertexProgram ); + } - stageVertex = new ProgrammableStage( nodeBuilderState.vertexShader, 'vertex' ); - this.programs.vertex.set( nodeBuilderState.vertexShader, stageVertex ); + if ( this.localClipIntersection !== material.clipIntersection ) { - backend.createProgram( stageVertex ); + this.localClipIntersection = material.clipIntersection; + update = true; } - let stageFragment = this.programs.fragment.get( nodeBuilderState.fragmentShader ); + } - if ( stageFragment === undefined ) { + if ( update ) { - if ( previousPipeline && previousPipeline.fragmentProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.fragmentProgram ); + this.version += parent.version; + this.cacheKey = hash$1( parent.cacheKey, this.localClippingCount, this.localClipIntersection === true ? 1 : 0 ); - stageFragment = new ProgrammableStage( nodeBuilderState.fragmentShader, 'fragment' ); - this.programs.fragment.set( nodeBuilderState.fragmentShader, stageFragment ); + } - backend.createProgram( stageFragment ); + } - } +} - // determine render pipeline +let _id$7 = 0; - const cacheKey = this._getRenderCacheKey( renderObject, stageVertex, stageFragment ); +function getKeys( obj ) { - let pipeline = this.caches.get( cacheKey ); + const keys = Object.keys( obj ); - if ( pipeline === undefined ) { + let proto = Object.getPrototypeOf( obj ); - if ( previousPipeline && previousPipeline.usedTimes === 0 ) this._releasePipeline( previousPipeline ); + while ( proto ) { - pipeline = this._getRenderPipeline( renderObject, stageVertex, stageFragment, cacheKey, promises ); + const descriptors = Object.getOwnPropertyDescriptors( proto ); - } else { + for ( const key in descriptors ) { - renderObject.pipeline = pipeline; + if ( descriptors[ key ] !== undefined ) { - } + const descriptor = descriptors[ key ]; - // keep track of all used times + if ( descriptor && typeof descriptor.get === 'function' ) { - pipeline.usedTimes ++; - stageVertex.usedTimes ++; - stageFragment.usedTimes ++; + keys.push( key ); - // + } - data.pipeline = pipeline; + } } - return data.pipeline; + proto = Object.getPrototypeOf( proto ); } - delete( object ) { + return keys; - const pipeline = this.get( object ).pipeline; +} - if ( pipeline ) { +class RenderObject { - // pipeline + constructor( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext ) { - pipeline.usedTimes --; + this._nodes = nodes; + this._geometries = geometries; - if ( pipeline.usedTimes === 0 ) this._releasePipeline( pipeline ); + this.id = _id$7 ++; - // programs + this.renderer = renderer; + this.object = object; + this.material = material; + this.scene = scene; + this.camera = camera; + this.lightsNode = lightsNode; + this.context = renderContext; - if ( pipeline.isComputePipeline ) { + this.geometry = object.geometry; + this.version = material.version; - pipeline.computeProgram.usedTimes --; + this.drawRange = null; - if ( pipeline.computeProgram.usedTimes === 0 ) this._releaseProgram( pipeline.computeProgram ); + this.attributes = null; + this.pipeline = null; + this.vertexBuffers = null; + this.drawParams = null; - } else { + this.bundle = null; - pipeline.fragmentProgram.usedTimes --; - pipeline.vertexProgram.usedTimes --; + this.updateClipping( renderContext.clippingContext ); - if ( pipeline.vertexProgram.usedTimes === 0 ) this._releaseProgram( pipeline.vertexProgram ); - if ( pipeline.fragmentProgram.usedTimes === 0 ) this._releaseProgram( pipeline.fragmentProgram ); + this.clippingContextVersion = this.clippingContext.version; - } + this.initialNodesCacheKey = this.getDynamicCacheKey(); + this.initialCacheKey = this.getCacheKey(); - } + this._nodeBuilderState = null; + this._bindings = null; + this._monitor = null; - return super.delete( object ); + this.onDispose = null; - } + this.isRenderObject = true; - dispose() { + this.onMaterialDispose = () => { - super.dispose(); + this.dispose(); - this.caches = new Map(); - this.programs = { - vertex: new Map(), - fragment: new Map(), - compute: new Map() }; - } + this.material.addEventListener( 'dispose', this.onMaterialDispose ); - updateForRender( renderObject ) { + } - this.getForRender( renderObject ); + updateClipping( parent ) { - } + const material = this.material; - _getComputePipeline( computeNode, stageCompute, cacheKey, bindings ) { + let clippingContext = this.clippingContext; - // check for existing pipeline + if ( Array.isArray( material.clippingPlanes ) ) { - cacheKey = cacheKey || this._getComputeCacheKey( computeNode, stageCompute ); + if ( clippingContext === parent || ! clippingContext ) { - let pipeline = this.caches.get( cacheKey ); + clippingContext = new ClippingContext(); + this.clippingContext = clippingContext; - if ( pipeline === undefined ) { + } - pipeline = new ComputePipeline( cacheKey, stageCompute ); + clippingContext.update( parent, material ); - this.caches.set( cacheKey, pipeline ); + } else if ( this.clippingContext !== parent ) { - this.backend.createComputePipeline( pipeline, bindings ); + this.clippingContext = parent; } - return pipeline; - } - _getRenderPipeline( renderObject, stageVertex, stageFragment, cacheKey, promises ) { - - // check for existing pipeline + get clippingNeedsUpdate() { - cacheKey = cacheKey || this._getRenderCacheKey( renderObject, stageVertex, stageFragment ); + if ( this.clippingContext.version === this.clippingContextVersion ) return false; - let pipeline = this.caches.get( cacheKey ); + this.clippingContextVersion = this.clippingContext.version; - if ( pipeline === undefined ) { + return true; - pipeline = new RenderPipeline( cacheKey, stageVertex, stageFragment ); + } - this.caches.set( cacheKey, pipeline ); + getNodeBuilderState() { - renderObject.pipeline = pipeline; + return this._nodeBuilderState || ( this._nodeBuilderState = this._nodes.getForRender( this ) ); - this.backend.createRenderPipeline( renderObject, promises ); + } - } + getMonitor() { - return pipeline; + return this._monitor || ( this._monitor = this.getNodeBuilderState().monitor ); } - _getComputeCacheKey( computeNode, stageCompute ) { + getBindings() { - return computeNode.id + ',' + stageCompute.id; + return this._bindings || ( this._bindings = this.getNodeBuilderState().createBindings() ); } - _getRenderCacheKey( renderObject, stageVertex, stageFragment ) { + getIndex() { - return stageVertex.id + ',' + stageFragment.id + ',' + this.backend.getRenderCacheKey( renderObject ); + return this._geometries.getIndex( this ); } - _releasePipeline( pipeline ) { + getChainArray() { - this.caches.delete( pipeline.cacheKey ); + return [ this.object, this.material, this.context, this.lightsNode ]; } - _releaseProgram( program ) { + getAttributes() { - const code = program.code; - const stage = program.stage; + if ( this.attributes !== null ) return this.attributes; - this.programs[ stage ].delete( code ); + const nodeAttributes = this.getNodeBuilderState().nodeAttributes; + const geometry = this.geometry; - } + const attributes = []; + const vertexBuffers = new Set(); - _needsComputeUpdate( computeNode ) { + for ( const nodeAttribute of nodeAttributes ) { - const data = this.get( computeNode ); + const attribute = nodeAttribute.node && nodeAttribute.node.attribute ? nodeAttribute.node.attribute : geometry.getAttribute( nodeAttribute.name ); - return data.pipeline === undefined || data.version !== computeNode.version; + if ( attribute === undefined ) continue; - } + attributes.push( attribute ); - _needsRenderUpdate( renderObject ) { + const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute; + vertexBuffers.add( bufferAttribute ); - const data = this.get( renderObject ); + } - return data.pipeline === undefined || this.backend.needsRenderUpdate( renderObject ); + this.attributes = attributes; + this.vertexBuffers = Array.from( vertexBuffers.values() ); + + return attributes; } -} + getVertexBuffers() { -class Bindings extends DataMap { + if ( this.vertexBuffers === null ) this.getAttributes(); - constructor( backend, nodes, textures, attributes, pipelines, info ) { + return this.vertexBuffers; - super(); + } - this.backend = backend; - this.textures = textures; - this.pipelines = pipelines; - this.attributes = attributes; - this.nodes = nodes; - this.info = info; + getDrawParameters() { - this.pipelines.bindings = this; // assign bindings to pipelines + const { object, material, geometry, group, drawRange } = this; - } + const drawParams = this.drawParams || ( this.drawParams = { + vertexCount: 0, + firstVertex: 0, + instanceCount: 0, + firstInstance: 0 + } ); - getForRender( renderObject ) { + const index = this.getIndex(); + const hasIndex = ( index !== null ); + const instanceCount = geometry.isInstancedBufferGeometry ? geometry.instanceCount : ( object.count > 1 ? object.count : 1 ); - const bindings = renderObject.getBindings(); + if ( instanceCount === 0 ) return null; - for ( const bindGroup of bindings ) { + drawParams.instanceCount = instanceCount; - const groupData = this.get( bindGroup ); + if ( object.isBatchedMesh === true ) return drawParams; - if ( groupData.bindGroup === undefined ) { + let rangeFactor = 1; - // each object defines an array of bindings (ubos, textures, samplers etc.) + if ( material.wireframe === true && ! object.isPoints && ! object.isLineSegments && ! object.isLine && ! object.isLineLoop ) { - this._init( bindGroup ); + rangeFactor = 2; - this.backend.createBindings( bindGroup, bindings ); + } - groupData.bindGroup = bindGroup; + let firstVertex = drawRange.start * rangeFactor; + let lastVertex = ( drawRange.start + drawRange.count ) * rangeFactor; - } + if ( group !== null ) { + + firstVertex = Math.max( firstVertex, group.start * rangeFactor ); + lastVertex = Math.min( lastVertex, ( group.start + group.count ) * rangeFactor ); } - return bindings; + const itemCount = hasIndex === true ? index.count : geometry.attributes.position.count; - } + firstVertex = Math.max( firstVertex, 0 ); + lastVertex = Math.min( lastVertex, itemCount ); - getForCompute( computeNode ) { + const count = lastVertex - firstVertex; - const bindings = this.nodes.getForCompute( computeNode ).bindings; + if ( count < 0 || count === Infinity ) return null; - for ( const bindGroup of bindings ) { + drawParams.vertexCount = count; + drawParams.firstVertex = firstVertex; - const groupData = this.get( bindGroup ); + return drawParams; - if ( groupData.bindGroup === undefined ) { + } - this._init( bindGroup ); + getGeometryCacheKey() { - this.backend.createBindings( bindGroup, bindings ); + const { geometry } = this; - groupData.bindGroup = bindGroup; + let cacheKey = ''; - } + for ( const name of Object.keys( geometry.attributes ).sort() ) { - } + const attribute = geometry.attributes[ name ]; - return bindings; + cacheKey += name + ','; - } + if ( attribute.data ) cacheKey += attribute.data.stride + ','; + if ( attribute.offset ) cacheKey += attribute.offset + ','; + if ( attribute.itemSize ) cacheKey += attribute.itemSize + ','; + if ( attribute.normalized ) cacheKey += 'n,'; - updateForCompute( computeNode ) { + } - this._updateBindings( this.getForCompute( computeNode ) ); + if ( geometry.index ) { - } + cacheKey += 'index,'; - updateForRender( renderObject ) { + } - this._updateBindings( this.getForRender( renderObject ) ); + return cacheKey; } - _updateBindings( bindings ) { + getMaterialCacheKey() { - for ( const bindGroup of bindings ) { + const { object, material } = this; - this._update( bindGroup, bindings ); + let cacheKey = material.customProgramCacheKey(); - } + for ( const property of getKeys( material ) ) { - } + if ( /^(is[A-Z]|_)|^(visible|version|uuid|name|opacity|userData)$/.test( property ) ) continue; - _init( bindGroup ) { + const value = material[ property ]; - for ( const binding of bindGroup.bindings ) { + let valueKey; - if ( binding.isSampledTexture ) { + if ( value !== null ) { - this.textures.updateTexture( binding.texture ); + // some material values require a formatting - } else if ( binding.isStorageBuffer ) { + const type = typeof value; - const attribute = binding.attribute; + if ( type === 'number' ) { - this.attributes.update( attribute, AttributeType.STORAGE ); + valueKey = value !== 0 ? '1' : '0'; // Convert to on/off, important for clearcoat, transmission, etc - } + } else if ( type === 'object' ) { - } + valueKey = '{'; - } + if ( value.isTexture ) { - _update( bindGroup, bindings ) { + valueKey += value.mapping; - const { backend } = this; + } - let needsBindingsUpdate = false; + valueKey += '}'; - // iterate over all bindings and check if buffer updates or a new binding group is required + } else { - for ( const binding of bindGroup.bindings ) { + valueKey = String( value ); - if ( binding.isNodeUniformsGroup ) { + } - const updated = this.nodes.updateGroup( binding ); + } else { - if ( ! updated ) continue; + valueKey = String( value ); } - if ( binding.isUniformBuffer ) { + cacheKey += /*property + ':' +*/ valueKey + ','; - const updated = binding.update(); + } - if ( updated ) { + cacheKey += this.clippingContext.cacheKey + ','; - backend.updateBinding( binding ); + if ( object.geometry ) { - } + cacheKey += this.getGeometryCacheKey(); - } else if ( binding.isSampler ) { + } - binding.update(); + if ( object.skeleton ) { - } else if ( binding.isSampledTexture ) { + cacheKey += object.skeleton.bones.length + ','; - if ( binding.needsBindingsUpdate( this.textures.get( binding.texture ).generation ) ) needsBindingsUpdate = true; + } - const updated = binding.update(); + if ( object.morphTargetInfluences ) { - const texture = binding.texture; + cacheKey += object.morphTargetInfluences.length + ','; - if ( updated ) { + } - this.textures.updateTexture( texture ); + if ( object.isBatchedMesh ) { - } + cacheKey += object._matricesTexture.uuid + ','; - const textureData = backend.get( texture ); + if ( object._colorsTexture !== null ) { - if ( backend.isWebGPUBackend === true && textureData.texture === undefined && textureData.externalTexture === undefined ) { + cacheKey += object._colorsTexture.uuid + ','; - // TODO: Remove this once we found why updated === false isn't bound to a texture in the WebGPU backend - console.error( 'Bindings._update: binding should be available:', binding, updated, texture, binding.textureNode.value, needsBindingsUpdate ); + } - this.textures.updateTexture( texture ); - needsBindingsUpdate = true; + } - } + if ( object.count > 1 ) { - if ( texture.isStorageTexture === true ) { + // TODO: https://github.com/mrdoob/three.js/pull/29066#issuecomment-2269400850 - const textureData = this.get( texture ); + cacheKey += object.uuid + ','; - if ( binding.store === true ) { + } - textureData.needsMipmap = true; + return hashString( cacheKey ); - } else if ( texture.generateMipmaps === true && this.textures.needsMipmaps( texture ) && textureData.needsMipmap === true ) { + } - this.backend.generateMipmaps( texture ); + get needsUpdate() { - textureData.needsMipmap = false; + return /*this.object.static !== true &&*/ ( this.initialNodesCacheKey !== this.getDynamicCacheKey() || this.clippingNeedsUpdate ); - } + } - } + getDynamicCacheKey() { - } + // Environment Nodes Cache Key - } + let cacheKey = this._nodes.getCacheKey( this.scene, this.lightsNode ); - if ( needsBindingsUpdate === true ) { + if ( this.object.receiveShadow ) { - this.backend.updateBindings( bindGroup, bindings ); + cacheKey += 1; } + return cacheKey; + } -} + getCacheKey() { -class NodeAttribute { + return this.getMaterialCacheKey() + this.getDynamicCacheKey(); - constructor( name, type, node = null ) { + } - this.isNodeAttribute = true; + dispose() { - this.name = name; - this.type = type; - this.node = node; + this.material.removeEventListener( 'dispose', this.onMaterialDispose ); + + this.onDispose(); } } -class NodeUniform { +const chainArray = []; - constructor( name, type, node ) { +class RenderObjects { - this.isNodeUniform = true; + constructor( renderer, nodes, geometries, pipelines, bindings, info ) { - this.name = name; - this.type = type; - this.node = node.getSelf(); + this.renderer = renderer; + this.nodes = nodes; + this.geometries = geometries; + this.pipelines = pipelines; + this.bindings = bindings; + this.info = info; + + this.chainMaps = {}; } - get value() { + get( object, material, scene, camera, lightsNode, renderContext, passId ) { - return this.node.value; + const chainMap = this.getChainMap( passId ); - } + // reuse chainArray + chainArray[ 0 ] = object; + chainArray[ 1 ] = material; + chainArray[ 2 ] = renderContext; + chainArray[ 3 ] = lightsNode; - set value( val ) { + let renderObject = chainMap.get( chainArray ); - this.node.value = val; + if ( renderObject === undefined ) { - } + renderObject = this.createRenderObject( this.nodes, this.geometries, this.renderer, object, material, scene, camera, lightsNode, renderContext, passId ); - get id() { + chainMap.set( chainArray, renderObject ); - return this.node.id; + } else { - } + renderObject.updateClipping( renderContext.clippingContext ); - get groupNode() { + if ( renderObject.version !== material.version || renderObject.needsUpdate ) { - return this.node.groupNode; + if ( renderObject.initialCacheKey !== renderObject.getCacheKey() ) { - } + renderObject.dispose(); -} + renderObject = this.get( object, material, scene, camera, lightsNode, renderContext, passId ); -class NodeVar { + } else { - constructor( name, type ) { + renderObject.version = material.version; - this.isNodeVar = true; + } - this.name = name; - this.type = type; + } - } + } -} + return renderObject; -class NodeVarying extends NodeVar { + } - constructor( name, type ) { + getChainMap( passId = 'default' ) { - super( name, type ); + return this.chainMaps[ passId ] || ( this.chainMaps[ passId ] = new ChainMap() ); - this.needsInterpolation = false; + } - this.isNodeVarying = true; + dispose() { + + this.chainMaps = {}; } -} + createRenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, passId ) { -class NodeCode { + const chainMap = this.getChainMap( passId ); - constructor( name, type, code = '' ) { + const renderObject = new RenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext ); - this.name = name; - this.type = type; - this.code = code; + renderObject.onDispose = () => { - Object.defineProperty( this, 'isNodeCode', { value: true } ); + this.pipelines.delete( renderObject ); + this.bindings.delete( renderObject ); + this.nodes.delete( renderObject ); - } + chainMap.delete( renderObject.getChainArray() ); -} + }; -let id$1 = 0; + return renderObject; -class NodeCache { + } - constructor( parent = null ) { - this.id = id$1 ++; - this.nodesData = new WeakMap(); +} - this.parent = parent; +class DataMap { + + constructor() { + + this.data = new WeakMap(); } - getData( node ) { + get( object ) { - let data = this.nodesData.get( node ); + let map = this.data.get( object ); - if ( data === undefined && this.parent !== null ) { + if ( map === undefined ) { - data = this.parent.getData( node ); + map = {}; + this.data.set( object, map ); } - return data; + return map; } - setData( node, data ) { - - this.nodesData.set( node, data ); + delete( object ) { - } + let map; -} + if ( this.data.has( object ) ) { -class ParameterNode extends PropertyNode { + map = this.data.get( object ); - constructor( nodeType, name = null ) { + this.data.delete( object ); - super( nodeType, name ); + } - this.isParameterNode = true; + return map; } - getHash() { + has( object ) { - return this.uuid; + return this.data.has( object ); } - generate() { + dispose() { - return this.name; + this.data = new WeakMap(); } } -ParameterNode.type = /*@__PURE__*/ registerNode( 'Parameter', ParameterNode ); +const AttributeType = { + VERTEX: 1, + INDEX: 2, + STORAGE: 4 +}; -const parameter = ( type, name ) => nodeObject( new ParameterNode( type, name ) ); +// size of a chunk in bytes (STD140 layout) -class CodeNode extends Node { +const GPU_CHUNK_BYTES = 16; - constructor( code = '', includes = [], language = '' ) { +// @TODO: Move to src/constants.js - super( 'code' ); +const BlendColorFactor = 211; +const OneMinusBlendColorFactor = 212; - this.isCodeNode = true; +class Attributes extends DataMap { - this.code = code; - this.language = language; + constructor( backend ) { - this.includes = includes; + super(); + + this.backend = backend; } - isGlobal() { + delete( attribute ) { - return true; + const attributeData = super.delete( attribute ); - } + if ( attributeData !== undefined ) { - setIncludes( includes ) { + this.backend.destroyAttribute( attribute ); - this.includes = includes; + } - return this; + return attributeData; } - getIncludes( /*builder*/ ) { + update( attribute, type ) { - return this.includes; + const data = this.get( attribute ); - } + if ( data.version === undefined ) { - generate( builder ) { + if ( type === AttributeType.VERTEX ) { - const includes = this.getIncludes( builder ); + this.backend.createAttribute( attribute ); - for ( const include of includes ) { + } else if ( type === AttributeType.INDEX ) { - include.build( builder ); + this.backend.createIndexAttribute( attribute ); - } + } else if ( type === AttributeType.STORAGE ) { - const nodeCode = builder.getCodeFromNode( this, this.getNodeType( builder ) ); - nodeCode.code = this.code; + this.backend.createStorageAttribute( attribute ); - return nodeCode.code; + } - } + data.version = this._getBufferAttribute( attribute ).version; - serialize( data ) { + } else { - super.serialize( data ); + const bufferAttribute = this._getBufferAttribute( attribute ); - data.code = this.code; - data.language = this.language; + if ( data.version < bufferAttribute.version || bufferAttribute.usage === DynamicDrawUsage ) { - } + this.backend.updateAttribute( attribute ); - deserialize( data ) { + data.version = bufferAttribute.version; - super.deserialize( data ); + } - this.code = data.code; - this.language = data.language; + } } -} - -CodeNode.type = /*@__PURE__*/ registerNode( 'Code', CodeNode ); + _getBufferAttribute( attribute ) { -const code = /*@__PURE__*/ nodeProxy( CodeNode ); + if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; -const js = ( src, includes ) => code( src, includes, 'js' ); -const wgsl = ( src, includes ) => code( src, includes, 'wgsl' ); -const glsl = ( src, includes ) => code( src, includes, 'glsl' ); + return attribute; -class FunctionNode extends CodeNode { + } - constructor( code = '', includes = [], language = '' ) { +} - super( code, includes, language ); +function arrayNeedsUint32( array ) { - } + // assumes larger values usually on last - getNodeType( builder ) { + for ( let i = array.length - 1; i >= 0; -- i ) { - return this.getNodeFunction( builder ).type; + if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 } - getInputs( builder ) { - - return this.getNodeFunction( builder ).inputs; + return false; - } +} - getNodeFunction( builder ) { +function getWireframeVersion( geometry ) { - const nodeData = builder.getDataFromNode( this ); + return ( geometry.index !== null ) ? geometry.index.version : geometry.attributes.position.version; - let nodeFunction = nodeData.nodeFunction; +} - if ( nodeFunction === undefined ) { +function getWireframeIndex( geometry ) { - nodeFunction = builder.parser.parseFunction( this.code ); + const indices = []; - nodeData.nodeFunction = nodeFunction; + const geometryIndex = geometry.index; + const geometryPosition = geometry.attributes.position; - } + if ( geometryIndex !== null ) { - return nodeFunction; + const array = geometryIndex.array; - } + for ( let i = 0, l = array.length; i < l; i += 3 ) { - generate( builder, output ) { + const a = array[ i + 0 ]; + const b = array[ i + 1 ]; + const c = array[ i + 2 ]; - super.generate( builder ); + indices.push( a, b, b, c, c, a ); - const nodeFunction = this.getNodeFunction( builder ); + } - const name = nodeFunction.name; - const type = nodeFunction.type; + } else { - const nodeCode = builder.getCodeFromNode( this, type ); + const array = geometryPosition.array; - if ( name !== '' ) { + for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { - // use a custom property name + const a = i + 0; + const b = i + 1; + const c = i + 2; - nodeCode.name = name; + indices.push( a, b, b, c, c, a ); } - const propertyName = builder.getPropertyName( nodeCode ); + } - const code = this.getNodeFunction( builder ).getCode( propertyName ); + const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); + attribute.version = getWireframeVersion( geometry ); - nodeCode.code = code + '\n'; + return attribute; - if ( output === 'property' ) { +} - return propertyName; +class Geometries extends DataMap { - } else { + constructor( attributes, info ) { - return builder.format( `${ propertyName }()`, type, output ); + super(); - } + this.attributes = attributes; + this.info = info; - } + this.wireframes = new WeakMap(); -} + this.attributeCall = new WeakMap(); -FunctionNode.type = /*@__PURE__*/ registerNode( 'Function', FunctionNode ); + } -const nativeFn = ( code, includes = [], language = '' ) => { + has( renderObject ) { - for ( let i = 0; i < includes.length; i ++ ) { + const geometry = renderObject.geometry; - const include = includes[ i ]; + return super.has( geometry ) && this.get( geometry ).initialized === true; - // TSL Function: glslFn, wgslFn + } - if ( typeof include === 'function' ) { + updateForRender( renderObject ) { - includes[ i ] = include.functionNode; + if ( this.has( renderObject ) === false ) this.initGeometry( renderObject ); - } + this.updateAttributes( renderObject ); } - const functionNode = nodeObject( new FunctionNode( code, includes, language ) ); + initGeometry( renderObject ) { - const fn = ( ...params ) => functionNode.call( ...params ); - fn.functionNode = functionNode; + const geometry = renderObject.geometry; + const geometryData = this.get( geometry ); - return fn; + geometryData.initialized = true; -}; + this.info.memory.geometries ++; -const glslFn = ( code, includes ) => nativeFn( code, includes, 'glsl' ); -const wgslFn = ( code, includes ) => nativeFn( code, includes, 'wgsl' ); + const onDispose = () => { -class Uniform { + this.info.memory.geometries --; - constructor( name, value ) { + const index = geometry.index; + const geometryAttributes = renderObject.getAttributes(); - this.name = name; - this.value = value; + if ( index !== null ) { - this.boundary = 0; // used to build the uniform buffer according to the STD140 layout - this.itemSize = 0; + this.attributes.delete( index ); - this.offset = 0; // this property is set by WebGPUUniformsGroup and marks the start position in the uniform buffer + } - } + for ( const geometryAttribute of geometryAttributes ) { - setValue( value ) { + this.attributes.delete( geometryAttribute ); - this.value = value; + } - } + const wireframeAttribute = this.wireframes.get( geometry ); - getValue() { + if ( wireframeAttribute !== undefined ) { - return this.value; + this.attributes.delete( wireframeAttribute ); + + } + + geometry.removeEventListener( 'dispose', onDispose ); + + }; + + geometry.addEventListener( 'dispose', onDispose ); } -} + updateAttributes( renderObject ) { -class NumberUniform extends Uniform { + const attributes = renderObject.getAttributes(); - constructor( name, value = 0 ) { + for ( const attribute of attributes ) { - super( name, value ); + if ( attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute ) { - this.isNumberUniform = true; + this.updateAttribute( attribute, AttributeType.STORAGE ); - this.boundary = 4; - this.itemSize = 1; + } else { - } + this.updateAttribute( attribute, AttributeType.VERTEX ); -} + } -class Vector2Uniform extends Uniform { + } - constructor( name, value = new Vector2() ) { + const index = this.getIndex( renderObject ); - super( name, value ); + if ( index !== null ) { - this.isVector2Uniform = true; + this.updateAttribute( index, AttributeType.INDEX ); - this.boundary = 8; - this.itemSize = 2; + } } -} + updateAttribute( attribute, type ) { -class Vector3Uniform extends Uniform { + const callId = this.info.render.calls; - constructor( name, value = new Vector3() ) { + if ( ! attribute.isInterleavedBufferAttribute ) { - super( name, value ); + if ( this.attributeCall.get( attribute ) !== callId ) { - this.isVector3Uniform = true; + this.attributes.update( attribute, type ); - this.boundary = 16; - this.itemSize = 3; + this.attributeCall.set( attribute, callId ); - } + } -} + } else { -class Vector4Uniform extends Uniform { + if ( this.attributeCall.get( attribute ) === undefined ) { - constructor( name, value = new Vector4() ) { + this.attributes.update( attribute, type ); - super( name, value ); + this.attributeCall.set( attribute, callId ); - this.isVector4Uniform = true; + } else if ( this.attributeCall.get( attribute.data ) !== callId ) { - this.boundary = 16; - this.itemSize = 4; + this.attributes.update( attribute, type ); - } + this.attributeCall.set( attribute.data, callId ); -} + this.attributeCall.set( attribute, callId ); -class ColorUniform extends Uniform { + } - constructor( name, value = new Color() ) { + } - super( name, value ); + } - this.isColorUniform = true; + getIndex( renderObject ) { - this.boundary = 16; - this.itemSize = 3; + const { geometry, material } = renderObject; - } + let index = geometry.index; -} + if ( material.wireframe === true ) { -class Matrix3Uniform extends Uniform { + const wireframes = this.wireframes; - constructor( name, value = new Matrix3() ) { + let wireframeAttribute = wireframes.get( geometry ); - super( name, value ); + if ( wireframeAttribute === undefined ) { - this.isMatrix3Uniform = true; + wireframeAttribute = getWireframeIndex( geometry ); - this.boundary = 48; - this.itemSize = 12; + wireframes.set( geometry, wireframeAttribute ); - } + } else if ( wireframeAttribute.version !== getWireframeVersion( geometry ) ) { -} + this.attributes.delete( wireframeAttribute ); -class Matrix4Uniform extends Uniform { + wireframeAttribute = getWireframeIndex( geometry ); - constructor( name, value = new Matrix4() ) { + wireframes.set( geometry, wireframeAttribute ); - super( name, value ); + } - this.isMatrix4Uniform = true; + index = wireframeAttribute; - this.boundary = 64; - this.itemSize = 16; + } + + return index; } } -class NumberNodeUniform extends NumberUniform { +class Info { - constructor( nodeUniform ) { + constructor() { - super( nodeUniform.name, nodeUniform.value ); + this.autoReset = true; - this.nodeUniform = nodeUniform; + this.frame = 0; + this.calls = 0; - } + this.render = { + calls: 0, + frameCalls: 0, + drawCalls: 0, + triangles: 0, + points: 0, + lines: 0, + timestamp: 0, + previousFrameCalls: 0, + timestampCalls: 0 + }; - getValue() { + this.compute = { + calls: 0, + frameCalls: 0, + timestamp: 0, + previousFrameCalls: 0, + timestampCalls: 0 + }; - return this.nodeUniform.value; + this.memory = { + geometries: 0, + textures: 0 + }; } -} - -class Vector2NodeUniform extends Vector2Uniform { + update( object, count, instanceCount ) { - constructor( nodeUniform ) { + this.render.drawCalls ++; - super( nodeUniform.name, nodeUniform.value ); + if ( object.isMesh || object.isSprite ) { - this.nodeUniform = nodeUniform; + this.render.triangles += instanceCount * ( count / 3 ); - } + } else if ( object.isPoints ) { - getValue() { + this.render.points += instanceCount * count; - return this.nodeUniform.value; + } else if ( object.isLineSegments ) { - } + this.render.lines += instanceCount * ( count / 2 ); -} + } else if ( object.isLine ) { -class Vector3NodeUniform extends Vector3Uniform { + this.render.lines += instanceCount * ( count - 1 ); - constructor( nodeUniform ) { + } else { - super( nodeUniform.name, nodeUniform.value ); + console.error( 'THREE.WebGPUInfo: Unknown object type.' ); - this.nodeUniform = nodeUniform; + } } - getValue() { + updateTimestamp( type, time ) { - return this.nodeUniform.value; + if ( this[ type ].timestampCalls === 0 ) { - } + this[ type ].timestamp = 0; -} + } -class Vector4NodeUniform extends Vector4Uniform { - constructor( nodeUniform ) { + this[ type ].timestamp += time; - super( nodeUniform.name, nodeUniform.value ); + this[ type ].timestampCalls ++; - this.nodeUniform = nodeUniform; - } + if ( this[ type ].timestampCalls >= this[ type ].previousFrameCalls ) { - getValue() { + this[ type ].timestampCalls = 0; - return this.nodeUniform.value; + } - } -} + } -class ColorNodeUniform extends ColorUniform { + reset() { - constructor( nodeUniform ) { + const previousRenderFrameCalls = this.render.frameCalls; + this.render.previousFrameCalls = previousRenderFrameCalls; - super( nodeUniform.name, nodeUniform.value ); + const previousComputeFrameCalls = this.compute.frameCalls; + this.compute.previousFrameCalls = previousComputeFrameCalls; - this.nodeUniform = nodeUniform; - } + this.render.drawCalls = 0; + this.render.frameCalls = 0; + this.compute.frameCalls = 0; - getValue() { + this.render.triangles = 0; + this.render.points = 0; + this.render.lines = 0; - return this.nodeUniform.value; } -} + dispose() { -class Matrix3NodeUniform extends Matrix3Uniform { + this.reset(); - constructor( nodeUniform ) { + this.calls = 0; - super( nodeUniform.name, nodeUniform.value ); + this.render.calls = 0; + this.compute.calls = 0; - this.nodeUniform = nodeUniform; + this.render.timestamp = 0; + this.compute.timestamp = 0; + this.memory.geometries = 0; + this.memory.textures = 0; } - getValue() { +} - return this.nodeUniform.value; +class Pipeline { + + constructor( cacheKey ) { + + this.cacheKey = cacheKey; + + this.usedTimes = 0; } } -class Matrix4NodeUniform extends Matrix4Uniform { +class RenderPipeline extends Pipeline { - constructor( nodeUniform ) { + constructor( cacheKey, vertexProgram, fragmentProgram ) { - super( nodeUniform.name, nodeUniform.value ); + super( cacheKey ); - this.nodeUniform = nodeUniform; + this.vertexProgram = vertexProgram; + this.fragmentProgram = fragmentProgram; } - getValue() { +} - return this.nodeUniform.value; +class ComputePipeline extends Pipeline { - } + constructor( cacheKey, computeProgram ) { -} + super( cacheKey ); -class StackNode extends Node { + this.computeProgram = computeProgram; - constructor( parent = null ) { + this.isComputePipeline = true; - super(); + } - this.nodes = []; - this.outputNode = null; +} - this.parent = parent; +let _id$6 = 0; - this._currentCond = null; +class ProgrammableStage { - this.isStackNode = true; + constructor( code, type, transforms = null, attributes = null ) { - } + this.id = _id$6 ++; - getNodeType( builder ) { + this.code = code; + this.stage = type; + this.transforms = transforms; + this.attributes = attributes; - return this.outputNode ? this.outputNode.getNodeType( builder ) : 'void'; + this.usedTimes = 0; } - add( node ) { +} - this.nodes.push( node ); +class Pipelines extends DataMap { - return this; + constructor( backend, nodes ) { - } + super(); - If( boolNode, method ) { + this.backend = backend; + this.nodes = nodes; - const methodNode = new ShaderNode( method ); - this._currentCond = select( boolNode, methodNode ); + this.bindings = null; // set by the bindings - return this.add( this._currentCond ); + this.caches = new Map(); + this.programs = { + vertex: new Map(), + fragment: new Map(), + compute: new Map() + }; } - ElseIf( boolNode, method ) { + getForCompute( computeNode, bindings ) { - const methodNode = new ShaderNode( method ); - const ifNode = select( boolNode, methodNode ); + const { backend } = this; - this._currentCond.elseNode = ifNode; - this._currentCond = ifNode; + const data = this.get( computeNode ); - return this; + if ( this._needsComputeUpdate( computeNode ) ) { - } + const previousPipeline = data.pipeline; - Else( method ) { + if ( previousPipeline ) { - this._currentCond.elseNode = new ShaderNode( method ); + previousPipeline.usedTimes --; + previousPipeline.computeProgram.usedTimes --; - return this; + } - } + // get shader - build( builder, ...params ) { + const nodeBuilderState = this.nodes.getForCompute( computeNode ); - const previousStack = getCurrentStack(); + // programmable stage - setCurrentStack( this ); + let stageCompute = this.programs.compute.get( nodeBuilderState.computeShader ); - for ( const node of this.nodes ) { + if ( stageCompute === undefined ) { - node.build( builder, 'void' ); + if ( previousPipeline && previousPipeline.computeProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.computeProgram ); - } + stageCompute = new ProgrammableStage( nodeBuilderState.computeShader, 'compute', nodeBuilderState.transforms, nodeBuilderState.nodeAttributes ); + this.programs.compute.set( nodeBuilderState.computeShader, stageCompute ); - setCurrentStack( previousStack ); + backend.createProgram( stageCompute ); - return this.outputNode ? this.outputNode.build( builder, ...params ) : super.build( builder, ...params ); + } - } + // determine compute pipeline - // + const cacheKey = this._getComputeCacheKey( computeNode, stageCompute ); - else( ...params ) { // @deprecated, r168 + let pipeline = this.caches.get( cacheKey ); - console.warn( 'TSL.StackNode: .else() has been renamed to .Else().' ); - return this.Else( ...params ); + if ( pipeline === undefined ) { - } + if ( previousPipeline && previousPipeline.usedTimes === 0 ) this._releasePipeline( previousPipeline ); - elseif( ...params ) { // @deprecated, r168 + pipeline = this._getComputePipeline( computeNode, stageCompute, cacheKey, bindings ); - console.warn( 'TSL.StackNode: .elseif() has been renamed to .ElseIf().' ); - return this.ElseIf( ...params ); + } - } + // keep track of all used times -} + pipeline.usedTimes ++; + stageCompute.usedTimes ++; -StackNode.type = /*@__PURE__*/ registerNode( 'Stack', StackNode ); + // -const stack = /*@__PURE__*/ nodeProxy( StackNode ); + data.version = computeNode.version; + data.pipeline = pipeline; -const LOD_MIN = 4; + } -// The standard deviations (radians) associated with the extra mips. These are -// chosen to approximate a Trowbridge-Reitz distribution function times the -// geometric shadowing function. These sigma values squared must match the -// variance #defines in cube_uv_reflection_fragment.glsl.js. -const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; + return data.pipeline; -// The maximum length of the blur for loop. Smaller sigmas will use fewer -// samples and exit early, but not recompile the shader. -const MAX_SAMPLES = 20; + } -const _flatCamera = /*@__PURE__*/ new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); -const _cubeCamera = /*@__PURE__*/ new PerspectiveCamera( 90, 1 ); -const _clearColor$2 = /*@__PURE__*/ new Color(); -let _oldTarget = null; -let _oldActiveCubeFace = 0; -let _oldActiveMipmapLevel = 0; + getForRender( renderObject, promises = null ) { -// Golden Ratio -const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; -const INV_PHI = 1 / PHI; + const { backend } = this; -// Vertices of a dodecahedron (except the opposites, which represent the -// same axis), used as axis directions evenly spread on a sphere. -const _axisDirections = [ - /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ), - /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ), - /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ), - /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ), - /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ), - /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ), - /*@__PURE__*/ new Vector3( - 1, 1, - 1 ), - /*@__PURE__*/ new Vector3( 1, 1, - 1 ), - /*@__PURE__*/ new Vector3( - 1, 1, 1 ), - /*@__PURE__*/ new Vector3( 1, 1, 1 ) -]; + const data = this.get( renderObject ); -// + if ( this._needsRenderUpdate( renderObject ) ) { -// WebGPU Face indices -const _faceLib = [ - 3, 1, 5, - 0, 4, 2 -]; + const previousPipeline = data.pipeline; -const direction = getDirection( uv(), attribute( 'faceIndex' ) ).normalize(); -const outputDirection = vec3( direction.x, direction.y.negate(), direction.z ); + if ( previousPipeline ) { -/** - * This class generates a Prefiltered, Mipmapped Radiance Environment Map - * (PMREM) from a cubeMap environment texture. This allows different levels of - * blur to be quickly accessed based on material roughness. It is packed into a - * special CubeUV format that allows us to perform custom interpolation so that - * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap - * chain, it only goes down to the LOD_MIN level (above), and then creates extra - * even more filtered 'mips' at the same LOD_MIN resolution, associated with - * higher roughness levels. In this way we maintain resolution to smoothly - * interpolate diffuse lighting while limiting sampling computation. - * - * Paper: Fast, Accurate Image-Based Lighting - * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view -*/ + previousPipeline.usedTimes --; + previousPipeline.vertexProgram.usedTimes --; + previousPipeline.fragmentProgram.usedTimes --; -class PMREMGenerator { + } - constructor( renderer ) { + // get shader - this._renderer = renderer; - this._pingPongRenderTarget = null; + const nodeBuilderState = renderObject.getNodeBuilderState(); - this._lodMax = 0; - this._cubeSize = 0; - this._lodPlanes = []; - this._sizeLods = []; - this._sigmas = []; - this._lodMeshes = []; + // programmable stages - this._blurMaterial = null; - this._cubemapMaterial = null; - this._equirectMaterial = null; - this._backgroundBox = null; + let stageVertex = this.programs.vertex.get( nodeBuilderState.vertexShader ); - } + if ( stageVertex === undefined ) { - /** - * Generates a PMREM from a supplied Scene, which can be faster than using an - * image if networking bandwidth is low. Optional sigma specifies a blur radius - * in radians to be applied to the scene before PMREM generation. Optional near - * and far planes ensure the scene is rendered in its entirety (the cubeCamera - * is placed at the origin). - */ - fromScene( scene, sigma = 0, near = 0.1, far = 100 ) { + if ( previousPipeline && previousPipeline.vertexProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.vertexProgram ); - _oldTarget = this._renderer.getRenderTarget(); - _oldActiveCubeFace = this._renderer.getActiveCubeFace(); - _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); + stageVertex = new ProgrammableStage( nodeBuilderState.vertexShader, 'vertex' ); + this.programs.vertex.set( nodeBuilderState.vertexShader, stageVertex ); - this._setSize( 256 ); + backend.createProgram( stageVertex ); - const cubeUVRenderTarget = this._allocateTargets(); - cubeUVRenderTarget.depthBuffer = true; + } - this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget ); + let stageFragment = this.programs.fragment.get( nodeBuilderState.fragmentShader ); - if ( sigma > 0 ) { + if ( stageFragment === undefined ) { - this._blur( cubeUVRenderTarget, 0, 0, sigma ); + if ( previousPipeline && previousPipeline.fragmentProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.fragmentProgram ); - } + stageFragment = new ProgrammableStage( nodeBuilderState.fragmentShader, 'fragment' ); + this.programs.fragment.set( nodeBuilderState.fragmentShader, stageFragment ); - this._applyPMREM( cubeUVRenderTarget ); + backend.createProgram( stageFragment ); - this._cleanup( cubeUVRenderTarget ); + } - return cubeUVRenderTarget; + // determine render pipeline - } + const cacheKey = this._getRenderCacheKey( renderObject, stageVertex, stageFragment ); - /** - * Generates a PMREM from an equirectangular texture, which can be either LDR - * or HDR. The ideal input image size is 1k (1024 x 512), - * as this matches best with the 256 x 256 cubemap output. - */ - fromEquirectangular( equirectangular, renderTarget = null ) { + let pipeline = this.caches.get( cacheKey ); - return this._fromTexture( equirectangular, renderTarget ); + if ( pipeline === undefined ) { - } + if ( previousPipeline && previousPipeline.usedTimes === 0 ) this._releasePipeline( previousPipeline ); - /** - * Generates a PMREM from an cubemap texture, which can be either LDR - * or HDR. The ideal input cube size is 256 x 256, - * as this matches best with the 256 x 256 cubemap output. - */ - fromCubemap( cubemap, renderTarget = null ) { + pipeline = this._getRenderPipeline( renderObject, stageVertex, stageFragment, cacheKey, promises ); - return this._fromTexture( cubemap, renderTarget ); + } else { - } + renderObject.pipeline = pipeline; - /** - * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during - * your texture's network fetch for increased concurrency. - */ - compileCubemapShader() { + } - if ( this._cubemapMaterial === null ) { + // keep track of all used times - this._cubemapMaterial = _getCubemapMaterial(); - this._compileMaterial( this._cubemapMaterial ); + pipeline.usedTimes ++; + stageVertex.usedTimes ++; + stageFragment.usedTimes ++; + + // + + data.pipeline = pipeline; } + return data.pipeline; + } - /** - * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during - * your texture's network fetch for increased concurrency. - */ - compileEquirectangularShader() { + delete( object ) { - if ( this._equirectMaterial === null ) { + const pipeline = this.get( object ).pipeline; - this._equirectMaterial = _getEquirectMaterial(); - this._compileMaterial( this._equirectMaterial ); + if ( pipeline ) { - } + // pipeline - } + pipeline.usedTimes --; - /** - * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, - * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on - * one of them will cause any others to also become unusable. - */ - dispose() { + if ( pipeline.usedTimes === 0 ) this._releasePipeline( pipeline ); - this._dispose(); + // programs - if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose(); - if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose(); - if ( this._backgroundBox !== null ) { + if ( pipeline.isComputePipeline ) { - this._backgroundBox.geometry.dispose(); - this._backgroundBox.material.dispose(); + pipeline.computeProgram.usedTimes --; + + if ( pipeline.computeProgram.usedTimes === 0 ) this._releaseProgram( pipeline.computeProgram ); + + } else { + + pipeline.fragmentProgram.usedTimes --; + pipeline.vertexProgram.usedTimes --; + + if ( pipeline.vertexProgram.usedTimes === 0 ) this._releaseProgram( pipeline.vertexProgram ); + if ( pipeline.fragmentProgram.usedTimes === 0 ) this._releaseProgram( pipeline.fragmentProgram ); + + } } + return super.delete( object ); + } - // private interface + dispose() { - _setSize( cubeSize ) { + super.dispose(); - this._lodMax = Math.floor( Math.log2( cubeSize ) ); - this._cubeSize = Math.pow( 2, this._lodMax ); + this.caches = new Map(); + this.programs = { + vertex: new Map(), + fragment: new Map(), + compute: new Map() + }; } - _dispose() { + updateForRender( renderObject ) { - if ( this._blurMaterial !== null ) this._blurMaterial.dispose(); + this.getForRender( renderObject ); - if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose(); + } - for ( let i = 0; i < this._lodPlanes.length; i ++ ) { + _getComputePipeline( computeNode, stageCompute, cacheKey, bindings ) { - this._lodPlanes[ i ].dispose(); + // check for existing pipeline + + cacheKey = cacheKey || this._getComputeCacheKey( computeNode, stageCompute ); + + let pipeline = this.caches.get( cacheKey ); + + if ( pipeline === undefined ) { + + pipeline = new ComputePipeline( cacheKey, stageCompute ); + + this.caches.set( cacheKey, pipeline ); + + this.backend.createComputePipeline( pipeline, bindings ); } + return pipeline; + } - _cleanup( outputTarget ) { + _getRenderPipeline( renderObject, stageVertex, stageFragment, cacheKey, promises ) { - this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel ); - outputTarget.scissorTest = false; - _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); + // check for existing pipeline - } + cacheKey = cacheKey || this._getRenderCacheKey( renderObject, stageVertex, stageFragment ); - _fromTexture( texture, renderTarget ) { + let pipeline = this.caches.get( cacheKey ); - if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) { + if ( pipeline === undefined ) { - this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) ); + pipeline = new RenderPipeline( cacheKey, stageVertex, stageFragment ); - } else { // Equirectangular + this.caches.set( cacheKey, pipeline ); - this._setSize( texture.image.width / 4 ); + renderObject.pipeline = pipeline; + + this.backend.createRenderPipeline( renderObject, promises ); } - _oldTarget = this._renderer.getRenderTarget(); - _oldActiveCubeFace = this._renderer.getActiveCubeFace(); - _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); + return pipeline; - const cubeUVRenderTarget = renderTarget || this._allocateTargets(); - this._textureToCubeUV( texture, cubeUVRenderTarget ); - this._applyPMREM( cubeUVRenderTarget ); - this._cleanup( cubeUVRenderTarget ); + } - return cubeUVRenderTarget; + _getComputeCacheKey( computeNode, stageCompute ) { + + return computeNode.id + ',' + stageCompute.id; } - _allocateTargets() { + _getRenderCacheKey( renderObject, stageVertex, stageFragment ) { - const width = 3 * Math.max( this._cubeSize, 16 * 7 ); - const height = 4 * this._cubeSize; + return stageVertex.id + ',' + stageFragment.id + ',' + this.backend.getRenderCacheKey( renderObject ); - const params = { - magFilter: LinearFilter, - minFilter: LinearFilter, - generateMipmaps: false, - type: HalfFloatType, - format: RGBAFormat, - colorSpace: LinearSRGBColorSpace, - //depthBuffer: false - }; + } - const cubeUVRenderTarget = _createRenderTarget( width, height, params ); + _releasePipeline( pipeline ) { - if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) { + this.caches.delete( pipeline.cacheKey ); - if ( this._pingPongRenderTarget !== null ) { + } - this._dispose(); + _releaseProgram( program ) { - } + const code = program.code; + const stage = program.stage; - this._pingPongRenderTarget = _createRenderTarget( width, height, params ); + this.programs[ stage ].delete( code ); - const { _lodMax } = this; - ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas, lodMeshes: this._lodMeshes } = _createPlanes( _lodMax ) ); + } - this._blurMaterial = _getBlurShader( _lodMax, width, height ); + _needsComputeUpdate( computeNode ) { - } + const data = this.get( computeNode ); - return cubeUVRenderTarget; + return data.pipeline === undefined || data.version !== computeNode.version; } - _compileMaterial( material ) { + _needsRenderUpdate( renderObject ) { - const tmpMesh = this._lodMeshes[ 0 ]; - tmpMesh.material = material; + const data = this.get( renderObject ); - this._renderer.compile( tmpMesh, _flatCamera ); + return data.pipeline === undefined || this.backend.needsRenderUpdate( renderObject ); } - _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) { +} - const cubeCamera = _cubeCamera; - cubeCamera.near = near; - cubeCamera.far = far; +class Bindings extends DataMap { - // px, py, pz, nx, ny, nz - const upSign = [ - 1, 1, - 1, - 1, - 1, - 1 ]; - const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ]; + constructor( backend, nodes, textures, attributes, pipelines, info ) { - const renderer = this._renderer; + super(); - const originalAutoClear = renderer.autoClear; + this.backend = backend; + this.textures = textures; + this.pipelines = pipelines; + this.attributes = attributes; + this.nodes = nodes; + this.info = info; - renderer.getClearColor( _clearColor$2 ); + this.pipelines.bindings = this; // assign bindings to pipelines - renderer.autoClear = false; + } - let backgroundBox = this._backgroundBox; + getForRender( renderObject ) { - if ( backgroundBox === null ) { + const bindings = renderObject.getBindings(); - const backgroundMaterial = new MeshBasicMaterial( { - name: 'PMREM.Background', - side: BackSide, - depthWrite: false, - depthTest: false - } ); + for ( const bindGroup of bindings ) { - backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial ); + const groupData = this.get( bindGroup ); - } + if ( groupData.bindGroup === undefined ) { - let useSolidColor = false; - const background = scene.background; + // each object defines an array of bindings (ubos, textures, samplers etc.) - if ( background ) { + this._init( bindGroup ); - if ( background.isColor ) { + this.backend.createBindings( bindGroup, bindings ); - backgroundBox.material.color.copy( background ); - scene.background = null; - useSolidColor = true; + groupData.bindGroup = bindGroup; } - } else { - - backgroundBox.material.color.copy( _clearColor$2 ); - useSolidColor = true; - } - renderer.setRenderTarget( cubeUVRenderTarget ); + return bindings; - renderer.clear(); + } - if ( useSolidColor ) { + getForCompute( computeNode ) { - renderer.render( backgroundBox, cubeCamera ); + const bindings = this.nodes.getForCompute( computeNode ).bindings; - } + for ( const bindGroup of bindings ) { - for ( let i = 0; i < 6; i ++ ) { + const groupData = this.get( bindGroup ); - const col = i % 3; + if ( groupData.bindGroup === undefined ) { - if ( col === 0 ) { + this._init( bindGroup ); - cubeCamera.up.set( 0, upSign[ i ], 0 ); - cubeCamera.lookAt( forwardSign[ i ], 0, 0 ); + this.backend.createBindings( bindGroup, bindings ); - } else if ( col === 1 ) { + groupData.bindGroup = bindGroup; - cubeCamera.up.set( 0, 0, upSign[ i ] ); - cubeCamera.lookAt( 0, forwardSign[ i ], 0 ); + } - } else { + } - cubeCamera.up.set( 0, upSign[ i ], 0 ); - cubeCamera.lookAt( 0, 0, forwardSign[ i ] ); + return bindings; - } + } - const size = this._cubeSize; + updateForCompute( computeNode ) { - _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size ); + this._updateBindings( this.getForCompute( computeNode ) ); - renderer.render( scene, cubeCamera ); + } - } + updateForRender( renderObject ) { - renderer.autoClear = originalAutoClear; - scene.background = background; + this._updateBindings( this.getForRender( renderObject ) ); } - _textureToCubeUV( texture, cubeUVRenderTarget ) { + _updateBindings( bindings ) { - const renderer = this._renderer; + for ( const bindGroup of bindings ) { - const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ); + this._update( bindGroup, bindings ); - if ( isCubeTexture ) { + } - if ( this._cubemapMaterial === null ) { + } - this._cubemapMaterial = _getCubemapMaterial( texture ); + _init( bindGroup ) { - } + for ( const binding of bindGroup.bindings ) { - } else { + if ( binding.isSampledTexture ) { - if ( this._equirectMaterial === null ) { + this.textures.updateTexture( binding.texture ); - this._equirectMaterial = _getEquirectMaterial( texture ); + } else if ( binding.isStorageBuffer ) { + + const attribute = binding.attribute; + + this.attributes.update( attribute, AttributeType.STORAGE ); } } - const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial; - material.fragmentNode.value = texture; - - const mesh = this._lodMeshes[ 0 ]; - mesh.material = material; + } - const size = this._cubeSize; + _update( bindGroup, bindings ) { - _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size ); + const { backend } = this; - renderer.setRenderTarget( cubeUVRenderTarget ); - renderer.render( mesh, _flatCamera ); + let needsBindingsUpdate = false; - } + // iterate over all bindings and check if buffer updates or a new binding group is required - _applyPMREM( cubeUVRenderTarget ) { + for ( const binding of bindGroup.bindings ) { - const renderer = this._renderer; - const autoClear = renderer.autoClear; - renderer.autoClear = false; - const n = this._lodPlanes.length; + if ( binding.isNodeUniformsGroup ) { - for ( let i = 1; i < n; i ++ ) { + const updated = this.nodes.updateGroup( binding ); - const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] ); + if ( ! updated ) continue; - const poleAxis = _axisDirections[ ( n - i - 1 ) % _axisDirections.length ]; + } - this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis ); + if ( binding.isUniformBuffer ) { - } + const updated = binding.update(); - renderer.autoClear = autoClear; + if ( updated ) { - } + backend.updateBinding( binding ); - /** - * This is a two-pass Gaussian blur for a cubemap. Normally this is done - * vertically and horizontally, but this breaks down on a cube. Here we apply - * the blur latitudinally (around the poles), and then longitudinally (towards - * the poles) to approximate the orthogonally-separable blur. It is least - * accurate at the poles, but still does a decent job. - */ - _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) { + } - const pingPongRenderTarget = this._pingPongRenderTarget; + } else if ( binding.isSampler ) { - this._halfBlur( - cubeUVRenderTarget, - pingPongRenderTarget, - lodIn, - lodOut, - sigma, - 'latitudinal', - poleAxis ); + binding.update(); - this._halfBlur( - pingPongRenderTarget, - cubeUVRenderTarget, - lodOut, - lodOut, - sigma, - 'longitudinal', - poleAxis ); + } else if ( binding.isSampledTexture ) { - } + if ( binding.needsBindingsUpdate( this.textures.get( binding.texture ).generation ) ) needsBindingsUpdate = true; - _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) { + const updated = binding.update(); - const renderer = this._renderer; - const blurMaterial = this._blurMaterial; + const texture = binding.texture; - if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) { + if ( updated ) { - console.error( 'blur direction must be either latitudinal or longitudinal!' ); + this.textures.updateTexture( texture ); - } + } - // Number of standard deviations at which to cut off the discrete approximation. - const STANDARD_DEVIATIONS = 3; + const textureData = backend.get( texture ); - const blurMesh = this._lodMeshes[ lodOut ]; - blurMesh.material = blurMaterial; + if ( backend.isWebGPUBackend === true && textureData.texture === undefined && textureData.externalTexture === undefined ) { - const blurUniforms = blurMaterial.uniforms; + // TODO: Remove this once we found why updated === false isn't bound to a texture in the WebGPU backend + console.error( 'Bindings._update: binding should be available:', binding, updated, texture, binding.textureNode.value, needsBindingsUpdate ); - const pixels = this._sizeLods[ lodIn ] - 1; - const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 ); - const sigmaPixels = sigmaRadians / radiansPerPixel; - const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES; + this.textures.updateTexture( texture ); + needsBindingsUpdate = true; - if ( samples > MAX_SAMPLES ) { + } - console.warn( `sigmaRadians, ${ - sigmaRadians}, is too large and will clip, as it requested ${ - samples} samples when the maximum is set to ${MAX_SAMPLES}` ); + if ( texture.isStorageTexture === true ) { - } + const textureData = this.get( texture ); - const weights = []; - let sum = 0; + if ( binding.store === true ) { - for ( let i = 0; i < MAX_SAMPLES; ++ i ) { + textureData.needsMipmap = true; - const x = i / sigmaPixels; - const weight = Math.exp( - x * x / 2 ); - weights.push( weight ); + } else if ( texture.generateMipmaps === true && this.textures.needsMipmaps( texture ) && textureData.needsMipmap === true ) { - if ( i === 0 ) { + this.backend.generateMipmaps( texture ); - sum += weight; + textureData.needsMipmap = false; - } else if ( i < samples ) { + } - sum += 2 * weight; + } } } - for ( let i = 0; i < weights.length; i ++ ) { + if ( needsBindingsUpdate === true ) { - weights[ i ] = weights[ i ] / sum; + this.backend.updateBindings( bindGroup, bindings ); } - targetIn.texture.frame = ( targetIn.texture.frame || 0 ) + 1; - - blurUniforms.envMap.value = targetIn.texture; - blurUniforms.samples.value = samples; - blurUniforms.weights.array = weights; - blurUniforms.latitudinal.value = direction === 'latitudinal' ? 1 : 0; - - if ( poleAxis ) { + } - blurUniforms.poleAxis.value = poleAxis; +} - } +class NodeAttribute { - const { _lodMax } = this; - blurUniforms.dTheta.value = radiansPerPixel; - blurUniforms.mipInt.value = _lodMax - lodIn; + constructor( name, type, node = null ) { - const outputSize = this._sizeLods[ lodOut ]; - const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 ); - const y = 4 * ( this._cubeSize - outputSize ); + this.isNodeAttribute = true; - _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize ); - renderer.setRenderTarget( targetOut ); - renderer.render( blurMesh, _flatCamera ); + this.name = name; + this.type = type; + this.node = node; } } -function _createPlanes( lodMax ) { +class NodeUniform { - const lodPlanes = []; - const sizeLods = []; - const sigmas = []; - const lodMeshes = []; + constructor( name, type, node ) { - let lod = lodMax; + this.isNodeUniform = true; - const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; + this.name = name; + this.type = type; + this.node = node.getSelf(); - for ( let i = 0; i < totalLods; i ++ ) { + } - const sizeLod = Math.pow( 2, lod ); - sizeLods.push( sizeLod ); - let sigma = 1.0 / sizeLod; + get value() { - if ( i > lodMax - LOD_MIN ) { + return this.node.value; - sigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ]; + } - } else if ( i === 0 ) { + set value( val ) { - sigma = 0; + this.node.value = val; - } + } - sigmas.push( sigma ); + get id() { - const texelSize = 1.0 / ( sizeLod - 2 ); - const min = - texelSize; - const max = 1 + texelSize; - const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ]; + return this.node.id; - const cubeFaces = 6; - const vertices = 6; - const positionSize = 3; - const uvSize = 2; - const faceIndexSize = 1; + } - const position = new Float32Array( positionSize * vertices * cubeFaces ); - const uv = new Float32Array( uvSize * vertices * cubeFaces ); - const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces ); + get groupNode() { - for ( let face = 0; face < cubeFaces; face ++ ) { - - const x = ( face % 3 ) * 2 / 3 - 1; - const y = face > 2 ? 0 : - 1; - const coordinates = [ - x, y, 0, - x + 2 / 3, y, 0, - x + 2 / 3, y + 1, 0, - x, y, 0, - x + 2 / 3, y + 1, 0, - x, y + 1, 0 - ]; + return this.node.groupNode; - const faceIdx = _faceLib[ face ]; - position.set( coordinates, positionSize * vertices * faceIdx ); - uv.set( uv1, uvSize * vertices * faceIdx ); - const fill = [ faceIdx, faceIdx, faceIdx, faceIdx, faceIdx, faceIdx ]; - faceIndex.set( fill, faceIndexSize * vertices * faceIdx ); + } - } +} - const planes = new BufferGeometry(); - planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) ); - planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) ); - planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) ); - lodPlanes.push( planes ); - lodMeshes.push( new Mesh( planes, null ) ); +class NodeVar { - if ( lod > LOD_MIN ) { + constructor( name, type ) { - lod --; + this.isNodeVar = true; - } + this.name = name; + this.type = type; } - return { lodPlanes, sizeLods, sigmas, lodMeshes }; - -} - -function _createRenderTarget( width, height, params ) { - - const cubeUVRenderTarget = new RenderTarget( width, height, params ); - cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; - cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; - cubeUVRenderTarget.texture.isPMREMTexture = true; - cubeUVRenderTarget.scissorTest = true; - return cubeUVRenderTarget; - } -function _setViewport( target, x, y, width, height ) { +class NodeVarying extends NodeVar { - target.viewport.set( x, y, width, height ); - target.scissor.set( x, y, width, height ); + constructor( name, type ) { -} + super( name, type ); -function _getMaterial( type ) { + this.needsInterpolation = false; - const material = new NodeMaterial(); - material.depthTest = false; - material.depthWrite = false; - material.blending = NoBlending; - material.name = `PMREM_${ type }`; + this.isNodeVarying = true; - return material; + } } -function _getBlurShader( lodMax, width, height ) { +class NodeCode { - const weights = uniformArray( new Array( MAX_SAMPLES ).fill( 0 ) ); - const poleAxis = uniform( new Vector3( 0, 1, 0 ) ); - const dTheta = uniform( 0 ); - const n = float( MAX_SAMPLES ); - const latitudinal = uniform( 0 ); // false, bool - const samples = uniform( 1 ); // int - const envMap = texture( null ); - const mipInt = uniform( 0 ); // int - const CUBEUV_TEXEL_WIDTH = float( 1 / width ); - const CUBEUV_TEXEL_HEIGHT = float( 1 / height ); - const CUBEUV_MAX_MIP = float( lodMax ); + constructor( name, type, code = '' ) { - const materialUniforms = { - n, - latitudinal, - weights, - poleAxis, - outputDirection, - dTheta, - samples, - envMap, - mipInt, - CUBEUV_TEXEL_WIDTH, - CUBEUV_TEXEL_HEIGHT, - CUBEUV_MAX_MIP - }; + this.name = name; + this.type = type; + this.code = code; - const material = _getMaterial( 'blur' ); - material.uniforms = materialUniforms; // TODO: Move to outside of the material - material.fragmentNode = blur( { ...materialUniforms, latitudinal: latitudinal.equal( 1 ) } ); + Object.defineProperty( this, 'isNodeCode', { value: true } ); - return material; + } } -function _getCubemapMaterial( envTexture ) { - - const material = _getMaterial( 'cubemap' ); - material.fragmentNode = cubeTexture( envTexture, outputDirection ); +let id$1 = 0; - return material; +class NodeCache { -} + constructor( parent = null ) { -function _getEquirectMaterial( envTexture ) { + this.id = id$1 ++; + this.nodesData = new WeakMap(); - const material = _getMaterial( 'equirect' ); - material.fragmentNode = texture( envTexture, equirectUV( outputDirection ), 0 ); + this.parent = parent; - return material; + } -} + getData( node ) { -let _id$5 = 0; + let data = this.nodesData.get( node ); -class BindGroup { + if ( data === undefined && this.parent !== null ) { - constructor( name = '', bindings = [], index = 0, bindingsReference = [] ) { + data = this.parent.getData( node ); - this.name = name; - this.bindings = bindings; - this.index = index; - this.bindingsReference = bindingsReference; + } - this.id = _id$5 ++; + return data; } -} + setData( node, data ) { -const rendererCache = new WeakMap(); + this.nodesData.set( node, data ); -const typeFromLength = new Map( [ - [ 2, 'vec2' ], - [ 3, 'vec3' ], - [ 4, 'vec4' ], - [ 9, 'mat3' ], - [ 16, 'mat4' ] -] ); + } -const typeFromArray = new Map( [ - [ Int8Array, 'int' ], - [ Int16Array, 'int' ], - [ Int32Array, 'int' ], - [ Uint8Array, 'uint' ], - [ Uint16Array, 'uint' ], - [ Uint32Array, 'uint' ], - [ Float32Array, 'float' ] -] ); +} -const toFloat = ( value ) => { +class ParameterNode extends PropertyNode { - value = Number( value ); + static get type() { - return value + ( value % 1 ? '' : '.0' ); + return 'ParameterNode'; -}; + } -class NodeBuilder { + constructor( nodeType, name = null ) { - constructor( object, renderer, parser ) { + super( nodeType, name ); - this.object = object; - this.material = ( object && object.material ) || null; - this.geometry = ( object && object.geometry ) || null; - this.renderer = renderer; - this.parser = parser; - this.scene = null; - this.camera = null; + this.isParameterNode = true; - this.nodes = []; - this.updateNodes = []; - this.updateBeforeNodes = []; - this.updateAfterNodes = []; - this.hashNodes = {}; + } - this.lightsNode = null; - this.environmentNode = null; - this.fogNode = null; + getHash() { - this.clippingContext = null; + return this.uuid; - this.vertexShader = null; - this.fragmentShader = null; - this.computeShader = null; + } - this.flowNodes = { vertex: [], fragment: [], compute: [] }; - this.flowCode = { vertex: '', fragment: '', compute: '' }; - this.uniforms = { vertex: [], fragment: [], compute: [], index: 0 }; - this.structs = { vertex: [], fragment: [], compute: [], index: 0 }; - this.bindings = { vertex: {}, fragment: {}, compute: {} }; - this.bindingsIndexes = {}; - this.bindGroups = null; - this.attributes = []; - this.bufferAttributes = []; - this.varyings = []; - this.codes = {}; - this.vars = {}; - this.flow = { code: '' }; - this.chaining = []; - this.stack = stack(); - this.stacks = []; - this.tab = '\t'; + generate() { - this.instanceBindGroups = true; + return this.name; - this.currentFunctionNode = null; + } - this.context = { - material: this.material - }; +} - this.cache = new NodeCache(); - this.globalCache = this.cache; +const parameter = ( type, name ) => nodeObject( new ParameterNode( type, name ) ); - this.flowsData = new WeakMap(); +class CodeNode extends Node { - this.shaderStage = null; - this.buildStage = null; + static get type() { - this.useComparisonMethod = false; + return 'CodeNode'; } - getBindGroupsCache() { + constructor( code = '', includes = [], language = '' ) { - let bindGroupsCache = rendererCache.get( this.renderer ); + super( 'code' ); - if ( bindGroupsCache === undefined ) { + this.isCodeNode = true; - bindGroupsCache = new ChainMap(); + this.code = code; + this.language = language; - rendererCache.set( this.renderer, bindGroupsCache ); + this.includes = includes; - } + } - return bindGroupsCache; + isGlobal() { + + return true; } - createRenderTarget( width, height, options ) { + setIncludes( includes ) { - return new RenderTarget( width, height, options ); + this.includes = includes; + + return this; } - createCubeRenderTarget( size, options ) { + getIncludes( /*builder*/ ) { - return new CubeRenderTarget( size, options ); + return this.includes; } - createPMREMGenerator() { + generate( builder ) { - // TODO: Move Materials.js to outside of the Nodes.js in order to remove this function and improve tree-shaking support + const includes = this.getIncludes( builder ); - return new PMREMGenerator( this.renderer ); + for ( const include of includes ) { - } + include.build( builder ); - includes( node ) { + } - return this.nodes.includes( node ); + const nodeCode = builder.getCodeFromNode( this, this.getNodeType( builder ) ); + nodeCode.code = this.code; - } + return nodeCode.code; - _getBindGroup( groupName, bindings ) { + } - const bindGroupsCache = this.getBindGroupsCache(); + serialize( data ) { - // + super.serialize( data ); - const bindingsArray = []; + data.code = this.code; + data.language = this.language; - let sharedGroup = true; + } - for ( const binding of bindings ) { + deserialize( data ) { - bindingsArray.push( binding ); + super.deserialize( data ); - sharedGroup = sharedGroup && binding.groupNode.shared !== true; + this.code = data.code; + this.language = data.language; - } + } - // +} - let bindGroup; +const code = /*@__PURE__*/ nodeProxy( CodeNode ); - if ( sharedGroup ) { +const js = ( src, includes ) => code( src, includes, 'js' ); +const wgsl = ( src, includes ) => code( src, includes, 'wgsl' ); +const glsl = ( src, includes ) => code( src, includes, 'glsl' ); - bindGroup = bindGroupsCache.get( bindingsArray ); +class FunctionNode extends CodeNode { - if ( bindGroup === undefined ) { + static get type() { - bindGroup = new BindGroup( groupName, bindingsArray, this.bindingsIndexes[ groupName ].group, bindingsArray ); + return 'FunctionNode'; - bindGroupsCache.set( bindingsArray, bindGroup ); + } - } + constructor( code = '', includes = [], language = '' ) { - } else { + super( code, includes, language ); - bindGroup = new BindGroup( groupName, bindingsArray, this.bindingsIndexes[ groupName ].group, bindingsArray ); + } - } + getNodeType( builder ) { - return bindGroup; + return this.getNodeFunction( builder ).type; } - getBindGroupArray( groupName, shaderStage ) { + getInputs( builder ) { - const bindings = this.bindings[ shaderStage ]; + return this.getNodeFunction( builder ).inputs; - let bindGroup = bindings[ groupName ]; + } - if ( bindGroup === undefined ) { + getNodeFunction( builder ) { - if ( this.bindingsIndexes[ groupName ] === undefined ) { + const nodeData = builder.getDataFromNode( this ); - this.bindingsIndexes[ groupName ] = { binding: 0, group: Object.keys( this.bindingsIndexes ).length }; + let nodeFunction = nodeData.nodeFunction; - } + if ( nodeFunction === undefined ) { - bindings[ groupName ] = bindGroup = []; + nodeFunction = builder.parser.parseFunction( this.code ); + + nodeData.nodeFunction = nodeFunction; } - return bindGroup; + return nodeFunction; } - getBindings() { - - let bindingsGroups = this.bindGroups; + generate( builder, output ) { - if ( bindingsGroups === null ) { + super.generate( builder ); - const groups = {}; - const bindings = this.bindings; + const nodeFunction = this.getNodeFunction( builder ); - for ( const shaderStage of shaderStages ) { + const name = nodeFunction.name; + const type = nodeFunction.type; - for ( const groupName in bindings[ shaderStage ] ) { + const nodeCode = builder.getCodeFromNode( this, type ); - const uniforms = bindings[ shaderStage ][ groupName ]; + if ( name !== '' ) { - const groupUniforms = groups[ groupName ] || ( groups[ groupName ] = [] ); - groupUniforms.push( ...uniforms ); + // use a custom property name - } + nodeCode.name = name; - } + } - bindingsGroups = []; + const propertyName = builder.getPropertyName( nodeCode ); - for ( const groupName in groups ) { + const code = this.getNodeFunction( builder ).getCode( propertyName ); - const group = groups[ groupName ]; + nodeCode.code = code + '\n'; - const bindingsGroup = this._getBindGroup( groupName, group ); + if ( output === 'property' ) { - bindingsGroups.push( bindingsGroup ); + return propertyName; - } + } else { - this.bindGroups = bindingsGroups; + return builder.format( `${ propertyName }()`, type, output ); } - return bindingsGroups; - } - setHashNode( node, hash ) { +} - this.hashNodes[ hash ] = node; +const nativeFn = ( code, includes = [], language = '' ) => { - } + for ( let i = 0; i < includes.length; i ++ ) { - addNode( node ) { + const include = includes[ i ]; - if ( this.nodes.includes( node ) === false ) { + // TSL Function: glslFn, wgslFn - this.nodes.push( node ); + if ( typeof include === 'function' ) { - this.setHashNode( node, node.getHash( this ) ); + includes[ i ] = include.functionNode; } } - buildUpdateNodes() { - - for ( const node of this.nodes ) { - - const updateType = node.getUpdateType(); - const updateBeforeType = node.getUpdateBeforeType(); - const updateAfterType = node.getUpdateAfterType(); - - if ( updateType !== NodeUpdateType.NONE ) { + const functionNode = nodeObject( new FunctionNode( code, includes, language ) ); - this.updateNodes.push( node.getSelf() ); + const fn = ( ...params ) => functionNode.call( ...params ); + fn.functionNode = functionNode; - } + return fn; - if ( updateBeforeType !== NodeUpdateType.NONE ) { +}; - this.updateBeforeNodes.push( node ); +const glslFn = ( code, includes ) => nativeFn( code, includes, 'glsl' ); +const wgslFn = ( code, includes ) => nativeFn( code, includes, 'wgsl' ); - } +class Uniform { - if ( updateAfterType !== NodeUpdateType.NONE ) { + constructor( name, value ) { - this.updateAfterNodes.push( node ); + this.name = name; + this.value = value; - } + this.boundary = 0; // used to build the uniform buffer according to the STD140 layout + this.itemSize = 0; - } + this.offset = 0; // this property is set by WebGPUUniformsGroup and marks the start position in the uniform buffer } - get currentNode() { + setValue( value ) { - return this.chaining[ this.chaining.length - 1 ]; + this.value = value; } - isFilteredTexture( texture ) { + getValue() { - return ( texture.magFilter === LinearFilter || texture.magFilter === LinearMipmapNearestFilter || texture.magFilter === NearestMipmapLinearFilter || texture.magFilter === LinearMipmapLinearFilter || - texture.minFilter === LinearFilter || texture.minFilter === LinearMipmapNearestFilter || texture.minFilter === NearestMipmapLinearFilter || texture.minFilter === LinearMipmapLinearFilter ); + return this.value; } - addChain( node ) { - - /* - if ( this.chaining.indexOf( node ) !== - 1 ) { +} - console.warn( 'Recursive node: ', node ); +class NumberUniform extends Uniform { - } - */ + constructor( name, value = 0 ) { - this.chaining.push( node ); + super( name, value ); - } + this.isNumberUniform = true; - removeChain( node ) { + this.boundary = 4; + this.itemSize = 1; - const lastChain = this.chaining.pop(); + } - if ( lastChain !== node ) { +} - throw new Error( 'NodeBuilder: Invalid node chaining!' ); +class Vector2Uniform extends Uniform { - } + constructor( name, value = new Vector2() ) { - } + super( name, value ); - getMethod( method ) { + this.isVector2Uniform = true; - return method; + this.boundary = 8; + this.itemSize = 2; } - getNodeFromHash( hash ) { +} - return this.hashNodes[ hash ]; +class Vector3Uniform extends Uniform { - } + constructor( name, value = new Vector3() ) { - addFlow( shaderStage, node ) { + super( name, value ); - this.flowNodes[ shaderStage ].push( node ); + this.isVector3Uniform = true; - return node; + this.boundary = 16; + this.itemSize = 3; } - setContext( context ) { +} - this.context = context; +class Vector4Uniform extends Uniform { - } + constructor( name, value = new Vector4() ) { - getContext() { + super( name, value ); - return this.context; + this.isVector4Uniform = true; + + this.boundary = 16; + this.itemSize = 4; } - getSharedContext() { +} - ({ ...this.context }); +class ColorUniform extends Uniform { - return this.context; + constructor( name, value = new Color() ) { - } + super( name, value ); - setCache( cache ) { + this.isColorUniform = true; - this.cache = cache; + this.boundary = 16; + this.itemSize = 3; } - getCache() { +} - return this.cache; +class Matrix3Uniform extends Uniform { - } + constructor( name, value = new Matrix3() ) { - getCacheFromNode( node, parent = true ) { + super( name, value ); - const data = this.getDataFromNode( node ); - if ( data.cache === undefined ) data.cache = new NodeCache( parent ? this.getCache() : null ); + this.isMatrix3Uniform = true; - return data.cache; + this.boundary = 48; + this.itemSize = 12; } - isAvailable( /*name*/ ) { +} - return false; +class Matrix4Uniform extends Uniform { - } + constructor( name, value = new Matrix4() ) { - getVertexIndex() { + super( name, value ); - console.warn( 'Abstract function.' ); + this.isMatrix4Uniform = true; + + this.boundary = 64; + this.itemSize = 16; } - getInstanceIndex() { +} - console.warn( 'Abstract function.' ); +class NumberNodeUniform extends NumberUniform { - } + constructor( nodeUniform ) { - getDrawIndex() { + super( nodeUniform.name, nodeUniform.value ); - console.warn( 'Abstract function.' ); + this.nodeUniform = nodeUniform; } - getFrontFacing() { + getValue() { - console.warn( 'Abstract function.' ); + return this.nodeUniform.value; } - getFragCoord() { +} - console.warn( 'Abstract function.' ); +class Vector2NodeUniform extends Vector2Uniform { - } + constructor( nodeUniform ) { - isFlipY() { + super( nodeUniform.name, nodeUniform.value ); - return false; + this.nodeUniform = nodeUniform; } - increaseUsage( node ) { - - const nodeData = this.getDataFromNode( node ); - nodeData.usageCount = nodeData.usageCount === undefined ? 1 : nodeData.usageCount + 1; + getValue() { - return nodeData.usageCount; + return this.nodeUniform.value; } - generateTexture( /* texture, textureProperty, uvSnippet */ ) { +} - console.warn( 'Abstract function.' ); +class Vector3NodeUniform extends Vector3Uniform { - } + constructor( nodeUniform ) { - generateTextureLod( /* texture, textureProperty, uvSnippet, levelSnippet */ ) { + super( nodeUniform.name, nodeUniform.value ); - console.warn( 'Abstract function.' ); + this.nodeUniform = nodeUniform; } - generateConst( type, value = null ) { + getValue() { - if ( value === null ) { + return this.nodeUniform.value; - if ( type === 'float' || type === 'int' || type === 'uint' ) value = 0; - else if ( type === 'bool' ) value = false; - else if ( type === 'color' ) value = new Color(); - else if ( type === 'vec2' ) value = new Vector2(); - else if ( type === 'vec3' ) value = new Vector3(); - else if ( type === 'vec4' ) value = new Vector4(); + } - } +} - if ( type === 'float' ) return toFloat( value ); - if ( type === 'int' ) return `${ Math.round( value ) }`; - if ( type === 'uint' ) return value >= 0 ? `${ Math.round( value ) }u` : '0u'; - if ( type === 'bool' ) return value ? 'true' : 'false'; - if ( type === 'color' ) return `${ this.getType( 'vec3' ) }( ${ toFloat( value.r ) }, ${ toFloat( value.g ) }, ${ toFloat( value.b ) } )`; +class Vector4NodeUniform extends Vector4Uniform { - const typeLength = this.getTypeLength( type ); + constructor( nodeUniform ) { - const componentType = this.getComponentType( type ); + super( nodeUniform.name, nodeUniform.value ); - const generateConst = value => this.generateConst( componentType, value ); + this.nodeUniform = nodeUniform; - if ( typeLength === 2 ) { + } - return `${ this.getType( type ) }( ${ generateConst( value.x ) }, ${ generateConst( value.y ) } )`; + getValue() { - } else if ( typeLength === 3 ) { + return this.nodeUniform.value; - return `${ this.getType( type ) }( ${ generateConst( value.x ) }, ${ generateConst( value.y ) }, ${ generateConst( value.z ) } )`; + } - } else if ( typeLength === 4 ) { +} - return `${ this.getType( type ) }( ${ generateConst( value.x ) }, ${ generateConst( value.y ) }, ${ generateConst( value.z ) }, ${ generateConst( value.w ) } )`; +class ColorNodeUniform extends ColorUniform { - } else if ( typeLength > 4 && value && ( value.isMatrix3 || value.isMatrix4 ) ) { + constructor( nodeUniform ) { - return `${ this.getType( type ) }( ${ value.elements.map( generateConst ).join( ', ' ) } )`; + super( nodeUniform.name, nodeUniform.value ); - } else if ( typeLength > 4 ) { + this.nodeUniform = nodeUniform; - return `${ this.getType( type ) }()`; + } - } + getValue() { - throw new Error( `NodeBuilder: Type '${type}' not found in generate constant attempt.` ); + return this.nodeUniform.value; } - getType( type ) { +} - if ( type === 'color' ) return 'vec3'; +class Matrix3NodeUniform extends Matrix3Uniform { - return type; + constructor( nodeUniform ) { + + super( nodeUniform.name, nodeUniform.value ); + + this.nodeUniform = nodeUniform; } - hasGeometryAttribute( name ) { + getValue() { - return this.geometry && this.geometry.getAttribute( name ) !== undefined; + return this.nodeUniform.value; } - getAttribute( name, type ) { +} - const attributes = this.attributes; +class Matrix4NodeUniform extends Matrix4Uniform { - // find attribute + constructor( nodeUniform ) { - for ( const attribute of attributes ) { + super( nodeUniform.name, nodeUniform.value ); - if ( attribute.name === name ) { + this.nodeUniform = nodeUniform; - return attribute; + } - } + getValue() { - } + return this.nodeUniform.value; - // create a new if no exist + } - const attribute = new NodeAttribute( name, type ); +} - attributes.push( attribute ); +class StackNode extends Node { - return attribute; + static get type() { + + return 'StackNode'; } - getPropertyName( node/*, shaderStage*/ ) { + constructor( parent = null ) { - return node.name; + super(); - } + this.nodes = []; + this.outputNode = null; - isVector( type ) { + this.parent = parent; - return /vec\d/.test( type ); + this._currentCond = null; + + this.isStackNode = true; } - isMatrix( type ) { + getNodeType( builder ) { - return /mat\d/.test( type ); + return this.outputNode ? this.outputNode.getNodeType( builder ) : 'void'; } - isReference( type ) { + add( node ) { - return type === 'void' || type === 'property' || type === 'sampler' || type === 'texture' || type === 'cubeTexture' || type === 'storageTexture' || type === 'depthTexture' || type === 'texture3D'; + this.nodes.push( node ); - } + return this; - needsToWorkingColorSpace( /*texture*/ ) { + } - return false; + If( boolNode, method ) { - } + const methodNode = new ShaderNode( method ); + this._currentCond = select( boolNode, methodNode ); - getComponentTypeFromTexture( texture ) { + return this.add( this._currentCond ); - const type = texture.type; + } - if ( texture.isDataTexture ) { + ElseIf( boolNode, method ) { - if ( type === IntType ) return 'int'; - if ( type === UnsignedIntType ) return 'uint'; + const methodNode = new ShaderNode( method ); + const ifNode = select( boolNode, methodNode ); - } + this._currentCond.elseNode = ifNode; + this._currentCond = ifNode; - return 'float'; + return this; } - getElementType( type ) { + Else( method ) { - if ( type === 'mat2' ) return 'vec2'; - if ( type === 'mat3' ) return 'vec3'; - if ( type === 'mat4' ) return 'vec4'; + this._currentCond.elseNode = new ShaderNode( method ); - return this.getComponentType( type ); + return this; } - getComponentType( type ) { + build( builder, ...params ) { - type = this.getVectorType( type ); + const previousStack = getCurrentStack(); - if ( type === 'float' || type === 'bool' || type === 'int' || type === 'uint' ) return type; + setCurrentStack( this ); - const componentType = /(b|i|u|)(vec|mat)([2-4])/.exec( type ); + for ( const node of this.nodes ) { - if ( componentType === null ) return null; + node.build( builder, 'void' ); - if ( componentType[ 1 ] === 'b' ) return 'bool'; - if ( componentType[ 1 ] === 'i' ) return 'int'; - if ( componentType[ 1 ] === 'u' ) return 'uint'; + } - return 'float'; + setCurrentStack( previousStack ); + + return this.outputNode ? this.outputNode.build( builder, ...params ) : super.build( builder, ...params ); } - getVectorType( type ) { + // - if ( type === 'color' ) return 'vec3'; - if ( type === 'texture' || type === 'cubeTexture' || type === 'storageTexture' || type === 'texture3D' ) return 'vec4'; + else( ...params ) { // @deprecated, r168 - return type; + console.warn( 'TSL.StackNode: .else() has been renamed to .Else().' ); + return this.Else( ...params ); } - getTypeFromLength( length, componentType = 'float' ) { - - if ( length === 1 ) return componentType; - - const baseType = typeFromLength.get( length ); - const prefix = componentType === 'float' ? '' : componentType[ 0 ]; + elseif( ...params ) { // @deprecated, r168 - return prefix + baseType; + console.warn( 'TSL.StackNode: .elseif() has been renamed to .ElseIf().' ); + return this.ElseIf( ...params ); } - getTypeFromArray( array ) { +} - return typeFromArray.get( array.constructor ); +const stack = /*@__PURE__*/ nodeProxy( StackNode ); - } +const LOD_MIN = 4; - getTypeFromAttribute( attribute ) { +// The standard deviations (radians) associated with the extra mips. These are +// chosen to approximate a Trowbridge-Reitz distribution function times the +// geometric shadowing function. These sigma values squared must match the +// variance #defines in cube_uv_reflection_fragment.glsl.js. +const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; - let dataAttribute = attribute; +// The maximum length of the blur for loop. Smaller sigmas will use fewer +// samples and exit early, but not recompile the shader. +const MAX_SAMPLES = 20; - if ( attribute.isInterleavedBufferAttribute ) dataAttribute = attribute.data; +const _flatCamera = /*@__PURE__*/ new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); +const _cubeCamera = /*@__PURE__*/ new PerspectiveCamera( 90, 1 ); +const _clearColor$2 = /*@__PURE__*/ new Color(); +let _oldTarget = null; +let _oldActiveCubeFace = 0; +let _oldActiveMipmapLevel = 0; - const array = dataAttribute.array; - const itemSize = attribute.itemSize; - const normalized = attribute.normalized; +// Golden Ratio +const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; +const INV_PHI = 1 / PHI; - let arrayType; +// Vertices of a dodecahedron (except the opposites, which represent the +// same axis), used as axis directions evenly spread on a sphere. +const _axisDirections = [ + /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ), + /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ), + /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ), + /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ), + /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ), + /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ), + /*@__PURE__*/ new Vector3( - 1, 1, - 1 ), + /*@__PURE__*/ new Vector3( 1, 1, - 1 ), + /*@__PURE__*/ new Vector3( - 1, 1, 1 ), + /*@__PURE__*/ new Vector3( 1, 1, 1 ) +]; - if ( ! ( attribute instanceof Float16BufferAttribute ) && normalized !== true ) { +// - arrayType = this.getTypeFromArray( array ); +// WebGPU Face indices +const _faceLib = [ + 3, 1, 5, + 0, 4, 2 +]; - } +const direction = getDirection( uv(), attribute( 'faceIndex' ) ).normalize(); +const outputDirection = vec3( direction.x, direction.y.negate(), direction.z ); - return this.getTypeFromLength( itemSize, arrayType ); +/** + * This class generates a Prefiltered, Mipmapped Radiance Environment Map + * (PMREM) from a cubeMap environment texture. This allows different levels of + * blur to be quickly accessed based on material roughness. It is packed into a + * special CubeUV format that allows us to perform custom interpolation so that + * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap + * chain, it only goes down to the LOD_MIN level (above), and then creates extra + * even more filtered 'mips' at the same LOD_MIN resolution, associated with + * higher roughness levels. In this way we maintain resolution to smoothly + * interpolate diffuse lighting while limiting sampling computation. + * + * Paper: Fast, Accurate Image-Based Lighting + * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view +*/ - } +class PMREMGenerator { - getTypeLength( type ) { + constructor( renderer ) { - const vecType = this.getVectorType( type ); - const vecNum = /vec([2-4])/.exec( vecType ); + this._renderer = renderer; + this._pingPongRenderTarget = null; - if ( vecNum !== null ) return Number( vecNum[ 1 ] ); - if ( vecType === 'float' || vecType === 'bool' || vecType === 'int' || vecType === 'uint' ) return 1; - if ( /mat2/.test( type ) === true ) return 4; - if ( /mat3/.test( type ) === true ) return 9; - if ( /mat4/.test( type ) === true ) return 16; + this._lodMax = 0; + this._cubeSize = 0; + this._lodPlanes = []; + this._sizeLods = []; + this._sigmas = []; + this._lodMeshes = []; - return 0; + this._blurMaterial = null; + this._cubemapMaterial = null; + this._equirectMaterial = null; + this._backgroundBox = null; } - getVectorFromMatrix( type ) { + /** + * Generates a PMREM from a supplied Scene, which can be faster than using an + * image if networking bandwidth is low. Optional sigma specifies a blur radius + * in radians to be applied to the scene before PMREM generation. Optional near + * and far planes ensure the scene is rendered in its entirety (the cubeCamera + * is placed at the origin). + */ + fromScene( scene, sigma = 0, near = 0.1, far = 100 ) { - return type.replace( 'mat', 'vec' ); + _oldTarget = this._renderer.getRenderTarget(); + _oldActiveCubeFace = this._renderer.getActiveCubeFace(); + _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); - } + this._setSize( 256 ); - changeComponentType( type, newComponentType ) { + const cubeUVRenderTarget = this._allocateTargets(); + cubeUVRenderTarget.depthBuffer = true; - return this.getTypeFromLength( this.getTypeLength( type ), newComponentType ); + this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget ); - } + if ( sigma > 0 ) { - getIntegerType( type ) { + this._blur( cubeUVRenderTarget, 0, 0, sigma ); - const componentType = this.getComponentType( type ); + } - if ( componentType === 'int' || componentType === 'uint' ) return type; + this._applyPMREM( cubeUVRenderTarget ); - return this.changeComponentType( type, 'int' ); + this._cleanup( cubeUVRenderTarget ); + + return cubeUVRenderTarget; } - addStack() { + /** + * Generates a PMREM from an equirectangular texture, which can be either LDR + * or HDR. The ideal input image size is 1k (1024 x 512), + * as this matches best with the 256 x 256 cubemap output. + */ + fromEquirectangular( equirectangular, renderTarget = null ) { - this.stack = stack( this.stack ); + return this._fromTexture( equirectangular, renderTarget ); - this.stacks.push( getCurrentStack() || this.stack ); - setCurrentStack( this.stack ); + } - return this.stack; + /** + * Generates a PMREM from an cubemap texture, which can be either LDR + * or HDR. The ideal input cube size is 256 x 256, + * as this matches best with the 256 x 256 cubemap output. + */ + fromCubemap( cubemap, renderTarget = null ) { + + return this._fromTexture( cubemap, renderTarget ); } - removeStack() { + /** + * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during + * your texture's network fetch for increased concurrency. + */ + async compileCubemapShader() { - const lastStack = this.stack; - this.stack = lastStack.parent; + if ( this._cubemapMaterial === null ) { - setCurrentStack( this.stacks.pop() ); + this._cubemapMaterial = _getCubemapMaterial(); + await this._compileMaterial( this._cubemapMaterial ); - return lastStack; + } } - getDataFromNode( node, shaderStage = this.shaderStage, cache = null ) { + /** + * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during + * your texture's network fetch for increased concurrency. + */ + async compileEquirectangularShader() { - cache = cache === null ? ( node.isGlobal( this ) ? this.globalCache : this.cache ) : cache; + if ( this._equirectMaterial === null ) { - let nodeData = cache.getData( node ); + this._equirectMaterial = _getEquirectMaterial(); + await this._compileMaterial( this._equirectMaterial ); - if ( nodeData === undefined ) { + } - nodeData = {}; + } - cache.setData( node, nodeData ); + /** + * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, + * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on + * one of them will cause any others to also become unusable. + */ + dispose() { - } + this._dispose(); - if ( nodeData[ shaderStage ] === undefined ) nodeData[ shaderStage ] = {}; + if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose(); + if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose(); + if ( this._backgroundBox !== null ) { - return nodeData[ shaderStage ]; + this._backgroundBox.geometry.dispose(); + this._backgroundBox.material.dispose(); + + } } - getNodeProperties( node, shaderStage = 'any' ) { + // private interface - const nodeData = this.getDataFromNode( node, shaderStage ); + _setSize( cubeSize ) { - return nodeData.properties || ( nodeData.properties = { outputNode: null } ); + this._lodMax = Math.floor( Math.log2( cubeSize ) ); + this._cubeSize = Math.pow( 2, this._lodMax ); } - getBufferAttributeFromNode( node, type ) { - - const nodeData = this.getDataFromNode( node ); + _dispose() { - let bufferAttribute = nodeData.bufferAttribute; + if ( this._blurMaterial !== null ) this._blurMaterial.dispose(); - if ( bufferAttribute === undefined ) { + if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose(); - const index = this.uniforms.index ++; + for ( let i = 0; i < this._lodPlanes.length; i ++ ) { - bufferAttribute = new NodeAttribute( 'nodeAttribute' + index, type, node ); + this._lodPlanes[ i ].dispose(); - this.bufferAttributes.push( bufferAttribute ); + } - nodeData.bufferAttribute = bufferAttribute; + } - } + _cleanup( outputTarget ) { - return bufferAttribute; + this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel ); + outputTarget.scissorTest = false; + _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); } - getStructTypeFromNode( node, shaderStage = this.shaderStage ) { - - const nodeData = this.getDataFromNode( node, shaderStage ); + _fromTexture( texture, renderTarget ) { - if ( nodeData.structType === undefined ) { + if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) { - const index = this.structs.index ++; + this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) ); - node.name = `StructType${ index }`; - this.structs[ shaderStage ].push( node ); + } else { // Equirectangular - nodeData.structType = node; + this._setSize( texture.image.width / 4 ); } - return node; + _oldTarget = this._renderer.getRenderTarget(); + _oldActiveCubeFace = this._renderer.getActiveCubeFace(); + _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); - } + const cubeUVRenderTarget = renderTarget || this._allocateTargets(); + this._textureToCubeUV( texture, cubeUVRenderTarget ); + this._applyPMREM( cubeUVRenderTarget ); + this._cleanup( cubeUVRenderTarget ); - getUniformFromNode( node, type, shaderStage = this.shaderStage, name = null ) { + return cubeUVRenderTarget; - const nodeData = this.getDataFromNode( node, shaderStage, this.globalCache ); + } - let nodeUniform = nodeData.uniform; + _allocateTargets() { - if ( nodeUniform === undefined ) { + const width = 3 * Math.max( this._cubeSize, 16 * 7 ); + const height = 4 * this._cubeSize; - const index = this.uniforms.index ++; + const params = { + magFilter: LinearFilter, + minFilter: LinearFilter, + generateMipmaps: false, + type: HalfFloatType, + format: RGBAFormat, + colorSpace: LinearSRGBColorSpace, + //depthBuffer: false + }; - nodeUniform = new NodeUniform( name || ( 'nodeUniform' + index ), type, node ); + const cubeUVRenderTarget = _createRenderTarget( width, height, params ); - this.uniforms[ shaderStage ].push( nodeUniform ); + if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) { - nodeData.uniform = nodeUniform; + if ( this._pingPongRenderTarget !== null ) { - } + this._dispose(); - return nodeUniform; + } - } + this._pingPongRenderTarget = _createRenderTarget( width, height, params ); - getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage ) { + const { _lodMax } = this; + ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas, lodMeshes: this._lodMeshes } = _createPlanes( _lodMax ) ); - const nodeData = this.getDataFromNode( node, shaderStage ); + this._blurMaterial = _getBlurShader( _lodMax, width, height ); - let nodeVar = nodeData.variable; + } - if ( nodeVar === undefined ) { + return cubeUVRenderTarget; - const vars = this.vars[ shaderStage ] || ( this.vars[ shaderStage ] = [] ); + } - if ( name === null ) name = 'nodeVar' + vars.length; + async _compileMaterial( material ) { - nodeVar = new NodeVar( name, type ); + const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material ); + await this._renderer.compile( tmpMesh, _flatCamera ); - vars.push( nodeVar ); + } - nodeData.variable = nodeVar; - - } - - return nodeVar; + _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) { - } + const cubeCamera = _cubeCamera; + cubeCamera.near = near; + cubeCamera.far = far; - getVaryingFromNode( node, name = null, type = node.getNodeType( this ) ) { + // px, py, pz, nx, ny, nz + const upSign = [ - 1, 1, - 1, - 1, - 1, - 1 ]; + const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ]; - const nodeData = this.getDataFromNode( node, 'any' ); + const renderer = this._renderer; - let nodeVarying = nodeData.varying; + const originalAutoClear = renderer.autoClear; - if ( nodeVarying === undefined ) { + renderer.getClearColor( _clearColor$2 ); - const varyings = this.varyings; - const index = varyings.length; + renderer.autoClear = false; - if ( name === null ) name = 'nodeVarying' + index; + let backgroundBox = this._backgroundBox; - nodeVarying = new NodeVarying( name, type ); + if ( backgroundBox === null ) { - varyings.push( nodeVarying ); + const backgroundMaterial = new MeshBasicMaterial( { + name: 'PMREM.Background', + side: BackSide, + depthWrite: false, + depthTest: false + } ); - nodeData.varying = nodeVarying; + backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial ); } - return nodeVarying; - - } - - getCodeFromNode( node, type, shaderStage = this.shaderStage ) { - - const nodeData = this.getDataFromNode( node ); + let useSolidColor = false; + const background = scene.background; - let nodeCode = nodeData.code; + if ( background ) { - if ( nodeCode === undefined ) { + if ( background.isColor ) { - const codes = this.codes[ shaderStage ] || ( this.codes[ shaderStage ] = [] ); - const index = codes.length; + backgroundBox.material.color.copy( background ); + scene.background = null; + useSolidColor = true; - nodeCode = new NodeCode( 'nodeCode' + index, type ); + } - codes.push( nodeCode ); + } else { - nodeData.code = nodeCode; + backgroundBox.material.color.copy( _clearColor$2 ); + useSolidColor = true; } - return nodeCode; - - } - - addLineFlowCode( code ) { - - if ( code === '' ) return this; + renderer.setRenderTarget( cubeUVRenderTarget ); - code = this.tab + code; + renderer.clear(); - if ( ! /;\s*$/.test( code ) ) { + if ( useSolidColor ) { - code = code + ';\n'; + renderer.render( backgroundBox, cubeCamera ); } - this.flow.code += code; + for ( let i = 0; i < 6; i ++ ) { - return this; + const col = i % 3; - } + if ( col === 0 ) { - addFlowCode( code ) { + cubeCamera.up.set( 0, upSign[ i ], 0 ); + cubeCamera.lookAt( forwardSign[ i ], 0, 0 ); - this.flow.code += code; + } else if ( col === 1 ) { - return this; + cubeCamera.up.set( 0, 0, upSign[ i ] ); + cubeCamera.lookAt( 0, forwardSign[ i ], 0 ); - } + } else { - addFlowTab() { + cubeCamera.up.set( 0, upSign[ i ], 0 ); + cubeCamera.lookAt( 0, 0, forwardSign[ i ] ); - this.tab += '\t'; + } - return this; + const size = this._cubeSize; - } + _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size ); - removeFlowTab() { + renderer.render( scene, cubeCamera ); - this.tab = this.tab.slice( 0, - 1 ); + } - return this; + renderer.autoClear = originalAutoClear; + scene.background = background; } - getFlowData( node/*, shaderStage*/ ) { + _textureToCubeUV( texture, cubeUVRenderTarget ) { - return this.flowsData.get( node ); + const renderer = this._renderer; - } + const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ); - flowNode( node ) { + if ( isCubeTexture ) { - const output = node.getNodeType( this ); + if ( this._cubemapMaterial === null ) { - const flowData = this.flowChildNode( node, output ); + this._cubemapMaterial = _getCubemapMaterial( texture ); - this.flowsData.set( node, flowData ); + } - return flowData; + } else { - } + if ( this._equirectMaterial === null ) { - buildFunctionNode( shaderNode ) { + this._equirectMaterial = _getEquirectMaterial( texture ); - const fn = new FunctionNode(); + } - const previous = this.currentFunctionNode; + } - this.currentFunctionNode = fn; + const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial; + material.fragmentNode.value = texture; - fn.code = this.buildFunctionCode( shaderNode ); + const mesh = this._lodMeshes[ 0 ]; + mesh.material = material; - this.currentFunctionNode = previous; + const size = this._cubeSize; - return fn; + _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size ); - } + renderer.setRenderTarget( cubeUVRenderTarget ); + renderer.render( mesh, _flatCamera ); - flowShaderNode( shaderNode ) { + } - const layout = shaderNode.layout; + _applyPMREM( cubeUVRenderTarget ) { - const inputs = { - [ Symbol.iterator ]() { + const renderer = this._renderer; + const autoClear = renderer.autoClear; + renderer.autoClear = false; + const n = this._lodPlanes.length; - let index = 0; - const values = Object.values( this ); - return { - next: () => ( { - value: values[ index ], - done: index ++ >= values.length - } ) - }; + for ( let i = 1; i < n; i ++ ) { - } - }; + const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] ); - for ( const input of layout.inputs ) { + const poleAxis = _axisDirections[ ( n - i - 1 ) % _axisDirections.length ]; - inputs[ input.name ] = new ParameterNode( input.type, input.name ); + this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis ); } - // - - shaderNode.layout = null; - - const callNode = shaderNode.call( inputs ); - const flowData = this.flowStagesNode( callNode, layout.type ); + renderer.autoClear = autoClear; - shaderNode.layout = layout; + } - return flowData; + /** + * This is a two-pass Gaussian blur for a cubemap. Normally this is done + * vertically and horizontally, but this breaks down on a cube. Here we apply + * the blur latitudinally (around the poles), and then longitudinally (towards + * the poles) to approximate the orthogonally-separable blur. It is least + * accurate at the poles, but still does a decent job. + */ + _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) { - } + const pingPongRenderTarget = this._pingPongRenderTarget; - flowStagesNode( node, output = null ) { + this._halfBlur( + cubeUVRenderTarget, + pingPongRenderTarget, + lodIn, + lodOut, + sigma, + 'latitudinal', + poleAxis ); - const previousFlow = this.flow; - const previousVars = this.vars; - const previousCache = this.cache; - const previousBuildStage = this.buildStage; - const previousStack = this.stack; + this._halfBlur( + pingPongRenderTarget, + cubeUVRenderTarget, + lodOut, + lodOut, + sigma, + 'longitudinal', + poleAxis ); - const flow = { - code: '' - }; + } - this.flow = flow; - this.vars = {}; - this.cache = new NodeCache(); - this.stack = stack(); + _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) { - for ( const buildStage of defaultBuildStages ) { + const renderer = this._renderer; + const blurMaterial = this._blurMaterial; - this.setBuildStage( buildStage ); + if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) { - flow.result = node.build( this, output ); + console.error( 'blur direction must be either latitudinal or longitudinal!' ); } - flow.vars = this.getVars( this.shaderStage ); + // Number of standard deviations at which to cut off the discrete approximation. + const STANDARD_DEVIATIONS = 3; - this.flow = previousFlow; - this.vars = previousVars; - this.cache = previousCache; - this.stack = previousStack; + const blurMesh = this._lodMeshes[ lodOut ]; + blurMesh.material = blurMaterial; - this.setBuildStage( previousBuildStage ); + const blurUniforms = blurMaterial.uniforms; - return flow; + const pixels = this._sizeLods[ lodIn ] - 1; + const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 ); + const sigmaPixels = sigmaRadians / radiansPerPixel; + const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES; - } + if ( samples > MAX_SAMPLES ) { - getFunctionOperator() { + console.warn( `sigmaRadians, ${ + sigmaRadians}, is too large and will clip, as it requested ${ + samples} samples when the maximum is set to ${MAX_SAMPLES}` ); - return null; + } - } + const weights = []; + let sum = 0; - flowChildNode( node, output = null ) { + for ( let i = 0; i < MAX_SAMPLES; ++ i ) { - const previousFlow = this.flow; + const x = i / sigmaPixels; + const weight = Math.exp( - x * x / 2 ); + weights.push( weight ); - const flow = { - code: '' - }; + if ( i === 0 ) { - this.flow = flow; + sum += weight; - flow.result = node.build( this, output ); + } else if ( i < samples ) { - this.flow = previousFlow; + sum += 2 * weight; - return flow; + } - } + } - flowNodeFromShaderStage( shaderStage, node, output = null, propertyName = null ) { + for ( let i = 0; i < weights.length; i ++ ) { - const previousShaderStage = this.shaderStage; + weights[ i ] = weights[ i ] / sum; - this.setShaderStage( shaderStage ); + } - const flowData = this.flowChildNode( node, output ); + targetIn.texture.frame = ( targetIn.texture.frame || 0 ) + 1; - if ( propertyName !== null ) { + blurUniforms.envMap.value = targetIn.texture; + blurUniforms.samples.value = samples; + blurUniforms.weights.array = weights; + blurUniforms.latitudinal.value = direction === 'latitudinal' ? 1 : 0; - flowData.code += `${ this.tab + propertyName } = ${ flowData.result };\n`; + if ( poleAxis ) { + + blurUniforms.poleAxis.value = poleAxis; } - this.flowCode[ shaderStage ] = this.flowCode[ shaderStage ] + flowData.code; + const { _lodMax } = this; + blurUniforms.dTheta.value = radiansPerPixel; + blurUniforms.mipInt.value = _lodMax - lodIn; - this.setShaderStage( previousShaderStage ); + const outputSize = this._sizeLods[ lodOut ]; + const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 ); + const y = 4 * ( this._cubeSize - outputSize ); - return flowData; + _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize ); + renderer.setRenderTarget( targetOut ); + renderer.render( blurMesh, _flatCamera ); } - getAttributesArray() { +} - return this.attributes.concat( this.bufferAttributes ); +function _createPlanes( lodMax ) { - } + const lodPlanes = []; + const sizeLods = []; + const sigmas = []; + const lodMeshes = []; - getAttributes( /*shaderStage*/ ) { + let lod = lodMax; - console.warn( 'Abstract function.' ); + const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; - } + for ( let i = 0; i < totalLods; i ++ ) { - getVaryings( /*shaderStage*/ ) { + const sizeLod = Math.pow( 2, lod ); + sizeLods.push( sizeLod ); + let sigma = 1.0 / sizeLod; - console.warn( 'Abstract function.' ); + if ( i > lodMax - LOD_MIN ) { - } + sigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ]; - getVar( type, name ) { + } else if ( i === 0 ) { - return `${ this.getType( type ) } ${ name }`; + sigma = 0; - } + } - getVars( shaderStage ) { + sigmas.push( sigma ); - let snippet = ''; + const texelSize = 1.0 / ( sizeLod - 2 ); + const min = - texelSize; + const max = 1 + texelSize; + const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ]; - const vars = this.vars[ shaderStage ]; + const cubeFaces = 6; + const vertices = 6; + const positionSize = 3; + const uvSize = 2; + const faceIndexSize = 1; - if ( vars !== undefined ) { + const position = new Float32Array( positionSize * vertices * cubeFaces ); + const uv = new Float32Array( uvSize * vertices * cubeFaces ); + const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces ); - for ( const variable of vars ) { + for ( let face = 0; face < cubeFaces; face ++ ) { - snippet += `${ this.getVar( variable.type, variable.name ) }; `; + const x = ( face % 3 ) * 2 / 3 - 1; + const y = face > 2 ? 0 : - 1; + const coordinates = [ + x, y, 0, + x + 2 / 3, y, 0, + x + 2 / 3, y + 1, 0, + x, y, 0, + x + 2 / 3, y + 1, 0, + x, y + 1, 0 + ]; - } + const faceIdx = _faceLib[ face ]; + position.set( coordinates, positionSize * vertices * faceIdx ); + uv.set( uv1, uvSize * vertices * faceIdx ); + const fill = [ faceIdx, faceIdx, faceIdx, faceIdx, faceIdx, faceIdx ]; + faceIndex.set( fill, faceIndexSize * vertices * faceIdx ); } - return snippet; + const planes = new BufferGeometry(); + planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) ); + planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) ); + planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) ); + lodPlanes.push( planes ); + lodMeshes.push( new Mesh( planes, null ) ); - } + if ( lod > LOD_MIN ) { - getUniforms( /*shaderStage*/ ) { + lod --; - console.warn( 'Abstract function.' ); + } } - getCodes( shaderStage ) { + return { lodPlanes, sizeLods, sigmas, lodMeshes }; - const codes = this.codes[ shaderStage ]; +} - let code = ''; +function _createRenderTarget( width, height, params ) { - if ( codes !== undefined ) { + const cubeUVRenderTarget = new RenderTarget( width, height, params ); + cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; + cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; + cubeUVRenderTarget.texture.isPMREMTexture = true; + cubeUVRenderTarget.scissorTest = true; + return cubeUVRenderTarget; - for ( const nodeCode of codes ) { +} - code += nodeCode.code + '\n'; +function _setViewport( target, x, y, width, height ) { - } + target.viewport.set( x, y, width, height ); + target.scissor.set( x, y, width, height ); - } +} - return code; +function _getMaterial( type ) { - } + const material = new NodeMaterial(); + material.depthTest = false; + material.depthWrite = false; + material.blending = NoBlending; + material.name = `PMREM_${ type }`; - getHash() { + return material; - return this.vertexShader + this.fragmentShader + this.computeShader; +} - } +function _getBlurShader( lodMax, width, height ) { - setShaderStage( shaderStage ) { + const weights = uniformArray( new Array( MAX_SAMPLES ).fill( 0 ) ); + const poleAxis = uniform( new Vector3( 0, 1, 0 ) ); + const dTheta = uniform( 0 ); + const n = float( MAX_SAMPLES ); + const latitudinal = uniform( 0 ); // false, bool + const samples = uniform( 1 ); // int + const envMap = texture( null ); + const mipInt = uniform( 0 ); // int + const CUBEUV_TEXEL_WIDTH = float( 1 / width ); + const CUBEUV_TEXEL_HEIGHT = float( 1 / height ); + const CUBEUV_MAX_MIP = float( lodMax ); - this.shaderStage = shaderStage; + const materialUniforms = { + n, + latitudinal, + weights, + poleAxis, + outputDirection, + dTheta, + samples, + envMap, + mipInt, + CUBEUV_TEXEL_WIDTH, + CUBEUV_TEXEL_HEIGHT, + CUBEUV_MAX_MIP + }; - } + const material = _getMaterial( 'blur' ); + material.uniforms = materialUniforms; // TODO: Move to outside of the material + material.fragmentNode = blur( { ...materialUniforms, latitudinal: latitudinal.equal( 1 ) } ); - getShaderStage() { + return material; - return this.shaderStage; +} - } +function _getCubemapMaterial( envTexture ) { - setBuildStage( buildStage ) { + const material = _getMaterial( 'cubemap' ); + material.fragmentNode = cubeTexture( envTexture, outputDirection ); - this.buildStage = buildStage; + return material; - } +} - getBuildStage() { +function _getEquirectMaterial( envTexture ) { - return this.buildStage; + const material = _getMaterial( 'equirect' ); + material.fragmentNode = texture( envTexture, equirectUV( outputDirection ), 0 ); - } + return material; - buildCode() { +} - console.warn( 'Abstract function.' ); +let _id$5 = 0; - } +class BindGroup { - build() { + constructor( name = '', bindings = [], index = 0, bindingsReference = [] ) { - const { object, material, renderer } = this; + this.name = name; + this.bindings = bindings; + this.index = index; + this.bindingsReference = bindingsReference; - if ( material !== null ) { + this.id = _id$5 ++; - let nodeMaterial = renderer.nodes.library.fromMaterial( material ); + } - if ( nodeMaterial === null ) { +} - console.error( `NodeMaterial: Material "${ material.type }" is not compatible.` ); +const rendererCache = new WeakMap(); - nodeMaterial = new NodeMaterial(); +const typeFromLength = new Map( [ + [ 2, 'vec2' ], + [ 3, 'vec3' ], + [ 4, 'vec4' ], + [ 9, 'mat3' ], + [ 16, 'mat4' ] +] ); - } +const typeFromArray = new Map( [ + [ Int8Array, 'int' ], + [ Int16Array, 'int' ], + [ Int32Array, 'int' ], + [ Uint8Array, 'uint' ], + [ Uint16Array, 'uint' ], + [ Uint32Array, 'uint' ], + [ Float32Array, 'float' ] +] ); - nodeMaterial.build( this ); +const toFloat = ( value ) => { - } else { + value = Number( value ); - this.addFlow( 'compute', object ); + return value + ( value % 1 ? '' : '.0' ); - } +}; - // setup() -> stage 1: create possible new nodes and returns an output reference node - // analyze() -> stage 2: analyze nodes to possible optimization and validation - // generate() -> stage 3: generate shader +class NodeBuilder { - for ( const buildStage of defaultBuildStages ) { + constructor( object, renderer, parser ) { - this.setBuildStage( buildStage ); + this.object = object; + this.material = ( object && object.material ) || null; + this.geometry = ( object && object.geometry ) || null; + this.renderer = renderer; + this.parser = parser; + this.scene = null; + this.camera = null; - if ( this.context.vertex && this.context.vertex.isNode ) { + this.nodes = []; + this.updateNodes = []; + this.updateBeforeNodes = []; + this.updateAfterNodes = []; + this.hashNodes = {}; - this.flowNodeFromShaderStage( 'vertex', this.context.vertex ); + this.monitor = null; - } + this.lightsNode = null; + this.environmentNode = null; + this.fogNode = null; - for ( const shaderStage of shaderStages ) { + this.clippingContext = null; - this.setShaderStage( shaderStage ); + this.vertexShader = null; + this.fragmentShader = null; + this.computeShader = null; - const flowNodes = this.flowNodes[ shaderStage ]; + this.flowNodes = { vertex: [], fragment: [], compute: [] }; + this.flowCode = { vertex: '', fragment: '', compute: '' }; + this.uniforms = { vertex: [], fragment: [], compute: [], index: 0 }; + this.structs = { vertex: [], fragment: [], compute: [], index: 0 }; + this.bindings = { vertex: {}, fragment: {}, compute: {} }; + this.bindingsIndexes = {}; + this.bindGroups = null; + this.attributes = []; + this.bufferAttributes = []; + this.varyings = []; + this.codes = {}; + this.vars = {}; + this.flow = { code: '' }; + this.chaining = []; + this.stack = stack(); + this.stacks = []; + this.tab = '\t'; - for ( const node of flowNodes ) { + this.currentFunctionNode = null; - if ( buildStage === 'generate' ) { + this.context = { + material: this.material + }; - this.flowNode( node ); + this.cache = new NodeCache(); + this.globalCache = this.cache; - } else { + this.flowsData = new WeakMap(); - node.build( this ); + this.shaderStage = null; + this.buildStage = null; - } + this.useComparisonMethod = false; - } + } - } + getBindGroupsCache() { - } + let bindGroupsCache = rendererCache.get( this.renderer ); - this.setBuildStage( null ); - this.setShaderStage( null ); + if ( bindGroupsCache === undefined ) { - // stage 4: build code for a specific output + bindGroupsCache = new ChainMap(); - this.buildCode(); - this.buildUpdateNodes(); + rendererCache.set( this.renderer, bindGroupsCache ); - return this; + } - } + return bindGroupsCache; - getNodeUniform( uniformNode, type ) { + } - if ( type === 'float' || type === 'int' || type === 'uint' ) return new NumberNodeUniform( uniformNode ); - if ( type === 'vec2' || type === 'ivec2' || type === 'uvec2' ) return new Vector2NodeUniform( uniformNode ); - if ( type === 'vec3' || type === 'ivec3' || type === 'uvec3' ) return new Vector3NodeUniform( uniformNode ); - if ( type === 'vec4' || type === 'ivec4' || type === 'uvec4' ) return new Vector4NodeUniform( uniformNode ); - if ( type === 'color' ) return new ColorNodeUniform( uniformNode ); - if ( type === 'mat3' ) return new Matrix3NodeUniform( uniformNode ); - if ( type === 'mat4' ) return new Matrix4NodeUniform( uniformNode ); + createRenderTarget( width, height, options ) { - throw new Error( `Uniform "${type}" not declared.` ); + return new RenderTarget( width, height, options ); } - createNodeMaterial( type = 'NodeMaterial' ) { // @deprecated, r168 + createCubeRenderTarget( size, options ) { - throw new Error( `THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${ type }() instead.` ); + return new CubeRenderTarget( size, options ); } - format( snippet, fromType, toType ) { - - fromType = this.getVectorType( fromType ); - toType = this.getVectorType( toType ); + createPMREMGenerator() { - if ( fromType === toType || toType === null || this.isReference( toType ) ) { + // TODO: Move Materials.js to outside of the Nodes.js in order to remove this function and improve tree-shaking support - return snippet; + return new PMREMGenerator( this.renderer ); - } + } - const fromTypeLength = this.getTypeLength( fromType ); - const toTypeLength = this.getTypeLength( toType ); + includes( node ) { - if ( fromTypeLength === 16 && toTypeLength === 9 ) { + return this.nodes.includes( node ); - return `${ this.getType( toType ) }(${ snippet }[0].xyz, ${ snippet }[1].xyz, ${ snippet }[2].xyz)`; + } - } + _getBindGroup( groupName, bindings ) { - if ( fromTypeLength === 9 && toTypeLength === 4 ) { + const bindGroupsCache = this.getBindGroupsCache(); - return `${ this.getType( toType ) }(${ snippet }[0].xy, ${ snippet }[1].xy)`; + // - } + const bindingsArray = []; + let sharedGroup = true; - if ( fromTypeLength > 4 ) { // fromType is matrix-like + for ( const binding of bindings ) { - // @TODO: ignore for now + bindingsArray.push( binding ); - return snippet; + sharedGroup = sharedGroup && binding.groupNode.shared !== true; } - if ( toTypeLength > 4 || toTypeLength === 0 ) { // toType is matrix-like or unknown + // - // @TODO: ignore for now + let bindGroup; - return snippet; + if ( sharedGroup ) { - } + bindGroup = bindGroupsCache.get( bindingsArray ); - if ( fromTypeLength === toTypeLength ) { + if ( bindGroup === undefined ) { - return `${ this.getType( toType ) }( ${ snippet } )`; + bindGroup = new BindGroup( groupName, bindingsArray, this.bindingsIndexes[ groupName ].group, bindingsArray ); - } + bindGroupsCache.set( bindingsArray, bindGroup ); - if ( fromTypeLength > toTypeLength ) { + } - return this.format( `${ snippet }.${ 'xyz'.slice( 0, toTypeLength ) }`, this.getTypeFromLength( toTypeLength, this.getComponentType( fromType ) ), toType ); + } else { + + bindGroup = new BindGroup( groupName, bindingsArray, this.bindingsIndexes[ groupName ].group, bindingsArray ); } - if ( toTypeLength === 4 && fromTypeLength > 1 ) { // toType is vec4-like + return bindGroup; - return `${ this.getType( toType ) }( ${ this.format( snippet, fromType, 'vec3' ) }, 1.0 )`; + } - } + getBindGroupArray( groupName, shaderStage ) { - if ( fromTypeLength === 2 ) { // fromType is vec2-like and toType is vec3-like + const bindings = this.bindings[ shaderStage ]; - return `${ this.getType( toType ) }( ${ this.format( snippet, fromType, 'vec2' ) }, 0.0 )`; + let bindGroup = bindings[ groupName ]; - } + if ( bindGroup === undefined ) { - if ( fromTypeLength === 1 && toTypeLength > 1 && fromType !== this.getComponentType( toType ) ) { // fromType is float-like + if ( this.bindingsIndexes[ groupName ] === undefined ) { - // convert a number value to vector type, e.g: - // vec3( 1u ) -> vec3( float( 1u ) ) + this.bindingsIndexes[ groupName ] = { binding: 0, group: Object.keys( this.bindingsIndexes ).length }; - snippet = `${ this.getType( this.getComponentType( toType ) ) }( ${ snippet } )`; + } + + bindings[ groupName ] = bindGroup = []; } - return `${ this.getType( toType ) }( ${ snippet } )`; // fromType is float-like + return bindGroup; } - getSignature() { + getBindings() { - return `// Three.js r${ REVISION } - Node System\n`; + let bindingsGroups = this.bindGroups; - } + if ( bindingsGroups === null ) { -} + const groups = {}; + const bindings = this.bindings; -class NodeFrame { + for ( const shaderStage of shaderStages ) { - constructor() { + for ( const groupName in bindings[ shaderStage ] ) { - this.time = 0; - this.deltaTime = 0; + const uniforms = bindings[ shaderStage ][ groupName ]; - this.frameId = 0; - this.renderId = 0; + const groupUniforms = groups[ groupName ] || ( groups[ groupName ] = [] ); + groupUniforms.push( ...uniforms ); - this.startTime = null; + } - this.updateMap = new WeakMap(); - this.updateBeforeMap = new WeakMap(); - this.updateAfterMap = new WeakMap(); + } - this.renderer = null; - this.material = null; - this.camera = null; - this.object = null; - this.scene = null; + bindingsGroups = []; - } + for ( const groupName in groups ) { - _getMaps( referenceMap, nodeRef ) { + const group = groups[ groupName ]; - let maps = referenceMap.get( nodeRef ); + const bindingsGroup = this._getBindGroup( groupName, group ); - if ( maps === undefined ) { + bindingsGroups.push( bindingsGroup ); - maps = { - renderMap: new WeakMap(), - frameMap: new WeakMap() - }; + } - referenceMap.set( nodeRef, maps ); + this.bindGroups = bindingsGroups; } - return maps; + return bindingsGroups; } - updateBeforeNode( node ) { - - const updateType = node.getUpdateBeforeType(); - const reference = node.updateReference( this ); - - if ( updateType === NodeUpdateType.FRAME ) { - - const { frameMap } = this._getMaps( this.updateBeforeMap, reference ); + sortBindingGroups() { - if ( frameMap.get( reference ) !== this.frameId ) { + const bindingsGroups = this.getBindings(); - if ( node.updateBefore( this ) !== false ) { + bindingsGroups.sort( ( a, b ) => ( a.bindings[ 0 ].groupNode.order - b.bindings[ 0 ].groupNode.order ) ); - frameMap.set( reference, this.frameId ); + for ( let i = 0; i < bindingsGroups.length; i ++ ) { - } + const bindingGroup = bindingsGroups[ i ]; + this.bindingsIndexes[ bindingGroup.name ].group = i; - } + bindingGroup.index = i; - } else if ( updateType === NodeUpdateType.RENDER ) { + } - const { renderMap } = this._getMaps( this.updateBeforeMap, reference ); + } - if ( renderMap.get( reference ) !== this.renderId ) { + setHashNode( node, hash ) { - if ( node.updateBefore( this ) !== false ) { + this.hashNodes[ hash ] = node; - renderMap.set( reference, this.renderId ); + } - } + addNode( node ) { - } + if ( this.nodes.includes( node ) === false ) { - } else if ( updateType === NodeUpdateType.OBJECT ) { + this.nodes.push( node ); - node.updateBefore( this ); + this.setHashNode( node, node.getHash( this ) ); } } - updateAfterNode( node ) { - - const updateType = node.getUpdateAfterType(); - const reference = node.updateReference( this ); - - if ( updateType === NodeUpdateType.FRAME ) { - - const { frameMap } = this._getMaps( this.updateAfterMap, reference ); + buildUpdateNodes() { - if ( frameMap.get( reference ) !== this.frameId ) { + for ( const node of this.nodes ) { - if ( node.updateAfter( this ) !== false ) { + const updateType = node.getUpdateType(); + const updateBeforeType = node.getUpdateBeforeType(); + const updateAfterType = node.getUpdateAfterType(); - frameMap.set( reference, this.frameId ); + if ( updateType !== NodeUpdateType.NONE ) { - } + this.updateNodes.push( node.getSelf() ); } - } else if ( updateType === NodeUpdateType.RENDER ) { - - const { renderMap } = this._getMaps( this.updateAfterMap, reference ); + if ( updateBeforeType !== NodeUpdateType.NONE ) { - if ( renderMap.get( reference ) !== this.renderId ) { + this.updateBeforeNodes.push( node.getSelf() ); - if ( node.updateAfter( this ) !== false ) { + } - renderMap.set( reference, this.renderId ); + if ( updateAfterType !== NodeUpdateType.NONE ) { - } + this.updateAfterNodes.push( node.getSelf() ); } - } else if ( updateType === NodeUpdateType.OBJECT ) { - - node.updateAfter( this ); - } } - updateNode( node ) { - - const updateType = node.getUpdateType(); - const reference = node.updateReference( this ); - - if ( updateType === NodeUpdateType.FRAME ) { + get currentNode() { - const { frameMap } = this._getMaps( this.updateMap, reference ); + return this.chaining[ this.chaining.length - 1 ]; - if ( frameMap.get( reference ) !== this.frameId ) { + } - if ( node.update( this ) !== false ) { + isFilteredTexture( texture ) { - frameMap.set( reference, this.frameId ); + return ( texture.magFilter === LinearFilter || texture.magFilter === LinearMipmapNearestFilter || texture.magFilter === NearestMipmapLinearFilter || texture.magFilter === LinearMipmapLinearFilter || + texture.minFilter === LinearFilter || texture.minFilter === LinearMipmapNearestFilter || texture.minFilter === NearestMipmapLinearFilter || texture.minFilter === LinearMipmapLinearFilter ); - } + } - } + addChain( node ) { - } else if ( updateType === NodeUpdateType.RENDER ) { + /* + if ( this.chaining.indexOf( node ) !== - 1 ) { - const { renderMap } = this._getMaps( this.updateMap, reference ); + console.warn( 'Recursive node: ', node ); - if ( renderMap.get( reference ) !== this.renderId ) { + } + */ - if ( node.update( this ) !== false ) { + this.chaining.push( node ); - renderMap.set( reference, this.renderId ); + } - } + removeChain( node ) { - } + const lastChain = this.chaining.pop(); - } else if ( updateType === NodeUpdateType.OBJECT ) { + if ( lastChain !== node ) { - node.update( this ); + throw new Error( 'NodeBuilder: Invalid node chaining!' ); } } - update() { - - this.frameId ++; - - if ( this.lastTime === undefined ) this.lastTime = performance.now(); - - this.deltaTime = ( performance.now() - this.lastTime ) / 1000; - - this.lastTime = performance.now(); + getMethod( method ) { - this.time += this.deltaTime; + return method; } -} - -class NodeFunctionInput { - - constructor( type, name, count = null, qualifier = '', isConst = false ) { + getNodeFromHash( hash ) { - this.type = type; - this.name = name; - this.count = count; - this.qualifier = qualifier; - this.isConst = isConst; + return this.hashNodes[ hash ]; } -} + addFlow( shaderStage, node ) { -NodeFunctionInput.isNodeFunctionInput = true; + this.flowNodes[ shaderStage ].push( node ); -class StructTypeNode extends Node { + return node; - constructor( types ) { + } - super(); + setContext( context ) { - this.types = types; - this.isStructTypeNode = true; + this.context = context; } - getMemberTypes() { + getContext() { - return this.types; + return this.context; } -} - -StructTypeNode.type = /*@__PURE__*/ registerNode( 'StructType', StructTypeNode ); + getSharedContext() { -class OutputStructNode extends Node { + ({ ...this.context }); - constructor( ...members ) { + return this.context; - super(); + } - this.members = members; + setCache( cache ) { - this.isOutputStructNode = true; + this.cache = cache; } - setup( builder ) { - - super.setup( builder ); + getCache() { - const members = this.members; - const types = []; + return this.cache; - for ( let i = 0; i < members.length; i ++ ) { + } - types.push( members[ i ].getNodeType( builder ) ); + getCacheFromNode( node, parent = true ) { - } + const data = this.getDataFromNode( node ); + if ( data.cache === undefined ) data.cache = new NodeCache( parent ? this.getCache() : null ); - this.nodeType = builder.getStructTypeFromNode( new StructTypeNode( types ) ).name; + return data.cache; } - generate( builder, output ) { + isAvailable( /*name*/ ) { - const propertyName = builder.getOutputStructName(); - const members = this.members; + return false; - const structPrefix = propertyName !== '' ? propertyName + '.' : ''; + } - for ( let i = 0; i < members.length; i ++ ) { + getVertexIndex() { - const snippet = members[ i ].build( builder, output ); + console.warn( 'Abstract function.' ); - builder.addLineFlowCode( `${ structPrefix }m${ i } = ${ snippet }` ); + } - } + getInstanceIndex() { - return propertyName; + console.warn( 'Abstract function.' ); } -} + getDrawIndex() { -OutputStructNode.type = /*@__PURE__*/ registerNode( 'OutputStruct', OutputStructNode ); + console.warn( 'Abstract function.' ); -const outputStruct = /*@__PURE__*/ nodeProxy( OutputStructNode ); + } -function getTextureIndex( textures, name ) { + getFrontFacing() { - for ( let i = 0; i < textures.length; i ++ ) { + console.warn( 'Abstract function.' ); - if ( textures[ i ].name === name ) { + } - return i; + getFragCoord() { - } + console.warn( 'Abstract function.' ); } - return - 1; - -} + isFlipY() { -class MRTNode extends OutputStructNode { + return false; - constructor( outputNodes ) { + } - super(); + increaseUsage( node ) { - this.outputNodes = outputNodes; + const nodeData = this.getDataFromNode( node ); + nodeData.usageCount = nodeData.usageCount === undefined ? 1 : nodeData.usageCount + 1; - this.isMRTNode = true; + return nodeData.usageCount; } - has( name ) { + generateTexture( /* texture, textureProperty, uvSnippet */ ) { - return this.outputNodes[ name ] !== undefined; + console.warn( 'Abstract function.' ); } - get( name ) { + generateTextureLod( /* texture, textureProperty, uvSnippet, levelSnippet */ ) { - return this.outputNodes[ name ]; + console.warn( 'Abstract function.' ); } - merge( mrtNode ) { + generateConst( type, value = null ) { - const outputs = { ...this.outputNodes, ...mrtNode.outputNodes }; + if ( value === null ) { - return mrt( outputs ); + if ( type === 'float' || type === 'int' || type === 'uint' ) value = 0; + else if ( type === 'bool' ) value = false; + else if ( type === 'color' ) value = new Color(); + else if ( type === 'vec2' ) value = new Vector2(); + else if ( type === 'vec3' ) value = new Vector3(); + else if ( type === 'vec4' ) value = new Vector4(); - } + } - setup( builder ) { + if ( type === 'float' ) return toFloat( value ); + if ( type === 'int' ) return `${ Math.round( value ) }`; + if ( type === 'uint' ) return value >= 0 ? `${ Math.round( value ) }u` : '0u'; + if ( type === 'bool' ) return value ? 'true' : 'false'; + if ( type === 'color' ) return `${ this.getType( 'vec3' ) }( ${ toFloat( value.r ) }, ${ toFloat( value.g ) }, ${ toFloat( value.b ) } )`; - const outputNodes = this.outputNodes; - const mrt = builder.renderer.getRenderTarget(); + const typeLength = this.getTypeLength( type ); - const members = []; + const componentType = this.getComponentType( type ); - const textures = mrt.textures; + const generateConst = value => this.generateConst( componentType, value ); - for ( const name in outputNodes ) { + if ( typeLength === 2 ) { - const index = getTextureIndex( textures, name ); + return `${ this.getType( type ) }( ${ generateConst( value.x ) }, ${ generateConst( value.y ) } )`; - members[ index ] = vec4( outputNodes[ name ] ); + } else if ( typeLength === 3 ) { - } + return `${ this.getType( type ) }( ${ generateConst( value.x ) }, ${ generateConst( value.y ) }, ${ generateConst( value.z ) } )`; - this.members = members; + } else if ( typeLength === 4 ) { - return super.setup( builder ); + return `${ this.getType( type ) }( ${ generateConst( value.x ) }, ${ generateConst( value.y ) }, ${ generateConst( value.z ) }, ${ generateConst( value.w ) } )`; - } + } else if ( typeLength > 4 && value && ( value.isMatrix3 || value.isMatrix4 ) ) { -} + return `${ this.getType( type ) }( ${ value.elements.map( generateConst ).join( ', ' ) } )`; -MRTNode.type = /*@__PURE__*/ registerNode( 'MRT', MRTNode ); + } else if ( typeLength > 4 ) { -const mrt = /*@__PURE__*/ nodeProxy( MRTNode ); + return `${ this.getType( type ) }()`; -class FunctionOverloadingNode extends Node { + } - constructor( functionNodes = [], ...parametersNodes ) { + throw new Error( `NodeBuilder: Type '${type}' not found in generate constant attempt.` ); - super(); + } - this.functionNodes = functionNodes; - this.parametersNodes = parametersNodes; + getType( type ) { - this._candidateFnCall = null; + if ( type === 'color' ) return 'vec3'; - this.global = true; + return type; } - getNodeType() { + hasGeometryAttribute( name ) { - return this.functionNodes[ 0 ].shaderNode.layout.type; + return this.geometry && this.geometry.getAttribute( name ) !== undefined; } - setup( builder ) { - - const params = this.parametersNodes; - - let candidateFnCall = this._candidateFnCall; + getAttribute( name, type ) { - if ( candidateFnCall === null ) { + const attributes = this.attributes; - let candidateFn = null; - let candidateScore = - 1; + // find attribute - for ( const functionNode of this.functionNodes ) { + for ( const attribute of attributes ) { - const shaderNode = functionNode.shaderNode; - const layout = shaderNode.layout; + if ( attribute.name === name ) { - if ( layout === null ) { + return attribute; - throw new Error( 'FunctionOverloadingNode: FunctionNode must be a layout.' ); + } - } + } - const inputs = layout.inputs; + // create a new if no exist - if ( params.length === inputs.length ) { + const attribute = new NodeAttribute( name, type ); - let score = 0; + attributes.push( attribute ); - for ( let i = 0; i < params.length; i ++ ) { + return attribute; - const param = params[ i ]; - const input = inputs[ i ]; + } - if ( param.getNodeType( builder ) === input.type ) { + getPropertyName( node/*, shaderStage*/ ) { - score ++; + return node.name; - } else { + } - score = 0; + isVector( type ) { - } + return /vec\d/.test( type ); - } + } - if ( score > candidateScore ) { + isMatrix( type ) { - candidateFn = functionNode; - candidateScore = score; + return /mat\d/.test( type ); - } + } - } + isReference( type ) { - } + return type === 'void' || type === 'property' || type === 'sampler' || type === 'texture' || type === 'cubeTexture' || type === 'storageTexture' || type === 'depthTexture' || type === 'texture3D'; - this._candidateFnCall = candidateFnCall = candidateFn( ...params ); + } - } + needsToWorkingColorSpace( /*texture*/ ) { - return candidateFnCall; + return false; } -} + getComponentTypeFromTexture( texture ) { -FunctionOverloadingNode.type = /*@__PURE__*/ registerNode( 'FunctionOverloading', FunctionOverloadingNode ); + const type = texture.type; -const overloadingBaseFn = /*@__PURE__*/ nodeProxy( FunctionOverloadingNode ); + if ( texture.isDataTexture ) { -const overloadingFn = ( functionNodes ) => ( ...params ) => overloadingBaseFn( functionNodes, ...params ); + if ( type === IntType ) return 'int'; + if ( type === UnsignedIntType ) return 'uint'; -class TimerNode extends UniformNode { + } - constructor( scope = TimerNode.LOCAL, scale = 1, value = 0 ) { + return 'float'; - super( value ); + } - this.scope = scope; - this.scale = scale; + getElementType( type ) { - this.updateType = NodeUpdateType.FRAME; + if ( type === 'mat2' ) return 'vec2'; + if ( type === 'mat3' ) return 'vec3'; + if ( type === 'mat4' ) return 'vec4'; + + return this.getComponentType( type ); } - /* - @TODO: - getNodeType( builder ) { - const scope = this.scope; + getComponentType( type ) { - if ( scope === TimerNode.FRAME ) { + type = this.getVectorType( type ); - return 'uint'; + if ( type === 'float' || type === 'bool' || type === 'int' || type === 'uint' ) return type; - } + const componentType = /(b|i|u|)(vec|mat)([2-4])/.exec( type ); + + if ( componentType === null ) return null; + + if ( componentType[ 1 ] === 'b' ) return 'bool'; + if ( componentType[ 1 ] === 'i' ) return 'int'; + if ( componentType[ 1 ] === 'u' ) return 'uint'; return 'float'; } -*/ - update( frame ) { - const scope = this.scope; - const scale = this.scale; + getVectorType( type ) { - if ( scope === TimerNode.LOCAL ) { + if ( type === 'color' ) return 'vec3'; + if ( type === 'texture' || type === 'cubeTexture' || type === 'storageTexture' || type === 'texture3D' ) return 'vec4'; - this.value += frame.deltaTime * scale; + return type; - } else if ( scope === TimerNode.DELTA ) { + } - this.value = frame.deltaTime * scale; + getTypeFromLength( length, componentType = 'float' ) { - } else if ( scope === TimerNode.FRAME ) { + if ( length === 1 ) return componentType; - this.value = frame.frameId; + const baseType = typeFromLength.get( length ); + const prefix = componentType === 'float' ? '' : componentType[ 0 ]; - } else { + return prefix + baseType; - // global + } - this.value = frame.time * scale; + getTypeFromArray( array ) { - } + return typeFromArray.get( array.constructor ); } - serialize( data ) { - - super.serialize( data ); - - data.scope = this.scope; - data.scale = this.scale; + getTypeFromAttribute( attribute ) { - } + let dataAttribute = attribute; - deserialize( data ) { + if ( attribute.isInterleavedBufferAttribute ) dataAttribute = attribute.data; - super.deserialize( data ); + const array = dataAttribute.array; + const itemSize = attribute.itemSize; + const normalized = attribute.normalized; - this.scope = data.scope; - this.scale = data.scale; + let arrayType; - } + if ( ! ( attribute instanceof Float16BufferAttribute ) && normalized !== true ) { -} + arrayType = this.getTypeFromArray( array ); -TimerNode.LOCAL = 'local'; -TimerNode.GLOBAL = 'global'; -TimerNode.DELTA = 'delta'; -TimerNode.FRAME = 'frame'; + } -TimerNode.type = /*@__PURE__*/ registerNode( 'Timer', TimerNode ); + return this.getTypeFromLength( itemSize, arrayType ); -// @TODO: add support to use node in timeScale -const timerLocal = ( timeScale, value = 0 ) => nodeObject( new TimerNode( TimerNode.LOCAL, timeScale, value ) ); -const timerGlobal = ( timeScale, value = 0 ) => nodeObject( new TimerNode( TimerNode.GLOBAL, timeScale, value ) ); -const timerDelta = ( timeScale, value = 0 ) => nodeObject( new TimerNode( TimerNode.DELTA, timeScale, value ) ); -const frameId = /*@__PURE__*/ nodeImmutable( TimerNode, TimerNode.FRAME ).toUint(); + } -class OscNode extends Node { + getTypeLength( type ) { - constructor( method = OscNode.SINE, timeNode = timerLocal() ) { + const vecType = this.getVectorType( type ); + const vecNum = /vec([2-4])/.exec( vecType ); - super(); + if ( vecNum !== null ) return Number( vecNum[ 1 ] ); + if ( vecType === 'float' || vecType === 'bool' || vecType === 'int' || vecType === 'uint' ) return 1; + if ( /mat2/.test( type ) === true ) return 4; + if ( /mat3/.test( type ) === true ) return 9; + if ( /mat4/.test( type ) === true ) return 16; - this.method = method; - this.timeNode = timeNode; + return 0; } - getNodeType( builder ) { + getVectorFromMatrix( type ) { - return this.timeNode.getNodeType( builder ); + return type.replace( 'mat', 'vec' ); } - setup() { - - const method = this.method; - const timeNode = nodeObject( this.timeNode ); + changeComponentType( type, newComponentType ) { - let outputNode = null; + return this.getTypeFromLength( this.getTypeLength( type ), newComponentType ); - if ( method === OscNode.SINE ) { + } - outputNode = timeNode.add( 0.75 ).mul( Math.PI * 2 ).sin().mul( 0.5 ).add( 0.5 ); + getIntegerType( type ) { - } else if ( method === OscNode.SQUARE ) { + const componentType = this.getComponentType( type ); - outputNode = timeNode.fract().round(); + if ( componentType === 'int' || componentType === 'uint' ) return type; - } else if ( method === OscNode.TRIANGLE ) { + return this.changeComponentType( type, 'int' ); - outputNode = timeNode.add( 0.5 ).fract().mul( 2 ).sub( 1 ).abs(); + } - } else if ( method === OscNode.SAWTOOTH ) { + addStack() { - outputNode = timeNode.fract(); + this.stack = stack( this.stack ); - } + this.stacks.push( getCurrentStack() || this.stack ); + setCurrentStack( this.stack ); - return outputNode; + return this.stack; } - serialize( data ) { + removeStack() { - super.serialize( data ); + const lastStack = this.stack; + this.stack = lastStack.parent; - data.method = this.method; + setCurrentStack( this.stacks.pop() ); + + return lastStack; } - deserialize( data ) { + getDataFromNode( node, shaderStage = this.shaderStage, cache = null ) { - super.deserialize( data ); + cache = cache === null ? ( node.isGlobal( this ) ? this.globalCache : this.cache ) : cache; - this.method = data.method; + let nodeData = cache.getData( node ); - } + if ( nodeData === undefined ) { -} + nodeData = {}; -OscNode.SINE = 'sine'; -OscNode.SQUARE = 'square'; -OscNode.TRIANGLE = 'triangle'; -OscNode.SAWTOOTH = 'sawtooth'; + cache.setData( node, nodeData ); -OscNode.type = /*@__PURE__*/ registerNode( 'Osc', OscNode ); + } -const oscSine = /*@__PURE__*/ nodeProxy( OscNode, OscNode.SINE ); -const oscSquare = /*@__PURE__*/ nodeProxy( OscNode, OscNode.SQUARE ); -const oscTriangle = /*@__PURE__*/ nodeProxy( OscNode, OscNode.TRIANGLE ); -const oscSawtooth = /*@__PURE__*/ nodeProxy( OscNode, OscNode.SAWTOOTH ); + if ( nodeData[ shaderStage ] === undefined ) nodeData[ shaderStage ] = {}; -class SpriteSheetUVNode extends Node { + return nodeData[ shaderStage ]; - constructor( countNode, uvNode = uv(), frameNode = float( 0 ) ) { + } - super( 'vec2' ); + getNodeProperties( node, shaderStage = 'any' ) { - this.countNode = countNode; - this.uvNode = uvNode; - this.frameNode = frameNode; + const nodeData = this.getDataFromNode( node, shaderStage ); + + return nodeData.properties || ( nodeData.properties = { outputNode: null } ); } - setup() { + getBufferAttributeFromNode( node, type ) { - const { frameNode, uvNode, countNode } = this; + const nodeData = this.getDataFromNode( node ); - const { width, height } = countNode; + let bufferAttribute = nodeData.bufferAttribute; - const frameNum = frameNode.mod( width.mul( height ) ).floor(); + if ( bufferAttribute === undefined ) { - const column = frameNum.mod( width ); - const row = height.sub( frameNum.add( 1 ).div( width ).ceil() ); + const index = this.uniforms.index ++; - const scale = countNode.reciprocal(); - const uvFrameOffset = vec2( column, row ); + bufferAttribute = new NodeAttribute( 'nodeAttribute' + index, type, node ); - return uvNode.add( uvFrameOffset ).mul( scale ); + this.bufferAttributes.push( bufferAttribute ); - } + nodeData.bufferAttribute = bufferAttribute; -} + } -SpriteSheetUVNode.type = /*@__PURE__*/ registerNode( 'SpriteSheetUV', SpriteSheetUVNode ); + return bufferAttribute; -const spritesheetUV = /*@__PURE__*/ nodeProxy( SpriteSheetUVNode ); + } -class StorageArrayElementNode extends ArrayElementNode { + getStructTypeFromNode( node, shaderStage = this.shaderStage ) { - constructor( storageBufferNode, indexNode ) { + const nodeData = this.getDataFromNode( node, shaderStage ); - super( storageBufferNode, indexNode ); + if ( nodeData.structType === undefined ) { - this.isStorageArrayElementNode = true; + const index = this.structs.index ++; - } + node.name = `StructType${ index }`; + this.structs[ shaderStage ].push( node ); - set storageBufferNode( value ) { + nodeData.structType = node; - this.node = value; + } + + return node; } - get storageBufferNode() { + getUniformFromNode( node, type, shaderStage = this.shaderStage, name = null ) { - return this.node; + const nodeData = this.getDataFromNode( node, shaderStage, this.globalCache ); - } + let nodeUniform = nodeData.uniform; - setup( builder ) { + if ( nodeUniform === undefined ) { - if ( builder.isAvailable( 'storageBuffer' ) === false ) { + const index = this.uniforms.index ++; - if ( ! this.node.instanceIndex && this.node.bufferObject === true ) { + nodeUniform = new NodeUniform( name || ( 'nodeUniform' + index ), type, node ); - builder.setupPBO( this.node ); + this.uniforms[ shaderStage ].push( nodeUniform ); - } + nodeData.uniform = nodeUniform; } - return super.setup( builder ); + return nodeUniform; } - generate( builder, output ) { + getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage ) { - let snippet; + const nodeData = this.getDataFromNode( node, shaderStage ); - const isAssignContext = builder.context.assign; + let nodeVar = nodeData.variable; - // + if ( nodeVar === undefined ) { - if ( builder.isAvailable( 'storageBuffer' ) === false ) { + const vars = this.vars[ shaderStage ] || ( this.vars[ shaderStage ] = [] ); - const { node } = this; + if ( name === null ) name = 'nodeVar' + vars.length; - if ( ! node.instanceIndex && this.node.bufferObject === true && isAssignContext !== true ) { + nodeVar = new NodeVar( name, type ); - snippet = builder.generatePBO( this ); + vars.push( nodeVar ); - } else { + nodeData.variable = nodeVar; - snippet = node.build( builder ); + } - } + return nodeVar; - } else { + } - snippet = super.generate( builder ); + getVaryingFromNode( node, name = null, type = node.getNodeType( this ) ) { - } + const nodeData = this.getDataFromNode( node, 'any' ); - if ( isAssignContext !== true ) { + let nodeVarying = nodeData.varying; - const type = this.getNodeType( builder ); + if ( nodeVarying === undefined ) { - snippet = builder.format( snippet, type, output ); + const varyings = this.varyings; + const index = varyings.length; + + if ( name === null ) name = 'nodeVarying' + index; + + nodeVarying = new NodeVarying( name, type ); + + varyings.push( nodeVarying ); + + nodeData.varying = nodeVarying; } - return snippet; + return nodeVarying; } -} + getCodeFromNode( node, type, shaderStage = this.shaderStage ) { -StorageArrayElementNode.type = /*@__PURE__*/ registerNode( 'StorageArrayElement', StorageArrayElementNode ); + const nodeData = this.getDataFromNode( node ); -const storageElement = /*@__PURE__*/ nodeProxy( StorageArrayElementNode ); + let nodeCode = nodeData.code; -class TriplanarTexturesNode extends Node { + if ( nodeCode === undefined ) { - constructor( textureXNode, textureYNode = null, textureZNode = null, scaleNode = float( 1 ), positionNode = positionLocal, normalNode = normalLocal ) { + const codes = this.codes[ shaderStage ] || ( this.codes[ shaderStage ] = [] ); + const index = codes.length; - super( 'vec4' ); + nodeCode = new NodeCode( 'nodeCode' + index, type ); - this.textureXNode = textureXNode; - this.textureYNode = textureYNode; - this.textureZNode = textureZNode; + codes.push( nodeCode ); - this.scaleNode = scaleNode; + nodeData.code = nodeCode; - this.positionNode = positionNode; - this.normalNode = normalNode; + } - } + return nodeCode; - setup() { + } - const { textureXNode, textureYNode, textureZNode, scaleNode, positionNode, normalNode } = this; + addFlowCodeHierarchy( node, nodeBlock ) { - // Ref: https://github.com/keijiro/StandardTriplanar + const { flowCodes, flowCodeBlock } = this.getDataFromNode( node ); - // Blending factor of triplanar mapping - let bf = normalNode.abs().normalize(); - bf = bf.div( bf.dot( vec3( 1.0 ) ) ); + let needsFlowCode = true; + let nodeBlockHierarchy = nodeBlock; - // Triplanar mapping - const tx = positionNode.yz.mul( scaleNode ); - const ty = positionNode.zx.mul( scaleNode ); - const tz = positionNode.xy.mul( scaleNode ); + while ( nodeBlockHierarchy ) { - // Base color - const textureX = textureXNode.value; - const textureY = textureYNode !== null ? textureYNode.value : textureX; - const textureZ = textureZNode !== null ? textureZNode.value : textureX; + if ( flowCodeBlock.get( nodeBlockHierarchy ) === true ) { - const cx = texture( textureX, tx ).mul( bf.x ); - const cy = texture( textureY, ty ).mul( bf.y ); - const cz = texture( textureZ, tz ).mul( bf.z ); + needsFlowCode = false; + break; - return add( cx, cy, cz ); + } - } + nodeBlockHierarchy = this.getDataFromNode( nodeBlockHierarchy ).parentNodeBlock; -} + } -TriplanarTexturesNode.type = /*@__PURE__*/ registerNode( 'TriplanarTextures', TriplanarTexturesNode ); + if ( needsFlowCode ) { -const triplanarTextures = /*@__PURE__*/ nodeProxy( TriplanarTexturesNode ); -const triplanarTexture = ( ...params ) => triplanarTextures( ...params ); + for ( const flowCode of flowCodes ) { -const _reflectorPlane = new Plane(); -const _normal = new Vector3(); -const _reflectorWorldPosition = new Vector3(); -const _cameraWorldPosition = new Vector3(); -const _rotationMatrix = new Matrix4(); -const _lookAtPosition = new Vector3( 0, 0, - 1 ); -const clipPlane = new Vector4(); + this.addLineFlowCode( flowCode ); -const _view = new Vector3(); -const _target = new Vector3(); -const _q = new Vector4(); + } -const _size$9 = new Vector2(); + } -const _defaultRT = new RenderTarget(); -const _defaultUV = viewportUV.flipX(); + } -let _inReflector = false; + addLineFlowCodeBlock( node, code, nodeBlock ) { -class ReflectorNode extends TextureNode { + const nodeData = this.getDataFromNode( node ); + const flowCodes = nodeData.flowCodes || ( nodeData.flowCodes = [] ); + const codeBlock = nodeData.flowCodeBlock || ( nodeData.flowCodeBlock = new WeakMap() ); - constructor( parameters = {} ) { + flowCodes.push( code ); + codeBlock.set( nodeBlock, true ); - super( _defaultRT.texture, _defaultUV ); + } - const { - target = new Object3D(), - resolution = 1, - generateMipmaps = false, - bounces = true - } = parameters; + addLineFlowCode( code, node = null ) { - // + if ( code === '' ) return this; - this.target = target; - this.resolution = resolution; - this.generateMipmaps = generateMipmaps; - this.bounces = bounces; + if ( node !== null && this.context.nodeBlock ) { - this.updateBeforeType = bounces ? NodeUpdateType.RENDER : NodeUpdateType.FRAME; + this.addLineFlowCodeBlock( node, code, this.context.nodeBlock ); - this.virtualCameras = new WeakMap(); - this.renderTargets = new WeakMap(); + } + code = this.tab + code; - } + if ( ! /;\s*$/.test( code ) ) { - _updateResolution( renderTarget, renderer ) { + code = code + ';\n'; - const resolution = this.resolution; + } - renderer.getDrawingBufferSize( _size$9 ); + this.flow.code += code; - renderTarget.setSize( Math.round( _size$9.width * resolution ), Math.round( _size$9.height * resolution ) ); + return this; } - setup( builder ) { + addFlowCode( code ) { - this._updateResolution( _defaultRT, builder.renderer ); + this.flow.code += code; - return super.setup( builder ); + return this; } - getTextureNode() { + addFlowTab() { - return this.textureNode; + this.tab += '\t'; - } + return this; - getVirtualCamera( camera ) { + } - let virtualCamera = this.virtualCameras.get( camera ); + removeFlowTab() { - if ( virtualCamera === undefined ) { + this.tab = this.tab.slice( 0, - 1 ); - virtualCamera = camera.clone(); + return this; - this.virtualCameras.set( camera, virtualCamera ); + } - } + getFlowData( node/*, shaderStage*/ ) { - return virtualCamera; + return this.flowsData.get( node ); } - getRenderTarget( camera ) { + flowNode( node ) { - let renderTarget = this.renderTargets.get( camera ); + const output = node.getNodeType( this ); - if ( renderTarget === undefined ) { + const flowData = this.flowChildNode( node, output ); - renderTarget = new RenderTarget( 0, 0, { type: HalfFloatType } ); + this.flowsData.set( node, flowData ); - if ( this.generateMipmaps === true ) { + return flowData; - renderTarget.texture.minFilter = LinearMipMapLinearFilter; - renderTarget.texture.generateMipmaps = true; + } - } + buildFunctionNode( shaderNode ) { - this.renderTargets.set( camera, renderTarget ); + const fn = new FunctionNode(); - } + const previous = this.currentFunctionNode; - return renderTarget; + this.currentFunctionNode = fn; - } + fn.code = this.buildFunctionCode( shaderNode ); - updateBefore( frame ) { + this.currentFunctionNode = previous; - if ( this.bounces === false && _inReflector ) return false; + return fn; - _inReflector = true; + } - const { scene, camera, renderer, material } = frame; - const { target } = this; + flowShaderNode( shaderNode ) { - const virtualCamera = this.getVirtualCamera( camera ); - const renderTarget = this.getRenderTarget( virtualCamera ); + const layout = shaderNode.layout; - renderer.getDrawingBufferSize( _size$9 ); + const inputs = { + [ Symbol.iterator ]() { - this._updateResolution( renderTarget, renderer ); + let index = 0; + const values = Object.values( this ); + return { + next: () => ( { + value: values[ index ], + done: index ++ >= values.length + } ) + }; - // + } + }; - _reflectorWorldPosition.setFromMatrixPosition( target.matrixWorld ); - _cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld ); + for ( const input of layout.inputs ) { - _rotationMatrix.extractRotation( target.matrixWorld ); + inputs[ input.name ] = new ParameterNode( input.type, input.name ); - _normal.set( 0, 0, 1 ); - _normal.applyMatrix4( _rotationMatrix ); + } - _view.subVectors( _reflectorWorldPosition, _cameraWorldPosition ); + // - // Avoid rendering when reflector is facing away + shaderNode.layout = null; - if ( _view.dot( _normal ) > 0 ) return; + const callNode = shaderNode.call( inputs ); + const flowData = this.flowStagesNode( callNode, layout.type ); - _view.reflect( _normal ).negate(); - _view.add( _reflectorWorldPosition ); + shaderNode.layout = layout; - _rotationMatrix.extractRotation( camera.matrixWorld ); + return flowData; - _lookAtPosition.set( 0, 0, - 1 ); - _lookAtPosition.applyMatrix4( _rotationMatrix ); - _lookAtPosition.add( _cameraWorldPosition ); + } - _target.subVectors( _reflectorWorldPosition, _lookAtPosition ); - _target.reflect( _normal ).negate(); - _target.add( _reflectorWorldPosition ); + flowStagesNode( node, output = null ) { - // + const previousFlow = this.flow; + const previousVars = this.vars; + const previousCache = this.cache; + const previousBuildStage = this.buildStage; + const previousStack = this.stack; - virtualCamera.coordinateSystem = camera.coordinateSystem; - virtualCamera.position.copy( _view ); - virtualCamera.up.set( 0, 1, 0 ); - virtualCamera.up.applyMatrix4( _rotationMatrix ); - virtualCamera.up.reflect( _normal ); - virtualCamera.lookAt( _target ); + const flow = { + code: '' + }; - virtualCamera.near = camera.near; - virtualCamera.far = camera.far; + this.flow = flow; + this.vars = {}; + this.cache = new NodeCache(); + this.stack = stack(); - virtualCamera.updateMatrixWorld(); - virtualCamera.projectionMatrix.copy( camera.projectionMatrix ); + for ( const buildStage of defaultBuildStages ) { - // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html - // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf - _reflectorPlane.setFromNormalAndCoplanarPoint( _normal, _reflectorWorldPosition ); - _reflectorPlane.applyMatrix4( virtualCamera.matrixWorldInverse ); + this.setBuildStage( buildStage ); - clipPlane.set( _reflectorPlane.normal.x, _reflectorPlane.normal.y, _reflectorPlane.normal.z, _reflectorPlane.constant ); + flow.result = node.build( this, output ); - const projectionMatrix = virtualCamera.projectionMatrix; + } - _q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ]; - _q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ]; - _q.z = - 1.0; - _q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ]; + flow.vars = this.getVars( this.shaderStage ); - // Calculate the scaled plane vector - clipPlane.multiplyScalar( 1.0 / clipPlane.dot( _q ) ); + this.flow = previousFlow; + this.vars = previousVars; + this.cache = previousCache; + this.stack = previousStack; - const clipBias = 0; + this.setBuildStage( previousBuildStage ); - // Replacing the third row of the projection matrix - projectionMatrix.elements[ 2 ] = clipPlane.x; - projectionMatrix.elements[ 6 ] = clipPlane.y; - projectionMatrix.elements[ 10 ] = clipPlane.z - clipBias; - projectionMatrix.elements[ 14 ] = clipPlane.w; + return flow; - // + } - this.value = renderTarget.texture; + getFunctionOperator() { - material.visible = false; + return null; - const currentRenderTarget = renderer.getRenderTarget(); - const currentMRT = renderer.getMRT(); + } - renderer.setMRT( null ); - renderer.setRenderTarget( renderTarget ); + flowChildNode( node, output = null ) { - renderer.render( scene, virtualCamera ); + const previousFlow = this.flow; - renderer.setMRT( currentMRT ); - renderer.setRenderTarget( currentRenderTarget ); + const flow = { + code: '' + }; - material.visible = true; + this.flow = flow; - _inReflector = false; + flow.result = node.build( this, output ); - } + this.flow = previousFlow; -} + return flow; -const reflector = ( parameters ) => nodeObject( new ReflectorNode( parameters ) ); + } -ReflectorNode.type = /*@__PURE__*/ registerNode( 'Reflector', ReflectorNode ); + flowNodeFromShaderStage( shaderStage, node, output = null, propertyName = null ) { -// Helper for passes that need to fill the viewport with a single quad. + const previousShaderStage = this.shaderStage; -const _camera = /*@__PURE__*/ new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); + this.setShaderStage( shaderStage ); -// https://github.com/mrdoob/three.js/pull/21358 + const flowData = this.flowChildNode( node, output ); -class QuadGeometry extends BufferGeometry { + if ( propertyName !== null ) { - constructor( flipY = false ) { + flowData.code += `${ this.tab + propertyName } = ${ flowData.result };\n`; - super(); + } - const uv = flipY === false ? [ 0, - 1, 0, 1, 2, 1 ] : [ 0, 2, 0, 0, 2, 0 ]; + this.flowCode[ shaderStage ] = this.flowCode[ shaderStage ] + flowData.code; - this.setAttribute( 'position', new Float32BufferAttribute( [ - 1, 3, 0, - 1, - 1, 0, 3, - 1, 0 ], 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uv, 2 ) ); + this.setShaderStage( previousShaderStage ); + + return flowData; } -} + getAttributesArray() { -const _geometry = /*@__PURE__*/ new QuadGeometry(); + return this.attributes.concat( this.bufferAttributes ); -class QuadMesh extends Mesh { + } - constructor( material = null ) { + getAttributes( /*shaderStage*/ ) { - super( _geometry, material ); + console.warn( 'Abstract function.' ); - this.camera = _camera; + } - this.isQuadMesh = true; + getVaryings( /*shaderStage*/ ) { + + console.warn( 'Abstract function.' ); } - renderAsync( renderer ) { + getVar( type, name ) { - return renderer.renderAsync( this, _camera ); + return `${ this.getType( type ) } ${ name }`; } - render( renderer ) { + getVars( shaderStage ) { - renderer.render( this, _camera ); + let snippet = ''; + + const vars = this.vars[ shaderStage ]; + + if ( vars !== undefined ) { + + for ( const variable of vars ) { + + snippet += `${ this.getVar( variable.type, variable.name ) }; `; + + } + + } + + return snippet; } -} + getUniforms( /*shaderStage*/ ) { -const _size$8 = /*@__PURE__*/ new Vector2(); + console.warn( 'Abstract function.' ); -class RTTNode extends TextureNode { + } - constructor( node, width = null, height = null, options = { type: HalfFloatType } ) { + getCodes( shaderStage ) { - const renderTarget = new RenderTarget( width, height, options ); + const codes = this.codes[ shaderStage ]; - super( renderTarget.texture, uv() ); + let code = ''; - this.node = node; - this.width = width; - this.height = height; + if ( codes !== undefined ) { - this.renderTarget = renderTarget; + for ( const nodeCode of codes ) { - this.textureNeedsUpdate = true; - this.autoUpdate = true; + code += nodeCode.code + '\n'; - this.updateMap = new WeakMap(); + } - this._rttNode = null; - this._quadMesh = new QuadMesh( new NodeMaterial() ); + } - this.updateBeforeType = NodeUpdateType.RENDER; + return code; } - get autoSize() { + getHash() { - return this.width === null; + return this.vertexShader + this.fragmentShader + this.computeShader; } - setup( builder ) { - - this._rttNode = this.node.context( builder.getSharedContext() ); - this._quadMesh.material.name = 'RTT'; - this._quadMesh.material.needsUpdate = true; + setShaderStage( shaderStage ) { - return super.setup( builder ); + this.shaderStage = shaderStage; } - setSize( width, height ) { + getShaderStage() { - this.width = width; - this.height = height; + return this.shaderStage; - const effectiveWidth = width * this.pixelRatio; - const effectiveHeight = height * this.pixelRatio; + } - this.renderTarget.setSize( effectiveWidth, effectiveHeight ); + setBuildStage( buildStage ) { - this.textureNeedsUpdate = true; + this.buildStage = buildStage; } - setPixelRatio( pixelRatio ) { + getBuildStage() { - this.pixelRatio = pixelRatio; + return this.buildStage; - this.setSize( this.width, this.height ); + } + + buildCode() { + + console.warn( 'Abstract function.' ); } - updateBefore( { renderer } ) { + build() { - if ( this.textureNeedsUpdate === false && this.autoUpdate === false ) return; + const { object, material, renderer } = this; - this.textureNeedsUpdate = false; + if ( material !== null ) { - // + let nodeMaterial = renderer.nodes.library.fromMaterial( material ); - if ( this.autoSize === true ) { + if ( nodeMaterial === null ) { - this.pixelRatio = renderer.getPixelRatio(); + console.error( `NodeMaterial: Material "${ material.type }" is not compatible.` ); - const size = renderer.getSize( _size$8 ); + nodeMaterial = new NodeMaterial(); - this.setSize( size.width, size.height ); + } + + nodeMaterial.build( this ); + + } else { + + this.addFlow( 'compute', object ); } - // + // setup() -> stage 1: create possible new nodes and returns an output reference node + // analyze() -> stage 2: analyze nodes to possible optimization and validation + // generate() -> stage 3: generate shader - this._quadMesh.material.fragmentNode = this._rttNode; + for ( const buildStage of defaultBuildStages ) { - // + this.setBuildStage( buildStage ); - const currentRenderTarget = renderer.getRenderTarget(); + if ( this.context.vertex && this.context.vertex.isNode ) { - renderer.setRenderTarget( this.renderTarget ); + this.flowNodeFromShaderStage( 'vertex', this.context.vertex ); - this._quadMesh.render( renderer ); + } - renderer.setRenderTarget( currentRenderTarget ); + for ( const shaderStage of shaderStages ) { - } + this.setShaderStage( shaderStage ); - clone() { + const flowNodes = this.flowNodes[ shaderStage ]; - const newNode = new TextureNode( this.value, this.uvNode, this.levelNode ); - newNode.sampler = this.sampler; - newNode.referenceNode = this; + for ( const node of flowNodes ) { - return newNode; + if ( buildStage === 'generate' ) { - } + this.flowNode( node ); -} + } else { -RTTNode.type = /*@__PURE__*/ registerNode( 'RTT', RTTNode ); + node.build( this ); -const rtt = ( node, ...params ) => nodeObject( new RTTNode( nodeObject( node ), ...params ) ); -const convertToTexture = ( node, ...params ) => node.isTextureNode ? node : rtt( node, ...params ); + } -class VertexColorNode extends AttributeNode { + } - constructor( index = 0 ) { + } - super( null, 'vec4' ); + } - this.isVertexColorNode = true; + this.setBuildStage( null ); + this.setShaderStage( null ); - this.index = index; + // stage 4: build code for a specific output + + this.buildCode(); + this.buildUpdateNodes(); + + return this; } - getAttributeName( /*builder*/ ) { + getNodeUniform( uniformNode, type ) { - const index = this.index; + if ( type === 'float' || type === 'int' || type === 'uint' ) return new NumberNodeUniform( uniformNode ); + if ( type === 'vec2' || type === 'ivec2' || type === 'uvec2' ) return new Vector2NodeUniform( uniformNode ); + if ( type === 'vec3' || type === 'ivec3' || type === 'uvec3' ) return new Vector3NodeUniform( uniformNode ); + if ( type === 'vec4' || type === 'ivec4' || type === 'uvec4' ) return new Vector4NodeUniform( uniformNode ); + if ( type === 'color' ) return new ColorNodeUniform( uniformNode ); + if ( type === 'mat3' ) return new Matrix3NodeUniform( uniformNode ); + if ( type === 'mat4' ) return new Matrix4NodeUniform( uniformNode ); - return 'color' + ( index > 0 ? index : '' ); + throw new Error( `Uniform "${type}" not declared.` ); } - generate( builder ) { + createNodeMaterial( type = 'NodeMaterial' ) { // @deprecated, r168 - const attributeName = this.getAttributeName( builder ); - const geometryAttribute = builder.hasGeometryAttribute( attributeName ); + throw new Error( `THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${ type }() instead.` ); - let result; + } - if ( geometryAttribute === true ) { + format( snippet, fromType, toType ) { - result = super.generate( builder ); + fromType = this.getVectorType( fromType ); + toType = this.getVectorType( toType ); - } else { + if ( fromType === toType || toType === null || this.isReference( toType ) ) { - // Vertex color fallback should be white - result = builder.generateConst( this.nodeType, new Vector4( 1, 1, 1, 1 ) ); + return snippet; } - return result; + const fromTypeLength = this.getTypeLength( fromType ); + const toTypeLength = this.getTypeLength( toType ); - } + if ( fromTypeLength === 16 && toTypeLength === 9 ) { - serialize( data ) { + return `${ this.getType( toType ) }(${ snippet }[0].xyz, ${ snippet }[1].xyz, ${ snippet }[2].xyz)`; - super.serialize( data ); + } - data.index = this.index; + if ( fromTypeLength === 9 && toTypeLength === 4 ) { - } + return `${ this.getType( toType ) }(${ snippet }[0].xy, ${ snippet }[1].xy)`; - deserialize( data ) { + } - super.deserialize( data ); - this.index = data.index; + if ( fromTypeLength > 4 ) { // fromType is matrix-like - } + // @TODO: ignore for now -} + return snippet; -VertexColorNode.type = /*@__PURE__*/ registerNode( 'VertexColor', VertexColorNode ); + } -const vertexColor = ( ...params ) => nodeObject( new VertexColorNode( ...params ) ); + if ( toTypeLength > 4 || toTypeLength === 0 ) { // toType is matrix-like or unknown -class PointUVNode extends Node { + // @TODO: ignore for now - constructor() { + return snippet; - super( 'vec2' ); + } - this.isPointUVNode = true; + if ( fromTypeLength === toTypeLength ) { - } + return `${ this.getType( toType ) }( ${ snippet } )`; - generate( /*builder*/ ) { + } - return 'vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )'; + if ( fromTypeLength > toTypeLength ) { - } + return this.format( `${ snippet }.${ 'xyz'.slice( 0, toTypeLength ) }`, this.getTypeFromLength( toTypeLength, this.getComponentType( fromType ) ), toType ); -} + } -PointUVNode.type = /*@__PURE__*/ registerNode( 'PointUV', PointUVNode ); + if ( toTypeLength === 4 && fromTypeLength > 1 ) { // toType is vec4-like -const pointUV = /*@__PURE__*/ nodeImmutable( PointUVNode ); + return `${ this.getType( toType ) }( ${ this.format( snippet, fromType, 'vec3' ) }, 1.0 )`; -class SceneNode extends Node { + } - constructor( scope = SceneNode.BACKGROUND_BLURRINESS, scene = null ) { + if ( fromTypeLength === 2 ) { // fromType is vec2-like and toType is vec3-like - super(); + return `${ this.getType( toType ) }( ${ this.format( snippet, fromType, 'vec2' ) }, 0.0 )`; - this.scope = scope; - this.scene = scene; + } + + if ( fromTypeLength === 1 && toTypeLength > 1 && fromType !== this.getComponentType( toType ) ) { // fromType is float-like + + // convert a number value to vector type, e.g: + // vec3( 1u ) -> vec3( float( 1u ) ) + + snippet = `${ this.getType( this.getComponentType( toType ) ) }( ${ snippet } )`; + + } + + return `${ this.getType( toType ) }( ${ snippet } )`; // fromType is float-like } - setup( builder ) { + getSignature() { - const scope = this.scope; - const scene = this.scene !== null ? this.scene : builder.scene; + return `// Three.js r${ REVISION } - Node System\n`; - let output; + } - if ( scope === SceneNode.BACKGROUND_BLURRINESS ) { +} - output = reference( 'backgroundBlurriness', 'float', scene ); +class NodeFrame { - } else if ( scope === SceneNode.BACKGROUND_INTENSITY ) { + constructor() { - output = reference( 'backgroundIntensity', 'float', scene ); + this.time = 0; + this.deltaTime = 0; - } else { + this.frameId = 0; + this.renderId = 0; - console.error( 'THREE.SceneNode: Unknown scope:', scope ); + this.startTime = null; - } + this.updateMap = new WeakMap(); + this.updateBeforeMap = new WeakMap(); + this.updateAfterMap = new WeakMap(); - return output; + this.renderer = null; + this.material = null; + this.camera = null; + this.object = null; + this.scene = null; } -} + _getMaps( referenceMap, nodeRef ) { -SceneNode.BACKGROUND_BLURRINESS = 'backgroundBlurriness'; -SceneNode.BACKGROUND_INTENSITY = 'backgroundIntensity'; + let maps = referenceMap.get( nodeRef ); -SceneNode.type = /*@__PURE__*/ registerNode( 'Scene', SceneNode ); + if ( maps === undefined ) { -const backgroundBlurriness = /*@__PURE__*/ nodeImmutable( SceneNode, SceneNode.BACKGROUND_BLURRINESS ); -const backgroundIntensity = /*@__PURE__*/ nodeImmutable( SceneNode, SceneNode.BACKGROUND_INTENSITY ); + maps = { + renderMap: new WeakMap(), + frameMap: new WeakMap() + }; -const GPUPrimitiveTopology = { - PointList: 'point-list', - LineList: 'line-list', - LineStrip: 'line-strip', - TriangleList: 'triangle-list', - TriangleStrip: 'triangle-strip', -}; + referenceMap.set( nodeRef, maps ); -const GPUCompareFunction = { - Never: 'never', - Less: 'less', - Equal: 'equal', - LessEqual: 'less-equal', - Greater: 'greater', - NotEqual: 'not-equal', - GreaterEqual: 'greater-equal', - Always: 'always' -}; + } -const GPUStoreOp = { - Store: 'store', - Discard: 'discard' -}; + return maps; -const GPULoadOp = { - Load: 'load', - Clear: 'clear' -}; + } -const GPUFrontFace = { - CCW: 'ccw', - CW: 'cw' -}; + updateBeforeNode( node ) { -const GPUCullMode = { - None: 'none', - Front: 'front', - Back: 'back' -}; + const updateType = node.getUpdateBeforeType(); + const reference = node.updateReference( this ); -const GPUIndexFormat = { - Uint16: 'uint16', - Uint32: 'uint32' -}; + if ( updateType === NodeUpdateType.FRAME ) { -const GPUTextureFormat = { + const { frameMap } = this._getMaps( this.updateBeforeMap, reference ); - // 8-bit formats + if ( frameMap.get( reference ) !== this.frameId ) { - R8Unorm: 'r8unorm', - R8Snorm: 'r8snorm', - R8Uint: 'r8uint', - R8Sint: 'r8sint', + if ( node.updateBefore( this ) !== false ) { - // 16-bit formats + frameMap.set( reference, this.frameId ); - R16Uint: 'r16uint', - R16Sint: 'r16sint', - R16Float: 'r16float', - RG8Unorm: 'rg8unorm', - RG8Snorm: 'rg8snorm', - RG8Uint: 'rg8uint', - RG8Sint: 'rg8sint', - - // 32-bit formats - - R32Uint: 'r32uint', - R32Sint: 'r32sint', - R32Float: 'r32float', - RG16Uint: 'rg16uint', - RG16Sint: 'rg16sint', - RG16Float: 'rg16float', - RGBA8Unorm: 'rgba8unorm', - RGBA8UnormSRGB: 'rgba8unorm-srgb', - RGBA8Snorm: 'rgba8snorm', - RGBA8Uint: 'rgba8uint', - RGBA8Sint: 'rgba8sint', - BGRA8Unorm: 'bgra8unorm', - BGRA8UnormSRGB: 'bgra8unorm-srgb', - // Packed 32-bit formats - RGB9E5UFloat: 'rgb9e5ufloat', - RGB10A2Unorm: 'rgb10a2unorm', - RG11B10uFloat: 'rgb10a2unorm', - - // 64-bit formats + } - RG32Uint: 'rg32uint', - RG32Sint: 'rg32sint', - RG32Float: 'rg32float', - RGBA16Uint: 'rgba16uint', - RGBA16Sint: 'rgba16sint', - RGBA16Float: 'rgba16float', + } - // 128-bit formats + } else if ( updateType === NodeUpdateType.RENDER ) { - RGBA32Uint: 'rgba32uint', - RGBA32Sint: 'rgba32sint', - RGBA32Float: 'rgba32float', + const { renderMap } = this._getMaps( this.updateBeforeMap, reference ); - // Depth and stencil formats + if ( renderMap.get( reference ) !== this.renderId ) { - Stencil8: 'stencil8', - Depth16Unorm: 'depth16unorm', - Depth24Plus: 'depth24plus', - Depth24PlusStencil8: 'depth24plus-stencil8', - Depth32Float: 'depth32float', + if ( node.updateBefore( this ) !== false ) { - // 'depth32float-stencil8' extension + renderMap.set( reference, this.renderId ); - Depth32FloatStencil8: 'depth32float-stencil8', + } - // BC compressed formats usable if 'texture-compression-bc' is both - // supported by the device/user agent and enabled in requestDevice. + } - BC1RGBAUnorm: 'bc1-rgba-unorm', - BC1RGBAUnormSRGB: 'bc1-rgba-unorm-srgb', - BC2RGBAUnorm: 'bc2-rgba-unorm', - BC2RGBAUnormSRGB: 'bc2-rgba-unorm-srgb', - BC3RGBAUnorm: 'bc3-rgba-unorm', - BC3RGBAUnormSRGB: 'bc3-rgba-unorm-srgb', - BC4RUnorm: 'bc4-r-unorm', - BC4RSnorm: 'bc4-r-snorm', - BC5RGUnorm: 'bc5-rg-unorm', - BC5RGSnorm: 'bc5-rg-snorm', - BC6HRGBUFloat: 'bc6h-rgb-ufloat', - BC6HRGBFloat: 'bc6h-rgb-float', - BC7RGBAUnorm: 'bc7-rgba-unorm', - BC7RGBAUnormSRGB: 'bc7-rgba-srgb', + } else if ( updateType === NodeUpdateType.OBJECT ) { - // ETC2 compressed formats usable if 'texture-compression-etc2' is both - // supported by the device/user agent and enabled in requestDevice. + node.updateBefore( this ); - ETC2RGB8Unorm: 'etc2-rgb8unorm', - ETC2RGB8UnormSRGB: 'etc2-rgb8unorm-srgb', - ETC2RGB8A1Unorm: 'etc2-rgb8a1unorm', - ETC2RGB8A1UnormSRGB: 'etc2-rgb8a1unorm-srgb', - ETC2RGBA8Unorm: 'etc2-rgba8unorm', - ETC2RGBA8UnormSRGB: 'etc2-rgba8unorm-srgb', - EACR11Unorm: 'eac-r11unorm', - EACR11Snorm: 'eac-r11snorm', - EACRG11Unorm: 'eac-rg11unorm', - EACRG11Snorm: 'eac-rg11snorm', + } - // ASTC compressed formats usable if 'texture-compression-astc' is both - // supported by the device/user agent and enabled in requestDevice. + } - ASTC4x4Unorm: 'astc-4x4-unorm', - ASTC4x4UnormSRGB: 'astc-4x4-unorm-srgb', - ASTC5x4Unorm: 'astc-5x4-unorm', - ASTC5x4UnormSRGB: 'astc-5x4-unorm-srgb', - ASTC5x5Unorm: 'astc-5x5-unorm', - ASTC5x5UnormSRGB: 'astc-5x5-unorm-srgb', - ASTC6x5Unorm: 'astc-6x5-unorm', - ASTC6x5UnormSRGB: 'astc-6x5-unorm-srgb', - ASTC6x6Unorm: 'astc-6x6-unorm', - ASTC6x6UnormSRGB: 'astc-6x6-unorm-srgb', - ASTC8x5Unorm: 'astc-8x5-unorm', - ASTC8x5UnormSRGB: 'astc-8x5-unorm-srgb', - ASTC8x6Unorm: 'astc-8x6-unorm', - ASTC8x6UnormSRGB: 'astc-8x6-unorm-srgb', - ASTC8x8Unorm: 'astc-8x8-unorm', - ASTC8x8UnormSRGB: 'astc-8x8-unorm-srgb', - ASTC10x5Unorm: 'astc-10x5-unorm', - ASTC10x5UnormSRGB: 'astc-10x5-unorm-srgb', - ASTC10x6Unorm: 'astc-10x6-unorm', - ASTC10x6UnormSRGB: 'astc-10x6-unorm-srgb', - ASTC10x8Unorm: 'astc-10x8-unorm', - ASTC10x8UnormSRGB: 'astc-10x8-unorm-srgb', - ASTC10x10Unorm: 'astc-10x10-unorm', - ASTC10x10UnormSRGB: 'astc-10x10-unorm-srgb', - ASTC12x10Unorm: 'astc-12x10-unorm', - ASTC12x10UnormSRGB: 'astc-12x10-unorm-srgb', - ASTC12x12Unorm: 'astc-12x12-unorm', - ASTC12x12UnormSRGB: 'astc-12x12-unorm-srgb', + updateAfterNode( node ) { -}; + const updateType = node.getUpdateAfterType(); + const reference = node.updateReference( this ); -const GPUAddressMode = { - ClampToEdge: 'clamp-to-edge', - Repeat: 'repeat', - MirrorRepeat: 'mirror-repeat' -}; + if ( updateType === NodeUpdateType.FRAME ) { -const GPUFilterMode = { - Linear: 'linear', - Nearest: 'nearest' -}; + const { frameMap } = this._getMaps( this.updateAfterMap, reference ); -const GPUBlendFactor = { - Zero: 'zero', - One: 'one', - Src: 'src', - OneMinusSrc: 'one-minus-src', - SrcAlpha: 'src-alpha', - OneMinusSrcAlpha: 'one-minus-src-alpha', - Dst: 'dst', - OneMinusDstColor: 'one-minus-dst', - DstAlpha: 'dst-alpha', - OneMinusDstAlpha: 'one-minus-dst-alpha', - SrcAlphaSaturated: 'src-alpha-saturated', - Constant: 'constant', - OneMinusConstant: 'one-minus-constant' -}; + if ( frameMap.get( reference ) !== this.frameId ) { -const GPUBlendOperation = { - Add: 'add', - Subtract: 'subtract', - ReverseSubtract: 'reverse-subtract', - Min: 'min', - Max: 'max' -}; + if ( node.updateAfter( this ) !== false ) { -const GPUColorWriteFlags = { - None: 0, - Red: 0x1, - Green: 0x2, - Blue: 0x4, - Alpha: 0x8, - All: 0xF -}; + frameMap.set( reference, this.frameId ); -const GPUStencilOperation = { - Keep: 'keep', - Zero: 'zero', - Replace: 'replace', - Invert: 'invert', - IncrementClamp: 'increment-clamp', - DecrementClamp: 'decrement-clamp', - IncrementWrap: 'increment-wrap', - DecrementWrap: 'decrement-wrap' -}; + } -const GPUBufferBindingType = { - Uniform: 'uniform', - Storage: 'storage', - ReadOnlyStorage: 'read-only-storage' -}; + } -const GPUStorageTextureAccess = { - WriteOnly: 'write-only', - ReadOnly: 'read-only', - ReadWrite: 'read-write', -}; + } else if ( updateType === NodeUpdateType.RENDER ) { -const GPUTextureSampleType = { - Float: 'float', - UnfilterableFloat: 'unfilterable-float', - Depth: 'depth', - SInt: 'sint', - UInt: 'uint' -}; + const { renderMap } = this._getMaps( this.updateAfterMap, reference ); -const GPUTextureDimension = { - OneD: '1d', - TwoD: '2d', - ThreeD: '3d' -}; + if ( renderMap.get( reference ) !== this.renderId ) { -const GPUTextureViewDimension = { - OneD: '1d', - TwoD: '2d', - TwoDArray: '2d-array', - Cube: 'cube', - CubeArray: 'cube-array', - ThreeD: '3d' -}; + if ( node.updateAfter( this ) !== false ) { -const GPUTextureAspect = { - All: 'all', - StencilOnly: 'stencil-only', - DepthOnly: 'depth-only' -}; + renderMap.set( reference, this.renderId ); -const GPUInputStepMode = { - Vertex: 'vertex', - Instance: 'instance' -}; + } -const GPUFeatureName = { - DepthClipControl: 'depth-clip-control', - Depth32FloatStencil8: 'depth32float-stencil8', - TextureCompressionBC: 'texture-compression-bc', - TextureCompressionETC2: 'texture-compression-etc2', - TextureCompressionASTC: 'texture-compression-astc', - TimestampQuery: 'timestamp-query', - IndirectFirstInstance: 'indirect-first-instance', - ShaderF16: 'shader-f16', - RG11B10UFloat: 'rg11b10ufloat-renderable', - BGRA8UNormStorage: 'bgra8unorm-storage', - Float32Filterable: 'float32-filterable', - ClipDistances: 'clip-distances', - DualSourceBlending: 'dual-source-blending', - Subgroups: 'subgroups' -}; + } -class StorageBufferNode extends BufferNode { + } else if ( updateType === NodeUpdateType.OBJECT ) { - constructor( value, bufferType, bufferCount = 0 ) { + node.updateAfter( this ); - super( value, bufferType, bufferCount ); + } - this.isStorageBufferNode = true; + } - this.access = GPUBufferBindingType.Storage; + updateNode( node ) { - this.bufferObject = false; - this.bufferCount = bufferCount; + const updateType = node.getUpdateType(); + const reference = node.updateReference( this ); - this._attribute = null; - this._varying = null; + if ( updateType === NodeUpdateType.FRAME ) { - this.global = true; + const { frameMap } = this._getMaps( this.updateMap, reference ); - if ( value.isStorageBufferAttribute !== true && value.isStorageInstancedBufferAttribute !== true ) { + if ( frameMap.get( reference ) !== this.frameId ) { - // TOOD: Improve it, possibly adding a new property to the BufferAttribute to identify it as a storage buffer read-only attribute in Renderer + if ( node.update( this ) !== false ) { - if ( value.isInstancedBufferAttribute ) value.isStorageInstancedBufferAttribute = true; - else value.isStorageBufferAttribute = true; + frameMap.set( reference, this.frameId ); - } + } - } + } - getHash( builder ) { + } else if ( updateType === NodeUpdateType.RENDER ) { - if ( this.bufferCount === 0 ) { + const { renderMap } = this._getMaps( this.updateMap, reference ); - let bufferData = builder.globalCache.getData( this.value ); + if ( renderMap.get( reference ) !== this.renderId ) { - if ( bufferData === undefined ) { + if ( node.update( this ) !== false ) { - bufferData = { - node: this - }; + renderMap.set( reference, this.renderId ); - builder.globalCache.setData( this.value, bufferData ); + } } - return bufferData.node.uuid; - - } - - return this.uuid; - - } + } else if ( updateType === NodeUpdateType.OBJECT ) { - getInputType( /*builder*/ ) { + node.update( this ); - return 'storageBuffer'; + } } - element( indexNode ) { + update() { - return storageElement( this, indexNode ); + this.frameId ++; - } + if ( this.lastTime === undefined ) this.lastTime = performance.now(); - setBufferObject( value ) { + this.deltaTime = ( performance.now() - this.lastTime ) / 1000; - this.bufferObject = value; + this.lastTime = performance.now(); - return this; + this.time += this.deltaTime; } - setAccess( value ) { - - this.access = value; - - return this; +} - } +class NodeFunctionInput { - toReadOnly() { + constructor( type, name, count = null, qualifier = '', isConst = false ) { - return this.setAccess( GPUBufferBindingType.ReadOnlyStorage ); + this.type = type; + this.name = name; + this.count = count; + this.qualifier = qualifier; + this.isConst = isConst; } - generate( builder ) { +} - if ( builder.isAvailable( 'storageBuffer' ) ) { +NodeFunctionInput.isNodeFunctionInput = true; - return super.generate( builder ); +class StructTypeNode extends Node { - } + static get type() { - const nodeType = this.getNodeType( builder ); + return 'StructTypeNode'; - if ( this._attribute === null ) { + } - this._attribute = bufferAttribute( this.value ); - this._varying = varying( this._attribute ); + constructor( types ) { - } + super(); + this.types = types; + this.isStructTypeNode = true; - const output = this._varying.build( builder, nodeType ); + } - builder.registerTransform( output, this._attribute ); + getMemberTypes() { - return output; + return this.types; } } -StorageBufferNode.type = /*@__PURE__*/ registerNode( 'StorageBuffer', StorageBufferNode ); - -// Read-Write Storage -const storage = ( value, type, count ) => nodeObject( new StorageBufferNode( value, type, count ) ); -const storageObject = ( value, type, count ) => nodeObject( new StorageBufferNode( value, type, count ).setBufferObject( true ) ); - -class StorageTextureNode extends TextureNode { - - constructor( value, uvNode, storeNode = null ) { +class OutputStructNode extends Node { - super( value, uvNode ); + static get type() { - this.storeNode = storeNode; + return 'OutputStructNode'; - this.isStorageTextureNode = true; + } - this.access = GPUStorageTextureAccess.WriteOnly; + constructor( ...members ) { - } + super(); - getInputType( /*builder*/ ) { + this.members = members; - return 'storageTexture'; + this.isOutputStructNode = true; } @@ -55143,2733 +54810,2728 @@ class StorageTextureNode extends TextureNode { super.setup( builder ); - const properties = builder.getNodeProperties( this ); - properties.storeNode = this.storeNode; + const members = this.members; + const types = []; - } + for ( let i = 0; i < members.length; i ++ ) { - setAccess( value ) { + types.push( members[ i ].getNodeType( builder ) ); - this.access = value; - return this; + } + + this.nodeType = builder.getStructTypeFromNode( new StructTypeNode( types ) ).name; } generate( builder, output ) { - let snippet; + const propertyName = builder.getOutputStructName(); + const members = this.members; - if ( this.storeNode !== null ) { + const structPrefix = propertyName !== '' ? propertyName + '.' : ''; - snippet = this.generateStore( builder ); + for ( let i = 0; i < members.length; i ++ ) { - } else { + const snippet = members[ i ].build( builder, output ); - snippet = super.generate( builder, output ); + builder.addLineFlowCode( `${ structPrefix }m${ i } = ${ snippet }`, this ); } - return snippet; + return propertyName; } - toReadOnly() { - - return this.setAccess( GPUStorageTextureAccess.ReadOnly ); +} - } +const outputStruct = /*@__PURE__*/ nodeProxy( OutputStructNode ); - toWriteOnly() { +function getTextureIndex( textures, name ) { - return this.setAccess( GPUStorageTextureAccess.WriteOnly ); + for ( let i = 0; i < textures.length; i ++ ) { - } + if ( textures[ i ].name === name ) { - generateStore( builder ) { + return i; - const properties = builder.getNodeProperties( this ); + } - const { uvNode, storeNode } = properties; + } - const textureProperty = super.generate( builder, 'property' ); - const uvSnippet = uvNode.build( builder, 'uvec2' ); - const storeSnippet = storeNode.build( builder, 'vec4' ); + return - 1; - const snippet = builder.generateTextureStore( builder, textureProperty, uvSnippet, storeSnippet ); +} - builder.addLineFlowCode( snippet ); +class MRTNode extends OutputStructNode { - } + static get type() { -} + return 'MRTNode'; -StorageTextureNode.type = /*@__PURE__*/ registerNode( 'StorageTexture', StorageTextureNode ); + } -const storageTexture = /*@__PURE__*/ nodeProxy( StorageTextureNode ); + constructor( outputNodes ) { -const textureStore = ( value, uvNode, storeNode ) => { + super(); - const node = storageTexture( value, uvNode, storeNode ); + this.outputNodes = outputNodes; - if ( storeNode !== null ) node.append(); + this.isMRTNode = true; - return node; + } -}; + has( name ) { -class UserDataNode extends ReferenceNode { + return this.outputNodes[ name ] !== undefined; - constructor( property, inputType, userData = null ) { + } - super( property, inputType, userData ); + get( name ) { - this.userData = userData; + return this.outputNodes[ name ]; } - update( frame ) { + merge( mrtNode ) { - this.reference = this.userData !== null ? this.userData : frame.object.userData; + const outputs = { ...this.outputNodes, ...mrtNode.outputNodes }; - super.update( frame ); + return mrt( outputs ); } -} - -UserDataNode.type = /*@__PURE__*/ registerNode( 'UserData', UserDataNode ); + setup( builder ) { -const userData = ( name, inputType, userData ) => nodeObject( new UserDataNode( name, inputType, userData ) ); + const outputNodes = this.outputNodes; + const mrt = builder.renderer.getRenderTarget(); -class PosterizeNode extends TempNode { + const members = []; - constructor( sourceNode, stepsNode ) { + const textures = mrt.textures; - super(); + for ( const name in outputNodes ) { - this.sourceNode = sourceNode; - this.stepsNode = stepsNode; + const index = getTextureIndex( textures, name ); - } + members[ index ] = vec4( outputNodes[ name ] ); - setup() { + } - const { sourceNode, stepsNode } = this; + this.members = members; - return sourceNode.mul( stepsNode ).floor().div( stepsNode ); + return super.setup( builder ); } } -PosterizeNode.type = /*@__PURE__*/ registerNode( 'Posterize', PosterizeNode ); +const mrt = /*@__PURE__*/ nodeProxy( MRTNode ); -const posterize = /*@__PURE__*/ nodeProxy( PosterizeNode ); +class FunctionOverloadingNode extends Node { -let _sharedFramebuffer = null; + static get type() { -class ViewportSharedTextureNode extends ViewportTextureNode { + return 'FunctionOverloadingNode'; - constructor( uvNode = viewportUV, levelNode = null ) { + } - if ( _sharedFramebuffer === null ) { + constructor( functionNodes = [], ...parametersNodes ) { - _sharedFramebuffer = new FramebufferTexture(); + super(); - } + this.functionNodes = functionNodes; + this.parametersNodes = parametersNodes; - super( uvNode, levelNode, _sharedFramebuffer ); + this._candidateFnCall = null; + + this.global = true; } - updateReference() { + getNodeType() { - return this; + return this.functionNodes[ 0 ].shaderNode.layout.type; } -} + setup( builder ) { -ViewportSharedTextureNode.type = /*@__PURE__*/ registerNode( 'ViewportSharedTexture', ViewportSharedTextureNode ); + const params = this.parametersNodes; -const viewportSharedTexture = /*@__PURE__*/ nodeProxy( ViewportSharedTextureNode ); + let candidateFnCall = this._candidateFnCall; -const _size$7 = /*@__PURE__*/ new Vector2(); + if ( candidateFnCall === null ) { -class PassTextureNode extends TextureNode { + let candidateFn = null; + let candidateScore = - 1; - constructor( passNode, texture ) { + for ( const functionNode of this.functionNodes ) { - super( texture ); + const shaderNode = functionNode.shaderNode; + const layout = shaderNode.layout; - this.passNode = passNode; + if ( layout === null ) { - this.setUpdateMatrix( false ); + throw new Error( 'FunctionOverloadingNode: FunctionNode must be a layout.' ); - } + } - setup( builder ) { + const inputs = layout.inputs; - if ( builder.object.isQuadMesh ) this.passNode.build( builder ); + if ( params.length === inputs.length ) { - return super.setup( builder ); + let score = 0; - } + for ( let i = 0; i < params.length; i ++ ) { - clone() { + const param = params[ i ]; + const input = inputs[ i ]; - return new this.constructor( this.passNode, this.value ); + if ( param.getNodeType( builder ) === input.type ) { - } + score ++; -} + } else { -PassTextureNode.type = /*@__PURE__*/ registerNode( 'PassTexture', PassTextureNode ); + score = 0; -class PassMultipleTextureNode extends PassTextureNode { + } - constructor( passNode, textureName, previousTexture = false ) { + } - super( passNode, null ); + if ( score > candidateScore ) { - this.textureName = textureName; - this.previousTexture = previousTexture; + candidateFn = functionNode; + candidateScore = score; - } + } - updateTexture() { + } - this.value = this.previousTexture ? this.passNode.getPreviousTexture( this.textureName ) : this.passNode.getTexture( this.textureName ); + } + + this._candidateFnCall = candidateFnCall = candidateFn( ...params ); + + } + + return candidateFnCall; } - setup( builder ) { +} - this.updateTexture(); +const overloadingBaseFn = /*@__PURE__*/ nodeProxy( FunctionOverloadingNode ); - return super.setup( builder ); +const overloadingFn = ( functionNodes ) => ( ...params ) => overloadingBaseFn( functionNodes, ...params ); + +class TimerNode extends UniformNode { + + static get type() { + + return 'TimerNode'; } - clone() { + constructor( scope = TimerNode.LOCAL, scale = 1, value = 0 ) { - return new this.constructor( this.passNode, this.textureName, this.previousTexture ); + super( value ); + + this.scope = scope; + this.scale = scale; + + this.updateType = NodeUpdateType.FRAME; } + /* + @TODO: + getNodeType( builder ) { -} + const scope = this.scope; -PassMultipleTextureNode.type = /*@__PURE__*/ registerNode( 'PassMultipleTexture', PassMultipleTextureNode ); + if ( scope === TimerNode.FRAME ) { -class PassNode extends TempNode { + return 'uint'; - constructor( scope, scene, camera, options = {} ) { + } - super( 'vec4' ); + return 'float'; - this.scope = scope; - this.scene = scene; - this.camera = camera; - this.options = options; + } +*/ + update( frame ) { - this._pixelRatio = 1; - this._width = 1; - this._height = 1; + const scope = this.scope; + const scale = this.scale; - const depthTexture = new DepthTexture(); - depthTexture.isRenderTargetTexture = true; - //depthTexture.type = FloatType; - depthTexture.name = 'depth'; + if ( scope === TimerNode.LOCAL ) { - const renderTarget = new RenderTarget( this._width * this._pixelRatio, this._height * this._pixelRatio, { type: HalfFloatType, ...options, } ); - renderTarget.texture.name = 'output'; - renderTarget.depthTexture = depthTexture; + this.value += frame.deltaTime * scale; - this.renderTarget = renderTarget; + } else if ( scope === TimerNode.DELTA ) { - this.updateBeforeType = NodeUpdateType.FRAME; + this.value = frame.deltaTime * scale; - this._textures = { - output: renderTarget.texture, - depth: depthTexture - }; + } else if ( scope === TimerNode.FRAME ) { - this._textureNodes = {}; - this._linearDepthNodes = {}; - this._viewZNodes = {}; + this.value = frame.frameId; - this._previousTextures = {}; - this._previousTextureNodes = {}; + } else { - this._cameraNear = uniform( 0 ); - this._cameraFar = uniform( 0 ); + // global - this._mrt = null; + this.value = frame.time * scale; - this.isPassNode = true; + } } - setMRT( mrt ) { + serialize( data ) { - this._mrt = mrt; + super.serialize( data ); - return this; + data.scope = this.scope; + data.scale = this.scale; } - getMRT() { + deserialize( data ) { - return this._mrt; + super.deserialize( data ); + + this.scope = data.scope; + this.scale = data.scale; } - isGlobal() { +} - return true; +TimerNode.LOCAL = 'local'; +TimerNode.GLOBAL = 'global'; +TimerNode.DELTA = 'delta'; +TimerNode.FRAME = 'frame'; - } +// @TODO: add support to use node in timeScale +const timerLocal = ( timeScale, value = 0 ) => nodeObject( new TimerNode( TimerNode.LOCAL, timeScale, value ) ); +const timerGlobal = ( timeScale, value = 0 ) => nodeObject( new TimerNode( TimerNode.GLOBAL, timeScale, value ) ); +const timerDelta = ( timeScale, value = 0 ) => nodeObject( new TimerNode( TimerNode.DELTA, timeScale, value ) ); +const frameId = /*@__PURE__*/ nodeImmutable( TimerNode, TimerNode.FRAME ).toUint(); - getTexture( name ) { +class OscNode extends Node { - let texture = this._textures[ name ]; + static get type() { - if ( texture === undefined ) { + return 'OscNode'; - const refTexture = this.renderTarget.texture; + } - texture = refTexture.clone(); - texture.isRenderTargetTexture = true; - texture.name = name; + constructor( method = OscNode.SINE, timeNode = timerLocal() ) { - this._textures[ name ] = texture; + super(); - this.renderTarget.textures.push( texture ); + this.method = method; + this.timeNode = timeNode; - } + } - return texture; + getNodeType( builder ) { + + return this.timeNode.getNodeType( builder ); } - getPreviousTexture( name ) { + setup() { - let texture = this._previousTextures[ name ]; + const method = this.method; + const timeNode = nodeObject( this.timeNode ); - if ( texture === undefined ) { + let outputNode = null; - texture = this.getTexture( name ).clone(); - texture.isRenderTargetTexture = true; + if ( method === OscNode.SINE ) { - this._previousTextures[ name ] = texture; + outputNode = timeNode.add( 0.75 ).mul( Math.PI * 2 ).sin().mul( 0.5 ).add( 0.5 ); + + } else if ( method === OscNode.SQUARE ) { + + outputNode = timeNode.fract().round(); + + } else if ( method === OscNode.TRIANGLE ) { + + outputNode = timeNode.add( 0.5 ).fract().mul( 2 ).sub( 1 ).abs(); + + } else if ( method === OscNode.SAWTOOTH ) { + + outputNode = timeNode.fract(); } - return texture; + return outputNode; } - toggleTexture( name ) { - - const prevTexture = this._previousTextures[ name ]; + serialize( data ) { - if ( prevTexture !== undefined ) { + super.serialize( data ); - const texture = this._textures[ name ]; + data.method = this.method; - const index = this.renderTarget.textures.indexOf( texture ); - this.renderTarget.textures[ index ] = prevTexture; + } - this._textures[ name ] = prevTexture; - this._previousTextures[ name ] = texture; + deserialize( data ) { - this._textureNodes[ name ].updateTexture(); - this._previousTextureNodes[ name ].updateTexture(); + super.deserialize( data ); - } + this.method = data.method; } - getTextureNode( name = 'output' ) { +} - let textureNode = this._textureNodes[ name ]; +OscNode.SINE = 'sine'; +OscNode.SQUARE = 'square'; +OscNode.TRIANGLE = 'triangle'; +OscNode.SAWTOOTH = 'sawtooth'; - if ( textureNode === undefined ) { +const oscSine = /*@__PURE__*/ nodeProxy( OscNode, OscNode.SINE ); +const oscSquare = /*@__PURE__*/ nodeProxy( OscNode, OscNode.SQUARE ); +const oscTriangle = /*@__PURE__*/ nodeProxy( OscNode, OscNode.TRIANGLE ); +const oscSawtooth = /*@__PURE__*/ nodeProxy( OscNode, OscNode.SAWTOOTH ); - this._textureNodes[ name ] = textureNode = nodeObject( new PassMultipleTextureNode( this, name ) ); - this._textureNodes[ name ].updateTexture(); +class SpriteSheetUVNode extends Node { - } + static get type() { - return textureNode; + return 'SpriteSheetUVNode'; } - getPreviousTextureNode( name = 'output' ) { + constructor( countNode, uvNode = uv(), frameNode = float( 0 ) ) { - let textureNode = this._previousTextureNodes[ name ]; + super( 'vec2' ); - if ( textureNode === undefined ) { + this.countNode = countNode; + this.uvNode = uvNode; + this.frameNode = frameNode; - if ( this._textureNodes[ name ] === undefined ) this.getTextureNode( name ); + } - this._previousTextureNodes[ name ] = textureNode = nodeObject( new PassMultipleTextureNode( this, name, true ) ); - this._previousTextureNodes[ name ].updateTexture(); + setup() { - } + const { frameNode, uvNode, countNode } = this; - return textureNode; + const { width, height } = countNode; - } + const frameNum = frameNode.mod( width.mul( height ) ).floor(); - getViewZNode( name = 'depth' ) { + const column = frameNum.mod( width ); + const row = height.sub( frameNum.add( 1 ).div( width ).ceil() ); - let viewZNode = this._viewZNodes[ name ]; + const scale = countNode.reciprocal(); + const uvFrameOffset = vec2( column, row ); - if ( viewZNode === undefined ) { + return uvNode.add( uvFrameOffset ).mul( scale ); - const cameraNear = this._cameraNear; - const cameraFar = this._cameraFar; + } - this._viewZNodes[ name ] = viewZNode = perspectiveDepthToViewZ( this.getTextureNode( name ), cameraNear, cameraFar ); +} - } +const spritesheetUV = /*@__PURE__*/ nodeProxy( SpriteSheetUVNode ); - return viewZNode; +class StorageArrayElementNode extends ArrayElementNode { + + static get type() { + + return 'StorageArrayElementNode'; } - getLinearDepthNode( name = 'depth' ) { + constructor( storageBufferNode, indexNode ) { - let linearDepthNode = this._linearDepthNodes[ name ]; + super( storageBufferNode, indexNode ); - if ( linearDepthNode === undefined ) { + this.isStorageArrayElementNode = true; - const cameraNear = this._cameraNear; - const cameraFar = this._cameraFar; - const viewZNode = this.getViewZNode( name ); + } - // TODO: just if ( builder.camera.isPerspectiveCamera ) + set storageBufferNode( value ) { - this._linearDepthNodes[ name ] = linearDepthNode = viewZToOrthographicDepth( viewZNode, cameraNear, cameraFar ); + this.node = value; - } + } - return linearDepthNode; + get storageBufferNode() { + + return this.node; } - setup( { renderer } ) { + setup( builder ) { - this.renderTarget.samples = this.options.samples === undefined ? renderer.samples : this.options.samples; + if ( builder.isAvailable( 'storageBuffer' ) === false ) { - // Disable MSAA for WebGL backend for now - if ( renderer.backend.isWebGLBackend === true ) { + if ( this.node.bufferObject === true ) { - this.renderTarget.samples = 0; + builder.setupPBO( this.node ); - } + } - this.renderTarget.depthTexture.isMultisampleRenderTargetTexture = this.renderTarget.samples > 1; + } - return this.scope === PassNode.COLOR ? this.getTextureNode() : this.getLinearDepthNode(); + return super.setup( builder ); } - updateBefore( frame ) { + generate( builder, output ) { - const { renderer } = frame; - const { scene, camera } = this; + let snippet; - this._pixelRatio = renderer.getPixelRatio(); + const isAssignContext = builder.context.assign; - const size = renderer.getSize( _size$7 ); + // - this.setSize( size.width, size.height ); + if ( builder.isAvailable( 'storageBuffer' ) === false ) { - const currentRenderTarget = renderer.getRenderTarget(); - const currentMRT = renderer.getMRT(); + if ( this.node.bufferObject === true && isAssignContext !== true ) { - this._cameraNear.value = camera.near; - this._cameraFar.value = camera.far; + snippet = builder.generatePBO( this ); - for ( const name in this._previousTextures ) { + } else { - this.toggleTexture( name ); + snippet = this.node.build( builder ); - } + } - renderer.setRenderTarget( this.renderTarget ); - renderer.setMRT( this._mrt ); + } else { - renderer.render( scene, camera ); + snippet = super.generate( builder ); - renderer.setRenderTarget( currentRenderTarget ); - renderer.setMRT( currentMRT ); + } - } + if ( isAssignContext !== true ) { - setSize( width, height ) { + const type = this.getNodeType( builder ); - this._width = width; - this._height = height; + snippet = builder.format( snippet, type, output ); - const effectiveWidth = this._width * this._pixelRatio; - const effectiveHeight = this._height * this._pixelRatio; + } - this.renderTarget.setSize( effectiveWidth, effectiveHeight ); + return snippet; } - setPixelRatio( pixelRatio ) { - - this._pixelRatio = pixelRatio; +} - this.setSize( this._width, this._height ); +const storageElement = /*@__PURE__*/ nodeProxy( StorageArrayElementNode ); - } +class TriplanarTexturesNode extends Node { - dispose() { + static get type() { - this.renderTarget.dispose(); + return 'TriplanarTexturesNode'; } + constructor( textureXNode, textureYNode = null, textureZNode = null, scaleNode = float( 1 ), positionNode = positionLocal, normalNode = normalLocal ) { -} + super( 'vec4' ); -PassNode.COLOR = 'color'; -PassNode.DEPTH = 'depth'; + this.textureXNode = textureXNode; + this.textureYNode = textureYNode; + this.textureZNode = textureZNode; -PassNode.type = /*@__PURE__*/ registerNode( 'Pass', PassNode ); + this.scaleNode = scaleNode; -const pass = ( scene, camera, options ) => nodeObject( new PassNode( PassNode.COLOR, scene, camera, options ) ); -const passTexture = ( pass, texture ) => nodeObject( new PassTextureNode( pass, texture ) ); -const depthPass = ( scene, camera ) => nodeObject( new PassNode( PassNode.DEPTH, scene, camera ) ); + this.positionNode = positionNode; + this.normalNode = normalNode; -// WebGPU: The use of a single QuadMesh for both gaussian blur passes results in a single RenderObject with a SampledTexture binding that -// alternates between source textures and triggers creation of new BindGroups and BindGroupLayouts every frame. + } -const _quadMesh1 = /*@__PURE__*/ new QuadMesh(); -const _quadMesh2 = /*@__PURE__*/ new QuadMesh(); + setup() { -class GaussianBlurNode extends TempNode { + const { textureXNode, textureYNode, textureZNode, scaleNode, positionNode, normalNode } = this; - constructor( textureNode, directionNode = null, sigma = 2 ) { + // Ref: https://github.com/keijiro/StandardTriplanar - super( 'vec4' ); + // Blending factor of triplanar mapping + let bf = normalNode.abs().normalize(); + bf = bf.div( bf.dot( vec3( 1.0 ) ) ); - this.textureNode = textureNode; - this.directionNode = directionNode; - this.sigma = sigma; + // Triplanar mapping + const tx = positionNode.yz.mul( scaleNode ); + const ty = positionNode.zx.mul( scaleNode ); + const tz = positionNode.xy.mul( scaleNode ); - this._invSize = uniform( new Vector2() ); - this._passDirection = uniform( new Vector2() ); + // Base color + const textureX = textureXNode.value; + const textureY = textureYNode !== null ? textureYNode.value : textureX; + const textureZ = textureZNode !== null ? textureZNode.value : textureX; - this._horizontalRT = new RenderTarget(); - this._horizontalRT.texture.name = 'GaussianBlurNode.horizontal'; - this._verticalRT = new RenderTarget(); - this._verticalRT.texture.name = 'GaussianBlurNode.vertical'; + const cx = texture( textureX, tx ).mul( bf.x ); + const cy = texture( textureY, ty ).mul( bf.y ); + const cz = texture( textureZ, tz ).mul( bf.z ); - this._textureNode = passTexture( this, this._verticalRT.texture ); + return add( cx, cy, cz ); - this.updateBeforeType = NodeUpdateType.RENDER; + } - this.resolution = new Vector2( 1, 1 ); +} - } +const triplanarTextures = /*@__PURE__*/ nodeProxy( TriplanarTexturesNode ); +const triplanarTexture = ( ...params ) => triplanarTextures( ...params ); - setSize( width, height ) { +const _reflectorPlane = new Plane(); +const _normal = new Vector3(); +const _reflectorWorldPosition = new Vector3(); +const _cameraWorldPosition = new Vector3(); +const _rotationMatrix = new Matrix4(); +const _lookAtPosition = new Vector3( 0, 0, - 1 ); +const clipPlane = new Vector4(); - width = Math.max( Math.round( width * this.resolution.x ), 1 ); - height = Math.max( Math.round( height * this.resolution.y ), 1 ); +const _view = new Vector3(); +const _target = new Vector3(); +const _q = new Vector4(); - this._invSize.value.set( 1 / width, 1 / height ); - this._horizontalRT.setSize( width, height ); - this._verticalRT.setSize( width, height ); +const _size$9 = new Vector2(); - } +const _defaultRT = new RenderTarget(); +const _defaultUV = screenUV.flipX(); - updateBefore( frame ) { +let _inReflector = false; - const { renderer } = frame; +class ReflectorNode extends TextureNode { - const textureNode = this.textureNode; - const map = textureNode.value; + static get type() { - const currentRenderTarget = renderer.getRenderTarget(); - const currentMRT = renderer.getMRT(); + return 'ReflectorNode'; - const currentTexture = textureNode.value; + } - _quadMesh1.material = this._material; - _quadMesh2.material = this._material; + constructor( parameters = {} ) { - this.setSize( map.image.width, map.image.height ); + super( _defaultRT.texture, _defaultUV ); - const textureType = map.type; + const { + target = new Object3D(), + resolution = 1, + generateMipmaps = false, + bounces = true + } = parameters; - this._horizontalRT.texture.type = textureType; - this._verticalRT.texture.type = textureType; + // - // clear + this.target = target; + this.resolution = resolution; + this.generateMipmaps = generateMipmaps; + this.bounces = bounces; - renderer.setMRT( null ); + this.updateBeforeType = bounces ? NodeUpdateType.RENDER : NodeUpdateType.FRAME; - // horizontal + this.virtualCameras = new WeakMap(); + this.renderTargets = new WeakMap(); - renderer.setRenderTarget( this._horizontalRT ); - this._passDirection.value.set( 1, 0 ); + } - _quadMesh1.render( renderer ); + _updateResolution( renderTarget, renderer ) { - // vertical + const resolution = this.resolution; - textureNode.value = this._horizontalRT.texture; - renderer.setRenderTarget( this._verticalRT ); + renderer.getDrawingBufferSize( _size$9 ); - this._passDirection.value.set( 0, 1 ); + renderTarget.setSize( Math.round( _size$9.width * resolution ), Math.round( _size$9.height * resolution ) ); - _quadMesh2.render( renderer ); + } - // restore + setup( builder ) { - renderer.setRenderTarget( currentRenderTarget ); - renderer.setMRT( currentMRT ); - textureNode.value = currentTexture; + this._updateResolution( _defaultRT, builder.renderer ); + + return super.setup( builder ); } getTextureNode() { - return this._textureNode; + return this.textureNode; } - setup( builder ) { + getVirtualCamera( camera ) { - const textureNode = this.textureNode; + let virtualCamera = this.virtualCameras.get( camera ); - if ( textureNode.isTextureNode !== true ) { + if ( virtualCamera === undefined ) { - console.error( 'GaussianBlurNode requires a TextureNode.' ); + virtualCamera = camera.clone(); - return vec4(); + this.virtualCameras.set( camera, virtualCamera ); } - // + return virtualCamera; - const uvNode = textureNode.uvNode || uv(); - const directionNode = vec2( this.directionNode || 1 ); + } - const sampleTexture = ( uv ) => textureNode.uv( uv ); + getRenderTarget( camera ) { - const blur = Fn( () => { + let renderTarget = this.renderTargets.get( camera ); - const kernelSize = 3 + ( 2 * this.sigma ); - const gaussianCoefficients = this._getCoefficients( kernelSize ); + if ( renderTarget === undefined ) { - const invSize = this._invSize; - const direction = directionNode.mul( this._passDirection ); + renderTarget = new RenderTarget( 0, 0, { type: HalfFloatType } ); - const weightSum = float( gaussianCoefficients[ 0 ] ).toVar(); - const diffuseSum = vec4( sampleTexture( uvNode ).mul( weightSum ) ).toVar(); + if ( this.generateMipmaps === true ) { - for ( let i = 1; i < kernelSize; i ++ ) { - - const x = float( i ); - const w = float( gaussianCoefficients[ i ] ); - - const uvOffset = vec2( direction.mul( invSize.mul( x ) ) ).toVar(); - - const sample1 = vec4( sampleTexture( uvNode.add( uvOffset ) ) ); - const sample2 = vec4( sampleTexture( uvNode.sub( uvOffset ) ) ); - - diffuseSum.addAssign( sample1.add( sample2 ).mul( w ) ); - weightSum.addAssign( mul( 2.0, w ) ); + renderTarget.texture.minFilter = LinearMipMapLinearFilter; + renderTarget.texture.generateMipmaps = true; } - return diffuseSum.div( weightSum ); - - } ); - - // - - const material = this._material || ( this._material = new NodeMaterial() ); - material.fragmentNode = blur().context( builder.getSharedContext() ); - material.name = 'Gaussian_blur'; - material.needsUpdate = true; - - // - - const properties = builder.getNodeProperties( this ); - properties.textureNode = textureNode; - - // - - return this._textureNode; - - } + this.renderTargets.set( camera, renderTarget ); - dispose() { + } - this._horizontalRT.dispose(); - this._verticalRT.dispose(); + return renderTarget; } - _getCoefficients( kernelRadius ) { - - const coefficients = []; - - for ( let i = 0; i < kernelRadius; i ++ ) { + updateBefore( frame ) { - coefficients.push( 0.39894 * Math.exp( - 0.5 * i * i / ( kernelRadius * kernelRadius ) ) / kernelRadius ); + if ( this.bounces === false && _inReflector ) return false; - } + _inReflector = true; - return coefficients; + const { scene, camera, renderer, material } = frame; + const { target } = this; - } + const virtualCamera = this.getVirtualCamera( camera ); + const renderTarget = this.getRenderTarget( virtualCamera ); -} + renderer.getDrawingBufferSize( _size$9 ); -GaussianBlurNode.type = /*@__PURE__*/ registerNode( 'GaussianBlur', GaussianBlurNode ); + this._updateResolution( renderTarget, renderer ); -const gaussianBlur = ( node, directionNode, sigma ) => nodeObject( new GaussianBlurNode( convertToTexture( node ), directionNode, sigma ) ); + // -const _size$6 = /*@__PURE__*/ new Vector2(); + _reflectorWorldPosition.setFromMatrixPosition( target.matrixWorld ); + _cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld ); -const _quadMeshComp = /*@__PURE__*/ new QuadMesh(); + _rotationMatrix.extractRotation( target.matrixWorld ); -class AfterImageNode extends TempNode { + _normal.set( 0, 0, 1 ); + _normal.applyMatrix4( _rotationMatrix ); - constructor( textureNode, damp = 0.96 ) { + _view.subVectors( _reflectorWorldPosition, _cameraWorldPosition ); - super( textureNode ); + // Avoid rendering when reflector is facing away - this.textureNode = textureNode; - this.textureNodeOld = texture(); - this.damp = uniform( damp ); + if ( _view.dot( _normal ) > 0 ) return; - this._compRT = new RenderTarget(); - this._compRT.texture.name = 'AfterImageNode.comp'; + _view.reflect( _normal ).negate(); + _view.add( _reflectorWorldPosition ); - this._oldRT = new RenderTarget(); - this._oldRT.texture.name = 'AfterImageNode.old'; + _rotationMatrix.extractRotation( camera.matrixWorld ); - this._textureNode = passTexture( this, this._compRT.texture ); + _lookAtPosition.set( 0, 0, - 1 ); + _lookAtPosition.applyMatrix4( _rotationMatrix ); + _lookAtPosition.add( _cameraWorldPosition ); - this.updateBeforeType = NodeUpdateType.RENDER; + _target.subVectors( _reflectorWorldPosition, _lookAtPosition ); + _target.reflect( _normal ).negate(); + _target.add( _reflectorWorldPosition ); - } + // - getTextureNode() { + virtualCamera.coordinateSystem = camera.coordinateSystem; + virtualCamera.position.copy( _view ); + virtualCamera.up.set( 0, 1, 0 ); + virtualCamera.up.applyMatrix4( _rotationMatrix ); + virtualCamera.up.reflect( _normal ); + virtualCamera.lookAt( _target ); - return this._textureNode; + virtualCamera.near = camera.near; + virtualCamera.far = camera.far; - } + virtualCamera.updateMatrixWorld(); + virtualCamera.projectionMatrix.copy( camera.projectionMatrix ); - setSize( width, height ) { + // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html + // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf + _reflectorPlane.setFromNormalAndCoplanarPoint( _normal, _reflectorWorldPosition ); + _reflectorPlane.applyMatrix4( virtualCamera.matrixWorldInverse ); - this._compRT.setSize( width, height ); - this._oldRT.setSize( width, height ); + clipPlane.set( _reflectorPlane.normal.x, _reflectorPlane.normal.y, _reflectorPlane.normal.z, _reflectorPlane.constant ); - } + const projectionMatrix = virtualCamera.projectionMatrix; - updateBefore( frame ) { + _q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ]; + _q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ]; + _q.z = - 1.0; + _q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ]; - const { renderer } = frame; + // Calculate the scaled plane vector + clipPlane.multiplyScalar( 1.0 / clipPlane.dot( _q ) ); - const textureNode = this.textureNode; - const map = textureNode.value; + const clipBias = 0; - const textureType = map.type; + // Replacing the third row of the projection matrix + projectionMatrix.elements[ 2 ] = clipPlane.x; + projectionMatrix.elements[ 6 ] = clipPlane.y; + projectionMatrix.elements[ 10 ] = clipPlane.z - clipBias; + projectionMatrix.elements[ 14 ] = clipPlane.w; - this._compRT.texture.type = textureType; - this._oldRT.texture.type = textureType; + // - renderer.getDrawingBufferSize( _size$6 ); + this.value = renderTarget.texture; - this.setSize( _size$6.x, _size$6.y ); + material.visible = false; const currentRenderTarget = renderer.getRenderTarget(); - const currentTexture = textureNode.value; - - this.textureNodeOld.value = this._oldRT.texture; + const currentMRT = renderer.getMRT(); - // comp - renderer.setRenderTarget( this._compRT ); - _quadMeshComp.render( renderer ); + renderer.setMRT( null ); + renderer.setRenderTarget( renderTarget ); - // Swap the textures - const temp = this._oldRT; - this._oldRT = this._compRT; - this._compRT = temp; + renderer.render( scene, virtualCamera ); + renderer.setMRT( currentMRT ); renderer.setRenderTarget( currentRenderTarget ); - textureNode.value = currentTexture; + + material.visible = true; + + _inReflector = false; } - setup( builder ) { +} - const textureNode = this.textureNode; - const textureNodeOld = this.textureNodeOld; +const reflector = ( parameters ) => nodeObject( new ReflectorNode( parameters ) ); - // +// Helper for passes that need to fill the viewport with a single quad. - const uvNode = textureNode.uvNode || uv(); +const _camera = /*@__PURE__*/ new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); - textureNodeOld.uvNode = uvNode; +// https://github.com/mrdoob/three.js/pull/21358 - const sampleTexture = ( uv ) => textureNode.uv( uv ); +class QuadGeometry extends BufferGeometry { - const when_gt = Fn( ( [ x_immutable, y_immutable ] ) => { + constructor( flipY = false ) { - const y = float( y_immutable ).toVar(); - const x = vec4( x_immutable ).toVar(); + super(); - return max$1( sign( x.sub( y ) ), 0.0 ); + const uv = flipY === false ? [ 0, - 1, 0, 1, 2, 1 ] : [ 0, 2, 0, 0, 2, 0 ]; - } ); + this.setAttribute( 'position', new Float32BufferAttribute( [ - 1, 3, 0, - 1, - 1, 0, 3, - 1, 0 ], 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uv, 2 ) ); - const afterImg = Fn( () => { + } - const texelOld = vec4( textureNodeOld ); - const texelNew = vec4( sampleTexture( uvNode ) ); +} - texelOld.mulAssign( this.damp.mul( when_gt( texelOld, 0.1 ) ) ); - return max$1( texelNew, texelOld ); +const _geometry = /*@__PURE__*/ new QuadGeometry(); - } ); +class QuadMesh extends Mesh { - // + constructor( material = null ) { - const materialComposed = this._materialComposed || ( this._materialComposed = new NodeMaterial() ); - materialComposed.name = 'AfterImage'; - materialComposed.fragmentNode = afterImg(); + super( _geometry, material ); - _quadMeshComp.material = materialComposed; + this.camera = _camera; - // + this.isQuadMesh = true; - const properties = builder.getNodeProperties( this ); - properties.textureNode = textureNode; + } - // + renderAsync( renderer ) { - return this._textureNode; + return renderer.renderAsync( this, _camera ); } - dispose() { + render( renderer ) { - this._compRT.dispose(); - this._oldRT.dispose(); + renderer.render( this, _camera ); } } -const afterImage = ( node, damp ) => nodeObject( new AfterImageNode( convertToTexture( node ), damp ) ); - -const grayscale = /*@__PURE__*/ Fn( ( [ color ] ) => { +const _size$8 = /*@__PURE__*/ new Vector2(); - return luminance( color.rgb ); +class RTTNode extends TextureNode { -} ); + static get type() { -const saturation = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { + return 'RTTNode'; - return adjustment.mix( luminance( color.rgb ), color.rgb ); + } -} ); + constructor( node, width = null, height = null, options = { type: HalfFloatType } ) { -const vibrance = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { + const renderTarget = new RenderTarget( width, height, options ); - const average = add( color.r, color.g, color.b ).div( 3.0 ); + super( renderTarget.texture, uv() ); - const mx = color.r.max( color.g.max( color.b ) ); - const amt = mx.sub( average ).mul( adjustment ).mul( - 3.0 ); + this.node = node; + this.width = width; + this.height = height; - return mix( color.rgb, mx, amt ); + this.renderTarget = renderTarget; -} ); + this.textureNeedsUpdate = true; + this.autoUpdate = true; -const hue = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { + this.updateMap = new WeakMap(); - const k = vec3( 0.57735, 0.57735, 0.57735 ); + this._rttNode = null; + this._quadMesh = new QuadMesh( new NodeMaterial() ); - const cosAngle = adjustment.cos(); + this.updateBeforeType = NodeUpdateType.RENDER; - return vec3( color.rgb.mul( cosAngle ).add( k.cross( color.rgb ).mul( adjustment.sin() ).add( k.mul( dot( k, color.rgb ).mul( cosAngle.oneMinus() ) ) ) ) ); + } -} ); + get autoSize() { -const _luminanceCoefficients = /*@__PURE__*/ new Vector3(); -const luminance = ( - color, - luminanceCoefficients = vec3( ... ColorManagement.getLuminanceCoefficients( _luminanceCoefficients ) ) -) => dot( color, luminanceCoefficients ); + return this.width === null; -const threshold = ( color, threshold ) => mix( vec3( 0.0 ), color, luminance( color ).sub( threshold ).max( 0 ) ); + } -const _quadMesh$4 = /*@__PURE__*/ new QuadMesh(); + setup( builder ) { -class AnamorphicNode extends TempNode { + this._rttNode = this.node.context( builder.getSharedContext() ); + this._quadMesh.material.name = 'RTT'; + this._quadMesh.material.needsUpdate = true; - constructor( textureNode, tresholdNode, scaleNode, samples ) { + return super.setup( builder ); - super( 'vec4' ); + } - this.textureNode = textureNode; - this.tresholdNode = tresholdNode; - this.scaleNode = scaleNode; - this.colorNode = vec3( 0.1, 0.0, 1.0 ); - this.samples = samples; - this.resolution = new Vector2( 1, 1 ); + setSize( width, height ) { - this._renderTarget = new RenderTarget(); - this._renderTarget.texture.name = 'anamorphic'; + this.width = width; + this.height = height; - this._invSize = uniform( new Vector2() ); + const effectiveWidth = width * this.pixelRatio; + const effectiveHeight = height * this.pixelRatio; - this._textureNode = passTexture( this, this._renderTarget.texture ); + this.renderTarget.setSize( effectiveWidth, effectiveHeight ); - this.updateBeforeType = NodeUpdateType.RENDER; + this.textureNeedsUpdate = true; } - getTextureNode() { + setPixelRatio( pixelRatio ) { - return this._textureNode; + this.pixelRatio = pixelRatio; - } + this.setSize( this.width, this.height ); - setSize( width, height ) { + } - this._invSize.value.set( 1 / width, 1 / height ); + updateBefore( { renderer } ) { - width = Math.max( Math.round( width * this.resolution.x ), 1 ); - height = Math.max( Math.round( height * this.resolution.y ), 1 ); + if ( this.textureNeedsUpdate === false && this.autoUpdate === false ) return; - this._renderTarget.setSize( width, height ); + this.textureNeedsUpdate = false; - } + // - updateBefore( frame ) { + if ( this.autoSize === true ) { - const { renderer } = frame; + this.pixelRatio = renderer.getPixelRatio(); - const textureNode = this.textureNode; - const map = textureNode.value; + const size = renderer.getSize( _size$8 ); - this._renderTarget.texture.type = map.type; + this.setSize( size.width, size.height ); - const currentRenderTarget = renderer.getRenderTarget(); - const currentTexture = textureNode.value; + } - _quadMesh$4.material = this._material; + // - this.setSize( map.image.width, map.image.height ); + this._quadMesh.material.fragmentNode = this._rttNode; - // render + // - renderer.setRenderTarget( this._renderTarget ); + const currentRenderTarget = renderer.getRenderTarget(); - _quadMesh$4.render( renderer ); + renderer.setRenderTarget( this.renderTarget ); - // restore + this._quadMesh.render( renderer ); renderer.setRenderTarget( currentRenderTarget ); - textureNode.value = currentTexture; } - setup( builder ) { - - const textureNode = this.textureNode; - const uvNode = textureNode.uvNode || uv(); + clone() { - const sampleTexture = ( uv ) => textureNode.uv( uv ); + const newNode = new TextureNode( this.value, this.uvNode, this.levelNode ); + newNode.sampler = this.sampler; + newNode.referenceNode = this; - const anamorph = Fn( () => { + return newNode; - const samples = this.samples; - const halfSamples = Math.floor( samples / 2 ); + } - const total = vec3( 0 ).toVar(); +} - Loop( { start: - halfSamples, end: halfSamples }, ( { i } ) => { +const rtt = ( node, ...params ) => nodeObject( new RTTNode( nodeObject( node ), ...params ) ); +const convertToTexture = ( node, ...params ) => node.isTextureNode ? node : rtt( node, ...params ); - const softness = float( i ).abs().div( halfSamples ).oneMinus(); +class VertexColorNode extends AttributeNode { - const uv = vec2( uvNode.x.add( this._invSize.x.mul( i ).mul( this.scaleNode ) ), uvNode.y ); - const color = sampleTexture( uv ); - const pass = threshold( color, this.tresholdNode ).mul( softness ); + static get type() { - total.addAssign( pass ); + return 'VertexColorNode'; - } ); + } - return total.mul( this.colorNode ); + constructor( index = 0 ) { - } ); + super( null, 'vec4' ); - // + this.isVertexColorNode = true; - const material = this._material || ( this._material = new NodeMaterial() ); - material.name = 'Anamorphic'; - material.fragmentNode = anamorph(); + this.index = index; - // + } - const properties = builder.getNodeProperties( this ); - properties.textureNode = textureNode; + getAttributeName( /*builder*/ ) { - // + const index = this.index; - return this._textureNode; + return 'color' + ( index > 0 ? index : '' ); } - dispose() { - - this._renderTarget.dispose(); - - } + generate( builder ) { -} + const attributeName = this.getAttributeName( builder ); + const geometryAttribute = builder.hasGeometryAttribute( attributeName ); -const anamorphic = ( node, threshold = .9, scale = 3, samples = 32 ) => nodeObject( new AnamorphicNode( convertToTexture( node ), nodeObject( threshold ), nodeObject( scale ), samples ) ); + let result; -class SobelOperatorNode extends TempNode { + if ( geometryAttribute === true ) { - constructor( textureNode ) { + result = super.generate( builder ); - super(); + } else { - this.textureNode = textureNode; + // Vertex color fallback should be white + result = builder.generateConst( this.nodeType, new Vector4( 1, 1, 1, 1 ) ); - this.updateBeforeType = NodeUpdateType.RENDER; + } - this._invSize = uniform( new Vector2() ); + return result; } - updateBefore() { + serialize( data ) { - const map = this.textureNode.value; + super.serialize( data ); - this._invSize.value.set( 1 / map.image.width, 1 / map.image.height ); + data.index = this.index; } - setup() { - - const { textureNode } = this; + deserialize( data ) { - const uvNode = textureNode.uvNode || uv(); + super.deserialize( data ); - const sampleTexture = ( uv ) => textureNode.uv( uv ); + this.index = data.index; - const sobel = Fn( () => { + } - // Sobel Edge Detection (see https://youtu.be/uihBwtPIBxM) +} - const texel = this._invSize; +const vertexColor = ( ...params ) => nodeObject( new VertexColorNode( ...params ) ); - // kernel definition (in glsl matrices are filled in column-major order) +class PointUVNode extends Node { - const Gx = mat3( - 1, - 2, - 1, 0, 0, 0, 1, 2, 1 ); // x direction kernel - const Gy = mat3( - 1, 0, 1, - 2, 0, 2, - 1, 0, 1 ); // y direction kernel + static get type() { - // fetch the 3x3 neighbourhood of a fragment + return 'PointUVNode'; - // first column + } - const tx0y0 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( - 1, - 1 ) ) ) ).xyz ); - const tx0y1 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( - 1, 0 ) ) ) ).xyz ); - const tx0y2 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( - 1, 1 ) ) ) ).xyz ); + constructor() { - // second column + super( 'vec2' ); - const tx1y0 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 0, - 1 ) ) ) ).xyz ); - const tx1y1 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 0, 0 ) ) ) ).xyz ); - const tx1y2 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 0, 1 ) ) ) ).xyz ); + this.isPointUVNode = true; - // third column + } - const tx2y0 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 1, - 1 ) ) ) ).xyz ); - const tx2y1 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 1, 0 ) ) ) ).xyz ); - const tx2y2 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 1, 1 ) ) ) ).xyz ); + generate( /*builder*/ ) { - // gradient value in x direction + return 'vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )'; - const valueGx = add( - Gx[ 0 ][ 0 ].mul( tx0y0 ), - Gx[ 1 ][ 0 ].mul( tx1y0 ), - Gx[ 2 ][ 0 ].mul( tx2y0 ), - Gx[ 0 ][ 1 ].mul( tx0y1 ), - Gx[ 1 ][ 1 ].mul( tx1y1 ), - Gx[ 2 ][ 1 ].mul( tx2y1 ), - Gx[ 0 ][ 2 ].mul( tx0y2 ), - Gx[ 1 ][ 2 ].mul( tx1y2 ), - Gx[ 2 ][ 2 ].mul( tx2y2 ) - ); + } +} - // gradient value in y direction +const pointUV = /*@__PURE__*/ nodeImmutable( PointUVNode ); - const valueGy = add( - Gy[ 0 ][ 0 ].mul( tx0y0 ), - Gy[ 1 ][ 0 ].mul( tx1y0 ), - Gy[ 2 ][ 0 ].mul( tx2y0 ), - Gy[ 0 ][ 1 ].mul( tx0y1 ), - Gy[ 1 ][ 1 ].mul( tx1y1 ), - Gy[ 2 ][ 1 ].mul( tx2y1 ), - Gy[ 0 ][ 2 ].mul( tx0y2 ), - Gy[ 1 ][ 2 ].mul( tx1y2 ), - Gy[ 2 ][ 2 ].mul( tx2y2 ) - ); +class SceneNode extends Node { - // magnitute of the total gradient + static get type() { - const G = valueGx.mul( valueGx ).add( valueGy.mul( valueGy ) ).sqrt(); + return 'SceneNode'; - return vec4( vec3( G ), 1 ); + } - } ); + constructor( scope = SceneNode.BACKGROUND_BLURRINESS, scene = null ) { - const outputNode = sobel(); + super(); - return outputNode; + this.scope = scope; + this.scene = scene; } -} + setup( builder ) { -SobelOperatorNode.type = /*@__PURE__*/ registerNode( 'SobelOperator', SobelOperatorNode ); + const scope = this.scope; + const scene = this.scene !== null ? this.scene : builder.scene; -const sobel = ( node ) => nodeObject( new SobelOperatorNode( convertToTexture( node ) ) ); + let output; -class DepthOfFieldNode extends TempNode { + if ( scope === SceneNode.BACKGROUND_BLURRINESS ) { - constructor( textureNode, viewZNode, focusNode, apertureNode, maxblurNode ) { + output = reference( 'backgroundBlurriness', 'float', scene ); - super(); + } else if ( scope === SceneNode.BACKGROUND_INTENSITY ) { - this.textureNode = textureNode; - this.viewZNode = viewZNode; + output = reference( 'backgroundIntensity', 'float', scene ); - this.focusNode = focusNode; - this.apertureNode = apertureNode; - this.maxblurNode = maxblurNode; + } else { - this._aspect = uniform( 0 ); + console.error( 'THREE.SceneNode: Unknown scope:', scope ); - this.updateBeforeType = NodeUpdateType.RENDER; + } + + return output; } - updateBefore() { +} - const map = this.textureNode.value; +SceneNode.BACKGROUND_BLURRINESS = 'backgroundBlurriness'; +SceneNode.BACKGROUND_INTENSITY = 'backgroundIntensity'; - this._aspect.value = map.image.width / map.image.height; - - } +const backgroundBlurriness = /*@__PURE__*/ nodeImmutable( SceneNode, SceneNode.BACKGROUND_BLURRINESS ); +const backgroundIntensity = /*@__PURE__*/ nodeImmutable( SceneNode, SceneNode.BACKGROUND_INTENSITY ); - setup() { +const GPUPrimitiveTopology = { + PointList: 'point-list', + LineList: 'line-list', + LineStrip: 'line-strip', + TriangleList: 'triangle-list', + TriangleStrip: 'triangle-strip', +}; - const textureNode = this.textureNode; - const uvNode = textureNode.uvNode || uv(); +const GPUCompareFunction = { + Never: 'never', + Less: 'less', + Equal: 'equal', + LessEqual: 'less-equal', + Greater: 'greater', + NotEqual: 'not-equal', + GreaterEqual: 'greater-equal', + Always: 'always' +}; - const sampleTexture = ( uv ) => textureNode.uv( uv ); +const GPUStoreOp = { + Store: 'store', + Discard: 'discard' +}; - const dof = Fn( () => { +const GPULoadOp = { + Load: 'load', + Clear: 'clear' +}; - const aspectcorrect = vec2( 1.0, this._aspect ); +const GPUFrontFace = { + CCW: 'ccw', + CW: 'cw' +}; - const factor = this.focusNode.add( this.viewZNode ); +const GPUCullMode = { + None: 'none', + Front: 'front', + Back: 'back' +}; - const dofblur = vec2( clamp( factor.mul( this.apertureNode ), this.maxblurNode.negate(), this.maxblurNode ) ); +const GPUIndexFormat = { + Uint16: 'uint16', + Uint32: 'uint32' +}; - const dofblur9 = dofblur.mul( 0.9 ); - const dofblur7 = dofblur.mul( 0.7 ); - const dofblur4 = dofblur.mul( 0.4 ); +const GPUTextureFormat = { - let col = vec4( 0.0 ); + // 8-bit formats - col = col.add( sampleTexture( uvNode ) ); + R8Unorm: 'r8unorm', + R8Snorm: 'r8snorm', + R8Uint: 'r8uint', + R8Sint: 'r8sint', - col = col.add( sampleTexture( uvNode.add( vec2( 0.0, 0.4 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.40, 0.0 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.0, - 0.4 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.40, 0.0 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.0, - 0.4 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.0, 0.4 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.0, - 0.4 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); - col = col.add( sampleTexture( uvNode.add( vec2( 0.0, 0.4 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + // 16-bit formats - col = col.div( 41 ); - col.a = 1; + R16Uint: 'r16uint', + R16Sint: 'r16sint', + R16Float: 'r16float', + RG8Unorm: 'rg8unorm', + RG8Snorm: 'rg8snorm', + RG8Uint: 'rg8uint', + RG8Sint: 'rg8sint', - return vec4( col ); + // 32-bit formats + R32Uint: 'r32uint', + R32Sint: 'r32sint', + R32Float: 'r32float', + RG16Uint: 'rg16uint', + RG16Sint: 'rg16sint', + RG16Float: 'rg16float', + RGBA8Unorm: 'rgba8unorm', + RGBA8UnormSRGB: 'rgba8unorm-srgb', + RGBA8Snorm: 'rgba8snorm', + RGBA8Uint: 'rgba8uint', + RGBA8Sint: 'rgba8sint', + BGRA8Unorm: 'bgra8unorm', + BGRA8UnormSRGB: 'bgra8unorm-srgb', + // Packed 32-bit formats + RGB9E5UFloat: 'rgb9e5ufloat', + RGB10A2Unorm: 'rgb10a2unorm', + RG11B10uFloat: 'rgb10a2unorm', - } ); + // 64-bit formats - const outputNode = dof(); + RG32Uint: 'rg32uint', + RG32Sint: 'rg32sint', + RG32Float: 'rg32float', + RGBA16Uint: 'rgba16uint', + RGBA16Sint: 'rgba16sint', + RGBA16Float: 'rgba16float', - return outputNode; + // 128-bit formats - } + RGBA32Uint: 'rgba32uint', + RGBA32Sint: 'rgba32sint', + RGBA32Float: 'rgba32float', -} + // Depth and stencil formats -DepthOfFieldNode.type = /*@__PURE__*/ registerNode( 'DepthOfField', DepthOfFieldNode ); + Stencil8: 'stencil8', + Depth16Unorm: 'depth16unorm', + Depth24Plus: 'depth24plus', + Depth24PlusStencil8: 'depth24plus-stencil8', + Depth32Float: 'depth32float', -const dof = ( node, viewZNode, focus = 1, aperture = 0.025, maxblur = 1 ) => nodeObject( new DepthOfFieldNode( convertToTexture( node ), nodeObject( viewZNode ), nodeObject( focus ), nodeObject( aperture ), nodeObject( maxblur ) ) ); + // 'depth32float-stencil8' extension -class DotScreenNode extends TempNode { + Depth32FloatStencil8: 'depth32float-stencil8', - constructor( inputNode, center = new Vector2( 0.5, 0.5 ), angle = 1.57, scale = 1 ) { + // BC compressed formats usable if 'texture-compression-bc' is both + // supported by the device/user agent and enabled in requestDevice. - super( 'vec4' ); + BC1RGBAUnorm: 'bc1-rgba-unorm', + BC1RGBAUnormSRGB: 'bc1-rgba-unorm-srgb', + BC2RGBAUnorm: 'bc2-rgba-unorm', + BC2RGBAUnormSRGB: 'bc2-rgba-unorm-srgb', + BC3RGBAUnorm: 'bc3-rgba-unorm', + BC3RGBAUnormSRGB: 'bc3-rgba-unorm-srgb', + BC4RUnorm: 'bc4-r-unorm', + BC4RSnorm: 'bc4-r-snorm', + BC5RGUnorm: 'bc5-rg-unorm', + BC5RGSnorm: 'bc5-rg-snorm', + BC6HRGBUFloat: 'bc6h-rgb-ufloat', + BC6HRGBFloat: 'bc6h-rgb-float', + BC7RGBAUnorm: 'bc7-rgba-unorm', + BC7RGBAUnormSRGB: 'bc7-rgba-srgb', - this.inputNode = inputNode; - this.center = uniform( center ); - this.angle = uniform( angle ); - this.scale = uniform( scale ); + // ETC2 compressed formats usable if 'texture-compression-etc2' is both + // supported by the device/user agent and enabled in requestDevice. - } + ETC2RGB8Unorm: 'etc2-rgb8unorm', + ETC2RGB8UnormSRGB: 'etc2-rgb8unorm-srgb', + ETC2RGB8A1Unorm: 'etc2-rgb8a1unorm', + ETC2RGB8A1UnormSRGB: 'etc2-rgb8a1unorm-srgb', + ETC2RGBA8Unorm: 'etc2-rgba8unorm', + ETC2RGBA8UnormSRGB: 'etc2-rgba8unorm-srgb', + EACR11Unorm: 'eac-r11unorm', + EACR11Snorm: 'eac-r11snorm', + EACRG11Unorm: 'eac-rg11unorm', + EACRG11Snorm: 'eac-rg11snorm', - setup() { + // ASTC compressed formats usable if 'texture-compression-astc' is both + // supported by the device/user agent and enabled in requestDevice. - const inputNode = this.inputNode; + ASTC4x4Unorm: 'astc-4x4-unorm', + ASTC4x4UnormSRGB: 'astc-4x4-unorm-srgb', + ASTC5x4Unorm: 'astc-5x4-unorm', + ASTC5x4UnormSRGB: 'astc-5x4-unorm-srgb', + ASTC5x5Unorm: 'astc-5x5-unorm', + ASTC5x5UnormSRGB: 'astc-5x5-unorm-srgb', + ASTC6x5Unorm: 'astc-6x5-unorm', + ASTC6x5UnormSRGB: 'astc-6x5-unorm-srgb', + ASTC6x6Unorm: 'astc-6x6-unorm', + ASTC6x6UnormSRGB: 'astc-6x6-unorm-srgb', + ASTC8x5Unorm: 'astc-8x5-unorm', + ASTC8x5UnormSRGB: 'astc-8x5-unorm-srgb', + ASTC8x6Unorm: 'astc-8x6-unorm', + ASTC8x6UnormSRGB: 'astc-8x6-unorm-srgb', + ASTC8x8Unorm: 'astc-8x8-unorm', + ASTC8x8UnormSRGB: 'astc-8x8-unorm-srgb', + ASTC10x5Unorm: 'astc-10x5-unorm', + ASTC10x5UnormSRGB: 'astc-10x5-unorm-srgb', + ASTC10x6Unorm: 'astc-10x6-unorm', + ASTC10x6UnormSRGB: 'astc-10x6-unorm-srgb', + ASTC10x8Unorm: 'astc-10x8-unorm', + ASTC10x8UnormSRGB: 'astc-10x8-unorm-srgb', + ASTC10x10Unorm: 'astc-10x10-unorm', + ASTC10x10UnormSRGB: 'astc-10x10-unorm-srgb', + ASTC12x10Unorm: 'astc-12x10-unorm', + ASTC12x10UnormSRGB: 'astc-12x10-unorm-srgb', + ASTC12x12Unorm: 'astc-12x12-unorm', + ASTC12x12UnormSRGB: 'astc-12x12-unorm-srgb', - const pattern = Fn( () => { +}; - const s = sin( this.angle ); - const c = cos( this.angle ); +const GPUAddressMode = { + ClampToEdge: 'clamp-to-edge', + Repeat: 'repeat', + MirrorRepeat: 'mirror-repeat' +}; - const tex = uv().mul( viewportResolution ).sub( this.center ); - const point = vec2( c.mul( tex.x ).sub( s.mul( tex.y ) ), s.mul( tex.x ).add( c.mul( tex.y ) ) ).mul( this.scale ); +const GPUFilterMode = { + Linear: 'linear', + Nearest: 'nearest' +}; - return sin( point.x ).mul( sin( point.y ) ).mul( 4 ); +const GPUBlendFactor = { + Zero: 'zero', + One: 'one', + Src: 'src', + OneMinusSrc: 'one-minus-src', + SrcAlpha: 'src-alpha', + OneMinusSrcAlpha: 'one-minus-src-alpha', + Dst: 'dst', + OneMinusDstColor: 'one-minus-dst', + DstAlpha: 'dst-alpha', + OneMinusDstAlpha: 'one-minus-dst-alpha', + SrcAlphaSaturated: 'src-alpha-saturated', + Constant: 'constant', + OneMinusConstant: 'one-minus-constant' +}; - } ); +const GPUBlendOperation = { + Add: 'add', + Subtract: 'subtract', + ReverseSubtract: 'reverse-subtract', + Min: 'min', + Max: 'max' +}; - const dotScreen = Fn( () => { +const GPUColorWriteFlags = { + None: 0, + Red: 0x1, + Green: 0x2, + Blue: 0x4, + Alpha: 0x8, + All: 0xF +}; - const color = inputNode; +const GPUStencilOperation = { + Keep: 'keep', + Zero: 'zero', + Replace: 'replace', + Invert: 'invert', + IncrementClamp: 'increment-clamp', + DecrementClamp: 'decrement-clamp', + IncrementWrap: 'increment-wrap', + DecrementWrap: 'decrement-wrap' +}; - const average = add( color.r, color.g, color.b ).div( 3 ); +const GPUBufferBindingType = { + Uniform: 'uniform', + Storage: 'storage', + ReadOnlyStorage: 'read-only-storage' +}; - return vec4( vec3( average.mul( 10 ).sub( 5 ).add( pattern() ) ), color.a ); +const GPUStorageTextureAccess = { + WriteOnly: 'write-only', + ReadOnly: 'read-only', + ReadWrite: 'read-write', +}; - } ); +const GPUTextureSampleType = { + Float: 'float', + UnfilterableFloat: 'unfilterable-float', + Depth: 'depth', + SInt: 'sint', + UInt: 'uint' +}; - const outputNode = dotScreen(); +const GPUTextureDimension = { + OneD: '1d', + TwoD: '2d', + ThreeD: '3d' +}; - return outputNode; +const GPUTextureViewDimension = { + OneD: '1d', + TwoD: '2d', + TwoDArray: '2d-array', + Cube: 'cube', + CubeArray: 'cube-array', + ThreeD: '3d' +}; - } +const GPUTextureAspect = { + All: 'all', + StencilOnly: 'stencil-only', + DepthOnly: 'depth-only' +}; -} +const GPUInputStepMode = { + Vertex: 'vertex', + Instance: 'instance' +}; -DotScreenNode.type = /*@__PURE__*/ registerNode( 'DotScreen', DotScreenNode ); +const GPUFeatureName = { + DepthClipControl: 'depth-clip-control', + Depth32FloatStencil8: 'depth32float-stencil8', + TextureCompressionBC: 'texture-compression-bc', + TextureCompressionETC2: 'texture-compression-etc2', + TextureCompressionASTC: 'texture-compression-astc', + TimestampQuery: 'timestamp-query', + IndirectFirstInstance: 'indirect-first-instance', + ShaderF16: 'shader-f16', + RG11B10UFloat: 'rg11b10ufloat-renderable', + BGRA8UNormStorage: 'bgra8unorm-storage', + Float32Filterable: 'float32-filterable', + ClipDistances: 'clip-distances', + DualSourceBlending: 'dual-source-blending', + Subgroups: 'subgroups' +}; -const dotScreen = ( node, center, angle, scale ) => nodeObject( new DotScreenNode( nodeObject( node ), center, angle, scale ) ); +class StorageBufferNode extends BufferNode { -class RGBShiftNode extends TempNode { + static get type() { - constructor( textureNode, amount = 0.005, angle = 0 ) { + return 'StorageBufferNode'; - super( 'vec4' ); + } - this.textureNode = textureNode; - this.amount = uniform( amount ); - this.angle = uniform( angle ); + constructor( value, bufferType, bufferCount = 0 ) { - } + super( value, bufferType, bufferCount ); - setup() { + this.isStorageBufferNode = true; - const { textureNode } = this; + this.access = GPUBufferBindingType.Storage; + this.isAtomic = false; - const uvNode = textureNode.uvNode || uv(); + this.bufferObject = false; + this.bufferCount = bufferCount; - const sampleTexture = ( uv ) => textureNode.uv( uv ); + this._attribute = null; + this._varying = null; - const rgbShift = Fn( () => { + this.global = true; - const offset = vec2( cos( this.angle ), sin( this.angle ) ).mul( this.amount ); - const cr = sampleTexture( uvNode.add( offset ) ); - const cga = sampleTexture( uvNode ); - const cb = sampleTexture( uvNode.sub( offset ) ); + if ( value.isStorageBufferAttribute !== true && value.isStorageInstancedBufferAttribute !== true ) { - return vec4( cr.r, cga.g, cb.b, cga.a ); + // TOOD: Improve it, possibly adding a new property to the BufferAttribute to identify it as a storage buffer read-only attribute in Renderer - } ); + if ( value.isInstancedBufferAttribute ) value.isStorageInstancedBufferAttribute = true; + else value.isStorageBufferAttribute = true; - return rgbShift(); + } } -} + getHash( builder ) { -RGBShiftNode.type = /*@__PURE__*/ registerNode( 'RGBShift', RGBShiftNode ); + if ( this.bufferCount === 0 ) { -const rgbShift = ( node, amount, angle ) => nodeObject( new RGBShiftNode( convertToTexture( node ), amount, angle ) ); + let bufferData = builder.globalCache.getData( this.value ); -class FilmNode extends TempNode { + if ( bufferData === undefined ) { - constructor( inputNode, intensityNode = null, uvNode = null ) { + bufferData = { + node: this + }; - super(); + builder.globalCache.setData( this.value, bufferData ); - this.inputNode = inputNode; - this.intensityNode = intensityNode; - this.uvNode = uvNode; + } + + return bufferData.node.uuid; + + } + + return this.uuid; } - setup() { + getInputType( /*builder*/ ) { - const uvNode = this.uvNode || uv(); + return 'storageBuffer'; - const film = Fn( () => { + } - const base = this.inputNode.rgb; - const noise = rand( fract( uvNode.add( timerLocal() ) ) ); + element( indexNode ) { - let color = base.add( base.mul( clamp( noise.add( 0.1 ), 0, 1 ) ) ); + return storageElement( this, indexNode ); - if ( this.intensityNode !== null ) { + } - color = mix( base, color, this.intensityNode ); + setBufferObject( value ) { - } + this.bufferObject = value; - return vec4( color, this.inputNode.a ); + return this; - } ); + } - const outputNode = film(); + setAccess( value ) { - return outputNode; + this.access = value; + + return this; } -} + toReadOnly() { -FilmNode.type = /*@__PURE__*/ registerNode( 'Film', FilmNode ); + return this.setAccess( GPUBufferBindingType.ReadOnlyStorage ); -const film = /*@__PURE__*/ nodeProxy( FilmNode ); + } -class Lut3DNode extends TempNode { + setAtomic( value ) { - constructor( inputNode, lutNode, size, intensityNode ) { + this.isAtomic = value; - super(); + return this; - this.inputNode = inputNode; - this.lutNode = lutNode; - this.size = uniform( size ); - this.intensityNode = intensityNode; + } + + toAtomic() { + + return this.setAtomic( true ); } - setup() { + generate( builder ) { - const { inputNode, lutNode } = this; + if ( builder.isAvailable( 'storageBuffer' ) ) { - const sampleLut = ( uv ) => lutNode.uv( uv ); + return super.generate( builder ); - const lut3D = Fn( () => { + } - const base = inputNode; + const nodeType = this.getNodeType( builder ); - // pull the sample in by half a pixel so the sample begins at the center of the edge pixels. + if ( this._attribute === null ) { - const pixelWidth = float( 1.0 ).div( this.size ); - const halfPixelWidth = float( 0.5 ).div( this.size ); - const uvw = vec3( halfPixelWidth ).add( base.rgb.mul( float( 1.0 ).sub( pixelWidth ) ) ); + this._attribute = bufferAttribute( this.value ); + this._varying = varying( this._attribute ); - const lutValue = vec4( sampleLut( uvw ).rgb, base.a ); + } - return vec4( mix( base, lutValue, this.intensityNode ) ); - } ); + const output = this._varying.build( builder, nodeType ); - const outputNode = lut3D(); + builder.registerTransform( output, this._attribute ); - return outputNode; + return output; } } -Lut3DNode.type = /*@__PURE__*/ registerNode( 'Lut3D', Lut3DNode ); +// Read-Write Storage +const storage = ( value, type, count ) => nodeObject( new StorageBufferNode( value, type, count ) ); +const storageObject = ( value, type, count ) => nodeObject( new StorageBufferNode( value, type, count ).setBufferObject( true ) ); -const lut3D = ( node, lut, size, intensity ) => nodeObject( new Lut3DNode( nodeObject( node ), nodeObject( lut ), size, nodeObject( intensity ) ) ); +class StorageTextureNode extends TextureNode { -const _quadMesh$3 = /*@__PURE__*/ new QuadMesh(); -const _currentClearColor$1 = /*@__PURE__*/ new Color(); -const _size$5 = /*@__PURE__*/ new Vector2(); + static get type() { -class GTAONode extends TempNode { + return 'StorageTextureNode'; - constructor( depthNode, normalNode, camera ) { + } - super(); + constructor( value, uvNode, storeNode = null ) { - this.depthNode = depthNode; - this.normalNode = normalNode; + super( value, uvNode ); - this.radius = uniform( 0.25 ); - this.resolution = uniform( new Vector2() ); - this.thickness = uniform( 1 ); - this.distanceExponent = uniform( 1 ); - this.distanceFallOff = uniform( 1 ); - this.scale = uniform( 1 ); - this.noiseNode = texture( generateMagicSquareNoise() ); + this.storeNode = storeNode; - this.cameraProjectionMatrix = uniform( camera.projectionMatrix ); - this.cameraProjectionMatrixInverse = uniform( camera.projectionMatrixInverse ); + this.isStorageTextureNode = true; - this.SAMPLES = uniform( 16 ); + this.access = GPUStorageTextureAccess.WriteOnly; - this._aoRenderTarget = new RenderTarget(); - this._aoRenderTarget.texture.name = 'GTAONode.AO'; + } - this._material = null; - this._textureNode = passTexture( this, this._aoRenderTarget.texture ); + getInputType( /*builder*/ ) { - this.updateBeforeType = NodeUpdateType.FRAME; + return 'storageTexture'; } - getTextureNode() { + setup( builder ) { - return this._textureNode; + super.setup( builder ); + + const properties = builder.getNodeProperties( this ); + properties.storeNode = this.storeNode; } - setSize( width, height ) { + setAccess( value ) { - this.resolution.value.set( width, height ); - this._aoRenderTarget.setSize( width, height ); + this.access = value; + return this; } - updateBefore( frame ) { - - const { renderer } = frame; + generate( builder, output ) { - const size = renderer.getDrawingBufferSize( _size$5 ); + let snippet; - const currentRenderTarget = renderer.getRenderTarget(); - const currentMRT = renderer.getMRT(); - renderer.getClearColor( _currentClearColor$1 ); - const currentClearAlpha = renderer.getClearAlpha(); + if ( this.storeNode !== null ) { - _quadMesh$3.material = this._material; + snippet = this.generateStore( builder ); - this.setSize( size.width, size.height ); + } else { - // clear + snippet = super.generate( builder, output ); - renderer.setMRT( null ); - renderer.setClearColor( 0xffffff, 1 ); + } - // ao + return snippet; - renderer.setRenderTarget( this._aoRenderTarget ); - _quadMesh$3.render( renderer ); + } - // restore + toReadOnly() { - renderer.setRenderTarget( currentRenderTarget ); - renderer.setMRT( currentMRT ); - renderer.setClearColor( _currentClearColor$1, currentClearAlpha ); + return this.setAccess( GPUStorageTextureAccess.ReadOnly ); } - setup( builder ) { + toWriteOnly() { - const uvNode = uv(); + return this.setAccess( GPUStorageTextureAccess.WriteOnly ); - const sampleDepth = ( uv ) => this.depthNode.uv( uv ).x; - const sampleNoise = ( uv ) => this.noiseNode.uv( uv ); + } - const getSceneUvAndDepth = Fn( ( [ sampleViewPos ] )=> { + generateStore( builder ) { - const sampleClipPos = this.cameraProjectionMatrix.mul( vec4( sampleViewPos, 1.0 ) ); - let sampleUv = sampleClipPos.xy.div( sampleClipPos.w ).mul( 0.5 ).add( 0.5 ).toVar(); - sampleUv = vec2( sampleUv.x, sampleUv.y.oneMinus() ); - const sampleSceneDepth = sampleDepth( sampleUv ); - return vec3( sampleUv, sampleSceneDepth ); + const properties = builder.getNodeProperties( this ); - } ); + const { uvNode, storeNode } = properties; - const getViewPosition = Fn( ( [ screenPosition, depth ] ) => { + const textureProperty = super.generate( builder, 'property' ); + const uvSnippet = uvNode.build( builder, 'uvec2' ); + const storeSnippet = storeNode.build( builder, 'vec4' ); - screenPosition = vec2( screenPosition.x, screenPosition.y.oneMinus() ).mul( 2.0 ).sub( 1.0 ); + const snippet = builder.generateTextureStore( builder, textureProperty, uvSnippet, storeSnippet ); - const clipSpacePosition = vec4( vec3( screenPosition, depth ), 1.0 ); - const viewSpacePosition = vec4( this.cameraProjectionMatrixInverse.mul( clipSpacePosition ) ); + builder.addLineFlowCode( snippet, this ); - return viewSpacePosition.xyz.div( viewSpacePosition.w ); + } - } ); +} - const ao = Fn( () => { +const storageTexture = /*@__PURE__*/ nodeProxy( StorageTextureNode ); - const depth = sampleDepth( uvNode ); +const textureStore = ( value, uvNode, storeNode ) => { - depth.greaterThanEqual( 1.0 ).discard(); + const node = storageTexture( value, uvNode, storeNode ); - const viewPosition = getViewPosition( uvNode, depth ); - const viewNormal = this.normalNode.rgb.normalize(); + if ( storeNode !== null ) node.append(); - const radiusToUse = this.radius; + return node; - const noiseResolution = textureSize( this.noiseNode, 0 ); - let noiseUv = vec2( uvNode.x, uvNode.y.oneMinus() ); - noiseUv = noiseUv.mul( this.resolution.div( noiseResolution ) ); - const noiseTexel = sampleNoise( noiseUv ); - const randomVec = noiseTexel.xyz.mul( 2.0 ).sub( 1.0 ); - const tangent = vec3( randomVec.xy, 0.0 ).normalize(); - const bitangent = vec3( tangent.y.mul( - 1.0 ), tangent.x, 0.0 ); - const kernelMatrix = mat3( tangent, bitangent, vec3( 0.0, 0.0, 1.0 ) ); +}; - const DIRECTIONS = this.SAMPLES.lessThan( 30 ).select( 3, 5 ); - const STEPS = add( this.SAMPLES, DIRECTIONS.sub( 1 ) ).div( DIRECTIONS ); +class UserDataNode extends ReferenceNode { - const ao = float( 0 ).toVar(); + static get type() { - Loop( { start: int( 0 ), end: DIRECTIONS, type: 'int', condition: '<' }, ( { i } ) => { + return 'UserDataNode'; - const angle = float( i ).div( float( DIRECTIONS ) ).mul( PI ); - const sampleDir = vec4( cos( angle ), sin( angle ), 0., add( 0.5, mul( 0.5, noiseTexel.w ) ) ); - sampleDir.xyz = normalize( kernelMatrix.mul( sampleDir.xyz ) ); + } - const viewDir = normalize( viewPosition.xyz.negate() ); - const sliceBitangent = normalize( cross( sampleDir.xyz, viewDir ) ); - const sliceTangent = cross( sliceBitangent, viewDir ); - const normalInSlice = normalize( viewNormal.sub( sliceBitangent.mul( dot( viewNormal, sliceBitangent ) ) ) ); + constructor( property, inputType, userData = null ) { - const tangentToNormalInSlice = cross( normalInSlice, sliceBitangent ); - const cosHorizons = vec2( dot( viewDir, tangentToNormalInSlice ), dot( viewDir, tangentToNormalInSlice.negate() ) ).toVar(); + super( property, inputType, userData ); - Loop( { end: STEPS, type: 'int', name: 'j', condition: '<' }, ( { j } ) => { + this.userData = userData; - const sampleViewOffset = sampleDir.xyz.mul( radiusToUse ).mul( sampleDir.w ).mul( pow( div( float( j ).add( 1.0 ), float( STEPS ) ), this.distanceExponent ) ); + } - // x + updateReference( state ) { - const sampleSceneUvDepthX = getSceneUvAndDepth( viewPosition.add( sampleViewOffset ) ); - const sampleSceneViewPositionX = getViewPosition( sampleSceneUvDepthX.xy, sampleSceneUvDepthX.z ); - const viewDeltaX = sampleSceneViewPositionX.sub( viewPosition ); + this.reference = this.userData !== null ? this.userData : state.object.userData; - If( abs( viewDeltaX.z ).lessThan( this.thickness ), () => { + return this.reference; - const sampleCosHorizon = dot( viewDir, normalize( viewDeltaX ) ); - cosHorizons.x.addAssign( max$1( 0, mul( sampleCosHorizon.sub( cosHorizons.x ), mix( 1.0, float( 2.0 ).div( float( j ).add( 2 ) ), this.distanceFallOff ) ) ) ); + } - } ); +} - // y +const userData = ( name, inputType, userData ) => nodeObject( new UserDataNode( name, inputType, userData ) ); - const sampleSceneUvDepthY = getSceneUvAndDepth( viewPosition.sub( sampleViewOffset ) ); - const sampleSceneViewPositionY = getViewPosition( sampleSceneUvDepthY.xy, sampleSceneUvDepthY.z ); - const viewDeltaY = sampleSceneViewPositionY.sub( viewPosition ); +class PosterizeNode extends TempNode { - If( abs( viewDeltaY.z ).lessThan( this.thickness ), () => { + static get type() { - const sampleCosHorizon = dot( viewDir, normalize( viewDeltaY ) ); - cosHorizons.y.addAssign( max$1( 0, mul( sampleCosHorizon.sub( cosHorizons.y ), mix( 1.0, float( 2.0 ).div( float( j ).add( 2 ) ), this.distanceFallOff ) ) ) ); + return 'PosterizeNode'; - } ); + } - } ); + constructor( sourceNode, stepsNode ) { - const sinHorizons = sqrt( sub( 1.0, cosHorizons.mul( cosHorizons ) ) ); - const nx = dot( normalInSlice, sliceTangent ); - const ny = dot( normalInSlice, viewDir ); - const nxb = mul( 0.5, acos( cosHorizons.y ).sub( acos( cosHorizons.x ) ).add( sinHorizons.x.mul( cosHorizons.x ).sub( sinHorizons.y.mul( cosHorizons.y ) ) ) ); - const nyb = mul( 0.5, sub( 2.0, cosHorizons.x.mul( cosHorizons.x ) ).sub( cosHorizons.y.mul( cosHorizons.y ) ) ); - const occlusion = nx.mul( nxb ).add( ny.mul( nyb ) ); - ao.addAssign( occlusion ); + super(); - } ); + this.sourceNode = sourceNode; + this.stepsNode = stepsNode; - ao.assign( clamp( ao.div( DIRECTIONS ), 0, 1 ) ); - ao.assign( pow( ao, this.scale ) ); + } - return vec4( vec3( ao ), 1.0 ); + setup() { - } ); + const { sourceNode, stepsNode } = this; - const material = this._material || ( this._material = new NodeMaterial() ); - material.fragmentNode = ao().context( builder.getSharedContext() ); - material.name = 'GTAO'; - material.needsUpdate = true; + return sourceNode.mul( stepsNode ).floor().div( stepsNode ); - // + } - return this._textureNode; +} - } +const posterize = /*@__PURE__*/ nodeProxy( PosterizeNode ); - dispose() { +let _sharedFramebuffer = null; - this._aoRenderTarget.dispose(); +class ViewportSharedTextureNode extends ViewportTextureNode { - } + static get type() { -} + return 'ViewportSharedTextureNode'; -GTAONode.type = /*@__PURE__*/ registerNode( 'GTAO', GTAONode ); + } -function generateMagicSquareNoise( size = 5 ) { + constructor( uvNode = screenUV, levelNode = null ) { - const noiseSize = Math.floor( size ) % 2 === 0 ? Math.floor( size ) + 1 : Math.floor( size ); - const magicSquare = generateMagicSquare( noiseSize ); - const noiseSquareSize = magicSquare.length; - const data = new Uint8Array( noiseSquareSize * 4 ); + if ( _sharedFramebuffer === null ) { - for ( let inx = 0; inx < noiseSquareSize; ++ inx ) { + _sharedFramebuffer = new FramebufferTexture(); - const iAng = magicSquare[ inx ]; - const angle = ( 2 * Math.PI * iAng ) / noiseSquareSize; - const randomVec = new Vector3( - Math.cos( angle ), - Math.sin( angle ), - 0 - ).normalize(); - data[ inx * 4 ] = ( randomVec.x * 0.5 + 0.5 ) * 255; - data[ inx * 4 + 1 ] = ( randomVec.y * 0.5 + 0.5 ) * 255; - data[ inx * 4 + 2 ] = 127; - data[ inx * 4 + 3 ] = 255; + } + + super( uvNode, levelNode, _sharedFramebuffer ); } - const noiseTexture = new DataTexture( data, noiseSize, noiseSize ); - noiseTexture.wrapS = RepeatWrapping; - noiseTexture.wrapT = RepeatWrapping; - noiseTexture.needsUpdate = true; + updateReference() { - return noiseTexture; + return this; + + } } -function generateMagicSquare( size ) { +const viewportSharedTexture = /*@__PURE__*/ nodeProxy( ViewportSharedTextureNode ); - const noiseSize = Math.floor( size ) % 2 === 0 ? Math.floor( size ) + 1 : Math.floor( size ); - const noiseSquareSize = noiseSize * noiseSize; - const magicSquare = Array( noiseSquareSize ).fill( 0 ); - let i = Math.floor( noiseSize / 2 ); - let j = noiseSize - 1; +const _size$7 = /*@__PURE__*/ new Vector2(); - for ( let num = 1; num <= noiseSquareSize; ) { +class PassTextureNode extends TextureNode { - if ( i === - 1 && j === noiseSize ) { + static get type() { - j = noiseSize - 2; - i = 0; + return 'PassTextureNode'; - } else { + } - if ( j === noiseSize ) { + constructor( passNode, texture ) { - j = 0; + super( texture ); - } + this.passNode = passNode; - if ( i < 0 ) { + this.setUpdateMatrix( false ); - i = noiseSize - 1; + } - } + setup( builder ) { - } + if ( builder.object.isQuadMesh ) this.passNode.build( builder ); - if ( magicSquare[ i * noiseSize + j ] !== 0 ) { + return super.setup( builder ); - j -= 2; - i ++; - continue; + } - } else { + clone() { - magicSquare[ i * noiseSize + j ] = num ++; + return new this.constructor( this.passNode, this.value ); - } + } - j ++; - i --; +} + +class PassMultipleTextureNode extends PassTextureNode { + + static get type() { + + return 'PassMultipleTextureNode'; } - return magicSquare; + constructor( passNode, textureName, previousTexture = false ) { -} + super( passNode, null ); -const ao = ( depthNode, normalNode, camera ) => nodeObject( new GTAONode( nodeObject( depthNode ), nodeObject( normalNode ), camera ) ); + this.textureName = textureName; + this.previousTexture = previousTexture; -class DenoiseNode extends TempNode { + } - constructor( textureNode, depthNode, normalNode, noiseNode, camera ) { + updateTexture() { - super(); + this.value = this.previousTexture ? this.passNode.getPreviousTexture( this.textureName ) : this.passNode.getTexture( this.textureName ); - this.textureNode = textureNode; - this.depthNode = depthNode; - this.normalNode = normalNode; - this.noiseNode = noiseNode; + } - this.cameraProjectionMatrixInverse = uniform( camera.projectionMatrixInverse ); - this.lumaPhi = uniform( 5 ); - this.depthPhi = uniform( 5 ); - this.normalPhi = uniform( 5 ); - this.radius = uniform( 5 ); - this.index = uniform( 0 ); + setup( builder ) { - this._resolution = uniform( new Vector2() ); - this._sampleVectors = uniformArray( generatePdSamplePointInitializer( 16, 2, 1 ) ); + this.updateTexture(); - this.updateBeforeType = NodeUpdateType.RENDER; + return super.setup( builder ); } - updateBefore() { + clone() { - const map = this.textureNode.value; + return new this.constructor( this.passNode, this.textureName, this.previousTexture ); - this._resolution.value.set( map.image.width, map.image.height ); + } + +} + +class PassNode extends TempNode { + + static get type() { + + return 'PassNode'; } - setup() { + constructor( scope, scene, camera, options = {} ) { - const uvNode = uv(); + super( 'vec4' ); - const sampleTexture = ( uv ) => this.textureNode.uv( uv ); - const sampleDepth = ( uv ) => this.depthNode.uv( uv ).x; - const sampleNormal = ( uv ) => this.normalNode.uv( uv ); - const sampleNoise = ( uv ) => this.noiseNode.uv( uv ); + this.scope = scope; + this.scene = scene; + this.camera = camera; + this.options = options; - const getViewPosition = Fn( ( [ screenPosition, depth ] ) => { + this._pixelRatio = 1; + this._width = 1; + this._height = 1; - screenPosition = vec2( screenPosition.x, screenPosition.y.oneMinus() ).mul( 2.0 ).sub( 1.0 ); + const depthTexture = new DepthTexture(); + depthTexture.isRenderTargetTexture = true; + //depthTexture.type = FloatType; + depthTexture.name = 'depth'; - const clipSpacePosition = vec4( vec3( screenPosition, depth ), 1.0 ); - const viewSpacePosition = vec4( this.cameraProjectionMatrixInverse.mul( clipSpacePosition ) ); + const renderTarget = new RenderTarget( this._width * this._pixelRatio, this._height * this._pixelRatio, { type: HalfFloatType, ...options, } ); + renderTarget.texture.name = 'output'; + renderTarget.depthTexture = depthTexture; - return viewSpacePosition.xyz.div( viewSpacePosition.w ); + this.renderTarget = renderTarget; - } ); + this.updateBeforeType = NodeUpdateType.FRAME; - const denoiseSample = Fn( ( [ center, viewNormal, viewPosition, sampleUv ] ) => { + this._textures = { + output: renderTarget.texture, + depth: depthTexture + }; - const texel = sampleTexture( sampleUv ); - const depth = sampleDepth( sampleUv ); - const normal = sampleNormal( sampleUv ).rgb.normalize(); - const neighborColor = texel.rgb; - const viewPos = getViewPosition( sampleUv, depth ); + this._textureNodes = {}; + this._linearDepthNodes = {}; + this._viewZNodes = {}; - const normalDiff = dot( viewNormal, normal ).toVar(); - const normalSimilarity = pow( max$1( normalDiff, 0 ), this.normalPhi ).toVar(); - const lumaDiff = abs( luminance( neighborColor ).sub( luminance( center ) ) ).toVar(); - const lumaSimilarity = max$1( float( 1.0 ).sub( lumaDiff.div( this.lumaPhi ) ), 0 ).toVar(); - const depthDiff = abs( dot( viewPosition.sub( viewPos ), viewNormal ) ).toVar(); - const depthSimilarity = max$1( float( 1.0 ).sub( depthDiff.div( this.depthPhi ) ), 0 ); - const w = lumaSimilarity.mul( depthSimilarity ).mul( normalSimilarity ); + this._previousTextures = {}; + this._previousTextureNodes = {}; - return vec4( neighborColor.mul( w ), w ); + this._cameraNear = uniform( 0 ); + this._cameraFar = uniform( 0 ); - } ); + this._mrt = null; - const denoise = Fn( ( [ uvNode ] ) => { + this.isPassNode = true; - const depth = sampleDepth( uvNode ); - const viewNormal = sampleNormal( uvNode ).rgb.normalize(); + } - const texel = sampleTexture( uvNode ); + setMRT( mrt ) { - If( depth.greaterThanEqual( 1.0 ).or( dot( viewNormal, viewNormal ).equal( 0.0 ) ), () => { + this._mrt = mrt; - return texel; + return this; - } ); + } - const center = vec3( texel.rgb ); + getMRT() { - const viewPosition = getViewPosition( uvNode, depth ); + return this._mrt; - const noiseResolution = textureSize( this.noiseNode, 0 ); - let noiseUv = vec2( uvNode.x, uvNode.y.oneMinus() ); - noiseUv = noiseUv.mul( this._resolution.div( noiseResolution ) ); - const noiseTexel = sampleNoise( noiseUv ); + } - const x = sin( noiseTexel.element( this.index.mod( 4 ).mul( 2 ).mul( PI ) ) ); - const y = cos( noiseTexel.element( this.index.mod( 4 ).mul( 2 ).mul( PI ) ) ); + isGlobal() { - const noiseVec = vec2( x, y ); - const rotationMatrix = mat2( noiseVec.x, noiseVec.y.negate(), noiseVec.x, noiseVec.y ); + return true; - const totalWeight = float( 1.0 ).toVar(); - const denoised = vec3( texel.rgb ).toVar(); + } - Loop( { start: int( 0 ), end: int( 16 ), type: 'int', condition: '<' }, ( { i } ) => { + getTexture( name ) { - const sampleDir = this._sampleVectors.element( i ).toVar(); - const offset = rotationMatrix.mul( sampleDir.xy.mul( float( 1.0 ).add( sampleDir.z.mul( this.radius.sub( 1 ) ) ) ) ).div( this._resolution ).toVar(); - const sampleUv = uvNode.add( offset ).toVar(); + let texture = this._textures[ name ]; - const result = denoiseSample( center, viewNormal, viewPosition, sampleUv ); + if ( texture === undefined ) { - denoised.addAssign( result.xyz ); - totalWeight.addAssign( result.w ); + const refTexture = this.renderTarget.texture; - } ); + texture = refTexture.clone(); + texture.isRenderTargetTexture = true; + texture.name = name; - If( totalWeight.greaterThan( float( 0 ) ), () => { + this._textures[ name ] = texture; - denoised.divAssign( totalWeight ); + this.renderTarget.textures.push( texture ); - } ); + } - return vec4( denoised, texel.a ); + return texture; - } ).setLayout( { - name: 'denoise', - type: 'vec4', - inputs: [ - { name: 'uv', type: 'vec2' } - ] - } ); + } - const output = Fn( () => { + getPreviousTexture( name ) { - return denoise( uvNode ); + let texture = this._previousTextures[ name ]; - } ); + if ( texture === undefined ) { - const outputNode = output(); + texture = this.getTexture( name ).clone(); + texture.isRenderTargetTexture = true; - return outputNode; + this._previousTextures[ name ] = texture; + + } + + return texture; } -} + toggleTexture( name ) { -DenoiseNode.type = /*@__PURE__*/ registerNode( 'Denoise', DenoiseNode ); + const prevTexture = this._previousTextures[ name ]; -function generatePdSamplePointInitializer( samples, rings, radiusExponent ) { + if ( prevTexture !== undefined ) { - const poissonDisk = generateDenoiseSamples( samples, rings, radiusExponent ); + const texture = this._textures[ name ]; - const array = []; + const index = this.renderTarget.textures.indexOf( texture ); + this.renderTarget.textures[ index ] = prevTexture; - for ( let i = 0; i < samples; i ++ ) { + this._textures[ name ] = prevTexture; + this._previousTextures[ name ] = texture; - const sample = poissonDisk[ i ]; - array.push( sample ); + this._textureNodes[ name ].updateTexture(); + this._previousTextureNodes[ name ].updateTexture(); + + } } - return array; + getTextureNode( name = 'output' ) { -} + let textureNode = this._textureNodes[ name ]; -function generateDenoiseSamples( numSamples, numRings, radiusExponent ) { + if ( textureNode === undefined ) { - const samples = []; + this._textureNodes[ name ] = textureNode = nodeObject( new PassMultipleTextureNode( this, name ) ); + this._textureNodes[ name ].updateTexture(); - for ( let i = 0; i < numSamples; i ++ ) { + } - const angle = 2 * Math.PI * numRings * i / numSamples; - const radius = Math.pow( i / ( numSamples - 1 ), radiusExponent ); - samples.push( new Vector3( Math.cos( angle ), Math.sin( angle ), radius ) ); + return textureNode; } - return samples; + getPreviousTextureNode( name = 'output' ) { -} + let textureNode = this._previousTextureNodes[ name ]; -const denoise = ( node, depthNode, normalNode, noiseNode, camera ) => nodeObject( new DenoiseNode( convertToTexture( node ), nodeObject( depthNode ), nodeObject( normalNode ), nodeObject( noiseNode ), camera ) ); + if ( textureNode === undefined ) { -class FXAANode extends TempNode { + if ( this._textureNodes[ name ] === undefined ) this.getTextureNode( name ); - constructor( textureNode ) { + this._previousTextureNodes[ name ] = textureNode = nodeObject( new PassMultipleTextureNode( this, name, true ) ); + this._previousTextureNodes[ name ].updateTexture(); - super(); + } - this.textureNode = textureNode; + return textureNode; - this.updateBeforeType = NodeUpdateType.RENDER; + } - this._invSize = uniform( new Vector2() ); + getViewZNode( name = 'depth' ) { - } + let viewZNode = this._viewZNodes[ name ]; - updateBefore() { + if ( viewZNode === undefined ) { - const map = this.textureNode.value; + const cameraNear = this._cameraNear; + const cameraFar = this._cameraFar; - this._invSize.value.set( 1 / map.image.width, 1 / map.image.height ); + this._viewZNodes[ name ] = viewZNode = perspectiveDepthToViewZ( this.getTextureNode( name ), cameraNear, cameraFar ); + + } + + return viewZNode; } - setup() { + getLinearDepthNode( name = 'depth' ) { - const textureNode = this.textureNode.bias( - 100 ); - const uvNode = textureNode.uvNode || uv(); + let linearDepthNode = this._linearDepthNodes[ name ]; - // FXAA 3.11 implementation by NVIDIA, ported to WebGL by Agost Biro (biro@archilogic.com) + if ( linearDepthNode === undefined ) { - //---------------------------------------------------------------------------------- - // File: es3-kepler\FXAA\assets\shaders/FXAA_DefaultES.frag - // SDK Version: v3.00 - // Email: gameworks@nvidia.com - // Site: http://developer.nvidia.com/ - // - // Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. - // - // Redistribution and use in source and binary forms, with or without - // modification, are permitted provided that the following conditions - // are met: - // * Redistributions of source code must retain the above copyright - // notice, this list of conditions and the following disclaimer. - // * Redistributions in binary form must reproduce the above copyright - // notice, this list of conditions and the following disclaimer in the - // documentation and/or other materials provided with the distribution. - // * Neither the name of NVIDIA CORPORATION nor the names of its - // contributors may be used to endorse or promote products derived - // from this software without specific prior written permission. - // - // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY - // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // - //---------------------------------------------------------------------------------- + const cameraNear = this._cameraNear; + const cameraFar = this._cameraFar; + const viewZNode = this.getViewZNode( name ); - const FxaaTexTop = ( p ) => textureNode.uv( p ); - const FxaaTexOff = ( p, o, r ) => textureNode.uv( p.add( o.mul( r ) ) ); + // TODO: just if ( builder.camera.isPerspectiveCamera ) - const NUM_SAMPLES = int( 5 ); + this._linearDepthNodes[ name ] = linearDepthNode = viewZToOrthographicDepth( viewZNode, cameraNear, cameraFar ); - const contrast = Fn( ( [ a_immutable, b_immutable ] ) => { + } - // assumes colors have premultipliedAlpha, so that the calculated color contrast is scaled by alpha + return linearDepthNode; - const b = vec4( b_immutable ).toVar(); - const a = vec4( a_immutable ).toVar(); - const diff = vec4( abs( a.sub( b ) ) ).toVar(); + } - return max$1( max$1( max$1( diff.r, diff.g ), diff.b ), diff.a ); + setup( { renderer } ) { - } ); + this.renderTarget.samples = this.options.samples === undefined ? renderer.samples : this.options.samples; - // FXAA3 QUALITY - PC + // Disable MSAA for WebGL backend for now + if ( renderer.backend.isWebGLBackend === true ) { - const FxaaPixelShader = Fn( ( [ uv, fxaaQualityRcpFrame, fxaaQualityEdgeThreshold, fxaaQualityinvEdgeThreshold ] ) => { + this.renderTarget.samples = 0; - const rgbaM = FxaaTexTop( uv ).toVar(); - const rgbaS = FxaaTexOff( uv, vec2( 0.0, - 1.0 ), fxaaQualityRcpFrame.xy ).toVar(); - const rgbaE = FxaaTexOff( uv, vec2( 1.0, 0.0 ), fxaaQualityRcpFrame.xy ).toVar(); - const rgbaN = FxaaTexOff( uv, vec2( 0.0, 1.0 ), fxaaQualityRcpFrame.xy ).toVar(); - const rgbaW = FxaaTexOff( uv, vec2( - 1.0, 0.0 ), fxaaQualityRcpFrame.xy ).toVar(); - // . S . - // W M E - // . N . + } - const contrastN = contrast( rgbaM, rgbaN ).toVar(); - const contrastS = contrast( rgbaM, rgbaS ).toVar(); - const contrastE = contrast( rgbaM, rgbaE ).toVar(); - const contrastW = contrast( rgbaM, rgbaW ).toVar(); + this.renderTarget.depthTexture.isMultisampleRenderTargetTexture = this.renderTarget.samples > 1; - const maxValue = max$1( contrastN, max$1( contrastS, max$1( contrastE, contrastW ) ) ).toVar(); + return this.scope === PassNode.COLOR ? this.getTextureNode() : this.getLinearDepthNode(); - // . 0 . - // 0 0 0 - // . 0 . + } - If( maxValue.lessThan( fxaaQualityEdgeThreshold ), () => { + updateBefore( frame ) { - return rgbaM; // assuming define FXAA_DISCARD is always 0 + const { renderer } = frame; + const { scene, camera } = this; - } ); + this._pixelRatio = renderer.getPixelRatio(); - // + const size = renderer.getSize( _size$7 ); - const relativeVContrast = sub( contrastN.add( contrastS ), ( contrastE.add( contrastW ) ) ).toVar(); - relativeVContrast.mulAssign( fxaaQualityinvEdgeThreshold ); + this.setSize( size.width, size.height ); - // 45 deg edge detection and corners of objects, aka V/H contrast is too similar + const currentRenderTarget = renderer.getRenderTarget(); + const currentMRT = renderer.getMRT(); - If( abs( relativeVContrast ).lessThan( 0.3 ), () => { + this._cameraNear.value = camera.near; + this._cameraFar.value = camera.far; - // locate the edge + for ( const name in this._previousTextures ) { - const x = contrastE.greaterThan( contrastW ).select( 1, - 1 ).toVar(); - const y = contrastS.greaterThan( contrastN ).select( 1, - 1 ).toVar(); + this.toggleTexture( name ); - const dirToEdge = vec2( x, y ).toVar(); - // . 2 . . 1 . - // 1 0 2 ~= 0 0 1 - // . 1 . . 0 . + } - // tap 2 pixels and see which ones are "outside" the edge, to - // determine if the edge is vertical or horizontal + renderer.setRenderTarget( this.renderTarget ); + renderer.setMRT( this._mrt ); - const rgbaAlongH = FxaaTexOff( uv, vec2( dirToEdge.x, dirToEdge.y ), fxaaQualityRcpFrame.xy ); - const matchAlongH = contrast( rgbaM, rgbaAlongH ).toVar(); - // . 1 . - // 0 0 1 - // . 0 H + renderer.render( scene, camera ); - const rgbaAlongV = FxaaTexOff( uv, vec2( dirToEdge.x.negate(), dirToEdge.y.negate() ), fxaaQualityRcpFrame.xy ); - const matchAlongV = contrast( rgbaM, rgbaAlongV ).toVar(); - // V 1 . - // 0 0 1 - // . 0 . + renderer.setRenderTarget( currentRenderTarget ); + renderer.setMRT( currentMRT ); - relativeVContrast.assign( matchAlongV.sub( matchAlongH ) ); - relativeVContrast.mulAssign( fxaaQualityinvEdgeThreshold ); + } - If( abs( relativeVContrast ).lessThan( 0.3 ), () => { // 45 deg edge + setSize( width, height ) { - // 1 1 . - // 0 0 1 - // . 0 1 + this._width = width; + this._height = height; - // do a simple blur - const sum = rgbaN.add( rgbaS ).add( rgbaE ).add( rgbaW ); - return mix( rgbaM, sum.mul( 0.25 ), 0.4 ); + const effectiveWidth = this._width * this._pixelRatio; + const effectiveHeight = this._height * this._pixelRatio; - } ); + this.renderTarget.setSize( effectiveWidth, effectiveHeight ); - } ); + } - const offNP = vec2().toVar(); + setPixelRatio( pixelRatio ) { - If( relativeVContrast.lessThanEqual( 0 ), () => { + this._pixelRatio = pixelRatio; - rgbaN.assign( rgbaW ); - rgbaS.assign( rgbaE ); + this.setSize( this._width, this._height ); - // . 0 . 1 - // 1 0 1 -> 0 - // . 0 . 1 + } - offNP.x.assign( 0 ); - offNP.y.assign( fxaaQualityRcpFrame.y ); + dispose() { - } ).Else( () => { + this.renderTarget.dispose(); - offNP.x.assign( fxaaQualityRcpFrame.x ); - offNP.y.assign( 0 ); + } - } ); - const mn = contrast( rgbaM, rgbaN ).toVar(); - const ms = contrast( rgbaM, rgbaS ).toVar(); +} - If( mn.lessThanEqual( ms ), () => { +PassNode.COLOR = 'color'; +PassNode.DEPTH = 'depth'; - rgbaN.assign( rgbaS ); +const pass = ( scene, camera, options ) => nodeObject( new PassNode( PassNode.COLOR, scene, camera, options ) ); +const passTexture = ( pass, texture ) => nodeObject( new PassTextureNode( pass, texture ) ); +const depthPass = ( scene, camera ) => nodeObject( new PassNode( PassNode.DEPTH, scene, camera ) ); - } ); +// WebGPU: The use of a single QuadMesh for both gaussian blur passes results in a single RenderObject with a SampledTexture binding that +// alternates between source textures and triggers creation of new BindGroups and BindGroupLayouts every frame. - const doneN = int( 0 ).toVar(); - const doneP = int( 0 ).toVar(); +const _quadMesh1 = /*@__PURE__*/ new QuadMesh(); +const _quadMesh2 = /*@__PURE__*/ new QuadMesh(); - const nDist = float( 0 ).toVar(); - const pDist = float( 0 ).toVar(); +class GaussianBlurNode extends TempNode { - const posN = vec2( uv ).toVar(); - const posP = vec2( uv ).toVar(); + static get type() { - const iterationsUsedN = int( 0 ).toVar(); - const iterationsUsedP = int( 0 ).toVar(); + return 'GaussianBlurNode'; - Loop( NUM_SAMPLES, ( { i } ) => { + } - const increment = i.add( 1 ).toVar(); + constructor( textureNode, directionNode = null, sigma = 2 ) { - If( doneN.equal( 0 ), () => { + super( 'vec4' ); - nDist.addAssign( increment ); - posN.assign( uv.add( offNP.mul( nDist ) ) ); - const rgbaEndN = FxaaTexTop( posN.xy ); + this.textureNode = textureNode; + this.directionNode = directionNode; + this.sigma = sigma; - const nm = contrast( rgbaEndN, rgbaM ).toVar(); - const nn = contrast( rgbaEndN, rgbaN ).toVar(); + this._invSize = uniform( new Vector2() ); + this._passDirection = uniform( new Vector2() ); - If( nm.greaterThan( nn ), () => { + this._horizontalRT = new RenderTarget(); + this._horizontalRT.texture.name = 'GaussianBlurNode.horizontal'; + this._verticalRT = new RenderTarget(); + this._verticalRT.texture.name = 'GaussianBlurNode.vertical'; - doneN.assign( 1 ); + this._textureNode = passTexture( this, this._verticalRT.texture ); - } ); + this.updateBeforeType = NodeUpdateType.RENDER; - iterationsUsedN.assign( i ); + this.resolution = new Vector2( 1, 1 ); - } ); + } - If( doneP.equal( 0 ), () => { + setSize( width, height ) { - pDist.addAssign( increment ); - posP.assign( uv.sub( offNP.mul( pDist ) ) ); - const rgbaEndP = FxaaTexTop( posP.xy ); + width = Math.max( Math.round( width * this.resolution.x ), 1 ); + height = Math.max( Math.round( height * this.resolution.y ), 1 ); - const pm = contrast( rgbaEndP, rgbaM ).toVar(); - const pn = contrast( rgbaEndP, rgbaN ).toVar(); + this._invSize.value.set( 1 / width, 1 / height ); + this._horizontalRT.setSize( width, height ); + this._verticalRT.setSize( width, height ); - If( pm.greaterThan( pn ), () => { + } - doneP.assign( 1 ); + updateBefore( frame ) { - } ); + const { renderer } = frame; - iterationsUsedP.assign( i ); + const textureNode = this.textureNode; + const map = textureNode.value; - } ); + const currentRenderTarget = renderer.getRenderTarget(); + const currentMRT = renderer.getMRT(); - If( doneN.equal( 1 ).or( doneP.equal( 1 ) ), () => { + const currentTexture = textureNode.value; - Break(); + _quadMesh1.material = this._material; + _quadMesh2.material = this._material; - } ); + this.setSize( map.image.width, map.image.height ); - } ); + const textureType = map.type; - If( doneN.equal( 0 ).and( doneP.equal( 0 ) ), () => { + this._horizontalRT.texture.type = textureType; + this._verticalRT.texture.type = textureType; - return rgbaM; // failed to find end of edge + // clear - } ); + renderer.setMRT( null ); - const distN = float( 1 ).toVar(); - const distP = float( 1 ).toVar(); + // horizontal - If( doneN.equal( 1 ), () => { + renderer.setRenderTarget( this._horizontalRT ); - distN.assign( float( iterationsUsedN ).div( float( NUM_SAMPLES.sub( 1 ) ) ) ); + this._passDirection.value.set( 1, 0 ); - } ); + _quadMesh1.render( renderer ); - If( doneP.equal( 1 ), () => { + // vertical - distP.assign( float( iterationsUsedP ).div( float( NUM_SAMPLES.sub( 1 ) ) ) ); + textureNode.value = this._horizontalRT.texture; + renderer.setRenderTarget( this._verticalRT ); - } ); + this._passDirection.value.set( 0, 1 ); - const dist = min$1( distN, distP ); + _quadMesh2.render( renderer ); - // hacky way of reduces blurriness of mostly diagonal edges - // but reduces AA quality - dist.assign( pow( dist, 0.5 ) ); - dist.assign( float( 1 ).sub( dist ) ); + // restore - return mix( rgbaM, rgbaN, dist.mul( 0.5 ) ); + renderer.setRenderTarget( currentRenderTarget ); + renderer.setMRT( currentMRT ); + textureNode.value = currentTexture; - } ).setLayout( { - name: 'FxaaPixelShader', - type: 'vec4', - inputs: [ - { name: 'uv', type: 'vec2' }, - { name: 'fxaaQualityRcpFrame', type: 'vec2' }, - { name: 'fxaaQualityEdgeThreshold', type: 'float' }, - { name: 'fxaaQualityinvEdgeThreshold', type: 'float' }, - ] - } ); + } - const fxaa = Fn( () => { + getTextureNode() { - const edgeDetectionQuality = float( 0.2 ); - const invEdgeDetectionQuality = float( 1 ).div( edgeDetectionQuality ); + return this._textureNode; - return FxaaPixelShader( uvNode, this._invSize, edgeDetectionQuality, invEdgeDetectionQuality ); + } - } ); + setup( builder ) { - const outputNode = fxaa(); + const textureNode = this.textureNode; - return outputNode; + if ( textureNode.isTextureNode !== true ) { - } + console.error( 'GaussianBlurNode requires a TextureNode.' ); -} + return vec4(); -FXAANode.type = /*@__PURE__*/ registerNode( 'FXAA', FXAANode ); + } -const fxaa = ( node ) => nodeObject( new FXAANode( convertToTexture( node ) ) ); + // -const _quadMesh$2 = /*@__PURE__*/ new QuadMesh(); + const uvNode = textureNode.uvNode || uv(); + const directionNode = vec2( this.directionNode || 1 ); -const _clearColor$1 = /*@__PURE__*/ new Color( 0, 0, 0 ); -const _currentClearColor = /*@__PURE__*/ new Color(); -const _size$4 = /*@__PURE__*/ new Vector2(); + const sampleTexture = ( uv ) => textureNode.uv( uv ); -const _BlurDirectionX = /*@__PURE__*/ new Vector2( 1.0, 0.0 ); -const _BlurDirectionY = /*@__PURE__*/ new Vector2( 0.0, 1.0 ); + const blur = Fn( () => { -class BloomNode extends TempNode { + const kernelSize = 3 + ( 2 * this.sigma ); + const gaussianCoefficients = this._getCoefficients( kernelSize ); - constructor( inputNode, strength = 1, radius = 0, threshold = 0 ) { + const invSize = this._invSize; + const direction = directionNode.mul( this._passDirection ); - super(); + const weightSum = float( gaussianCoefficients[ 0 ] ).toVar(); + const diffuseSum = vec4( sampleTexture( uvNode ).mul( weightSum ) ).toVar(); - this.inputNode = inputNode; - this.strength = uniform( strength ); - this.radius = uniform( radius ); - this.threshold = uniform( threshold ); + for ( let i = 1; i < kernelSize; i ++ ) { - this.smoothWidth = uniform( 0.01 ); + const x = float( i ); + const w = float( gaussianCoefficients[ i ] ); - // + const uvOffset = vec2( direction.mul( invSize.mul( x ) ) ).toVar(); - this._renderTargetsHorizontal = []; - this._renderTargetsVertical = []; - this._nMips = 5; + const sample1 = vec4( sampleTexture( uvNode.add( uvOffset ) ) ); + const sample2 = vec4( sampleTexture( uvNode.sub( uvOffset ) ) ); - // render targets + diffuseSum.addAssign( sample1.add( sample2 ).mul( w ) ); + weightSum.addAssign( mul( 2.0, w ) ); - this._renderTargetBright = new RenderTarget( 1, 1, { type: HalfFloatType } ); - this._renderTargetBright.texture.name = 'UnrealBloomPass.bright'; - this._renderTargetBright.texture.generateMipmaps = false; + } - for ( let i = 0; i < this._nMips; i ++ ) { + return diffuseSum.div( weightSum ); - const renderTargetHorizontal = new RenderTarget( 1, 1, { type: HalfFloatType } ); + } ); - renderTargetHorizontal.texture.name = 'UnrealBloomPass.h' + i; - renderTargetHorizontal.texture.generateMipmaps = false; + // - this._renderTargetsHorizontal.push( renderTargetHorizontal ); + const material = this._material || ( this._material = new NodeMaterial() ); + material.fragmentNode = blur().context( builder.getSharedContext() ); + material.name = 'Gaussian_blur'; + material.needsUpdate = true; - const renderTargetVertical = new RenderTarget( 1, 1, { type: HalfFloatType } ); + // - renderTargetVertical.texture.name = 'UnrealBloomPass.v' + i; - renderTargetVertical.texture.generateMipmaps = false; + const properties = builder.getNodeProperties( this ); + properties.textureNode = textureNode; - this._renderTargetsVertical.push( renderTargetVertical ); + // - } + return this._textureNode; - // materials + } - this._compositeMaterial = null; - this._highPassFilterMaterial = null; - this._separableBlurMaterials = []; + dispose() { - // pass and texture nodes + this._horizontalRT.dispose(); + this._verticalRT.dispose(); - this._textureNodeBright = texture( this._renderTargetBright.texture ); - this._textureNodeBlur0 = texture( this._renderTargetsVertical[ 0 ].texture ); - this._textureNodeBlur1 = texture( this._renderTargetsVertical[ 1 ].texture ); - this._textureNodeBlur2 = texture( this._renderTargetsVertical[ 2 ].texture ); - this._textureNodeBlur3 = texture( this._renderTargetsVertical[ 3 ].texture ); - this._textureNodeBlur4 = texture( this._renderTargetsVertical[ 4 ].texture ); + } - this._textureOutput = passTexture( this, this._renderTargetsHorizontal[ 0 ].texture ); + _getCoefficients( kernelRadius ) { - this.updateBeforeType = NodeUpdateType.FRAME; + const coefficients = []; - } + for ( let i = 0; i < kernelRadius; i ++ ) { - getTextureNode() { + coefficients.push( 0.39894 * Math.exp( - 0.5 * i * i / ( kernelRadius * kernelRadius ) ) / kernelRadius ); - return this._textureOutput; + } - } + return coefficients; - setSize( width, height ) { + } - let resx = Math.round( width / 2 ); - let resy = Math.round( height / 2 ); +} - this._renderTargetBright.setSize( resx, resy ); +const gaussianBlur = ( node, directionNode, sigma ) => nodeObject( new GaussianBlurNode( convertToTexture( node ), directionNode, sigma ) ); - for ( let i = 0; i < this._nMips; i ++ ) { +const _size$6 = /*@__PURE__*/ new Vector2(); - this._renderTargetsHorizontal[ i ].setSize( resx, resy ); - this._renderTargetsVertical[ i ].setSize( resx, resy ); +const _quadMeshComp = /*@__PURE__*/ new QuadMesh(); - this._separableBlurMaterials[ i ].invSize.value.set( 1 / resx, 1 / resy ); +class AfterImageNode extends TempNode { - resx = Math.round( resx / 2 ); - resy = Math.round( resy / 2 ); + static get type() { - } + return 'AfterImageNode'; } - updateBefore( frame ) { - - const { renderer } = frame; + constructor( textureNode, damp = 0.96 ) { - const size = renderer.getDrawingBufferSize( _size$4 ); - this.setSize( size.width, size.height ); + super( textureNode ); - const currentRenderTarget = renderer.getRenderTarget(); - const currentMRT = renderer.getMRT(); - renderer.getClearColor( _currentClearColor ); - const currentClearAlpha = renderer.getClearAlpha(); + this.textureNode = textureNode; + this.textureNodeOld = texture(); + this.damp = uniform( damp ); - this.setSize( size.width, size.height ); + this._compRT = new RenderTarget(); + this._compRT.texture.name = 'AfterImageNode.comp'; - renderer.setMRT( null ); - renderer.setClearColor( _clearColor$1, 0 ); + this._oldRT = new RenderTarget(); + this._oldRT.texture.name = 'AfterImageNode.old'; - // 1. Extract Bright Areas + this._textureNode = passTexture( this, this._compRT.texture ); - renderer.setRenderTarget( this._renderTargetBright ); - _quadMesh$2.material = this._highPassFilterMaterial; - _quadMesh$2.render( renderer ); + this.updateBeforeType = NodeUpdateType.RENDER; - // 2. Blur All the mips progressively + } - let inputRenderTarget = this._renderTargetBright; + getTextureNode() { - for ( let i = 0; i < this._nMips; i ++ ) { + return this._textureNode; - _quadMesh$2.material = this._separableBlurMaterials[ i ]; + } - this._separableBlurMaterials[ i ].colorTexture.value = inputRenderTarget.texture; - this._separableBlurMaterials[ i ].direction.value = _BlurDirectionX; - renderer.setRenderTarget( this._renderTargetsHorizontal[ i ] ); - renderer.clear(); - _quadMesh$2.render( renderer ); + setSize( width, height ) { - this._separableBlurMaterials[ i ].colorTexture.value = this._renderTargetsHorizontal[ i ].texture; - this._separableBlurMaterials[ i ].direction.value = _BlurDirectionY; - renderer.setRenderTarget( this._renderTargetsVertical[ i ] ); - renderer.clear(); - _quadMesh$2.render( renderer ); + this._compRT.setSize( width, height ); + this._oldRT.setSize( width, height ); - inputRenderTarget = this._renderTargetsVertical[ i ]; + } - } + updateBefore( frame ) { - // 3. Composite All the mips + const { renderer } = frame; - renderer.setRenderTarget( this._renderTargetsHorizontal[ 0 ] ); - renderer.clear(); - _quadMesh$2.material = this._compositeMaterial; - _quadMesh$2.render( renderer ); + const textureNode = this.textureNode; + const map = textureNode.value; - // restore + const textureType = map.type; - renderer.setRenderTarget( currentRenderTarget ); - renderer.setMRT( currentMRT ); - renderer.setClearColor( _currentClearColor, currentClearAlpha ); + this._compRT.texture.type = textureType; + this._oldRT.texture.type = textureType; - } + renderer.getDrawingBufferSize( _size$6 ); - setup( builder ) { + this.setSize( _size$6.x, _size$6.y ); - // luminosity high pass material + const currentRenderTarget = renderer.getRenderTarget(); + const currentTexture = textureNode.value; - const luminosityHighPass = Fn( () => { + this.textureNodeOld.value = this._oldRT.texture; - const texel = this.inputNode; - const v = luminance( texel.rgb ); + // comp + renderer.setRenderTarget( this._compRT ); + _quadMeshComp.render( renderer ); - const alpha = smoothstep( this.threshold, this.threshold.add( this.smoothWidth ), v ); + // Swap the textures + const temp = this._oldRT; + this._oldRT = this._compRT; + this._compRT = temp; - return mix( vec4( 0 ), texel, alpha ); + renderer.setRenderTarget( currentRenderTarget ); + textureNode.value = currentTexture; - } ); + } - this._highPassFilterMaterial = this._highPassFilterMaterial || new NodeMaterial(); - this._highPassFilterMaterial.fragmentNode = luminosityHighPass().context( builder.getSharedContext() ); - this._highPassFilterMaterial.name = 'Bloom_highPass'; - this._highPassFilterMaterial.needsUpdate = true; + setup( builder ) { - // gaussian blur materials + const textureNode = this.textureNode; + const textureNodeOld = this.textureNodeOld; - const kernelSizeArray = [ 3, 5, 7, 9, 11 ]; + // - for ( let i = 0; i < this._nMips; i ++ ) { + const uvNode = textureNode.uvNode || uv(); - this._separableBlurMaterials.push( this._getSeperableBlurMaterial( builder, kernelSizeArray[ i ] ) ); + textureNodeOld.uvNode = uvNode; - } + const sampleTexture = ( uv ) => textureNode.uv( uv ); - // composite material + const when_gt = Fn( ( [ x_immutable, y_immutable ] ) => { - const bloomFactors = uniformArray( [ 1.0, 0.8, 0.6, 0.4, 0.2 ] ); - const bloomTintColors = uniformArray( [ new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ) ] ); - - const lerpBloomFactor = Fn( ( [ factor, radius ] ) => { + const y = float( y_immutable ).toVar(); + const x = vec4( x_immutable ).toVar(); - const mirrorFactor = float( 1.2 ).sub( factor ); - return mix( factor, mirrorFactor, radius ); + return max$1( sign( x.sub( y ) ), 0.0 ); - } ).setLayout( { - name: 'lerpBloomFactor', - type: 'float', - inputs: [ - { name: 'factor', type: 'float' }, - { name: 'radius', type: 'float' }, - ] } ); + const afterImg = Fn( () => { - const compositePass = Fn( () => { + const texelOld = vec4( textureNodeOld ); + const texelNew = vec4( sampleTexture( uvNode ) ); - const color0 = lerpBloomFactor( bloomFactors.element( 0 ), this.radius ).mul( vec4( bloomTintColors.element( 0 ), 1.0 ) ).mul( this._textureNodeBlur0 ); - const color1 = lerpBloomFactor( bloomFactors.element( 1 ), this.radius ).mul( vec4( bloomTintColors.element( 1 ), 1.0 ) ).mul( this._textureNodeBlur1 ); - const color2 = lerpBloomFactor( bloomFactors.element( 2 ), this.radius ).mul( vec4( bloomTintColors.element( 2 ), 1.0 ) ).mul( this._textureNodeBlur2 ); - const color3 = lerpBloomFactor( bloomFactors.element( 3 ), this.radius ).mul( vec4( bloomTintColors.element( 3 ), 1.0 ) ).mul( this._textureNodeBlur3 ); - const color4 = lerpBloomFactor( bloomFactors.element( 4 ), this.radius ).mul( vec4( bloomTintColors.element( 4 ), 1.0 ) ).mul( this._textureNodeBlur4 ); + texelOld.mulAssign( this.damp.mul( when_gt( texelOld, 0.1 ) ) ); + return max$1( texelNew, texelOld ); - const sum = color0.add( color1 ).add( color2 ).add( color3 ).add( color4 ); + } ); - return sum.mul( this.strength ); + // - } ); + const materialComposed = this._materialComposed || ( this._materialComposed = new NodeMaterial() ); + materialComposed.name = 'AfterImage'; + materialComposed.fragmentNode = afterImg(); - this._compositeMaterial = this._compositeMaterial || new NodeMaterial(); - this._compositeMaterial.fragmentNode = compositePass().context( builder.getSharedContext() ); - this._compositeMaterial.name = 'Bloom_comp'; - this._compositeMaterial.needsUpdate = true; + _quadMeshComp.material = materialComposed; // - return this._textureOutput; + const properties = builder.getNodeProperties( this ); + properties.textureNode = textureNode; + + // + + return this._textureNode; } dispose() { - for ( let i = 0; i < this._renderTargetsHorizontal.length; i ++ ) { + this._compRT.dispose(); + this._oldRT.dispose(); - this._renderTargetsHorizontal[ i ].dispose(); + } - } +} - for ( let i = 0; i < this._renderTargetsVertical.length; i ++ ) { +const afterImage = ( node, damp ) => nodeObject( new AfterImageNode( convertToTexture( node ), damp ) ); - this._renderTargetsVertical[ i ].dispose(); +const grayscale = /*@__PURE__*/ Fn( ( [ color ] ) => { - } + return luminance( color.rgb ); - this._renderTargetBright.dispose(); +} ); - } +const saturation = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { - _getSeperableBlurMaterial( builder, kernelRadius ) { + return adjustment.mix( luminance( color.rgb ), color.rgb ); - const coefficients = []; +} ); - for ( let i = 0; i < kernelRadius; i ++ ) { +const vibrance = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { - coefficients.push( 0.39894 * Math.exp( - 0.5 * i * i / ( kernelRadius * kernelRadius ) ) / kernelRadius ); + const average = add( color.r, color.g, color.b ).div( 3.0 ); - } + const mx = color.r.max( color.g.max( color.b ) ); + const amt = mx.sub( average ).mul( adjustment ).mul( - 3.0 ); - // + return mix( color.rgb, mx, amt ); - const colorTexture = texture(); - const gaussianCoefficients = uniformArray( coefficients ); - const invSize = uniform( new Vector2() ); - const direction = uniform( new Vector2( 0.5, 0.5 ) ); +} ); - const uvNode = uv(); - const sampleTexel = ( uv ) => colorTexture.uv( uv ); +const hue = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { - const seperableBlurPass = Fn( () => { + const k = vec3( 0.57735, 0.57735, 0.57735 ); - const weightSum = gaussianCoefficients.element( 0 ).toVar(); - const diffuseSum = sampleTexel( uvNode ).rgb.mul( weightSum ).toVar(); + const cosAngle = adjustment.cos(); - Loop( { start: int( 1 ), end: int( kernelRadius ), type: 'int', condition: '<' }, ( { i } ) => { + return vec3( color.rgb.mul( cosAngle ).add( k.cross( color.rgb ).mul( adjustment.sin() ).add( k.mul( dot( k, color.rgb ).mul( cosAngle.oneMinus() ) ) ) ) ); - const x = float( i ); - const w = gaussianCoefficients.element( i ); - const uvOffset = direction.mul( invSize ).mul( x ); - const sample1 = sampleTexel( uvNode.add( uvOffset ) ).rgb; - const sample2 = sampleTexel( uvNode.sub( uvOffset ) ).rgb; - diffuseSum.addAssign( add( sample1, sample2 ).mul( w ) ); - weightSum.addAssign( float( 2.0 ).mul( w ) ); +} ); - } ); +const _luminanceCoefficients = /*@__PURE__*/ new Vector3(); +const luminance = ( + color, + luminanceCoefficients = vec3( ... ColorManagement.getLuminanceCoefficients( _luminanceCoefficients ) ) +) => dot( color, luminanceCoefficients ); - return vec4( diffuseSum.div( weightSum ), 1.0 ); +const threshold = ( color, threshold ) => mix( vec3( 0.0 ), color, luminance( color ).sub( threshold ).max( 0 ) ); - } ); +const _quadMesh$5 = /*@__PURE__*/ new QuadMesh(); - const seperableBlurMaterial = new NodeMaterial(); - seperableBlurMaterial.fragmentNode = seperableBlurPass().context( builder.getSharedContext() ); - seperableBlurMaterial.name = 'Bloom_seperable'; - seperableBlurMaterial.needsUpdate = true; +class AnamorphicNode extends TempNode { - // uniforms - seperableBlurMaterial.colorTexture = colorTexture; - seperableBlurMaterial.direction = direction; - seperableBlurMaterial.invSize = invSize; + static get type() { - return seperableBlurMaterial; + return 'AnamorphicNode'; } -} + constructor( textureNode, tresholdNode, scaleNode, samples ) { -const bloom = ( node, strength, radius, threshold ) => nodeObject( new BloomNode( nodeObject( node ), strength, radius, threshold ) ); + super( 'vec4' ); -class TransitionNode extends TempNode { + this.textureNode = textureNode; + this.tresholdNode = tresholdNode; + this.scaleNode = scaleNode; + this.colorNode = vec3( 0.1, 0.0, 1.0 ); + this.samples = samples; + this.resolution = new Vector2( 1, 1 ); - constructor( textureNodeA, textureNodeB, mixTextureNode, mixRatioNode, thresholdNode, useTextureNode ) { + this._renderTarget = new RenderTarget(); + this._renderTarget.texture.name = 'anamorphic'; - super(); + this._invSize = uniform( new Vector2() ); - // Input textures + this._textureNode = passTexture( this, this._renderTarget.texture ); - this.textureNodeA = textureNodeA; - this.textureNodeB = textureNodeB; - this.mixTextureNode = mixTextureNode; + this.updateBeforeType = NodeUpdateType.RENDER; - // Uniforms + } - this.mixRatioNode = mixRatioNode; - this.thresholdNode = thresholdNode; - this.useTextureNode = useTextureNode; + getTextureNode() { - } + return this._textureNode; - setup() { + } - const { textureNodeA, textureNodeB, mixTextureNode, mixRatioNode, thresholdNode, useTextureNode } = this; + setSize( width, height ) { - const sampleTexture = ( textureNode ) => { + this._invSize.value.set( 1 / width, 1 / height ); - const uvNodeTexture = textureNode.uvNode || uv(); - return textureNode.uv( uvNodeTexture ); + width = Math.max( Math.round( width * this.resolution.x ), 1 ); + height = Math.max( Math.round( height * this.resolution.y ), 1 ); - }; + this._renderTarget.setSize( width, height ); - const transition = Fn( () => { + } - const texelOne = sampleTexture( textureNodeA ); - const texelTwo = sampleTexture( textureNodeB ); + updateBefore( frame ) { - const color = vec4().toVar(); + const { renderer } = frame; - If( useTextureNode.equal( int( 1 ) ), () => { + const textureNode = this.textureNode; + const map = textureNode.value; - const transitionTexel = sampleTexture( mixTextureNode ); - const r = mixRatioNode.mul( thresholdNode.mul( 2.0 ).add( 1.0 ) ).sub( thresholdNode ); - const mixf = clamp( sub( transitionTexel.r, r ).mul( float( 1.0 ).div( thresholdNode ) ), 0.0, 1.0 ); + this._renderTarget.texture.type = map.type; - color.assign( mix( texelOne, texelTwo, mixf ) ); + const currentRenderTarget = renderer.getRenderTarget(); + const currentTexture = textureNode.value; - } ).Else( () => { + _quadMesh$5.material = this._material; - color.assign( mix( texelTwo, texelOne, mixRatioNode ) ); + this.setSize( map.image.width, map.image.height ); - } ); + // render - return color; + renderer.setRenderTarget( this._renderTarget ); - } ); + _quadMesh$5.render( renderer ); - const outputNode = transition(); + // restore - return outputNode; + renderer.setRenderTarget( currentRenderTarget ); + textureNode.value = currentTexture; } -} + setup( builder ) { -TransitionNode.type = /*@__PURE__*/ registerNode( 'Transition', TransitionNode ); + const textureNode = this.textureNode; + const uvNode = textureNode.uvNode || uv(); -const transition = ( nodeA, nodeB, mixTexture, mixRatio = 0.0, threshold = 0.1, useTexture = 0 ) => nodeObject( new TransitionNode( convertToTexture( nodeA ), convertToTexture( nodeB ), convertToTexture( mixTexture ), nodeObject( mixRatio ), nodeObject( threshold ), nodeObject( useTexture ) ) ); + const sampleTexture = ( uv ) => textureNode.uv( uv ); -class PixelationNode extends TempNode { + const anamorph = Fn( () => { - constructor( textureNode, depthNode, normalNode, pixelSize, normalEdgeStrength, depthEdgeStrength ) { + const samples = this.samples; + const halfSamples = Math.floor( samples / 2 ); - super(); + const total = vec3( 0 ).toVar(); - // Input textures + Loop( { start: - halfSamples, end: halfSamples }, ( { i } ) => { - this.textureNode = textureNode; - this.depthNode = depthNode; - this.normalNode = normalNode; + const softness = float( i ).abs().div( halfSamples ).oneMinus(); - // Input uniforms + const uv = vec2( uvNode.x.add( this._invSize.x.mul( i ).mul( this.scaleNode ) ), uvNode.y ); + const color = sampleTexture( uv ); + const pass = threshold( color, this.tresholdNode ).mul( softness ); - this.pixelSize = pixelSize; - this.normalEdgeStrength = normalEdgeStrength; - this.depthEdgeStrength = depthEdgeStrength; + total.addAssign( pass ); - // Private uniforms + } ); - this._resolution = uniform( new Vector4() ); + return total.mul( this.colorNode ); - this.updateBeforeType = NodeUpdateType.RENDER; + } ); - } + // - updateBefore() { + const material = this._material || ( this._material = new NodeMaterial() ); + material.name = 'Anamorphic'; + material.fragmentNode = anamorph(); - const map = this.textureNode.value; + // - const width = map.image.width; - const height = map.image.height; + const properties = builder.getNodeProperties( this ); + properties.textureNode = textureNode; - this._resolution.value.set( width, height, 1 / width, 1 / height ); + // + + return this._textureNode; } - setup() { + dispose() { - const { textureNode, depthNode, normalNode } = this; + this._renderTarget.dispose(); - const uvNodeTexture = textureNode.uvNode || uv(); - const uvNodeDepth = depthNode.uvNode || uv(); - const uvNodeNormal = normalNode.uvNode || uv(); + } - const sampleTexture = () => textureNode.uv( uvNodeTexture ); +} - const sampleDepth = ( x, y ) => depthNode.uv( uvNodeDepth.add( vec2( x, y ).mul( this._resolution.zw ) ) ).r; +const anamorphic = ( node, threshold = .9, scale = 3, samples = 32 ) => nodeObject( new AnamorphicNode( convertToTexture( node ), nodeObject( threshold ), nodeObject( scale ), samples ) ); - const sampleNormal = ( x, y ) => normalNode.uv( uvNodeNormal.add( vec2( x, y ).mul( this._resolution.zw ) ) ).rgb.normalize(); +class SobelOperatorNode extends TempNode { - const depthEdgeIndicator = ( depth ) => { + static get type() { - const diff = property( 'float', 'diff' ); - diff.addAssign( clamp( sampleDepth( 1, 0 ).sub( depth ) ) ); - diff.addAssign( clamp( sampleDepth( - 1, 0 ).sub( depth ) ) ); - diff.addAssign( clamp( sampleDepth( 0, 1 ).sub( depth ) ) ); - diff.addAssign( clamp( sampleDepth( 0, - 1 ).sub( depth ) ) ); + return 'SobelOperatorNode'; - return floor( smoothstep( 0.01, 0.02, diff ).mul( 2 ) ).div( 2 ); + } - }; + constructor( textureNode ) { - const neighborNormalEdgeIndicator = ( x, y, depth, normal ) => { + super(); - const depthDiff = sampleDepth( x, y ).sub( depth ); - const neighborNormal = sampleNormal( x, y ); + this.textureNode = textureNode; - // Edge pixels should yield to faces who's normals are closer to the bias normal. + this.updateBeforeType = NodeUpdateType.RENDER; - const normalEdgeBias = vec3( 1, 1, 1 ); // This should probably be a parameter. - const normalDiff = dot( normal.sub( neighborNormal ), normalEdgeBias ); - const normalIndicator = clamp( smoothstep( - 0.01, 0.01, normalDiff ), 0.0, 1.0 ); + this._invSize = uniform( new Vector2() ); - // Only the shallower pixel should detect the normal edge. + } - const depthIndicator = clamp( sign( depthDiff.mul( .25 ).add( .0025 ) ), 0.0, 1.0 ); + updateBefore() { - return float( 1.0 ).sub( dot( normal, neighborNormal ) ).mul( depthIndicator ).mul( normalIndicator ); + const map = this.textureNode.value; - }; + this._invSize.value.set( 1 / map.image.width, 1 / map.image.height ); - const normalEdgeIndicator = ( depth, normal ) => { + } - const indicator = property( 'float', 'indicator' ); + setup() { - indicator.addAssign( neighborNormalEdgeIndicator( 0, - 1, depth, normal ) ); - indicator.addAssign( neighborNormalEdgeIndicator( 0, 1, depth, normal ) ); - indicator.addAssign( neighborNormalEdgeIndicator( - 1, 0, depth, normal ) ); - indicator.addAssign( neighborNormalEdgeIndicator( 1, 0, depth, normal ) ); + const { textureNode } = this; - return step( 0.1, indicator ); + const uvNode = textureNode.uvNode || uv(); - }; + const sampleTexture = ( uv ) => textureNode.uv( uv ); - const pixelation = Fn( () => { + const sobel = Fn( () => { - const texel = sampleTexture(); + // Sobel Edge Detection (see https://youtu.be/uihBwtPIBxM) - const depth = property( 'float', 'depth' ); - const normal = property( 'vec3', 'normal' ); + const texel = this._invSize; - If( this.depthEdgeStrength.greaterThan( 0.0 ).or( this.normalEdgeStrength.greaterThan( 0.0 ) ), () => { + // kernel definition (in glsl matrices are filled in column-major order) - depth.assign( sampleDepth( 0, 0 ) ); - normal.assign( sampleNormal( 0, 0 ) ); + const Gx = mat3( - 1, - 2, - 1, 0, 0, 0, 1, 2, 1 ); // x direction kernel + const Gy = mat3( - 1, 0, 1, - 2, 0, 2, - 1, 0, 1 ); // y direction kernel - } ); + // fetch the 3x3 neighbourhood of a fragment - const dei = property( 'float', 'dei' ); + // first column - If( this.depthEdgeStrength.greaterThan( 0.0 ), () => { + const tx0y0 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( - 1, - 1 ) ) ) ).xyz ); + const tx0y1 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( - 1, 0 ) ) ) ).xyz ); + const tx0y2 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( - 1, 1 ) ) ) ).xyz ); - dei.assign( depthEdgeIndicator( depth ) ); + // second column - } ); + const tx1y0 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 0, - 1 ) ) ) ).xyz ); + const tx1y1 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 0, 0 ) ) ) ).xyz ); + const tx1y2 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 0, 1 ) ) ) ).xyz ); - const nei = property( 'float', 'nei' ); + // third column - If( this.normalEdgeStrength.greaterThan( 0.0 ), () => { + const tx2y0 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 1, - 1 ) ) ) ).xyz ); + const tx2y1 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 1, 0 ) ) ) ).xyz ); + const tx2y2 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 1, 1 ) ) ) ).xyz ); - nei.assign( normalEdgeIndicator( depth, normal ) ); + // gradient value in x direction - } ); + const valueGx = add( + Gx[ 0 ][ 0 ].mul( tx0y0 ), + Gx[ 1 ][ 0 ].mul( tx1y0 ), + Gx[ 2 ][ 0 ].mul( tx2y0 ), + Gx[ 0 ][ 1 ].mul( tx0y1 ), + Gx[ 1 ][ 1 ].mul( tx1y1 ), + Gx[ 2 ][ 1 ].mul( tx2y1 ), + Gx[ 0 ][ 2 ].mul( tx0y2 ), + Gx[ 1 ][ 2 ].mul( tx1y2 ), + Gx[ 2 ][ 2 ].mul( tx2y2 ) + ); - const strength = dei.greaterThan( 0 ).select( float( 1.0 ).sub( dei.mul( this.depthEdgeStrength ) ), nei.mul( this.normalEdgeStrength ).add( 1 ) ); - return texel.mul( strength ); + // gradient value in y direction + + const valueGy = add( + Gy[ 0 ][ 0 ].mul( tx0y0 ), + Gy[ 1 ][ 0 ].mul( tx1y0 ), + Gy[ 2 ][ 0 ].mul( tx2y0 ), + Gy[ 0 ][ 1 ].mul( tx0y1 ), + Gy[ 1 ][ 1 ].mul( tx1y1 ), + Gy[ 2 ][ 1 ].mul( tx2y1 ), + Gy[ 0 ][ 2 ].mul( tx0y2 ), + Gy[ 1 ][ 2 ].mul( tx1y2 ), + Gy[ 2 ][ 2 ].mul( tx2y2 ) + ); + + // magnitute of the total gradient + + const G = valueGx.mul( valueGx ).add( valueGy.mul( valueGy ) ).sqrt(); + + return vec4( vec3( G ), 1 ); } ); - const outputNode = pixelation(); + const outputNode = sobel(); return outputNode; @@ -57877,5260 +57539,7620 @@ class PixelationNode extends TempNode { } -PixelationNode.type = /*@__PURE__*/ registerNode( 'Pixelation', PixelationNode ); +const sobel = ( node ) => nodeObject( new SobelOperatorNode( convertToTexture( node ) ) ); -const pixelation = ( node, depthNode, normalNode, pixelSize = 6, normalEdgeStrength = 0.3, depthEdgeStrength = 0.4 ) => nodeObject( new PixelationNode( convertToTexture( node ), convertToTexture( depthNode ), convertToTexture( normalNode ), nodeObject( pixelSize ), nodeObject( normalEdgeStrength ), nodeObject( depthEdgeStrength ) ) ); +class DepthOfFieldNode extends TempNode { -class PixelationPassNode extends PassNode { + static get type() { - constructor( scene, camera, pixelSize = 6, normalEdgeStrength = 0.3, depthEdgeStrength = 0.4 ) { + return 'DepthOfFieldNode'; - super( 'color', scene, camera, { minFilter: NearestFilter, magFilter: NearestFilter } ); + } - this.pixelSize = pixelSize; - this.normalEdgeStrength = normalEdgeStrength; - this.depthEdgeStrength = depthEdgeStrength; + constructor( textureNode, viewZNode, focusNode, apertureNode, maxblurNode ) { - this.isPixelationPassNode = true; + super(); - this._mrt = mrt( { - output: output, - normal: normalView - } ); + this.textureNode = textureNode; + this.viewZNode = viewZNode; - } + this.focusNode = focusNode; + this.apertureNode = apertureNode; + this.maxblurNode = maxblurNode; - setSize( width, height ) { + this._aspect = uniform( 0 ); - const pixelSize = this.pixelSize.value ? this.pixelSize.value : this.pixelSize; + this.updateBeforeType = NodeUpdateType.RENDER; - const adjustedWidth = Math.floor( width / pixelSize ); - const adjustedHeight = Math.floor( height / pixelSize ); + } - super.setSize( adjustedWidth, adjustedHeight ); + updateBefore() { + + const map = this.textureNode.value; + + this._aspect.value = map.image.width / map.image.height; } setup() { - const color = super.getTextureNode( 'output' ); - const depth = super.getTextureNode( 'depth' ); - const normal = super.getTextureNode( 'normal' ); - - return pixelation( color, depth, normal, this.pixelSize, this.normalEdgeStrength, this.depthEdgeStrength ); + const textureNode = this.textureNode; + const uvNode = textureNode.uvNode || uv(); - } + const sampleTexture = ( uv ) => textureNode.uv( uv ); -} + const dof = Fn( () => { -const pixelationPass = ( scene, camera, pixelSize, normalEdgeStrength, depthEdgeStrength ) => nodeObject( new PixelationPassNode( scene, camera, pixelSize, normalEdgeStrength, depthEdgeStrength ) ); + const aspectcorrect = vec2( 1.0, this._aspect ); -PixelationPassNode.type = /*@__PURE__*/ registerNode( 'PixelationPass', PixelationPassNode ); + const factor = this.focusNode.add( this.viewZNode ); -const _size$3 = /*@__PURE__*/ new Vector2(); + const dofblur = vec2( clamp( factor.mul( this.apertureNode ), this.maxblurNode.negate(), this.maxblurNode ) ); -/** -* -* Supersample Anti-Aliasing Render Pass -* -* This manual approach to SSAA re-renders the scene ones for each sample with camera jitter and accumulates the results. -* -* References: https://en.wikipedia.org/wiki/Supersampling -* -*/ + const dofblur9 = dofblur.mul( 0.9 ); + const dofblur7 = dofblur.mul( 0.7 ); + const dofblur4 = dofblur.mul( 0.4 ); -class SSAAPassNode extends PassNode { + let col = vec4( 0.0 ); - constructor( scene, camera ) { + col = col.add( sampleTexture( uvNode ) ); - super( PassNode.COLOR, scene, camera ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.0, 0.4 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.40, 0.0 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.0, - 0.4 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.40, 0.0 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.0, - 0.4 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.0, 0.4 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.0, - 0.4 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.0, 0.4 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); - this.isSSAAPassNode = true; + col = col.div( 41 ); + col.a = 1; - this.sampleLevel = 4; // specified as n, where the number of samples is 2^n, so sampleLevel = 4, is 2^4 samples, 16. - this.unbiased = true; - this.clearColor = new Color( 0x000000 ); - this.clearAlpha = 0; + return vec4( col ); - this._currentClearColor = new Color(); - this.sampleWeight = uniform( 1 ); + } ); - this.sampleRenderTarget = null; + const outputNode = dof(); - this._quadMesh = new QuadMesh(); + return outputNode; } - updateBefore( frame ) { +} - const { renderer } = frame; - const { scene, camera } = this; +const dof = ( node, viewZNode, focus = 1, aperture = 0.025, maxblur = 1 ) => nodeObject( new DepthOfFieldNode( convertToTexture( node ), nodeObject( viewZNode ), nodeObject( focus ), nodeObject( aperture ), nodeObject( maxblur ) ) ); - this._pixelRatio = renderer.getPixelRatio(); +class DotScreenNode extends TempNode { - const size = renderer.getSize( _size$3 ); + static get type() { - this.setSize( size.width, size.height ); - this.sampleRenderTarget.setSize( this.renderTarget.width, this.renderTarget.height ); + return 'DotScreenNode'; - // save current renderer settings + } - renderer.getClearColor( this._currentClearColor ); - const currentClearAlpha = renderer.getClearAlpha(); - const currentRenderTarget = renderer.getRenderTarget(); - const currentMRT = renderer.getMRT(); - const currentAutoClear = renderer.autoClear; + constructor( inputNode, center = new Vector2( 0.5, 0.5 ), angle = 1.57, scale = 1 ) { - // + super( 'vec4' ); - this._cameraNear.value = camera.near; - this._cameraFar.value = camera.far; - - renderer.setMRT( this.getMRT() ); - renderer.autoClear = false; - - const jitterOffsets = _JitterVectors[ Math.max( 0, Math.min( this.sampleLevel, 5 ) ) ]; - - const baseSampleWeight = 1.0 / jitterOffsets.length; - const roundingRange = 1 / 32; + this.inputNode = inputNode; + this.center = uniform( center ); + this.angle = uniform( angle ); + this.scale = uniform( scale ); - const viewOffset = { + } - fullWidth: this.renderTarget.width, - fullHeight: this.renderTarget.height, - offsetX: 0, - offsetY: 0, - width: this.renderTarget.width, - height: this.renderTarget.height + setup() { - }; + const inputNode = this.inputNode; - const originalViewOffset = Object.assign( {}, camera.view ); + const pattern = Fn( () => { - if ( originalViewOffset.enabled ) Object.assign( viewOffset, originalViewOffset ); + const s = sin( this.angle ); + const c = cos( this.angle ); - // render the scene multiple times, each slightly jitter offset from the last and accumulate the results. + const tex = uv().mul( screenSize ).sub( this.center ); + const point = vec2( c.mul( tex.x ).sub( s.mul( tex.y ) ), s.mul( tex.x ).add( c.mul( tex.y ) ) ).mul( this.scale ); - for ( let i = 0; i < jitterOffsets.length; i ++ ) { + return sin( point.x ).mul( sin( point.y ) ).mul( 4 ); - const jitterOffset = jitterOffsets[ i ]; + } ); - if ( camera.setViewOffset ) { + const dotScreen = Fn( () => { - camera.setViewOffset( + const color = inputNode; - viewOffset.fullWidth, viewOffset.fullHeight, + const average = add( color.r, color.g, color.b ).div( 3 ); - viewOffset.offsetX + jitterOffset[ 0 ] * 0.0625, viewOffset.offsetY + jitterOffset[ 1 ] * 0.0625, // 0.0625 = 1 / 16 + return vec4( vec3( average.mul( 10 ).sub( 5 ).add( pattern() ) ), color.a ); - viewOffset.width, viewOffset.height + } ); - ); + const outputNode = dotScreen(); - } + return outputNode; - this.sampleWeight.value = baseSampleWeight; + } - if ( this.unbiased ) { +} - // the theory is that equal weights for each sample lead to an accumulation of rounding errors. - // The following equation varies the sampleWeight per sample so that it is uniformly distributed - // across a range of values whose rounding errors cancel each other out. +const dotScreen = ( node, center, angle, scale ) => nodeObject( new DotScreenNode( nodeObject( node ), center, angle, scale ) ); - const uniformCenteredDistribution = ( - 0.5 + ( i + 0.5 ) / jitterOffsets.length ); - this.sampleWeight.value += roundingRange * uniformCenteredDistribution; +class RGBShiftNode extends TempNode { - } + static get type() { - renderer.setClearColor( this.clearColor, this.clearAlpha ); - renderer.setRenderTarget( this.sampleRenderTarget ); - renderer.clear(); - renderer.render( scene, camera ); + return 'RGBShiftNode'; - // accumulation + } - renderer.setRenderTarget( this.renderTarget ); + constructor( textureNode, amount = 0.005, angle = 0 ) { - if ( i === 0 ) { + super( 'vec4' ); - renderer.setClearColor( 0x000000, 0.0 ); - renderer.clear(); + this.textureNode = textureNode; + this.amount = uniform( amount ); + this.angle = uniform( angle ); - } + } - this._quadMesh.render( renderer ); + setup() { - } + const { textureNode } = this; - renderer.copyTextureToTexture( this.sampleRenderTarget.depthTexture, this.renderTarget.depthTexture ); + const uvNode = textureNode.uvNode || uv(); - // restore + const sampleTexture = ( uv ) => textureNode.uv( uv ); - if ( camera.setViewOffset && originalViewOffset.enabled ) { + const rgbShift = Fn( () => { - camera.setViewOffset( + const offset = vec2( cos( this.angle ), sin( this.angle ) ).mul( this.amount ); + const cr = sampleTexture( uvNode.add( offset ) ); + const cga = sampleTexture( uvNode ); + const cb = sampleTexture( uvNode.sub( offset ) ); - originalViewOffset.fullWidth, originalViewOffset.fullHeight, + return vec4( cr.r, cga.g, cb.b, cga.a ); - originalViewOffset.offsetX, originalViewOffset.offsetY, + } ); - originalViewOffset.width, originalViewOffset.height + return rgbShift(); - ); + } - } else if ( camera.clearViewOffset ) { +} - camera.clearViewOffset(); +const rgbShift = ( node, amount, angle ) => nodeObject( new RGBShiftNode( convertToTexture( node ), amount, angle ) ); - } +class FilmNode extends TempNode { - renderer.setRenderTarget( currentRenderTarget ); - renderer.setMRT( currentMRT ); + static get type() { - renderer.autoClear = currentAutoClear; - renderer.setClearColor( this._currentClearColor, currentClearAlpha ); + return 'FilmNode'; } - setup( builder ) { - - if ( this.sampleRenderTarget === null ) { - - this.sampleRenderTarget = this.renderTarget.clone(); + constructor( inputNode, intensityNode = null, uvNode = null ) { - } + super(); - let sampleTexture; + this.inputNode = inputNode; + this.intensityNode = intensityNode; + this.uvNode = uvNode; - const passMRT = this.getMRT(); + } - if ( passMRT !== null ) { + setup() { - const outputs = {}; + const uvNode = this.uvNode || uv(); - for ( const name in passMRT.outputNodes ) { + const film = Fn( () => { - const index = getTextureIndex( this.sampleRenderTarget.textures, name ); + const base = this.inputNode.rgb; + const noise = rand( fract( uvNode.add( timerLocal() ) ) ); - if ( index >= 0 ) { + let color = base.add( base.mul( clamp( noise.add( 0.1 ), 0, 1 ) ) ); - outputs[ name ] = texture( this.sampleRenderTarget.textures[ index ] ).mul( this.sampleWeight ); + if ( this.intensityNode !== null ) { - } + color = mix( base, color, this.intensityNode ); } - sampleTexture = mrt( outputs ); - - } else { - - sampleTexture = texture( this.sampleRenderTarget.texture ).mul( this.sampleWeight ); - - } - - this._quadMesh.material = new NodeMaterial(); - this._quadMesh.material.fragmentNode = sampleTexture; - this._quadMesh.material.transparent = true; - this._quadMesh.material.depthTest = false; - this._quadMesh.material.depthWrite = false; - this._quadMesh.material.premultipliedAlpha = true; - this._quadMesh.material.blending = AdditiveBlending; - this._quadMesh.material.normals = false; - this._quadMesh.material.name = 'SSAA'; - - return super.setup( builder ); - - } - - dispose() { - - super.dispose(); + return vec4( color, this.inputNode.a ); - if ( this.sampleRenderTarget !== null ) { + } ); - this.sampleRenderTarget.dispose(); + const outputNode = film(); - } + return outputNode; } } -SSAAPassNode.type = /*@__PURE__*/ registerNode( 'SSAAPass', SSAAPassNode ); - -// These jitter vectors are specified in integers because it is easier. -// I am assuming a [-8,8) integer grid, but it needs to be mapped onto [-0.5,0.5) -// before being used, thus these integers need to be scaled by 1/16. -// -// Sample patterns reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476218%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 -const _JitterVectors = [ - [ - [ 0, 0 ] - ], - [ - [ 4, 4 ], [ - 4, - 4 ] - ], - [ - [ - 2, - 6 ], [ 6, - 2 ], [ - 6, 2 ], [ 2, 6 ] - ], - [ - [ 1, - 3 ], [ - 1, 3 ], [ 5, 1 ], [ - 3, - 5 ], - [ - 5, 5 ], [ - 7, - 1 ], [ 3, 7 ], [ 7, - 7 ] - ], - [ - [ 1, 1 ], [ - 1, - 3 ], [ - 3, 2 ], [ 4, - 1 ], - [ - 5, - 2 ], [ 2, 5 ], [ 5, 3 ], [ 3, - 5 ], - [ - 2, 6 ], [ 0, - 7 ], [ - 4, - 6 ], [ - 6, 4 ], - [ - 8, 0 ], [ 7, - 4 ], [ 6, 7 ], [ - 7, - 8 ] - ], - [ - [ - 4, - 7 ], [ - 7, - 5 ], [ - 3, - 5 ], [ - 5, - 4 ], - [ - 1, - 4 ], [ - 2, - 2 ], [ - 6, - 1 ], [ - 4, 0 ], - [ - 7, 1 ], [ - 1, 2 ], [ - 6, 3 ], [ - 3, 3 ], - [ - 7, 6 ], [ - 3, 6 ], [ - 5, 7 ], [ - 1, 7 ], - [ 5, - 7 ], [ 1, - 6 ], [ 6, - 5 ], [ 4, - 4 ], - [ 2, - 3 ], [ 7, - 2 ], [ 1, - 1 ], [ 4, - 1 ], - [ 2, 1 ], [ 6, 2 ], [ 0, 4 ], [ 4, 4 ], - [ 2, 5 ], [ 7, 5 ], [ 5, 6 ], [ 3, 7 ] - ] -]; +const film = /*@__PURE__*/ nodeProxy( FilmNode ); -const ssaaPass = ( scene, camera ) => nodeObject( new SSAAPassNode( scene, camera ) ); +class Lut3DNode extends TempNode { -const _size$2 = /*@__PURE__*/ new Vector2(); + static get type() { -class StereoPassNode extends PassNode { + return 'Lut3DNode'; - constructor( scene, camera ) { + } - super( PassNode.COLOR, scene, camera ); + constructor( inputNode, lutNode, size, intensityNode ) { - this.isStereoPassNode = true; + super(); - this.stereo = new StereoCamera(); - this.stereo.aspect = 0.5; + this.inputNode = inputNode; + this.lutNode = lutNode; + this.size = uniform( size ); + this.intensityNode = intensityNode; } - updateBefore( frame ) { - - const { renderer } = frame; - const { scene, camera, stereo, renderTarget } = this; - - this._pixelRatio = renderer.getPixelRatio(); - - stereo.cameraL.coordinateSystem = renderer.coordinateSystem; - stereo.cameraR.coordinateSystem = renderer.coordinateSystem; - stereo.update( camera ); + setup() { - const size = renderer.getSize( _size$2 ); - this.setSize( size.width, size.height ); + const { inputNode, lutNode } = this; - const currentAutoClear = renderer.autoClear; - renderer.autoClear = false; + const sampleLut = ( uv ) => lutNode.uv( uv ); - const currentRenderTarget = renderer.getRenderTarget(); - const currentMRT = renderer.getMRT(); + const lut3D = Fn( () => { - this._cameraNear.value = camera.near; - this._cameraFar.value = camera.far; + const base = inputNode; - for ( const name in this._previousTextures ) { + // pull the sample in by half a pixel so the sample begins at the center of the edge pixels. - this.toggleTexture( name ); + const pixelWidth = float( 1.0 ).div( this.size ); + const halfPixelWidth = float( 0.5 ).div( this.size ); + const uvw = vec3( halfPixelWidth ).add( base.rgb.mul( float( 1.0 ).sub( pixelWidth ) ) ); - } + const lutValue = vec4( sampleLut( uvw ).rgb, base.a ); - renderer.setRenderTarget( renderTarget ); - renderer.setMRT( this._mrt ); - renderer.clear(); + return vec4( mix( base, lutValue, this.intensityNode ) ); - renderTarget.scissorTest = true; + } ); - renderTarget.scissor.set( 0, 0, renderTarget.width / 2, renderTarget.height ); - renderTarget.viewport.set( 0, 0, renderTarget.width / 2, renderTarget.height ); - renderer.render( scene, stereo.cameraL ); + const outputNode = lut3D(); - renderTarget.scissor.set( renderTarget.width / 2, 0, renderTarget.width / 2, renderTarget.height ); - renderTarget.viewport.set( renderTarget.width / 2, 0, renderTarget.width / 2, renderTarget.height ); - renderer.render( scene, stereo.cameraR ); + return outputNode; - renderTarget.scissorTest = false; + } - renderer.setRenderTarget( currentRenderTarget ); - renderer.setMRT( currentMRT ); +} - renderer.autoClear = currentAutoClear; +const lut3D = ( node, lut, size, intensity ) => nodeObject( new Lut3DNode( nodeObject( node ), nodeObject( lut ), size, nodeObject( intensity ) ) ); - } +const _quadMesh$4 = /*@__PURE__*/ new QuadMesh(); +const _currentClearColor$1 = /*@__PURE__*/ new Color(); +const _size$5 = /*@__PURE__*/ new Vector2(); -} +class GTAONode extends TempNode { -StereoPassNode.type = /*@__PURE__*/ registerNode( 'StereoPass', StereoPassNode ); + static get type() { -const stereoPass = ( scene, camera ) => nodeObject( new StereoPassNode( scene, camera ) ); + return 'GTAONode'; -const _size$1 = /*@__PURE__*/ new Vector2(); -const _quadMesh$1 = /*@__PURE__*/ new QuadMesh(); + } -class StereoCompositePassNode extends PassNode { + constructor( depthNode, normalNode, camera ) { - constructor( scene, camera ) { + super(); - super( PassNode.COLOR, scene, camera ); + this.depthNode = depthNode; + this.normalNode = normalNode; - this.isStereoCompositePassNode = true; + this.radius = uniform( 0.25 ); + this.resolution = uniform( new Vector2() ); + this.thickness = uniform( 1 ); + this.distanceExponent = uniform( 1 ); + this.distanceFallOff = uniform( 1 ); + this.scale = uniform( 1 ); + this.noiseNode = texture( generateMagicSquareNoise() ); - this.stereo = new StereoCamera(); - const _params = { minFilter: LinearFilter, magFilter: NearestFilter, type: HalfFloatType }; + this.cameraProjectionMatrix = uniform( camera.projectionMatrix ); + this.cameraProjectionMatrixInverse = uniform( camera.projectionMatrixInverse ); - this._renderTargetL = new RenderTarget( 1, 1, _params ); - this._renderTargetR = new RenderTarget( 1, 1, _params ); + this.SAMPLES = uniform( 16 ); - this._mapLeft = texture( this._renderTargetL.texture ); - this._mapRight = texture( this._renderTargetR.texture ); + this._aoRenderTarget = new RenderTarget(); + this._aoRenderTarget.texture.name = 'GTAONode.AO'; this._material = null; + this._textureNode = passTexture( this, this._aoRenderTarget.texture ); + + this.updateBeforeType = NodeUpdateType.FRAME; } - updateStereoCamera( coordinateSystem ) { + getTextureNode() { - this.stereo.cameraL.coordinateSystem = coordinateSystem; - this.stereo.cameraR.coordinateSystem = coordinateSystem; - this.stereo.update( this.camera ); + return this._textureNode; } setSize( width, height ) { - super.setSize( width, height ); - - this._renderTargetL.setSize( this.renderTarget.width, this.renderTarget.height ); - this._renderTargetR.setSize( this.renderTarget.width, this.renderTarget.height ); + this.resolution.value.set( width, height ); + this._aoRenderTarget.setSize( width, height ); } updateBefore( frame ) { const { renderer } = frame; - const { scene, stereo, renderTarget } = this; - - this._pixelRatio = renderer.getPixelRatio(); - - this.updateStereoCamera( renderer.coordinateSystem ); - const size = renderer.getSize( _size$1 ); - this.setSize( size.width, size.height ); + const size = renderer.getDrawingBufferSize( _size$5 ); const currentRenderTarget = renderer.getRenderTarget(); + const currentMRT = renderer.getMRT(); + renderer.getClearColor( _currentClearColor$1 ); + const currentClearAlpha = renderer.getClearAlpha(); - // left + _quadMesh$4.material = this._material; - renderer.setRenderTarget( this._renderTargetL ); - renderer.render( scene, stereo.cameraL ); + this.setSize( size.width, size.height ); - // right + // clear - renderer.setRenderTarget( this._renderTargetR ); - renderer.render( scene, stereo.cameraR ); + renderer.setMRT( null ); + renderer.setClearColor( 0xffffff, 1 ); - // composite + // ao - renderer.setRenderTarget( renderTarget ); - _quadMesh$1.material = this._material; - _quadMesh$1.render( renderer ); + renderer.setRenderTarget( this._aoRenderTarget ); + _quadMesh$4.render( renderer ); // restore renderer.setRenderTarget( currentRenderTarget ); + renderer.setMRT( currentMRT ); + renderer.setClearColor( _currentClearColor$1, currentClearAlpha ); } - dispose() { - - super.dispose(); - - this._renderTargetL.dispose(); - this._renderTargetR.dispose(); - - if ( this._material !== null ) { - - this._material.dispose(); - - } + setup( builder ) { - } + const uvNode = uv(); -} + const sampleDepth = ( uv ) => this.depthNode.uv( uv ).x; + const sampleNoise = ( uv ) => this.noiseNode.uv( uv ); -StereoCompositePassNode.type = /*@__PURE__*/ registerNode( 'StereoCompositePass', StereoCompositePassNode ); + const getSceneUvAndDepth = Fn( ( [ sampleViewPos ] )=> { -class AnaglyphPassNode extends StereoCompositePassNode { + const sampleClipPos = this.cameraProjectionMatrix.mul( vec4( sampleViewPos, 1.0 ) ); + let sampleUv = sampleClipPos.xy.div( sampleClipPos.w ).mul( 0.5 ).add( 0.5 ).toVar(); + sampleUv = vec2( sampleUv.x, sampleUv.y.oneMinus() ); + const sampleSceneDepth = sampleDepth( sampleUv ); + return vec3( sampleUv, sampleSceneDepth ); - constructor( scene, camera ) { + } ); - super( scene, camera ); + const getViewPosition = Fn( ( [ screenPosition, depth ] ) => { - this.isAnaglyphPassNode = true; + screenPosition = vec2( screenPosition.x, screenPosition.y.oneMinus() ).mul( 2.0 ).sub( 1.0 ); - // Dubois matrices from https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.7.6968&rep=rep1&type=pdf#page=4 + const clipSpacePosition = vec4( vec3( screenPosition, depth ), 1.0 ); + const viewSpacePosition = vec4( this.cameraProjectionMatrixInverse.mul( clipSpacePosition ) ); - this._colorMatrixLeft = uniform( new Matrix3().fromArray( [ - 0.456100, - 0.0400822, - 0.0152161, - 0.500484, - 0.0378246, - 0.0205971, - 0.176381, - 0.0157589, - 0.00546856 - ] ) ); + return viewSpacePosition.xyz.div( viewSpacePosition.w ); - this._colorMatrixRight = uniform( new Matrix3().fromArray( [ - - 0.0434706, 0.378476, - 0.0721527, - - 0.0879388, 0.73364, - 0.112961, - - 0.00155529, - 0.0184503, 1.2264 - ] ) ); + } ); - } + const ao = Fn( () => { - setup( builder ) { + const depth = sampleDepth( uvNode ); - const uvNode = uv(); + depth.greaterThanEqual( 1.0 ).discard(); - const anaglyph = Fn( () => { + const viewPosition = getViewPosition( uvNode, depth ); + const viewNormal = this.normalNode.rgb.normalize(); - const colorL = this._mapLeft.uv( uvNode ); - const colorR = this._mapRight.uv( uvNode ); + const radiusToUse = this.radius; - const color = clamp( this._colorMatrixLeft.mul( colorL.rgb ).add( this._colorMatrixRight.mul( colorR.rgb ) ) ); + const noiseResolution = textureSize( this.noiseNode, 0 ); + let noiseUv = vec2( uvNode.x, uvNode.y.oneMinus() ); + noiseUv = noiseUv.mul( this.resolution.div( noiseResolution ) ); + const noiseTexel = sampleNoise( noiseUv ); + const randomVec = noiseTexel.xyz.mul( 2.0 ).sub( 1.0 ); + const tangent = vec3( randomVec.xy, 0.0 ).normalize(); + const bitangent = vec3( tangent.y.mul( - 1.0 ), tangent.x, 0.0 ); + const kernelMatrix = mat3( tangent, bitangent, vec3( 0.0, 0.0, 1.0 ) ); - return vec4( color.rgb, max$1( colorL.a, colorR.a ) ); + const DIRECTIONS = this.SAMPLES.lessThan( 30 ).select( 3, 5 ); + const STEPS = add( this.SAMPLES, DIRECTIONS.sub( 1 ) ).div( DIRECTIONS ); - } ); + const ao = float( 0 ).toVar(); - const material = this._material || ( this._material = new NodeMaterial() ); - material.fragmentNode = anaglyph().context( builder.getSharedContext() ); - material.name = 'Anaglyph'; - material.needsUpdate = true; + Loop( { start: int( 0 ), end: DIRECTIONS, type: 'int', condition: '<' }, ( { i } ) => { - return super.setup( builder ); + const angle = float( i ).div( float( DIRECTIONS ) ).mul( PI ); + const sampleDir = vec4( cos( angle ), sin( angle ), 0., add( 0.5, mul( 0.5, noiseTexel.w ) ) ); + sampleDir.xyz = normalize( kernelMatrix.mul( sampleDir.xyz ) ); - } + const viewDir = normalize( viewPosition.xyz.negate() ); + const sliceBitangent = normalize( cross( sampleDir.xyz, viewDir ) ); + const sliceTangent = cross( sliceBitangent, viewDir ); + const normalInSlice = normalize( viewNormal.sub( sliceBitangent.mul( dot( viewNormal, sliceBitangent ) ) ) ); -} + const tangentToNormalInSlice = cross( normalInSlice, sliceBitangent ); + const cosHorizons = vec2( dot( viewDir, tangentToNormalInSlice ), dot( viewDir, tangentToNormalInSlice.negate() ) ).toVar(); -const anaglyphPass = ( scene, camera ) => nodeObject( new AnaglyphPassNode( scene, camera ) ); + Loop( { end: STEPS, type: 'int', name: 'j', condition: '<' }, ( { j } ) => { -class ParallaxBarrierPassNode extends StereoCompositePassNode { + const sampleViewOffset = sampleDir.xyz.mul( radiusToUse ).mul( sampleDir.w ).mul( pow( div( float( j ).add( 1.0 ), float( STEPS ) ), this.distanceExponent ) ); - constructor( scene, camera ) { + // x - super( scene, camera ); + const sampleSceneUvDepthX = getSceneUvAndDepth( viewPosition.add( sampleViewOffset ) ); + const sampleSceneViewPositionX = getViewPosition( sampleSceneUvDepthX.xy, sampleSceneUvDepthX.z ); + const viewDeltaX = sampleSceneViewPositionX.sub( viewPosition ); - this.isParallaxBarrierPassNode = true; + If( abs( viewDeltaX.z ).lessThan( this.thickness ), () => { - } + const sampleCosHorizon = dot( viewDir, normalize( viewDeltaX ) ); + cosHorizons.x.addAssign( max$1( 0, mul( sampleCosHorizon.sub( cosHorizons.x ), mix( 1.0, float( 2.0 ).div( float( j ).add( 2 ) ), this.distanceFallOff ) ) ) ); - setup( builder ) { + } ); - const uvNode = uv(); + // y - const parallaxBarrier = Fn( () => { + const sampleSceneUvDepthY = getSceneUvAndDepth( viewPosition.sub( sampleViewOffset ) ); + const sampleSceneViewPositionY = getViewPosition( sampleSceneUvDepthY.xy, sampleSceneUvDepthY.z ); + const viewDeltaY = sampleSceneViewPositionY.sub( viewPosition ); - const color = vec4().toVar(); + If( abs( viewDeltaY.z ).lessThan( this.thickness ), () => { - If( mod( viewportCoordinate.y, 2 ).greaterThan( 1 ), () => { + const sampleCosHorizon = dot( viewDir, normalize( viewDeltaY ) ); + cosHorizons.y.addAssign( max$1( 0, mul( sampleCosHorizon.sub( cosHorizons.y ), mix( 1.0, float( 2.0 ).div( float( j ).add( 2 ) ), this.distanceFallOff ) ) ) ); - color.assign( this._mapLeft.uv( uvNode ) ); + } ); - } ).Else( () => { + } ); - color.assign( this._mapRight.uv( uvNode ) ); + const sinHorizons = sqrt( sub( 1.0, cosHorizons.mul( cosHorizons ) ) ); + const nx = dot( normalInSlice, sliceTangent ); + const ny = dot( normalInSlice, viewDir ); + const nxb = mul( 0.5, acos( cosHorizons.y ).sub( acos( cosHorizons.x ) ).add( sinHorizons.x.mul( cosHorizons.x ).sub( sinHorizons.y.mul( cosHorizons.y ) ) ) ); + const nyb = mul( 0.5, sub( 2.0, cosHorizons.x.mul( cosHorizons.x ) ).sub( cosHorizons.y.mul( cosHorizons.y ) ) ); + const occlusion = nx.mul( nxb ).add( ny.mul( nyb ) ); + ao.addAssign( occlusion ); } ); - return color; + ao.assign( clamp( ao.div( DIRECTIONS ), 0, 1 ) ); + ao.assign( pow( ao, this.scale ) ); + + return vec4( vec3( ao ), 1.0 ); } ); const material = this._material || ( this._material = new NodeMaterial() ); - material.fragmentNode = parallaxBarrier().context( builder.getSharedContext() ); + material.fragmentNode = ao().context( builder.getSharedContext() ); + material.name = 'GTAO'; material.needsUpdate = true; - return super.setup( builder ); + // + + return this._textureNode; } -} + dispose() { -ParallaxBarrierPassNode.type = /*@__PURE__*/ registerNode( 'ParallaxBarrierPass', ParallaxBarrierPassNode ); + this._aoRenderTarget.dispose(); -const parallaxBarrierPass = ( scene, camera ) => nodeObject( new ParallaxBarrierPassNode( scene, camera ) ); + } -class ScriptableValueNode extends Node { +} - constructor( value = null ) { +function generateMagicSquareNoise( size = 5 ) { - super(); + const noiseSize = Math.floor( size ) % 2 === 0 ? Math.floor( size ) + 1 : Math.floor( size ); + const magicSquare = generateMagicSquare( noiseSize ); + const noiseSquareSize = magicSquare.length; + const data = new Uint8Array( noiseSquareSize * 4 ); - this._value = value; - this._cache = null; - - this.inputType = null; - this.outpuType = null; - - this.events = new EventDispatcher(); + for ( let inx = 0; inx < noiseSquareSize; ++ inx ) { - this.isScriptableValueNode = true; + const iAng = magicSquare[ inx ]; + const angle = ( 2 * Math.PI * iAng ) / noiseSquareSize; + const randomVec = new Vector3( + Math.cos( angle ), + Math.sin( angle ), + 0 + ).normalize(); + data[ inx * 4 ] = ( randomVec.x * 0.5 + 0.5 ) * 255; + data[ inx * 4 + 1 ] = ( randomVec.y * 0.5 + 0.5 ) * 255; + data[ inx * 4 + 2 ] = 127; + data[ inx * 4 + 3 ] = 255; } - get isScriptableOutputNode() { - - return this.outputType !== null; + const noiseTexture = new DataTexture( data, noiseSize, noiseSize ); + noiseTexture.wrapS = RepeatWrapping; + noiseTexture.wrapT = RepeatWrapping; + noiseTexture.needsUpdate = true; - } + return noiseTexture; - set value( val ) { +} - if ( this._value === val ) return; +function generateMagicSquare( size ) { - if ( this._cache && this.inputType === 'URL' && this.value.value instanceof ArrayBuffer ) { + const noiseSize = Math.floor( size ) % 2 === 0 ? Math.floor( size ) + 1 : Math.floor( size ); + const noiseSquareSize = noiseSize * noiseSize; + const magicSquare = Array( noiseSquareSize ).fill( 0 ); + let i = Math.floor( noiseSize / 2 ); + let j = noiseSize - 1; - URL.revokeObjectURL( this._cache ); + for ( let num = 1; num <= noiseSquareSize; ) { - this._cache = null; + if ( i === - 1 && j === noiseSize ) { - } + j = noiseSize - 2; + i = 0; - this._value = val; + } else { - this.events.dispatchEvent( { type: 'change' } ); + if ( j === noiseSize ) { - this.refresh(); + j = 0; - } + } - get value() { + if ( i < 0 ) { - return this._value; + i = noiseSize - 1; - } + } - refresh() { + } - this.events.dispatchEvent( { type: 'refresh' } ); + if ( magicSquare[ i * noiseSize + j ] !== 0 ) { - } + j -= 2; + i ++; + continue; - getValue() { + } else { - const value = this.value; + magicSquare[ i * noiseSize + j ] = num ++; - if ( value && this._cache === null && this.inputType === 'URL' && value.value instanceof ArrayBuffer ) { + } - this._cache = URL.createObjectURL( new Blob( [ value.value ] ) ); + j ++; + i --; - } else if ( value && value.value !== null && value.value !== undefined && ( - ( ( this.inputType === 'URL' || this.inputType === 'String' ) && typeof value.value === 'string' ) || - ( this.inputType === 'Number' && typeof value.value === 'number' ) || - ( this.inputType === 'Vector2' && value.value.isVector2 ) || - ( this.inputType === 'Vector3' && value.value.isVector3 ) || - ( this.inputType === 'Vector4' && value.value.isVector4 ) || - ( this.inputType === 'Color' && value.value.isColor ) || - ( this.inputType === 'Matrix3' && value.value.isMatrix3 ) || - ( this.inputType === 'Matrix4' && value.value.isMatrix4 ) - ) ) { + } - return value.value; + return magicSquare; - } +} - return this._cache || value; +const ao = ( depthNode, normalNode, camera ) => nodeObject( new GTAONode( nodeObject( depthNode ), nodeObject( normalNode ), camera ) ); - } +class DenoiseNode extends TempNode { - getNodeType( builder ) { + static get type() { - return this.value && this.value.isNode ? this.value.getNodeType( builder ) : 'float'; + return 'DenoiseNode'; } - setup() { + constructor( textureNode, depthNode, normalNode, noiseNode, camera ) { - return this.value && this.value.isNode ? this.value : float(); + super(); - } + this.textureNode = textureNode; + this.depthNode = depthNode; + this.normalNode = normalNode; + this.noiseNode = noiseNode; - serialize( data ) { + this.cameraProjectionMatrixInverse = uniform( camera.projectionMatrixInverse ); + this.lumaPhi = uniform( 5 ); + this.depthPhi = uniform( 5 ); + this.normalPhi = uniform( 5 ); + this.radius = uniform( 5 ); + this.index = uniform( 0 ); - super.serialize( data ); + this._resolution = uniform( new Vector2() ); + this._sampleVectors = uniformArray( generatePdSamplePointInitializer( 16, 2, 1 ) ); - if ( this.value !== null ) { + this.updateBeforeType = NodeUpdateType.RENDER; - if ( this.inputType === 'ArrayBuffer' ) { + } - data.value = arrayBufferToBase64( this.value ); + updateBefore() { - } else { + const map = this.textureNode.value; - data.value = this.value ? this.value.toJSON( data.meta ).uuid : null; + this._resolution.value.set( map.image.width, map.image.height ); - } + } - } else { + setup() { - data.value = null; + const uvNode = uv(); - } + const sampleTexture = ( uv ) => this.textureNode.uv( uv ); + const sampleDepth = ( uv ) => this.depthNode.uv( uv ).x; + const sampleNormal = ( uv ) => this.normalNode.uv( uv ); + const sampleNoise = ( uv ) => this.noiseNode.uv( uv ); - data.inputType = this.inputType; - data.outputType = this.outputType; + const getViewPosition = Fn( ( [ screenPosition, depth ] ) => { - } + screenPosition = vec2( screenPosition.x, screenPosition.y.oneMinus() ).mul( 2.0 ).sub( 1.0 ); - deserialize( data ) { + const clipSpacePosition = vec4( vec3( screenPosition, depth ), 1.0 ); + const viewSpacePosition = vec4( this.cameraProjectionMatrixInverse.mul( clipSpacePosition ) ); - super.deserialize( data ); + return viewSpacePosition.xyz.div( viewSpacePosition.w ); - let value = null; + } ); - if ( data.value !== null ) { + const denoiseSample = Fn( ( [ center, viewNormal, viewPosition, sampleUv ] ) => { - if ( data.inputType === 'ArrayBuffer' ) { + const texel = sampleTexture( sampleUv ); + const depth = sampleDepth( sampleUv ); + const normal = sampleNormal( sampleUv ).rgb.normalize(); + const neighborColor = texel.rgb; + const viewPos = getViewPosition( sampleUv, depth ); - value = base64ToArrayBuffer( data.value ); + const normalDiff = dot( viewNormal, normal ).toVar(); + const normalSimilarity = pow( max$1( normalDiff, 0 ), this.normalPhi ).toVar(); + const lumaDiff = abs( luminance( neighborColor ).sub( luminance( center ) ) ).toVar(); + const lumaSimilarity = max$1( float( 1.0 ).sub( lumaDiff.div( this.lumaPhi ) ), 0 ).toVar(); + const depthDiff = abs( dot( viewPosition.sub( viewPos ), viewNormal ) ).toVar(); + const depthSimilarity = max$1( float( 1.0 ).sub( depthDiff.div( this.depthPhi ) ), 0 ); + const w = lumaSimilarity.mul( depthSimilarity ).mul( normalSimilarity ); - } else if ( data.inputType === 'Texture' ) { + return vec4( neighborColor.mul( w ), w ); - value = data.meta.textures[ data.value ]; + } ); - } else { + const denoise = Fn( ( [ uvNode ] ) => { - value = data.meta.nodes[ data.value ] || null; + const depth = sampleDepth( uvNode ); + const viewNormal = sampleNormal( uvNode ).rgb.normalize(); - } + const texel = sampleTexture( uvNode ); - } + If( depth.greaterThanEqual( 1.0 ).or( dot( viewNormal, viewNormal ).equal( 0.0 ) ), () => { - this.value = value; + return texel; - this.inputType = data.inputType; - this.outputType = data.outputType; + } ); - } + const center = vec3( texel.rgb ); -} + const viewPosition = getViewPosition( uvNode, depth ); -ScriptableValueNode.type = /*@__PURE__*/ registerNode( 'ScriptableValue', ScriptableValueNode ); + const noiseResolution = textureSize( this.noiseNode, 0 ); + let noiseUv = vec2( uvNode.x, uvNode.y.oneMinus() ); + noiseUv = noiseUv.mul( this._resolution.div( noiseResolution ) ); + const noiseTexel = sampleNoise( noiseUv ); -const scriptableValue = /*@__PURE__*/ nodeProxy( ScriptableValueNode ); + const x = sin( noiseTexel.element( this.index.mod( 4 ).mul( 2 ).mul( PI ) ) ); + const y = cos( noiseTexel.element( this.index.mod( 4 ).mul( 2 ).mul( PI ) ) ); -class Resources extends Map { + const noiseVec = vec2( x, y ); + const rotationMatrix = mat2( noiseVec.x, noiseVec.y.negate(), noiseVec.x, noiseVec.y ); - get( key, callback = null, ...params ) { + const totalWeight = float( 1.0 ).toVar(); + const denoised = vec3( texel.rgb ).toVar(); - if ( this.has( key ) ) return super.get( key ); + Loop( { start: int( 0 ), end: int( 16 ), type: 'int', condition: '<' }, ( { i } ) => { - if ( callback !== null ) { + const sampleDir = this._sampleVectors.element( i ).toVar(); + const offset = rotationMatrix.mul( sampleDir.xy.mul( float( 1.0 ).add( sampleDir.z.mul( this.radius.sub( 1 ) ) ) ) ).div( this._resolution ).toVar(); + const sampleUv = uvNode.add( offset ).toVar(); - const value = callback( ...params ); - this.set( key, value ); - return value; + const result = denoiseSample( center, viewNormal, viewPosition, sampleUv ); - } + denoised.addAssign( result.xyz ); + totalWeight.addAssign( result.w ); - } + } ); -} + If( totalWeight.greaterThan( float( 0 ) ), () => { -class Parameters { + denoised.divAssign( totalWeight ); - constructor( scriptableNode ) { + } ); - this.scriptableNode = scriptableNode; + return vec4( denoised, texel.a ); - } + } ).setLayout( { + name: 'denoise', + type: 'vec4', + inputs: [ + { name: 'uv', type: 'vec2' } + ] + } ); - get parameters() { + const output = Fn( () => { - return this.scriptableNode.parameters; + return denoise( uvNode ); - } + } ); - get layout() { + const outputNode = output(); - return this.scriptableNode.getLayout(); + return outputNode; } - getInputLayout( id ) { +} - return this.scriptableNode.getInputLayout( id ); +function generatePdSamplePointInitializer( samples, rings, radiusExponent ) { - } + const poissonDisk = generateDenoiseSamples( samples, rings, radiusExponent ); - get( name ) { + const array = []; - const param = this.parameters[ name ]; - const value = param ? param.getValue() : null; + for ( let i = 0; i < samples; i ++ ) { - return value; + const sample = poissonDisk[ i ]; + array.push( sample ); } + return array; + } -const global = new Resources(); +function generateDenoiseSamples( numSamples, numRings, radiusExponent ) { -class ScriptableNode extends Node { + const samples = []; - constructor( codeNode = null, parameters = {} ) { + for ( let i = 0; i < numSamples; i ++ ) { - super(); + const angle = 2 * Math.PI * numRings * i / numSamples; + const radius = Math.pow( i / ( numSamples - 1 ), radiusExponent ); + samples.push( new Vector3( Math.cos( angle ), Math.sin( angle ), radius ) ); - this.codeNode = codeNode; - this.parameters = parameters; + } - this._local = new Resources(); - this._output = scriptableValue(); - this._outputs = {}; - this._source = this.source; - this._method = null; - this._object = null; - this._value = null; - this._needsOutputUpdate = true; + return samples; - this.onRefresh = this.onRefresh.bind( this ); +} - this.isScriptableNode = true; +const denoise = ( node, depthNode, normalNode, noiseNode, camera ) => nodeObject( new DenoiseNode( convertToTexture( node ), nodeObject( depthNode ), nodeObject( normalNode ), nodeObject( noiseNode ), camera ) ); - } +class FXAANode extends TempNode { - get source() { + static get type() { - return this.codeNode ? this.codeNode.code : ''; + return 'FXAANode'; } - setLocal( name, value ) { + constructor( textureNode ) { - return this._local.set( name, value ); + super(); - } + this.textureNode = textureNode; - getLocal( name ) { + this.updateBeforeType = NodeUpdateType.RENDER; - return this._local.get( name ); + this._invSize = uniform( new Vector2() ); } - onRefresh() { + updateBefore() { - this._refresh(); + const map = this.textureNode.value; + + this._invSize.value.set( 1 / map.image.width, 1 / map.image.height ); } - getInputLayout( id ) { + setup() { - for ( const element of this.getLayout() ) { + const textureNode = this.textureNode.bias( - 100 ); + const uvNode = textureNode.uvNode || uv(); - if ( element.inputType && ( element.id === id || element.name === id ) ) { + // FXAA 3.11 implementation by NVIDIA, ported to WebGL by Agost Biro (biro@archilogic.com) - return element; + //---------------------------------------------------------------------------------- + // File: es3-kepler\FXAA\assets\shaders/FXAA_DefaultES.frag + // SDK Version: v3.00 + // Email: gameworks@nvidia.com + // Site: http://developer.nvidia.com/ + // + // Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. + // + // Redistribution and use in source and binary forms, with or without + // modification, are permitted provided that the following conditions + // are met: + // * Redistributions of source code must retain the above copyright + // notice, this list of conditions and the following disclaimer. + // * Redistributions in binary form must reproduce the above copyright + // notice, this list of conditions and the following disclaimer in the + // documentation and/or other materials provided with the distribution. + // * Neither the name of NVIDIA CORPORATION nor the names of its + // contributors may be used to endorse or promote products derived + // from this software without specific prior written permission. + // + // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + // + //---------------------------------------------------------------------------------- - } + const FxaaTexTop = ( p ) => textureNode.uv( p ); + const FxaaTexOff = ( p, o, r ) => textureNode.uv( p.add( o.mul( r ) ) ); - } + const NUM_SAMPLES = int( 5 ); - } + const contrast = Fn( ( [ a_immutable, b_immutable ] ) => { - getOutputLayout( id ) { + // assumes colors have premultipliedAlpha, so that the calculated color contrast is scaled by alpha - for ( const element of this.getLayout() ) { + const b = vec4( b_immutable ).toVar(); + const a = vec4( a_immutable ).toVar(); + const diff = vec4( abs( a.sub( b ) ) ).toVar(); - if ( element.outputType && ( element.id === id || element.name === id ) ) { + return max$1( max$1( max$1( diff.r, diff.g ), diff.b ), diff.a ); - return element; + } ); - } + // FXAA3 QUALITY - PC - } + const FxaaPixelShader = Fn( ( [ uv, fxaaQualityRcpFrame, fxaaQualityEdgeThreshold, fxaaQualityinvEdgeThreshold ] ) => { - } + const rgbaM = FxaaTexTop( uv ).toVar(); + const rgbaS = FxaaTexOff( uv, vec2( 0.0, - 1.0 ), fxaaQualityRcpFrame.xy ).toVar(); + const rgbaE = FxaaTexOff( uv, vec2( 1.0, 0.0 ), fxaaQualityRcpFrame.xy ).toVar(); + const rgbaN = FxaaTexOff( uv, vec2( 0.0, 1.0 ), fxaaQualityRcpFrame.xy ).toVar(); + const rgbaW = FxaaTexOff( uv, vec2( - 1.0, 0.0 ), fxaaQualityRcpFrame.xy ).toVar(); + // . S . + // W M E + // . N . - setOutput( name, value ) { + const contrastN = contrast( rgbaM, rgbaN ).toVar(); + const contrastS = contrast( rgbaM, rgbaS ).toVar(); + const contrastE = contrast( rgbaM, rgbaE ).toVar(); + const contrastW = contrast( rgbaM, rgbaW ).toVar(); - const outputs = this._outputs; + const maxValue = max$1( contrastN, max$1( contrastS, max$1( contrastE, contrastW ) ) ).toVar(); - if ( outputs[ name ] === undefined ) { + // . 0 . + // 0 0 0 + // . 0 . - outputs[ name ] = scriptableValue( value ); + If( maxValue.lessThan( fxaaQualityEdgeThreshold ), () => { - } else { + return rgbaM; // assuming define FXAA_DISCARD is always 0 - outputs[ name ].value = value; + } ); - } + // - return this; + const relativeVContrast = sub( contrastN.add( contrastS ), ( contrastE.add( contrastW ) ) ).toVar(); + relativeVContrast.mulAssign( fxaaQualityinvEdgeThreshold ); - } + // 45 deg edge detection and corners of objects, aka V/H contrast is too similar - getOutput( name ) { + If( abs( relativeVContrast ).lessThan( 0.3 ), () => { - return this._outputs[ name ]; + // locate the edge - } + const x = contrastE.greaterThan( contrastW ).select( 1, - 1 ).toVar(); + const y = contrastS.greaterThan( contrastN ).select( 1, - 1 ).toVar(); - getParameter( name ) { + const dirToEdge = vec2( x, y ).toVar(); + // . 2 . . 1 . + // 1 0 2 ~= 0 0 1 + // . 1 . . 0 . - return this.parameters[ name ]; + // tap 2 pixels and see which ones are "outside" the edge, to + // determine if the edge is vertical or horizontal - } + const rgbaAlongH = FxaaTexOff( uv, vec2( dirToEdge.x, dirToEdge.y ), fxaaQualityRcpFrame.xy ); + const matchAlongH = contrast( rgbaM, rgbaAlongH ).toVar(); + // . 1 . + // 0 0 1 + // . 0 H - setParameter( name, value ) { + const rgbaAlongV = FxaaTexOff( uv, vec2( dirToEdge.x.negate(), dirToEdge.y.negate() ), fxaaQualityRcpFrame.xy ); + const matchAlongV = contrast( rgbaM, rgbaAlongV ).toVar(); + // V 1 . + // 0 0 1 + // . 0 . - const parameters = this.parameters; + relativeVContrast.assign( matchAlongV.sub( matchAlongH ) ); + relativeVContrast.mulAssign( fxaaQualityinvEdgeThreshold ); - if ( value && value.isScriptableNode ) { + If( abs( relativeVContrast ).lessThan( 0.3 ), () => { // 45 deg edge - this.deleteParameter( name ); + // 1 1 . + // 0 0 1 + // . 0 1 - parameters[ name ] = value; - parameters[ name ].getDefaultOutput().events.addEventListener( 'refresh', this.onRefresh ); + // do a simple blur + const sum = rgbaN.add( rgbaS ).add( rgbaE ).add( rgbaW ); + return mix( rgbaM, sum.mul( 0.25 ), 0.4 ); - } else if ( value && value.isScriptableValueNode ) { + } ); - this.deleteParameter( name ); + } ); - parameters[ name ] = value; - parameters[ name ].events.addEventListener( 'refresh', this.onRefresh ); + const offNP = vec2().toVar(); - } else if ( parameters[ name ] === undefined ) { + If( relativeVContrast.lessThanEqual( 0 ), () => { - parameters[ name ] = scriptableValue( value ); - parameters[ name ].events.addEventListener( 'refresh', this.onRefresh ); + rgbaN.assign( rgbaW ); + rgbaS.assign( rgbaE ); - } else { + // . 0 . 1 + // 1 0 1 -> 0 + // . 0 . 1 - parameters[ name ].value = value; + offNP.x.assign( 0 ); + offNP.y.assign( fxaaQualityRcpFrame.y ); - } + } ).Else( () => { - return this; + offNP.x.assign( fxaaQualityRcpFrame.x ); + offNP.y.assign( 0 ); - } + } ); - getValue() { + const mn = contrast( rgbaM, rgbaN ).toVar(); + const ms = contrast( rgbaM, rgbaS ).toVar(); - return this.getDefaultOutput().getValue(); + If( mn.lessThanEqual( ms ), () => { - } + rgbaN.assign( rgbaS ); - deleteParameter( name ) { + } ); - let valueNode = this.parameters[ name ]; + const doneN = int( 0 ).toVar(); + const doneP = int( 0 ).toVar(); - if ( valueNode ) { + const nDist = float( 0 ).toVar(); + const pDist = float( 0 ).toVar(); - if ( valueNode.isScriptableNode ) valueNode = valueNode.getDefaultOutput(); + const posN = vec2( uv ).toVar(); + const posP = vec2( uv ).toVar(); - valueNode.events.removeEventListener( 'refresh', this.onRefresh ); + const iterationsUsedN = int( 0 ).toVar(); + const iterationsUsedP = int( 0 ).toVar(); - } + Loop( NUM_SAMPLES, ( { i } ) => { - return this; + const increment = i.add( 1 ).toVar(); - } + If( doneN.equal( 0 ), () => { - clearParameters() { + nDist.addAssign( increment ); + posN.assign( uv.add( offNP.mul( nDist ) ) ); + const rgbaEndN = FxaaTexTop( posN.xy ); - for ( const name of Object.keys( this.parameters ) ) { + const nm = contrast( rgbaEndN, rgbaM ).toVar(); + const nn = contrast( rgbaEndN, rgbaN ).toVar(); - this.deleteParameter( name ); + If( nm.greaterThan( nn ), () => { - } + doneN.assign( 1 ); - this.needsUpdate = true; + } ); - return this; + iterationsUsedN.assign( i ); - } + } ); - call( name, ...params ) { - - const object = this.getObject(); - const method = object[ name ]; + If( doneP.equal( 0 ), () => { - if ( typeof method === 'function' ) { + pDist.addAssign( increment ); + posP.assign( uv.sub( offNP.mul( pDist ) ) ); + const rgbaEndP = FxaaTexTop( posP.xy ); - return method( ...params ); + const pm = contrast( rgbaEndP, rgbaM ).toVar(); + const pn = contrast( rgbaEndP, rgbaN ).toVar(); - } + If( pm.greaterThan( pn ), () => { - } + doneP.assign( 1 ); - async callAsync( name, ...params ) { + } ); - const object = this.getObject(); - const method = object[ name ]; + iterationsUsedP.assign( i ); - if ( typeof method === 'function' ) { + } ); - return method.constructor.name === 'AsyncFunction' ? await method( ...params ) : method( ...params ); + If( doneN.equal( 1 ).or( doneP.equal( 1 ) ), () => { - } + Break(); - } + } ); - getNodeType( builder ) { + } ); - return this.getDefaultOutputNode().getNodeType( builder ); + If( doneN.equal( 0 ).and( doneP.equal( 0 ) ), () => { - } + return rgbaM; // failed to find end of edge - refresh( output = null ) { + } ); - if ( output !== null ) { + const distN = float( 1 ).toVar(); + const distP = float( 1 ).toVar(); - this.getOutput( output ).refresh(); + If( doneN.equal( 1 ), () => { - } else { + distN.assign( float( iterationsUsedN ).div( float( NUM_SAMPLES.sub( 1 ) ) ) ); - this._refresh(); + } ); - } + If( doneP.equal( 1 ), () => { - } + distP.assign( float( iterationsUsedP ).div( float( NUM_SAMPLES.sub( 1 ) ) ) ); - getObject() { + } ); - if ( this.needsUpdate ) this.dispose(); - if ( this._object !== null ) return this._object; + const dist = min$1( distN, distP ); - // + // hacky way of reduces blurriness of mostly diagonal edges + // but reduces AA quality + dist.assign( pow( dist, 0.5 ) ); + dist.assign( float( 1 ).sub( dist ) ); - const refresh = () => this.refresh(); - const setOutput = ( id, value ) => this.setOutput( id, value ); + return mix( rgbaM, rgbaN, dist.mul( 0.5 ) ); - const parameters = new Parameters( this ); + } ).setLayout( { + name: 'FxaaPixelShader', + type: 'vec4', + inputs: [ + { name: 'uv', type: 'vec2' }, + { name: 'fxaaQualityRcpFrame', type: 'vec2' }, + { name: 'fxaaQualityEdgeThreshold', type: 'float' }, + { name: 'fxaaQualityinvEdgeThreshold', type: 'float' }, + ] + } ); - const THREE = global.get( 'THREE' ); - const TSL = global.get( 'TSL' ); + const fxaa = Fn( () => { - const method = this.getMethod( this.codeNode ); - const params = [ parameters, this._local, global, refresh, setOutput, THREE, TSL ]; + const edgeDetectionQuality = float( 0.2 ); + const invEdgeDetectionQuality = float( 1 ).div( edgeDetectionQuality ); - this._object = method( ...params ); + return FxaaPixelShader( uvNode, this._invSize, edgeDetectionQuality, invEdgeDetectionQuality ); - const layout = this._object.layout; + } ); - if ( layout ) { + const outputNode = fxaa(); - if ( layout.cache === false ) { + return outputNode; - this._local.clear(); + } - } +} - // default output - this._output.outputType = layout.outputType || null; +const fxaa = ( node ) => nodeObject( new FXAANode( convertToTexture( node ) ) ); - if ( Array.isArray( layout.elements ) ) { +const _quadMesh$3 = /*@__PURE__*/ new QuadMesh(); - for ( const element of layout.elements ) { +const _clearColor$1 = /*@__PURE__*/ new Color( 0, 0, 0 ); +const _currentClearColor = /*@__PURE__*/ new Color(); +const _size$4 = /*@__PURE__*/ new Vector2(); - const id = element.id || element.name; +const _BlurDirectionX = /*@__PURE__*/ new Vector2( 1.0, 0.0 ); +const _BlurDirectionY = /*@__PURE__*/ new Vector2( 0.0, 1.0 ); - if ( element.inputType ) { +class BloomNode extends TempNode { - if ( this.getParameter( id ) === undefined ) this.setParameter( id, null ); + static get type() { - this.getParameter( id ).inputType = element.inputType; + return 'BloomNode'; - } + } - if ( element.outputType ) { + constructor( inputNode, strength = 1, radius = 0, threshold = 0 ) { - if ( this.getOutput( id ) === undefined ) this.setOutput( id, null ); + super(); - this.getOutput( id ).outputType = element.outputType; + this.inputNode = inputNode; + this.strength = uniform( strength ); + this.radius = uniform( radius ); + this.threshold = uniform( threshold ); - } + this.smoothWidth = uniform( 0.01 ); - } + // - } + this._renderTargetsHorizontal = []; + this._renderTargetsVertical = []; + this._nMips = 5; - } + // render targets - return this._object; + this._renderTargetBright = new RenderTarget( 1, 1, { type: HalfFloatType } ); + this._renderTargetBright.texture.name = 'UnrealBloomPass.bright'; + this._renderTargetBright.texture.generateMipmaps = false; - } + for ( let i = 0; i < this._nMips; i ++ ) { - deserialize( data ) { + const renderTargetHorizontal = new RenderTarget( 1, 1, { type: HalfFloatType } ); - super.deserialize( data ); + renderTargetHorizontal.texture.name = 'UnrealBloomPass.h' + i; + renderTargetHorizontal.texture.generateMipmaps = false; - for ( const name in this.parameters ) { + this._renderTargetsHorizontal.push( renderTargetHorizontal ); - let valueNode = this.parameters[ name ]; + const renderTargetVertical = new RenderTarget( 1, 1, { type: HalfFloatType } ); - if ( valueNode.isScriptableNode ) valueNode = valueNode.getDefaultOutput(); + renderTargetVertical.texture.name = 'UnrealBloomPass.v' + i; + renderTargetVertical.texture.generateMipmaps = false; - valueNode.events.addEventListener( 'refresh', this.onRefresh ); + this._renderTargetsVertical.push( renderTargetVertical ); } - } + // materials - getLayout() { + this._compositeMaterial = null; + this._highPassFilterMaterial = null; + this._separableBlurMaterials = []; - return this.getObject().layout; + // pass and texture nodes + + this._textureNodeBright = texture( this._renderTargetBright.texture ); + this._textureNodeBlur0 = texture( this._renderTargetsVertical[ 0 ].texture ); + this._textureNodeBlur1 = texture( this._renderTargetsVertical[ 1 ].texture ); + this._textureNodeBlur2 = texture( this._renderTargetsVertical[ 2 ].texture ); + this._textureNodeBlur3 = texture( this._renderTargetsVertical[ 3 ].texture ); + this._textureNodeBlur4 = texture( this._renderTargetsVertical[ 4 ].texture ); + + this._textureOutput = passTexture( this, this._renderTargetsHorizontal[ 0 ].texture ); + + this.updateBeforeType = NodeUpdateType.FRAME; } - getDefaultOutputNode() { + getTextureNode() { - const output = this.getDefaultOutput().value; + return this._textureOutput; - if ( output && output.isNode ) { + } - return output; + setSize( width, height ) { - } + let resx = Math.round( width / 2 ); + let resy = Math.round( height / 2 ); - return float(); + this._renderTargetBright.setSize( resx, resy ); - } + for ( let i = 0; i < this._nMips; i ++ ) { - getDefaultOutput() { + this._renderTargetsHorizontal[ i ].setSize( resx, resy ); + this._renderTargetsVertical[ i ].setSize( resx, resy ); - return this._exec()._output; + this._separableBlurMaterials[ i ].invSize.value.set( 1 / resx, 1 / resy ); + + resx = Math.round( resx / 2 ); + resy = Math.round( resy / 2 ); + + } } - getMethod() { + updateBefore( frame ) { - if ( this.needsUpdate ) this.dispose(); - if ( this._method !== null ) return this._method; + const { renderer } = frame; - // + const size = renderer.getDrawingBufferSize( _size$4 ); + this.setSize( size.width, size.height ); - const parametersProps = [ 'parameters', 'local', 'global', 'refresh', 'setOutput', 'THREE', 'TSL' ]; - const interfaceProps = [ 'layout', 'init', 'main', 'dispose' ]; + const currentRenderTarget = renderer.getRenderTarget(); + const currentMRT = renderer.getMRT(); + renderer.getClearColor( _currentClearColor ); + const currentClearAlpha = renderer.getClearAlpha(); - const properties = interfaceProps.join( ', ' ); - const declarations = 'var ' + properties + '; var output = {};\n'; - const returns = '\nreturn { ...output, ' + properties + ' };'; + this.setSize( size.width, size.height ); - const code = declarations + this.codeNode.code + returns; + renderer.setMRT( null ); + renderer.setClearColor( _clearColor$1, 0 ); - // + // 1. Extract Bright Areas - this._method = new Function( ...parametersProps, code ); + renderer.setRenderTarget( this._renderTargetBright ); + _quadMesh$3.material = this._highPassFilterMaterial; + _quadMesh$3.render( renderer ); - return this._method; + // 2. Blur All the mips progressively - } + let inputRenderTarget = this._renderTargetBright; - dispose() { + for ( let i = 0; i < this._nMips; i ++ ) { - if ( this._method === null ) return; + _quadMesh$3.material = this._separableBlurMaterials[ i ]; - if ( this._object && typeof this._object.dispose === 'function' ) { + this._separableBlurMaterials[ i ].colorTexture.value = inputRenderTarget.texture; + this._separableBlurMaterials[ i ].direction.value = _BlurDirectionX; + renderer.setRenderTarget( this._renderTargetsHorizontal[ i ] ); + renderer.clear(); + _quadMesh$3.render( renderer ); - this._object.dispose(); + this._separableBlurMaterials[ i ].colorTexture.value = this._renderTargetsHorizontal[ i ].texture; + this._separableBlurMaterials[ i ].direction.value = _BlurDirectionY; + renderer.setRenderTarget( this._renderTargetsVertical[ i ] ); + renderer.clear(); + _quadMesh$3.render( renderer ); + + inputRenderTarget = this._renderTargetsVertical[ i ]; } - this._method = null; - this._object = null; - this._source = null; - this._value = null; - this._needsOutputUpdate = true; - this._output.value = null; - this._outputs = {}; + // 3. Composite All the mips - } + renderer.setRenderTarget( this._renderTargetsHorizontal[ 0 ] ); + renderer.clear(); + _quadMesh$3.material = this._compositeMaterial; + _quadMesh$3.render( renderer ); - setup() { + // restore - return this.getDefaultOutputNode(); + renderer.setRenderTarget( currentRenderTarget ); + renderer.setMRT( currentMRT ); + renderer.setClearColor( _currentClearColor, currentClearAlpha ); } - getCacheKey( force ) { + setup( builder ) { - const cacheKey = [ this.source, this.getDefaultOutputNode().getCacheKey( force ) ]; + // luminosity high pass material - for ( const param in this.parameters ) { + const luminosityHighPass = Fn( () => { - cacheKey.push( this.parameters[ param ].getCacheKey( force ) ); + const texel = this.inputNode; + const v = luminance( texel.rgb ); - } + const alpha = smoothstep( this.threshold, this.threshold.add( this.smoothWidth ), v ); - return cacheKey.join( ',' ); + return mix( vec4( 0 ), texel, alpha ); - } + } ); - set needsUpdate( value ) { + this._highPassFilterMaterial = this._highPassFilterMaterial || new NodeMaterial(); + this._highPassFilterMaterial.fragmentNode = luminosityHighPass().context( builder.getSharedContext() ); + this._highPassFilterMaterial.name = 'Bloom_highPass'; + this._highPassFilterMaterial.needsUpdate = true; - if ( value === true ) this.dispose(); + // gaussian blur materials - } + const kernelSizeArray = [ 3, 5, 7, 9, 11 ]; - get needsUpdate() { + for ( let i = 0; i < this._nMips; i ++ ) { - return this.source !== this._source; + this._separableBlurMaterials.push( this._getSeperableBlurMaterial( builder, kernelSizeArray[ i ] ) ); - } + } - _exec() { + // composite material - if ( this.codeNode === null ) return this; + const bloomFactors = uniformArray( [ 1.0, 0.8, 0.6, 0.4, 0.2 ] ); + const bloomTintColors = uniformArray( [ new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ) ] ); - if ( this._needsOutputUpdate === true ) { + const lerpBloomFactor = Fn( ( [ factor, radius ] ) => { - this._value = this.call( 'main' ); + const mirrorFactor = float( 1.2 ).sub( factor ); + return mix( factor, mirrorFactor, radius ); - this._needsOutputUpdate = false; + } ).setLayout( { + name: 'lerpBloomFactor', + type: 'float', + inputs: [ + { name: 'factor', type: 'float' }, + { name: 'radius', type: 'float' }, + ] + } ); - } - this._output.value = this._value; + const compositePass = Fn( () => { - return this; + const color0 = lerpBloomFactor( bloomFactors.element( 0 ), this.radius ).mul( vec4( bloomTintColors.element( 0 ), 1.0 ) ).mul( this._textureNodeBlur0 ); + const color1 = lerpBloomFactor( bloomFactors.element( 1 ), this.radius ).mul( vec4( bloomTintColors.element( 1 ), 1.0 ) ).mul( this._textureNodeBlur1 ); + const color2 = lerpBloomFactor( bloomFactors.element( 2 ), this.radius ).mul( vec4( bloomTintColors.element( 2 ), 1.0 ) ).mul( this._textureNodeBlur2 ); + const color3 = lerpBloomFactor( bloomFactors.element( 3 ), this.radius ).mul( vec4( bloomTintColors.element( 3 ), 1.0 ) ).mul( this._textureNodeBlur3 ); + const color4 = lerpBloomFactor( bloomFactors.element( 4 ), this.radius ).mul( vec4( bloomTintColors.element( 4 ), 1.0 ) ).mul( this._textureNodeBlur4 ); - } + const sum = color0.add( color1 ).add( color2 ).add( color3 ).add( color4 ); - _refresh() { + return sum.mul( this.strength ); - this.needsUpdate = true; + } ); - this._exec(); + this._compositeMaterial = this._compositeMaterial || new NodeMaterial(); + this._compositeMaterial.fragmentNode = compositePass().context( builder.getSharedContext() ); + this._compositeMaterial.name = 'Bloom_comp'; + this._compositeMaterial.needsUpdate = true; - this._output.refresh(); + // + + return this._textureOutput; } -} + dispose() { -ScriptableNode.type = /*@__PURE__*/ registerNode( 'Scriptable', ScriptableNode ); + for ( let i = 0; i < this._renderTargetsHorizontal.length; i ++ ) { -const scriptable = /*@__PURE__*/ nodeProxy( ScriptableNode ); + this._renderTargetsHorizontal[ i ].dispose(); -class FogNode extends Node { + } - constructor( colorNode, factorNode ) { + for ( let i = 0; i < this._renderTargetsVertical.length; i ++ ) { - super( 'float' ); + this._renderTargetsVertical[ i ].dispose(); - this.isFogNode = true; + } - this.colorNode = colorNode; - this.factorNode = factorNode; + this._renderTargetBright.dispose(); } - getViewZNode( builder ) { - - let viewZ; + _getSeperableBlurMaterial( builder, kernelRadius ) { - const getViewZ = builder.context.getViewZ; + const coefficients = []; - if ( getViewZ !== undefined ) { + for ( let i = 0; i < kernelRadius; i ++ ) { - viewZ = getViewZ( this ); + coefficients.push( 0.39894 * Math.exp( - 0.5 * i * i / ( kernelRadius * kernelRadius ) ) / kernelRadius ); } - return ( viewZ || positionView.z ).negate(); + // - } + const colorTexture = texture(); + const gaussianCoefficients = uniformArray( coefficients ); + const invSize = uniform( new Vector2() ); + const direction = uniform( new Vector2( 0.5, 0.5 ) ); - setup() { + const uvNode = uv(); + const sampleTexel = ( uv ) => colorTexture.uv( uv ); - return this.factorNode; + const seperableBlurPass = Fn( () => { - } + const weightSum = gaussianCoefficients.element( 0 ).toVar(); + const diffuseSum = sampleTexel( uvNode ).rgb.mul( weightSum ).toVar(); -} + Loop( { start: int( 1 ), end: int( kernelRadius ), type: 'int', condition: '<' }, ( { i } ) => { -FogNode.type = /*@__PURE__*/ registerNode( 'Fog', FogNode ); + const x = float( i ); + const w = gaussianCoefficients.element( i ); + const uvOffset = direction.mul( invSize ).mul( x ); + const sample1 = sampleTexel( uvNode.add( uvOffset ) ).rgb; + const sample2 = sampleTexel( uvNode.sub( uvOffset ) ).rgb; + diffuseSum.addAssign( add( sample1, sample2 ).mul( w ) ); + weightSum.addAssign( float( 2.0 ).mul( w ) ); -const fog = /*@__PURE__*/ nodeProxy( FogNode ); + } ); -class FogRangeNode extends FogNode { + return vec4( diffuseSum.div( weightSum ), 1.0 ); - constructor( colorNode, nearNode, farNode ) { + } ); - super( colorNode ); + const seperableBlurMaterial = new NodeMaterial(); + seperableBlurMaterial.fragmentNode = seperableBlurPass().context( builder.getSharedContext() ); + seperableBlurMaterial.name = 'Bloom_seperable'; + seperableBlurMaterial.needsUpdate = true; - this.isFogRangeNode = true; + // uniforms + seperableBlurMaterial.colorTexture = colorTexture; + seperableBlurMaterial.direction = direction; + seperableBlurMaterial.invSize = invSize; - this.nearNode = nearNode; - this.farNode = farNode; + return seperableBlurMaterial; } - setup( builder ) { +} - const viewZ = this.getViewZNode( builder ); +const bloom = ( node, strength, radius, threshold ) => nodeObject( new BloomNode( nodeObject( node ), strength, radius, threshold ) ); - return smoothstep( this.nearNode, this.farNode, viewZ ); +class TransitionNode extends TempNode { - } + static get type() { -} + return 'TransitionNode'; -FogRangeNode.type = /*@__PURE__*/ registerNode( 'FogRange', FogRangeNode ); + } -const rangeFog = /*@__PURE__*/ nodeProxy( FogRangeNode ); + constructor( textureNodeA, textureNodeB, mixTextureNode, mixRatioNode, thresholdNode, useTextureNode ) { -class FogExp2Node extends FogNode { + super(); - constructor( colorNode, densityNode ) { + // Input textures - super( colorNode ); + this.textureNodeA = textureNodeA; + this.textureNodeB = textureNodeB; + this.mixTextureNode = mixTextureNode; - this.isFogExp2Node = true; + // Uniforms - this.densityNode = densityNode; + this.mixRatioNode = mixRatioNode; + this.thresholdNode = thresholdNode; + this.useTextureNode = useTextureNode; } - setup( builder ) { - - const viewZ = this.getViewZNode( builder ); - const density = this.densityNode; + setup() { - return density.mul( density, viewZ, viewZ ).negate().exp().oneMinus(); + const { textureNodeA, textureNodeB, mixTextureNode, mixRatioNode, thresholdNode, useTextureNode } = this; - } + const sampleTexture = ( textureNode ) => { -} + const uvNodeTexture = textureNode.uvNode || uv(); + return textureNode.uv( uvNodeTexture ); -FogExp2Node.type = /*@__PURE__*/ registerNode( 'FogExp2', FogExp2Node ); + }; -const densityFog = /*@__PURE__*/ nodeProxy( FogExp2Node ); + const transition = Fn( () => { -let min = null; -let max = null; + const texelOne = sampleTexture( textureNodeA ); + const texelTwo = sampleTexture( textureNodeB ); -class RangeNode extends Node { + const color = vec4().toVar(); - constructor( minNode = float(), maxNode = float() ) { + If( useTextureNode.equal( int( 1 ) ), () => { - super(); + const transitionTexel = sampleTexture( mixTextureNode ); + const r = mixRatioNode.mul( thresholdNode.mul( 2.0 ).add( 1.0 ) ).sub( thresholdNode ); + const mixf = clamp( sub( transitionTexel.r, r ).mul( float( 1.0 ).div( thresholdNode ) ), 0.0, 1.0 ); - this.minNode = minNode; - this.maxNode = maxNode; + color.assign( mix( texelOne, texelTwo, mixf ) ); - } + } ).Else( () => { - getVectorLength( builder ) { + color.assign( mix( texelTwo, texelOne, mixRatioNode ) ); - const minLength = builder.getTypeLength( getValueType( this.minNode.value ) ); - const maxLength = builder.getTypeLength( getValueType( this.maxNode.value ) ); + } ); - return minLength > maxLength ? minLength : maxLength; + return color; - } + } ); - getNodeType( builder ) { + const outputNode = transition(); - return builder.object.count > 1 ? builder.getTypeFromLength( this.getVectorLength( builder ) ) : 'float'; + return outputNode; } - setup( builder ) { +} - const object = builder.object; +const transition = ( nodeA, nodeB, mixTexture, mixRatio = 0.0, threshold = 0.1, useTexture = 0 ) => nodeObject( new TransitionNode( convertToTexture( nodeA ), convertToTexture( nodeB ), convertToTexture( mixTexture ), nodeObject( mixRatio ), nodeObject( threshold ), nodeObject( useTexture ) ) ); - let output = null; +class PixelationNode extends TempNode { - if ( object.count > 1 ) { + static get type() { - const minValue = this.minNode.value; - const maxValue = this.maxNode.value; + return 'PixelationNode'; - const minLength = builder.getTypeLength( getValueType( minValue ) ); - const maxLength = builder.getTypeLength( getValueType( maxValue ) ); + } - min = min || new Vector4(); - max = max || new Vector4(); + constructor( textureNode, depthNode, normalNode, pixelSize, normalEdgeStrength, depthEdgeStrength ) { - min.setScalar( 0 ); - max.setScalar( 0 ); + super(); - if ( minLength === 1 ) min.setScalar( minValue ); - else if ( minValue.isColor ) min.set( minValue.r, minValue.g, minValue.b ); - else min.set( minValue.x, minValue.y, minValue.z || 0, minValue.w || 0 ); + // Input textures - if ( maxLength === 1 ) max.setScalar( maxValue ); - else if ( maxValue.isColor ) max.set( maxValue.r, maxValue.g, maxValue.b ); - else max.set( maxValue.x, maxValue.y, maxValue.z || 0, maxValue.w || 0 ); + this.textureNode = textureNode; + this.depthNode = depthNode; + this.normalNode = normalNode; - const stride = 4; + // Input uniforms - const length = stride * object.count; - const array = new Float32Array( length ); + this.pixelSize = pixelSize; + this.normalEdgeStrength = normalEdgeStrength; + this.depthEdgeStrength = depthEdgeStrength; - for ( let i = 0; i < length; i ++ ) { + // Private uniforms - const index = i % stride; + this._resolution = uniform( new Vector4() ); - const minElementValue = min.getComponent( index ); - const maxElementValue = max.getComponent( index ); + this.updateBeforeType = NodeUpdateType.RENDER; - array[ i ] = MathUtils.lerp( minElementValue, maxElementValue, Math.random() ); + } - } + updateBefore() { - const nodeType = this.getNodeType( builder ); - - if ( object.count <= 4096 ) { + const map = this.textureNode.value; - output = buffer( array, 'vec4', object.count ).element( instanceIndex ).convert( nodeType ); + const width = map.image.width; + const height = map.image.height; - } else { + this._resolution.value.set( width, height, 1 / width, 1 / height ); - // TODO: Improve anonymous buffer attribute creation removing this part - const bufferAttribute = new InstancedBufferAttribute( array, 4 ); - builder.geometry.setAttribute( '__range' + this.id, bufferAttribute ); + } - output = instancedBufferAttribute( bufferAttribute ).convert( nodeType ); + setup() { - } + const { textureNode, depthNode, normalNode } = this; - } else { + const uvNodeTexture = textureNode.uvNode || uv(); + const uvNodeDepth = depthNode.uvNode || uv(); + const uvNodeNormal = normalNode.uvNode || uv(); - output = float( 0 ); + const sampleTexture = () => textureNode.uv( uvNodeTexture ); - } + const sampleDepth = ( x, y ) => depthNode.uv( uvNodeDepth.add( vec2( x, y ).mul( this._resolution.zw ) ) ).r; - return output; + const sampleNormal = ( x, y ) => normalNode.uv( uvNodeNormal.add( vec2( x, y ).mul( this._resolution.zw ) ) ).rgb.normalize(); - } + const depthEdgeIndicator = ( depth ) => { -} + const diff = property( 'float', 'diff' ); + diff.addAssign( clamp( sampleDepth( 1, 0 ).sub( depth ) ) ); + diff.addAssign( clamp( sampleDepth( - 1, 0 ).sub( depth ) ) ); + diff.addAssign( clamp( sampleDepth( 0, 1 ).sub( depth ) ) ); + diff.addAssign( clamp( sampleDepth( 0, - 1 ).sub( depth ) ) ); -RangeNode.type = /*@__PURE__*/ registerNode( 'Range', RangeNode ); + return floor( smoothstep( 0.01, 0.02, diff ).mul( 2 ) ).div( 2 ); -const range = /*@__PURE__*/ nodeProxy( RangeNode ); + }; -class LightNode extends Node { + const neighborNormalEdgeIndicator = ( x, y, depth, normal ) => { - constructor( scope = LightNode.TARGET_DIRECTION, light = null ) { + const depthDiff = sampleDepth( x, y ).sub( depth ); + const neighborNormal = sampleNormal( x, y ); - super(); + // Edge pixels should yield to faces who's normals are closer to the bias normal. - this.scope = scope; - this.light = light; + const normalEdgeBias = vec3( 1, 1, 1 ); // This should probably be a parameter. + const normalDiff = dot( normal.sub( neighborNormal ), normalEdgeBias ); + const normalIndicator = clamp( smoothstep( - 0.01, 0.01, normalDiff ), 0.0, 1.0 ); - } + // Only the shallower pixel should detect the normal edge. - setup() { + const depthIndicator = clamp( sign( depthDiff.mul( .25 ).add( .0025 ) ), 0.0, 1.0 ); - const { scope, light } = this; + return float( 1.0 ).sub( dot( normal, neighborNormal ) ).mul( depthIndicator ).mul( normalIndicator ); - let output = null; + }; - if ( scope === LightNode.TARGET_DIRECTION ) { + const normalEdgeIndicator = ( depth, normal ) => { - output = cameraViewMatrix.transformDirection( objectPosition( light ).sub( objectPosition( light.target ) ) ); + const indicator = property( 'float', 'indicator' ); - } + indicator.addAssign( neighborNormalEdgeIndicator( 0, - 1, depth, normal ) ); + indicator.addAssign( neighborNormalEdgeIndicator( 0, 1, depth, normal ) ); + indicator.addAssign( neighborNormalEdgeIndicator( - 1, 0, depth, normal ) ); + indicator.addAssign( neighborNormalEdgeIndicator( 1, 0, depth, normal ) ); - return output; + return step( 0.1, indicator ); - } + }; - serialize( data ) { + const pixelation = Fn( () => { - super.serialize( data ); + const texel = sampleTexture(); - data.scope = this.scope; + const depth = property( 'float', 'depth' ); + const normal = property( 'vec3', 'normal' ); - } + If( this.depthEdgeStrength.greaterThan( 0.0 ).or( this.normalEdgeStrength.greaterThan( 0.0 ) ), () => { - deserialize( data ) { + depth.assign( sampleDepth( 0, 0 ) ); + normal.assign( sampleNormal( 0, 0 ) ); - super.deserialize( data ); + } ); - this.scope = data.scope; + const dei = property( 'float', 'dei' ); - } + If( this.depthEdgeStrength.greaterThan( 0.0 ), () => { -} + dei.assign( depthEdgeIndicator( depth ) ); -LightNode.TARGET_DIRECTION = 'targetDirection'; + } ); -LightNode.type = /*@__PURE__*/ registerNode( 'Light', LightNode ); + const nei = property( 'float', 'nei' ); -const lightTargetDirection = /*@__PURE__*/ nodeProxy( LightNode, LightNode.TARGET_DIRECTION ); + If( this.normalEdgeStrength.greaterThan( 0.0 ), () => { -const BasicShadowMap = Fn( ( { depthTexture, shadowCoord } ) => { + nei.assign( normalEdgeIndicator( depth, normal ) ); - return texture( depthTexture, shadowCoord.xy ).compare( shadowCoord.z ); + } ); -} ); + const strength = dei.greaterThan( 0 ).select( float( 1.0 ).sub( dei.mul( this.depthEdgeStrength ) ), nei.mul( this.normalEdgeStrength ).add( 1 ) ); -const PCFShadowMap = Fn( ( { depthTexture, shadowCoord, shadow } ) => { + return texel.mul( strength ); - const depthCompare = ( uv, compare ) => texture( depthTexture, uv ).compare( compare ); + } ); - const mapSize = reference( 'mapSize', 'vec2', shadow ); - const radius = reference( 'radius', 'float', shadow ); + const outputNode = pixelation(); - const texelSize = vec2( 1 ).div( mapSize ); - const dx0 = texelSize.x.negate().mul( radius ); - const dy0 = texelSize.y.negate().mul( radius ); - const dx1 = texelSize.x.mul( radius ); - const dy1 = texelSize.y.mul( radius ); - const dx2 = dx0.div( 2 ); - const dy2 = dy0.div( 2 ); - const dx3 = dx1.div( 2 ); - const dy3 = dy1.div( 2 ); + return outputNode; - return add( - depthCompare( shadowCoord.xy.add( vec2( dx0, dy0 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( 0, dy0 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( dx1, dy0 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( dx2, dy2 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( 0, dy2 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( dx3, dy2 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( dx0, 0 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( dx2, 0 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy, shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( dx3, 0 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( dx1, 0 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( dx2, dy3 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( 0, dy3 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( dx3, dy3 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( dx0, dy1 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( 0, dy1 ) ), shadowCoord.z ), - depthCompare( shadowCoord.xy.add( vec2( dx1, dy1 ) ), shadowCoord.z ) - ).mul( 1 / 17 ); + } -} ); +} -const PCFSoftShadowMap = Fn( ( { depthTexture, shadowCoord, shadow } ) => { +const pixelation = ( node, depthNode, normalNode, pixelSize = 6, normalEdgeStrength = 0.3, depthEdgeStrength = 0.4 ) => nodeObject( new PixelationNode( convertToTexture( node ), convertToTexture( depthNode ), convertToTexture( normalNode ), nodeObject( pixelSize ), nodeObject( normalEdgeStrength ), nodeObject( depthEdgeStrength ) ) ); - const depthCompare = ( uv, compare ) => texture( depthTexture, uv ).compare( compare ); +class PixelationPassNode extends PassNode { - const mapSize = reference( 'mapSize', 'vec2', shadow ); + static get type() { - const texelSize = vec2( 1 ).div( mapSize ); - const dx = texelSize.x; - const dy = texelSize.y; + return 'PixelationPassNode'; - const uv = shadowCoord.xy; - const f = fract( uv.mul( mapSize ).add( 0.5 ) ); - uv.subAssign( f.mul( texelSize ) ); + } - return add( - depthCompare( uv, shadowCoord.z ), - depthCompare( uv.add( vec2( dx, 0 ) ), shadowCoord.z ), - depthCompare( uv.add( vec2( 0, dy ) ), shadowCoord.z ), - depthCompare( uv.add( texelSize ), shadowCoord.z ), - mix( - depthCompare( uv.add( vec2( dx.negate(), 0 ) ), shadowCoord.z ), - depthCompare( uv.add( vec2( dx.mul( 2 ), 0 ) ), shadowCoord.z ), - f.x - ), - mix( - depthCompare( uv.add( vec2( dx.negate(), dy ) ), shadowCoord.z ), - depthCompare( uv.add( vec2( dx.mul( 2 ), dy ) ), shadowCoord.z ), - f.x - ), - mix( - depthCompare( uv.add( vec2( 0, dy.negate() ) ), shadowCoord.z ), - depthCompare( uv.add( vec2( 0, dy.mul( 2 ) ) ), shadowCoord.z ), - f.y - ), - mix( - depthCompare( uv.add( vec2( dx, dy.negate() ) ), shadowCoord.z ), - depthCompare( uv.add( vec2( dx, dy.mul( 2 ) ) ), shadowCoord.z ), - f.y - ), - mix( - mix( - depthCompare( uv.add( vec2( dx.negate(), dy.negate() ) ), shadowCoord.z ), - depthCompare( uv.add( vec2( dx.mul( 2 ), dy.negate() ) ), shadowCoord.z ), - f.x - ), - mix( - depthCompare( uv.add( vec2( dx.negate(), dy.mul( 2 ) ) ), shadowCoord.z ), - depthCompare( uv.add( vec2( dx.mul( 2 ), dy.mul( 2 ) ) ), shadowCoord.z ), - f.x - ), - f.y - ) - ).mul( 1 / 9 ); + constructor( scene, camera, pixelSize = 6, normalEdgeStrength = 0.3, depthEdgeStrength = 0.4 ) { -} ); + super( 'color', scene, camera, { minFilter: NearestFilter, magFilter: NearestFilter } ); -const shadowFilterLib = [ BasicShadowMap, PCFShadowMap, PCFSoftShadowMap ]; + this.pixelSize = pixelSize; + this.normalEdgeStrength = normalEdgeStrength; + this.depthEdgeStrength = depthEdgeStrength; -// + this.isPixelationPassNode = true; -let overrideMaterial = null; + this._mrt = mrt( { + output: output, + normal: normalView + } ); -class AnalyticLightNode extends LightingNode { + } - constructor( light = null ) { + setSize( width, height ) { - super(); + const pixelSize = this.pixelSize.value ? this.pixelSize.value : this.pixelSize; - this.updateType = NodeUpdateType.FRAME; + const adjustedWidth = Math.floor( width / pixelSize ); + const adjustedHeight = Math.floor( height / pixelSize ); - this.light = light; + super.setSize( adjustedWidth, adjustedHeight ); - this.color = new Color(); - this.colorNode = uniform( this.color ); + } - this.baseColorNode = null; + setup() { - this.shadowMap = null; - this.shadowNode = null; - this.shadowColorNode = null; + const color = super.getTextureNode( 'output' ); + const depth = super.getTextureNode( 'depth' ); + const normal = super.getTextureNode( 'normal' ); - this.isAnalyticLightNode = true; + return pixelation( color, depth, normal, this.pixelSize, this.normalEdgeStrength, this.depthEdgeStrength ); } - getCacheKey() { +} - return super.getCacheKey() + '-' + ( this.light.id + '-' + ( this.light.castShadow ? '1' : '0' ) ); +const pixelationPass = ( scene, camera, pixelSize, normalEdgeStrength, depthEdgeStrength ) => nodeObject( new PixelationPassNode( scene, camera, pixelSize, normalEdgeStrength, depthEdgeStrength ) ); - } +const _size$3 = /*@__PURE__*/ new Vector2(); - getHash() { +/** +* +* Supersample Anti-Aliasing Render Pass +* +* This manual approach to SSAA re-renders the scene ones for each sample with camera jitter and accumulates the results. +* +* References: https://en.wikipedia.org/wiki/Supersampling +* +*/ - return this.light.uuid; +class SSAAPassNode extends PassNode { + + static get type() { + + return 'SSAAPassNode'; } - setupShadow( builder ) { + constructor( scene, camera ) { - const { object, renderer } = builder; + super( PassNode.COLOR, scene, camera ); - let shadowColorNode = this.shadowColorNode; + this.isSSAAPassNode = true; - if ( shadowColorNode === null ) { + this.sampleLevel = 4; // specified as n, where the number of samples is 2^n, so sampleLevel = 4, is 2^4 samples, 16. + this.unbiased = true; + this.clearColor = new Color( 0x000000 ); + this.clearAlpha = 0; - if ( overrideMaterial === null ) { + this._currentClearColor = new Color(); - overrideMaterial = new NodeMaterial(); - overrideMaterial.fragmentNode = vec4( 0, 0, 0, 1 ); - overrideMaterial.isShadowNodeMaterial = true; // Use to avoid other overrideMaterial override material.fragmentNode unintentionally when using material.shadowNode - overrideMaterial.name = 'ShadowMaterial'; + this.sampleWeight = uniform( 1 ); - } + this.sampleRenderTarget = null; - const depthTexture = new DepthTexture(); - depthTexture.compareFunction = LessCompare; + this._quadMesh = new QuadMesh(); - const shadow = this.light.shadow; - const shadowMap = builder.createRenderTarget( shadow.mapSize.width, shadow.mapSize.height ); - shadowMap.depthTexture = depthTexture; + } - shadow.camera.updateProjectionMatrix(); + updateBefore( frame ) { - // + const { renderer } = frame; + const { scene, camera } = this; - const shadowIntensity = reference( 'intensity', 'float', shadow ); - const bias = reference( 'bias', 'float', shadow ); - const normalBias = reference( 'normalBias', 'float', shadow ); + this._pixelRatio = renderer.getPixelRatio(); - const position = object.material.shadowPositionNode || positionWorld; + const size = renderer.getSize( _size$3 ); - let shadowCoord = uniform( shadow.matrix ).mul( position.add( normalWorld.mul( normalBias ) ) ); - shadowCoord = shadowCoord.xyz.div( shadowCoord.w ); + this.setSize( size.width, size.height ); + this.sampleRenderTarget.setSize( this.renderTarget.width, this.renderTarget.height ); - let coordZ = shadowCoord.z.add( bias ); + // save current renderer settings - if ( renderer.coordinateSystem === WebGPUCoordinateSystem ) { + renderer.getClearColor( this._currentClearColor ); + const currentClearAlpha = renderer.getClearAlpha(); + const currentRenderTarget = renderer.getRenderTarget(); + const currentMRT = renderer.getMRT(); + const currentAutoClear = renderer.autoClear; - coordZ = coordZ.mul( 2 ).sub( 1 ); // WebGPU: Convertion [ 0, 1 ] to [ - 1, 1 ] + // - } + this._cameraNear.value = camera.near; + this._cameraFar.value = camera.far; - shadowCoord = vec3( - shadowCoord.x, - shadowCoord.y.oneMinus(), // follow webgpu standards - coordZ - ); + renderer.setMRT( this.getMRT() ); + renderer.autoClear = false; - const frustumTest = shadowCoord.x.greaterThanEqual( 0 ) - .and( shadowCoord.x.lessThanEqual( 1 ) ) - .and( shadowCoord.y.greaterThanEqual( 0 ) ) - .and( shadowCoord.y.lessThanEqual( 1 ) ) - .and( shadowCoord.z.lessThanEqual( 1 ) ); + const jitterOffsets = _JitterVectors[ Math.max( 0, Math.min( this.sampleLevel, 5 ) ) ]; - // + const baseSampleWeight = 1.0 / jitterOffsets.length; + const roundingRange = 1 / 32; - const filterFn = shadow.filterNode || shadowFilterLib[ renderer.shadowMap.type ] || null; + const viewOffset = { - if ( filterFn === null ) { + fullWidth: this.renderTarget.width, + fullHeight: this.renderTarget.height, + offsetX: 0, + offsetY: 0, + width: this.renderTarget.width, + height: this.renderTarget.height - throw new Error( 'THREE.WebGPURenderer: Shadow map type not supported yet.' ); + }; - } + const originalViewOffset = Object.assign( {}, camera.view ); - const shadowColor = texture( shadowMap.texture, shadowCoord ); - const shadowNode = frustumTest.select( filterFn( { depthTexture, shadowCoord, shadow } ), float( 1 ) ); + if ( originalViewOffset.enabled ) Object.assign( viewOffset, originalViewOffset ); - this.shadowMap = shadowMap; + // render the scene multiple times, each slightly jitter offset from the last and accumulate the results. - this.shadowNode = shadowNode; - this.shadowColorNode = shadowColorNode = this.colorNode.mul( mix( 1, shadowNode.rgb.mix( shadowColor, 1 ), shadowIntensity.mul( shadowColor.a ) ) ); + for ( let i = 0; i < jitterOffsets.length; i ++ ) { - this.baseColorNode = this.colorNode; + const jitterOffset = jitterOffsets[ i ]; - } + if ( camera.setViewOffset ) { - // + camera.setViewOffset( - this.colorNode = shadowColorNode; + viewOffset.fullWidth, viewOffset.fullHeight, - this.updateBeforeType = NodeUpdateType.RENDER; + viewOffset.offsetX + jitterOffset[ 0 ] * 0.0625, viewOffset.offsetY + jitterOffset[ 1 ] * 0.0625, // 0.0625 = 1 / 16 - } + viewOffset.width, viewOffset.height - setup( builder ) { + ); - this.colorNode = this.baseColorNode || this.colorNode; + } - if ( this.light.castShadow ) { + this.sampleWeight.value = baseSampleWeight; - if ( builder.object.receiveShadow ) { + if ( this.unbiased ) { - this.setupShadow( builder ); + // the theory is that equal weights for each sample lead to an accumulation of rounding errors. + // The following equation varies the sampleWeight per sample so that it is uniformly distributed + // across a range of values whose rounding errors cancel each other out. + + const uniformCenteredDistribution = ( - 0.5 + ( i + 0.5 ) / jitterOffsets.length ); + this.sampleWeight.value += roundingRange * uniformCenteredDistribution; } - } else if ( this.shadowNode !== null ) { + renderer.setClearColor( this.clearColor, this.clearAlpha ); + renderer.setRenderTarget( this.sampleRenderTarget ); + renderer.clear(); + renderer.render( scene, camera ); - this.disposeShadow(); + // accumulation - } + renderer.setRenderTarget( this.renderTarget ); - } + if ( i === 0 ) { - updateShadow( frame ) { + renderer.setClearColor( 0x000000, 0.0 ); + renderer.clear(); - const { shadowMap, light } = this; - const { renderer, scene, camera } = frame; + } + this._quadMesh.render( renderer ); - const depthVersion = shadowMap.depthTexture.version; - this._depthVersionCached = depthVersion; + } - const currentOverrideMaterial = scene.overrideMaterial; + renderer.copyTextureToTexture( this.sampleRenderTarget.depthTexture, this.renderTarget.depthTexture ); - scene.overrideMaterial = overrideMaterial; + // restore - shadowMap.setSize( light.shadow.mapSize.width, light.shadow.mapSize.height ); + if ( camera.setViewOffset && originalViewOffset.enabled ) { - light.shadow.updateMatrices( light ); - light.shadow.camera.layers.mask = camera.layers.mask; + camera.setViewOffset( - const currentRenderTarget = renderer.getRenderTarget(); - const currentRenderObjectFunction = renderer.getRenderObjectFunction(); + originalViewOffset.fullWidth, originalViewOffset.fullHeight, - renderer.setRenderObjectFunction( ( object, ...params ) => { + originalViewOffset.offsetX, originalViewOffset.offsetY, - if ( object.castShadow === true ) { + originalViewOffset.width, originalViewOffset.height - renderer.renderObject( object, ...params ); + ); - } + } else if ( camera.clearViewOffset ) { - } ); + camera.clearViewOffset(); - renderer.setRenderTarget( shadowMap ); - renderer.render( scene, light.shadow.camera ); + } renderer.setRenderTarget( currentRenderTarget ); - renderer.setRenderObjectFunction( currentRenderObjectFunction ); + renderer.setMRT( currentMRT ); - scene.overrideMaterial = currentOverrideMaterial; + renderer.autoClear = currentAutoClear; + renderer.setClearColor( this._currentClearColor, currentClearAlpha ); } - disposeShadow() { + setup( builder ) { - this.shadowMap.dispose(); - this.shadowMap = null; + if ( this.sampleRenderTarget === null ) { - this.shadowNode = null; - this.shadowColorNode = null; + this.sampleRenderTarget = this.renderTarget.clone(); - this.baseColorNode = null; + } - this.updateBeforeType = NodeUpdateType.NONE; + let sampleTexture; - } + const passMRT = this.getMRT(); - updateBefore( frame ) { + if ( passMRT !== null ) { - const shadow = this.light.shadow; + const outputs = {}; - const needsUpdate = shadow.needsUpdate || shadow.autoUpdate; + for ( const name in passMRT.outputNodes ) { - if ( needsUpdate ) { + const index = getTextureIndex( this.sampleRenderTarget.textures, name ); - this.updateShadow( frame ); + if ( index >= 0 ) { - if ( this.shadowMap.depthTexture.version === this._depthVersionCached ) { + outputs[ name ] = texture( this.sampleRenderTarget.textures[ index ] ).mul( this.sampleWeight ); - shadow.needsUpdate = false; + } } - } + sampleTexture = mrt( outputs ); - } + } else { - update( /*frame*/ ) { + sampleTexture = texture( this.sampleRenderTarget.texture ).mul( this.sampleWeight ); - const { light } = this; + } - this.color.copy( light.color ).multiplyScalar( light.intensity ); + this._quadMesh.material = new NodeMaterial(); + this._quadMesh.material.fragmentNode = sampleTexture; + this._quadMesh.material.transparent = true; + this._quadMesh.material.depthTest = false; + this._quadMesh.material.depthWrite = false; + this._quadMesh.material.premultipliedAlpha = true; + this._quadMesh.material.blending = AdditiveBlending; + this._quadMesh.material.normals = false; + this._quadMesh.material.name = 'SSAA'; + + return super.setup( builder ); } -} + dispose() { -AnalyticLightNode.type = /*@__PURE__*/ registerNode( 'AnalyticLight', AnalyticLightNode ); + super.dispose(); -const getDistanceAttenuation = /*@__PURE__*/ Fn( ( inputs ) => { + if ( this.sampleRenderTarget !== null ) { - const { lightDistance, cutoffDistance, decayExponent } = inputs; + this.sampleRenderTarget.dispose(); - // based upon Frostbite 3 Moving to Physically-based Rendering - // page 32, equation 26: E[window1] - // https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf - const distanceFalloff = lightDistance.pow( decayExponent ).max( 0.01 ).reciprocal(); + } - return cutoffDistance.greaterThan( 0 ).select( - distanceFalloff.mul( lightDistance.div( cutoffDistance ).pow4().oneMinus().clamp().pow2() ), - distanceFalloff - ); + } -} ); // validated +} -class PointLightNode extends AnalyticLightNode { +// These jitter vectors are specified in integers because it is easier. +// I am assuming a [-8,8) integer grid, but it needs to be mapped onto [-0.5,0.5) +// before being used, thus these integers need to be scaled by 1/16. +// +// Sample patterns reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476218%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 +const _JitterVectors = [ + [ + [ 0, 0 ] + ], + [ + [ 4, 4 ], [ - 4, - 4 ] + ], + [ + [ - 2, - 6 ], [ 6, - 2 ], [ - 6, 2 ], [ 2, 6 ] + ], + [ + [ 1, - 3 ], [ - 1, 3 ], [ 5, 1 ], [ - 3, - 5 ], + [ - 5, 5 ], [ - 7, - 1 ], [ 3, 7 ], [ 7, - 7 ] + ], + [ + [ 1, 1 ], [ - 1, - 3 ], [ - 3, 2 ], [ 4, - 1 ], + [ - 5, - 2 ], [ 2, 5 ], [ 5, 3 ], [ 3, - 5 ], + [ - 2, 6 ], [ 0, - 7 ], [ - 4, - 6 ], [ - 6, 4 ], + [ - 8, 0 ], [ 7, - 4 ], [ 6, 7 ], [ - 7, - 8 ] + ], + [ + [ - 4, - 7 ], [ - 7, - 5 ], [ - 3, - 5 ], [ - 5, - 4 ], + [ - 1, - 4 ], [ - 2, - 2 ], [ - 6, - 1 ], [ - 4, 0 ], + [ - 7, 1 ], [ - 1, 2 ], [ - 6, 3 ], [ - 3, 3 ], + [ - 7, 6 ], [ - 3, 6 ], [ - 5, 7 ], [ - 1, 7 ], + [ 5, - 7 ], [ 1, - 6 ], [ 6, - 5 ], [ 4, - 4 ], + [ 2, - 3 ], [ 7, - 2 ], [ 1, - 1 ], [ 4, - 1 ], + [ 2, 1 ], [ 6, 2 ], [ 0, 4 ], [ 4, 4 ], + [ 2, 5 ], [ 7, 5 ], [ 5, 6 ], [ 3, 7 ] + ] +]; - constructor( light = null ) { +const ssaaPass = ( scene, camera ) => nodeObject( new SSAAPassNode( scene, camera ) ); - super( light ); +const _size$2 = /*@__PURE__*/ new Vector2(); - this.cutoffDistanceNode = uniform( 0 ); - this.decayExponentNode = uniform( 0 ); +class StereoPassNode extends PassNode { - } + static get type() { - update( frame ) { + return 'StereoPassNode'; - const { light } = this; + } - super.update( frame ); + constructor( scene, camera ) { - this.cutoffDistanceNode.value = light.distance; - this.decayExponentNode.value = light.decay; + super( PassNode.COLOR, scene, camera ); - } + this.isStereoPassNode = true; - setup( builder ) { - - const { colorNode, cutoffDistanceNode, decayExponentNode, light } = this; + this.stereo = new StereoCamera(); + this.stereo.aspect = 0.5; - const lightingModel = builder.context.lightingModel; + } - const lVector = objectViewPosition( light ).sub( positionView ); // @TODO: Add it into LightNode + updateBefore( frame ) { - const lightDirection = lVector.normalize(); - const lightDistance = lVector.length(); + const { renderer } = frame; + const { scene, camera, stereo, renderTarget } = this; - const lightAttenuation = getDistanceAttenuation( { - lightDistance, - cutoffDistance: cutoffDistanceNode, - decayExponent: decayExponentNode - } ); + this._pixelRatio = renderer.getPixelRatio(); - const lightColor = colorNode.mul( lightAttenuation ); + stereo.cameraL.coordinateSystem = renderer.coordinateSystem; + stereo.cameraR.coordinateSystem = renderer.coordinateSystem; + stereo.update( camera ); - const reflectedLight = builder.context.reflectedLight; + const size = renderer.getSize( _size$2 ); + this.setSize( size.width, size.height ); - lightingModel.direct( { - lightDirection, - lightColor, - reflectedLight - }, builder.stack, builder ); + const currentAutoClear = renderer.autoClear; + renderer.autoClear = false; - } + const currentRenderTarget = renderer.getRenderTarget(); + const currentMRT = renderer.getMRT(); -} + this._cameraNear.value = camera.near; + this._cameraFar.value = camera.far; -PointLightNode.type = /*@__PURE__*/ registerNode( 'PointLight', PointLightNode ); + for ( const name in this._previousTextures ) { -class DirectionalLightNode extends AnalyticLightNode { + this.toggleTexture( name ); - constructor( light = null ) { + } - super( light ); + renderer.setRenderTarget( renderTarget ); + renderer.setMRT( this._mrt ); + renderer.clear(); - } + renderTarget.scissorTest = true; - setup( builder ) { + renderTarget.scissor.set( 0, 0, renderTarget.width / 2, renderTarget.height ); + renderTarget.viewport.set( 0, 0, renderTarget.width / 2, renderTarget.height ); + renderer.render( scene, stereo.cameraL ); - super.setup( builder ); + renderTarget.scissor.set( renderTarget.width / 2, 0, renderTarget.width / 2, renderTarget.height ); + renderTarget.viewport.set( renderTarget.width / 2, 0, renderTarget.width / 2, renderTarget.height ); + renderer.render( scene, stereo.cameraR ); - const lightingModel = builder.context.lightingModel; + renderTarget.scissorTest = false; - const lightColor = this.colorNode; - const lightDirection = lightTargetDirection( this.light ); - const reflectedLight = builder.context.reflectedLight; + renderer.setRenderTarget( currentRenderTarget ); + renderer.setMRT( currentMRT ); - lightingModel.direct( { - lightDirection, - lightColor, - reflectedLight - }, builder.stack, builder ); + renderer.autoClear = currentAutoClear; } } -DirectionalLightNode.type = /*@__PURE__*/ registerNode( 'DirectionalLight', DirectionalLightNode ); - -const _matrix41 = /*@__PURE__*/ new Matrix4(); -const _matrix42 = /*@__PURE__*/ new Matrix4(); - -let ltcLib = null; +const stereoPass = ( scene, camera ) => nodeObject( new StereoPassNode( scene, camera ) ); -class RectAreaLightNode extends AnalyticLightNode { +const _size$1 = /*@__PURE__*/ new Vector2(); +const _quadMesh$2 = /*@__PURE__*/ new QuadMesh(); - constructor( light = null ) { +class StereoCompositePassNode extends PassNode { - super( light ); + static get type() { - this.halfHeight = uniform( new Vector3() ); - this.halfWidth = uniform( new Vector3() ); + return 'StereoCompositePassNode'; } - update( frame ) { + constructor( scene, camera ) { - super.update( frame ); + super( PassNode.COLOR, scene, camera ); - const { light } = this; + this.isStereoCompositePassNode = true; - const viewMatrix = frame.camera.matrixWorldInverse; + this.stereo = new StereoCamera(); + const _params = { minFilter: LinearFilter, magFilter: NearestFilter, type: HalfFloatType }; - _matrix42.identity(); - _matrix41.copy( light.matrixWorld ); - _matrix41.premultiply( viewMatrix ); - _matrix42.extractRotation( _matrix41 ); + this._renderTargetL = new RenderTarget( 1, 1, _params ); + this._renderTargetR = new RenderTarget( 1, 1, _params ); - this.halfWidth.value.set( light.width * 0.5, 0.0, 0.0 ); - this.halfHeight.value.set( 0.0, light.height * 0.5, 0.0 ); + this._mapLeft = texture( this._renderTargetL.texture ); + this._mapRight = texture( this._renderTargetR.texture ); - this.halfWidth.value.applyMatrix4( _matrix42 ); - this.halfHeight.value.applyMatrix4( _matrix42 ); + this._material = null; } - setup( builder ) { - - super.setup( builder ); + updateStereoCamera( coordinateSystem ) { - let ltc_1, ltc_2; + this.stereo.cameraL.coordinateSystem = coordinateSystem; + this.stereo.cameraR.coordinateSystem = coordinateSystem; + this.stereo.update( this.camera ); - if ( builder.isAvailable( 'float32Filterable' ) ) { + } - ltc_1 = texture( ltcLib.LTC_FLOAT_1 ); - ltc_2 = texture( ltcLib.LTC_FLOAT_2 ); + setSize( width, height ) { - } else { + super.setSize( width, height ); - ltc_1 = texture( ltcLib.LTC_HALF_1 ); - ltc_2 = texture( ltcLib.LTC_HALF_2 ); + this._renderTargetL.setSize( this.renderTarget.width, this.renderTarget.height ); + this._renderTargetR.setSize( this.renderTarget.width, this.renderTarget.height ); - } + } - const { colorNode, light } = this; - const lightingModel = builder.context.lightingModel; + updateBefore( frame ) { - const lightPosition = objectViewPosition( light ); - const reflectedLight = builder.context.reflectedLight; + const { renderer } = frame; + const { scene, stereo, renderTarget } = this; - lightingModel.directRectArea( { - lightColor: colorNode, - lightPosition, - halfWidth: this.halfWidth, - halfHeight: this.halfHeight, - reflectedLight, - ltc_1, - ltc_2 - }, builder.stack, builder ); + this._pixelRatio = renderer.getPixelRatio(); - } + this.updateStereoCamera( renderer.coordinateSystem ); - static setLTC( ltc ) { + const size = renderer.getSize( _size$1 ); + this.setSize( size.width, size.height ); - ltcLib = ltc; + const currentRenderTarget = renderer.getRenderTarget(); - } + // left -} + renderer.setRenderTarget( this._renderTargetL ); + renderer.render( scene, stereo.cameraL ); -RectAreaLightNode.type = /*@__PURE__*/ registerNode( 'RectAreaLight', RectAreaLightNode ); + // right -class SpotLightNode extends AnalyticLightNode { + renderer.setRenderTarget( this._renderTargetR ); + renderer.render( scene, stereo.cameraR ); - constructor( light = null ) { + // composite - super( light ); + renderer.setRenderTarget( renderTarget ); + _quadMesh$2.material = this._material; + _quadMesh$2.render( renderer ); - this.coneCosNode = uniform( 0 ); - this.penumbraCosNode = uniform( 0 ); + // restore - this.cutoffDistanceNode = uniform( 0 ); - this.decayExponentNode = uniform( 0 ); + renderer.setRenderTarget( currentRenderTarget ); } - update( frame ) { - - super.update( frame ); - - const { light } = this; - - this.coneCosNode.value = Math.cos( light.angle ); - this.penumbraCosNode.value = Math.cos( light.angle * ( 1 - light.penumbra ) ); + dispose() { - this.cutoffDistanceNode.value = light.distance; - this.decayExponentNode.value = light.decay; + super.dispose(); - } + this._renderTargetL.dispose(); + this._renderTargetR.dispose(); - getSpotAttenuation( angleCosine ) { + if ( this._material !== null ) { - const { coneCosNode, penumbraCosNode } = this; + this._material.dispose(); - return smoothstep( coneCosNode, penumbraCosNode, angleCosine ); + } } - setup( builder ) { +} - super.setup( builder ); +class AnaglyphPassNode extends StereoCompositePassNode { - const lightingModel = builder.context.lightingModel; + static get type() { - const { colorNode, cutoffDistanceNode, decayExponentNode, light } = this; + return 'AnaglyphPassNode'; - const lVector = objectViewPosition( light ).sub( positionView ); // @TODO: Add it into LightNode + } - const lightDirection = lVector.normalize(); - const angleCos = lightDirection.dot( lightTargetDirection( light ) ); - const spotAttenuation = this.getSpotAttenuation( angleCos ); + constructor( scene, camera ) { - const lightDistance = lVector.length(); + super( scene, camera ); - const lightAttenuation = getDistanceAttenuation( { - lightDistance, - cutoffDistance: cutoffDistanceNode, - decayExponent: decayExponentNode - } ); + this.isAnaglyphPassNode = true; - const lightColor = colorNode.mul( spotAttenuation ).mul( lightAttenuation ); + // Dubois matrices from https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.7.6968&rep=rep1&type=pdf#page=4 - const reflectedLight = builder.context.reflectedLight; + this._colorMatrixLeft = uniform( new Matrix3().fromArray( [ + 0.456100, - 0.0400822, - 0.0152161, + 0.500484, - 0.0378246, - 0.0205971, + 0.176381, - 0.0157589, - 0.00546856 + ] ) ); - lightingModel.direct( { - lightDirection, - lightColor, - reflectedLight - }, builder.stack, builder ); + this._colorMatrixRight = uniform( new Matrix3().fromArray( [ + - 0.0434706, 0.378476, - 0.0721527, + - 0.0879388, 0.73364, - 0.112961, + - 0.00155529, - 0.0184503, 1.2264 + ] ) ); } -} - -SpotLightNode.type = /*@__PURE__*/ registerNode( 'SpotLight', SpotLightNode ); - -class IESSpotLightNode extends SpotLightNode { - - getSpotAttenuation( angleCosine ) { - - const iesMap = this.light.iesMap; + setup( builder ) { - let spotAttenuation = null; + const uvNode = uv(); - if ( iesMap && iesMap.isTexture === true ) { + const anaglyph = Fn( () => { - const angle = angleCosine.acos().mul( 1.0 / Math.PI ); + const colorL = this._mapLeft.uv( uvNode ); + const colorR = this._mapRight.uv( uvNode ); - spotAttenuation = texture( iesMap, vec2( angle, 0 ), 0 ).r; + const color = clamp( this._colorMatrixLeft.mul( colorL.rgb ).add( this._colorMatrixRight.mul( colorR.rgb ) ) ); - } else { + return vec4( color.rgb, max$1( colorL.a, colorR.a ) ); - spotAttenuation = super.getSpotAttenuation( angleCosine ); + } ); - } + const material = this._material || ( this._material = new NodeMaterial() ); + material.fragmentNode = anaglyph().context( builder.getSharedContext() ); + material.name = 'Anaglyph'; + material.needsUpdate = true; - return spotAttenuation; + return super.setup( builder ); } } -IESSpotLightNode.type = /*@__PURE__*/ registerNode( 'IESSpotLight', IESSpotLightNode ); +const anaglyphPass = ( scene, camera ) => nodeObject( new AnaglyphPassNode( scene, camera ) ); -class AmbientLightNode extends AnalyticLightNode { +class ParallaxBarrierPassNode extends StereoCompositePassNode { - constructor( light = null ) { + static get type() { - super( light ); + return 'ParallaxBarrierPassNode'; } - setup( { context } ) { + constructor( scene, camera ) { - context.irradiance.addAssign( this.colorNode ); + super( scene, camera ); + + this.isParallaxBarrierPassNode = true; } -} + setup( builder ) { -AmbientLightNode.type = /*@__PURE__*/ registerNode( 'AmbientLight', AmbientLightNode ); + const uvNode = uv(); -class HemisphereLightNode extends AnalyticLightNode { + const parallaxBarrier = Fn( () => { - constructor( light = null ) { + const color = vec4().toVar(); - super( light ); + If( mod( screenCoordinate.y, 2 ).greaterThan( 1 ), () => { - this.lightPositionNode = objectPosition( light ); - this.lightDirectionNode = this.lightPositionNode.normalize(); + color.assign( this._mapLeft.uv( uvNode ) ); - this.groundColorNode = uniform( new Color() ); + } ).Else( () => { - } + color.assign( this._mapRight.uv( uvNode ) ); - update( frame ) { + } ); - const { light } = this; + return color; - super.update( frame ); + } ); - this.lightPositionNode.object3d = light; + const material = this._material || ( this._material = new NodeMaterial() ); + material.fragmentNode = parallaxBarrier().context( builder.getSharedContext() ); + material.needsUpdate = true; - this.groundColorNode.value.copy( light.groundColor ).multiplyScalar( light.intensity ); + return super.setup( builder ); } - setup( builder ) { +} - const { colorNode, groundColorNode, lightDirectionNode } = this; +const parallaxBarrierPass = ( scene, camera ) => nodeObject( new ParallaxBarrierPassNode( scene, camera ) ); - const dotNL = normalView.dot( lightDirectionNode ); - const hemiDiffuseWeight = dotNL.mul( 0.5 ).add( 0.5 ); +class ToonOutlinePassNode extends PassNode { - const irradiance = mix( groundColorNode, colorNode, hemiDiffuseWeight ); + static get type() { - builder.context.irradiance.addAssign( irradiance ); + return 'ToonOutlinePassNode'; } -} - -HemisphereLightNode.type = /*@__PURE__*/ registerNode( 'HemisphereLight', HemisphereLightNode ); - -class LightProbeNode extends AnalyticLightNode { - - constructor( light = null ) { - - super( light ); + constructor( scene, camera, colorNode, thicknessNode, alphaNode ) { - const array = []; + super( PassNode.COLOR, scene, camera ); - for ( let i = 0; i < 9; i ++ ) array.push( new Vector3() ); + this.colorNode = colorNode; + this.thicknessNode = thicknessNode; + this.alphaNode = alphaNode; - this.lightProbe = uniformArray( array ); + this._materialCache = new WeakMap(); } - update( frame ) { + updateBefore( frame ) { - const { light } = this; + const { renderer } = frame; - super.update( frame ); + const currentRenderObjectFunction = renderer.getRenderObjectFunction(); - // + renderer.setRenderObjectFunction( ( object, scene, camera, geometry, material, group, lightsNode ) => { - for ( let i = 0; i < 9; i ++ ) { + // only render outline for supported materials - this.lightProbe.array[ i ].copy( light.sh.coefficients[ i ] ).multiplyScalar( light.intensity ); + if ( material.isMeshToonMaterial || material.isMeshToonNodeMaterial ) { - } + if ( material.wireframe === false ) { - } + const outlineMaterial = this._getOutlineMaterial( material ); + renderer.renderObject( object, scene, camera, geometry, outlineMaterial, group, lightsNode ); - setup( builder ) { + } - const irradiance = shGetIrradianceAt( normalWorld, this.lightProbe ); + } - builder.context.irradiance.addAssign( irradiance ); + // default - } + renderer.renderObject( object, scene, camera, geometry, material, group, lightsNode ); -} + } ); -LightProbeNode.type = /*@__PURE__*/ registerNode( 'LightProbe', LightProbeNode ); + super.updateBefore( frame ); -const shGetIrradianceAt = /*@__PURE__*/ Fn( ( [ normal, shCoefficients ] ) => { + renderer.setRenderObjectFunction( currentRenderObjectFunction ); - // normal is assumed to have unit length + } - const x = normal.x, y = normal.y, z = normal.z; + _createMaterial() { - // band 0 - const result = shCoefficients.element( 0 ).mul( 0.886227 ); + const material = new NodeMaterial(); + material.isMeshToonOutlineMaterial = true; + material.name = 'Toon_Outline'; + material.side = BackSide; - // band 1 - result.addAssign( shCoefficients.element( 1 ).mul( 2.0 * 0.511664 ).mul( y ) ); - result.addAssign( shCoefficients.element( 2 ).mul( 2.0 * 0.511664 ).mul( z ) ); - result.addAssign( shCoefficients.element( 3 ).mul( 2.0 * 0.511664 ).mul( x ) ); + // vertex node - // band 2 - result.addAssign( shCoefficients.element( 4 ).mul( 2.0 * 0.429043 ).mul( x ).mul( y ) ); - result.addAssign( shCoefficients.element( 5 ).mul( 2.0 * 0.429043 ).mul( y ).mul( z ) ); - result.addAssign( shCoefficients.element( 6 ).mul( z.mul( z ).mul( 0.743125 ).sub( 0.247708 ) ) ); - result.addAssign( shCoefficients.element( 7 ).mul( 2.0 * 0.429043 ).mul( x ).mul( z ) ); - result.addAssign( shCoefficients.element( 8 ).mul( 0.429043 ).mul( mul( x, x ).sub( mul( y, y ) ) ) ); + const outlineNormal = normalLocal.negate(); + const mvp = cameraProjectionMatrix.mul( modelViewMatrix ); - return result; + const ratio = float( 1.0 ); // TODO: support outline thickness ratio for each vertex + const pos = mvp.mul( vec4( positionLocal, 1.0 ) ); + const pos2 = mvp.mul( vec4( positionLocal.add( outlineNormal ), 1.0 ) ); + const norm = normalize( pos.sub( pos2 ) ); // NOTE: subtract pos2 from pos because BackSide objectNormal is negative -} ); + material.vertexNode = pos.add( norm.mul( this.thicknessNode ).mul( pos.w ).mul( ratio ) ); -class NodeParser { + // color node - parseFunction( /*source*/ ) { + material.colorNode = vec4( this.colorNode, this.alphaNode ); - console.warn( 'Abstract function.' ); + return material; } -} + _getOutlineMaterial( originalMaterial ) { -class NodeFunction { + let outlineMaterial = this._materialCache.get( originalMaterial ); - constructor( type, inputs, name = '', precision = '' ) { + if ( outlineMaterial === undefined ) { - this.type = type; - this.inputs = inputs; - this.name = name; - this.precision = precision; + outlineMaterial = this._createMaterial(); - } + this._materialCache.set( originalMaterial, outlineMaterial ); - getCode( /*name = this.name*/ ) { + } - console.warn( 'Abstract function.' ); + return outlineMaterial; } } -NodeFunction.isNodeFunction = true; - -const declarationRegexp$1 = /^\s*(highp|mediump|lowp)?\s*([a-z_0-9]+)\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)/i; -const propertiesRegexp$1 = /[a-z_0-9]+/ig; - -const pragmaMain = '#pragma main'; - -const parse$1 = ( source ) => { +const toonOutlinePass = ( scene, camera, color = new Color( 0, 0, 0 ), thickness = 0.003, alpha = 1 ) => nodeObject( new ToonOutlinePassNode( scene, camera, nodeObject( color ), nodeObject( thickness ), nodeObject( alpha ) ) ); - source = source.trim(); - - const pragmaMainIndex = source.indexOf( pragmaMain ); +class ScriptableValueNode extends Node { - const mainCode = pragmaMainIndex !== - 1 ? source.slice( pragmaMainIndex + pragmaMain.length ) : source; + static get type() { - const declaration = mainCode.match( declarationRegexp$1 ); + return 'ScriptableValueNode'; - if ( declaration !== null && declaration.length === 5 ) { + } - // tokenizer + constructor( value = null ) { - const inputsCode = declaration[ 4 ]; - const propsMatches = []; + super(); - let nameMatch = null; + this._value = value; + this._cache = null; - while ( ( nameMatch = propertiesRegexp$1.exec( inputsCode ) ) !== null ) { + this.inputType = null; + this.outpuType = null; - propsMatches.push( nameMatch ); + this.events = new EventDispatcher(); - } + this.isScriptableValueNode = true; - // parser + } - const inputs = []; + get isScriptableOutputNode() { - let i = 0; + return this.outputType !== null; - while ( i < propsMatches.length ) { + } - const isConst = propsMatches[ i ][ 0 ] === 'const'; + set value( val ) { - if ( isConst === true ) { + if ( this._value === val ) return; - i ++; + if ( this._cache && this.inputType === 'URL' && this.value.value instanceof ArrayBuffer ) { - } + URL.revokeObjectURL( this._cache ); - let qualifier = propsMatches[ i ][ 0 ]; + this._cache = null; - if ( qualifier === 'in' || qualifier === 'out' || qualifier === 'inout' ) { + } - i ++; + this._value = val; - } else { + this.events.dispatchEvent( { type: 'change' } ); - qualifier = ''; + this.refresh(); - } + } - const type = propsMatches[ i ++ ][ 0 ]; + get value() { - let count = Number.parseInt( propsMatches[ i ][ 0 ] ); + return this._value; - if ( Number.isNaN( count ) === false ) i ++; - else count = null; + } - const name = propsMatches[ i ++ ][ 0 ]; + refresh() { - inputs.push( new NodeFunctionInput( type, name, count, qualifier, isConst ) ); + this.events.dispatchEvent( { type: 'refresh' } ); - } + } - // + getValue() { - const blockCode = mainCode.substring( declaration[ 0 ].length ); + const value = this.value; - const name = declaration[ 3 ] !== undefined ? declaration[ 3 ] : ''; - const type = declaration[ 2 ]; + if ( value && this._cache === null && this.inputType === 'URL' && value.value instanceof ArrayBuffer ) { - const precision = declaration[ 1 ] !== undefined ? declaration[ 1 ] : ''; + this._cache = URL.createObjectURL( new Blob( [ value.value ] ) ); - const headerCode = pragmaMainIndex !== - 1 ? source.slice( 0, pragmaMainIndex ) : ''; + } else if ( value && value.value !== null && value.value !== undefined && ( + ( ( this.inputType === 'URL' || this.inputType === 'String' ) && typeof value.value === 'string' ) || + ( this.inputType === 'Number' && typeof value.value === 'number' ) || + ( this.inputType === 'Vector2' && value.value.isVector2 ) || + ( this.inputType === 'Vector3' && value.value.isVector3 ) || + ( this.inputType === 'Vector4' && value.value.isVector4 ) || + ( this.inputType === 'Color' && value.value.isColor ) || + ( this.inputType === 'Matrix3' && value.value.isMatrix3 ) || + ( this.inputType === 'Matrix4' && value.value.isMatrix4 ) + ) ) { - return { - type, - inputs, - name, - precision, - inputsCode, - blockCode, - headerCode - }; + return value.value; - } else { + } - throw new Error( 'FunctionNode: Function is not a GLSL code.' ); + return this._cache || value; } -}; - -class GLSLNodeFunction extends NodeFunction { + getNodeType( builder ) { - constructor( source ) { + return this.value && this.value.isNode ? this.value.getNodeType( builder ) : 'float'; - const { type, inputs, name, precision, inputsCode, blockCode, headerCode } = parse$1( source ); + } - super( type, inputs, name, precision ); + setup() { - this.inputsCode = inputsCode; - this.blockCode = blockCode; - this.headerCode = headerCode; + return this.value && this.value.isNode ? this.value : float(); } - getCode( name = this.name ) { - - let code; + serialize( data ) { - const blockCode = this.blockCode; + super.serialize( data ); - if ( blockCode !== '' ) { + if ( this.value !== null ) { - const { type, inputsCode, headerCode, precision } = this; + if ( this.inputType === 'ArrayBuffer' ) { - let declarationCode = `${ type } ${ name } ( ${ inputsCode.trim() } )`; + data.value = arrayBufferToBase64( this.value ); - if ( precision !== '' ) { + } else { - declarationCode = `${ precision } ${ declarationCode }`; + data.value = this.value ? this.value.toJSON( data.meta ).uuid : null; } - code = headerCode + declarationCode + blockCode; - } else { - // interface function - - code = ''; + data.value = null; } - return code; + data.inputType = this.inputType; + data.outputType = this.outputType; } -} + deserialize( data ) { -class GLSLNodeParser extends NodeParser { + super.deserialize( data ); - parseFunction( source ) { + let value = null; - return new GLSLNodeFunction( source ); + if ( data.value !== null ) { - } + if ( data.inputType === 'ArrayBuffer' ) { -} + value = base64ToArrayBuffer( data.value ); -function painterSortStable( a, b ) { + } else if ( data.inputType === 'Texture' ) { - if ( a.groupOrder !== b.groupOrder ) { - - return a.groupOrder - b.groupOrder; - - } else if ( a.renderOrder !== b.renderOrder ) { - - return a.renderOrder - b.renderOrder; + value = data.meta.textures[ data.value ]; - } else if ( a.material.id !== b.material.id ) { + } else { - return a.material.id - b.material.id; + value = data.meta.nodes[ data.value ] || null; - } else if ( a.z !== b.z ) { + } - return a.z - b.z; + } - } else { + this.value = value; - return a.id - b.id; + this.inputType = data.inputType; + this.outputType = data.outputType; } } -function reversePainterSortStable( a, b ) { - - if ( a.groupOrder !== b.groupOrder ) { - - return a.groupOrder - b.groupOrder; +const scriptableValue = /*@__PURE__*/ nodeProxy( ScriptableValueNode ); - } else if ( a.renderOrder !== b.renderOrder ) { +class Resources extends Map { - return a.renderOrder - b.renderOrder; + get( key, callback = null, ...params ) { - } else if ( a.z !== b.z ) { + if ( this.has( key ) ) return super.get( key ); - return b.z - a.z; + if ( callback !== null ) { - } else { + const value = callback( ...params ); + this.set( key, value ); + return value; - return a.id - b.id; + } } } -class RenderList { +class Parameters { - constructor() { + constructor( scriptableNode ) { - this.renderItems = []; - this.renderItemsIndex = 0; + this.scriptableNode = scriptableNode; - this.opaque = []; - this.transparent = []; - this.bundles = []; + } - this.lightsNode = new LightsNode( [] ); - this.lightsArray = []; + get parameters() { - this.occlusionQueryCount = 0; + return this.scriptableNode.parameters; } - begin() { - - this.renderItemsIndex = 0; + get layout() { - this.opaque.length = 0; - this.transparent.length = 0; - this.bundles.length = 0; + return this.scriptableNode.getLayout(); - this.lightsArray.length = 0; + } - this.occlusionQueryCount = 0; + getInputLayout( id ) { - return this; + return this.scriptableNode.getInputLayout( id ); } - getNextRenderItem( object, geometry, material, groupOrder, z, group ) { - - let renderItem = this.renderItems[ this.renderItemsIndex ]; + get( name ) { - if ( renderItem === undefined ) { + const param = this.parameters[ name ]; + const value = param ? param.getValue() : null; - renderItem = { - id: object.id, - object: object, - geometry: geometry, - material: material, - groupOrder: groupOrder, - renderOrder: object.renderOrder, - z: z, - group: group - }; + return value; - this.renderItems[ this.renderItemsIndex ] = renderItem; + } - } else { +} - renderItem.id = object.id; - renderItem.object = object; - renderItem.geometry = geometry; - renderItem.material = material; - renderItem.groupOrder = groupOrder; - renderItem.renderOrder = object.renderOrder; - renderItem.z = z; - renderItem.group = group; +const global = new Resources(); - } +class ScriptableNode extends Node { - this.renderItemsIndex ++; + static get type() { - return renderItem; + return 'ScriptableNode'; } - push( object, geometry, material, groupOrder, z, group ) { - - const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group ); - - if ( object.occlusionTest === true ) this.occlusionQueryCount ++; + constructor( codeNode = null, parameters = {} ) { - ( material.transparent === true || material.transmission > 0 ? this.transparent : this.opaque ).push( renderItem ); + super(); - } + this.codeNode = codeNode; + this.parameters = parameters; - unshift( object, geometry, material, groupOrder, z, group ) { + this._local = new Resources(); + this._output = scriptableValue(); + this._outputs = {}; + this._source = this.source; + this._method = null; + this._object = null; + this._value = null; + this._needsOutputUpdate = true; - const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group ); + this.onRefresh = this.onRefresh.bind( this ); - ( material.transparent === true ? this.transparent : this.opaque ).unshift( renderItem ); + this.isScriptableNode = true; } - pushBundle( group ) { + get source() { - this.bundles.push( group ); + return this.codeNode ? this.codeNode.code : ''; } - pushLight( light ) { + setLocal( name, value ) { - this.lightsArray.push( light ); + return this._local.set( name, value ); } - getLightsNode() { + getLocal( name ) { - return this.lightsNode.fromLights( this.lightsArray ); + return this._local.get( name ); } - sort( customOpaqueSort, customTransparentSort ) { + onRefresh() { - if ( this.opaque.length > 1 ) this.opaque.sort( customOpaqueSort || painterSortStable ); - if ( this.transparent.length > 1 ) this.transparent.sort( customTransparentSort || reversePainterSortStable ); + this._refresh(); } - finish() { - - // update lights - - this.lightsNode.setLights( this.lightsArray ); - - // Clear references from inactive renderItems in the list + getInputLayout( id ) { - for ( let i = this.renderItemsIndex, il = this.renderItems.length; i < il; i ++ ) { + for ( const element of this.getLayout() ) { - const renderItem = this.renderItems[ i ]; + if ( element.inputType && ( element.id === id || element.name === id ) ) { - if ( renderItem.id === null ) break; + return element; - renderItem.id = null; - renderItem.object = null; - renderItem.geometry = null; - renderItem.material = null; - renderItem.groupOrder = null; - renderItem.renderOrder = null; - renderItem.z = null; - renderItem.group = null; + } } } -} + getOutputLayout( id ) { -class RenderLists { + for ( const element of this.getLayout() ) { - constructor() { + if ( element.outputType && ( element.id === id || element.name === id ) ) { - this.lists = new ChainMap(); + return element; + + } + + } } - get( scene, camera ) { + setOutput( name, value ) { - const lists = this.lists; - const keys = [ scene, camera ]; + const outputs = this._outputs; - let list = lists.get( keys ); + if ( outputs[ name ] === undefined ) { - if ( list === undefined ) { + outputs[ name ] = scriptableValue( value ); - list = new RenderList(); - lists.set( keys, list ); + } else { + + outputs[ name ].value = value; } - return list; + return this; } - dispose() { + getOutput( name ) { - this.lists = new ChainMap(); + return this._outputs[ name ]; } -} + getParameter( name ) { -let id = 0; + return this.parameters[ name ]; -class RenderContext { + } - constructor() { + setParameter( name, value ) { - this.id = id ++; + const parameters = this.parameters; - this.color = true; - this.clearColor = true; - this.clearColorValue = { r: 0, g: 0, b: 0, a: 1 }; + if ( value && value.isScriptableNode ) { - this.depth = true; - this.clearDepth = true; - this.clearDepthValue = 1; + this.deleteParameter( name ); - this.stencil = false; - this.clearStencil = true; - this.clearStencilValue = 1; + parameters[ name ] = value; + parameters[ name ].getDefaultOutput().events.addEventListener( 'refresh', this.onRefresh ); - this.viewport = false; - this.viewportValue = new Vector4(); + } else if ( value && value.isScriptableValueNode ) { - this.scissor = false; - this.scissorValue = new Vector4(); + this.deleteParameter( name ); - this.textures = null; - this.depthTexture = null; - this.activeCubeFace = 0; - this.sampleCount = 1; + parameters[ name ] = value; + parameters[ name ].events.addEventListener( 'refresh', this.onRefresh ); - this.width = 0; - this.height = 0; + } else if ( parameters[ name ] === undefined ) { - this.isRenderContext = true; + parameters[ name ] = scriptableValue( value ); + parameters[ name ].events.addEventListener( 'refresh', this.onRefresh ); - } + } else { - getCacheKey() { + parameters[ name ].value = value; - return getCacheKey( this ); + } + + return this; } -} + getValue() { -function getCacheKey( renderContext ) { + return this.getDefaultOutput().getValue(); - const { textures, activeCubeFace } = renderContext; + } - let key = ''; + deleteParameter( name ) { - for ( const texture of textures ) { + let valueNode = this.parameters[ name ]; - key += texture.id + ','; + if ( valueNode ) { - } + if ( valueNode.isScriptableNode ) valueNode = valueNode.getDefaultOutput(); - key += activeCubeFace; + valueNode.events.removeEventListener( 'refresh', this.onRefresh ); - return key; + } -} + return this; -class RenderContexts { + } - constructor() { + clearParameters() { - this.chainMaps = {}; + for ( const name of Object.keys( this.parameters ) ) { - } + this.deleteParameter( name ); - get( scene, camera, renderTarget = null ) { + } - const chainKey = [ scene, camera ]; + this.needsUpdate = true; - let attachmentState; + return this; - if ( renderTarget === null ) { + } - attachmentState = 'default'; + call( name, ...params ) { - } else { + const object = this.getObject(); + const method = object[ name ]; - const format = renderTarget.texture.format; - const count = renderTarget.textures.length; + if ( typeof method === 'function' ) { - attachmentState = `${ count }:${ format }:${ renderTarget.samples }:${ renderTarget.depthBuffer }:${ renderTarget.stencilBuffer }`; + return method( ...params ); } - const chainMap = this.getChainMap( attachmentState ); + } - let renderState = chainMap.get( chainKey ); + async callAsync( name, ...params ) { - if ( renderState === undefined ) { + const object = this.getObject(); + const method = object[ name ]; - renderState = new RenderContext(); + if ( typeof method === 'function' ) { - chainMap.set( chainKey, renderState ); + return method.constructor.name === 'AsyncFunction' ? await method( ...params ) : method( ...params ); } - if ( renderTarget !== null ) renderState.sampleCount = renderTarget.samples === 0 ? 1 : renderTarget.samples; + } - return renderState; + getNodeType( builder ) { + + return this.getDefaultOutputNode().getNodeType( builder ); } - getChainMap( attachmentState ) { + refresh( output = null ) { - return this.chainMaps[ attachmentState ] || ( this.chainMaps[ attachmentState ] = new ChainMap() ); + if ( output !== null ) { - } + this.getOutput( output ).refresh(); - dispose() { + } else { - this.chainMaps = {}; + this._refresh(); + + } } -} + getObject() { -const _size = /*@__PURE__*/ new Vector3(); + if ( this.needsUpdate ) this.dispose(); + if ( this._object !== null ) return this._object; -class Textures extends DataMap { + // - constructor( renderer, backend, info ) { + const refresh = () => this.refresh(); + const setOutput = ( id, value ) => this.setOutput( id, value ); - super(); + const parameters = new Parameters( this ); - this.renderer = renderer; - this.backend = backend; - this.info = info; + const THREE = global.get( 'THREE' ); + const TSL = global.get( 'TSL' ); - } + const method = this.getMethod( this.codeNode ); + const params = [ parameters, this._local, global, refresh, setOutput, THREE, TSL ]; - updateRenderTarget( renderTarget, activeMipmapLevel = 0 ) { + this._object = method( ...params ); - const renderTargetData = this.get( renderTarget ); + const layout = this._object.layout; - const sampleCount = renderTarget.samples === 0 ? 1 : renderTarget.samples; - const depthTextureMips = renderTargetData.depthTextureMips || ( renderTargetData.depthTextureMips = {} ); + if ( layout ) { - const textures = renderTarget.textures; + if ( layout.cache === false ) { - const size = this.getSize( textures[ 0 ] ); + this._local.clear(); - const mipWidth = size.width >> activeMipmapLevel; - const mipHeight = size.height >> activeMipmapLevel; + } - let depthTexture = renderTarget.depthTexture || depthTextureMips[ activeMipmapLevel ]; - let textureNeedsUpdate = false; + // default output + this._output.outputType = layout.outputType || null; - if ( depthTexture === undefined ) { + if ( Array.isArray( layout.elements ) ) { - depthTexture = new DepthTexture(); - depthTexture.format = renderTarget.stencilBuffer ? DepthStencilFormat : DepthFormat; - depthTexture.type = renderTarget.stencilBuffer ? UnsignedInt248Type : UnsignedIntType; // FloatType - depthTexture.image.width = mipWidth; - depthTexture.image.height = mipHeight; + for ( const element of layout.elements ) { - depthTextureMips[ activeMipmapLevel ] = depthTexture; + const id = element.id || element.name; - } + if ( element.inputType ) { - if ( renderTargetData.width !== size.width || size.height !== renderTargetData.height ) { + if ( this.getParameter( id ) === undefined ) this.setParameter( id, null ); - textureNeedsUpdate = true; - depthTexture.needsUpdate = true; + this.getParameter( id ).inputType = element.inputType; - depthTexture.image.width = mipWidth; - depthTexture.image.height = mipHeight; + } - } + if ( element.outputType ) { - renderTargetData.width = size.width; - renderTargetData.height = size.height; - renderTargetData.textures = textures; - renderTargetData.depthTexture = depthTexture; - renderTargetData.depth = renderTarget.depthBuffer; - renderTargetData.stencil = renderTarget.stencilBuffer; - renderTargetData.renderTarget = renderTarget; + if ( this.getOutput( id ) === undefined ) this.setOutput( id, null ); - if ( renderTargetData.sampleCount !== sampleCount ) { + this.getOutput( id ).outputType = element.outputType; - textureNeedsUpdate = true; - depthTexture.needsUpdate = true; + } - renderTargetData.sampleCount = sampleCount; + } + + } } - // + return this._object; - const options = { sampleCount }; + } - for ( let i = 0; i < textures.length; i ++ ) { + deserialize( data ) { - const texture = textures[ i ]; + super.deserialize( data ); - if ( textureNeedsUpdate ) texture.needsUpdate = true; + for ( const name in this.parameters ) { - this.updateTexture( texture, options ); + let valueNode = this.parameters[ name ]; - } + if ( valueNode.isScriptableNode ) valueNode = valueNode.getDefaultOutput(); - this.updateTexture( depthTexture, options ); + valueNode.events.addEventListener( 'refresh', this.onRefresh ); - // dispose handler + } - if ( renderTargetData.initialized !== true ) { + } - renderTargetData.initialized = true; + getLayout() { - // dispose + return this.getObject().layout; - const onDispose = () => { + } - renderTarget.removeEventListener( 'dispose', onDispose ); + getDefaultOutputNode() { - for ( let i = 0; i < textures.length; i ++ ) { + const output = this.getDefaultOutput().value; - this._destroyTexture( textures[ i ] ); + if ( output && output.isNode ) { - } + return output; - this._destroyTexture( depthTexture ); + } - this.delete( renderTarget ); + return float(); - }; + } - renderTarget.addEventListener( 'dispose', onDispose ); + getDefaultOutput() { - } + return this._exec()._output; } - updateTexture( texture, options = {} ) { - - const textureData = this.get( texture ); - if ( textureData.initialized === true && textureData.version === texture.version ) return; + getMethod() { - const isRenderTarget = texture.isRenderTargetTexture || texture.isDepthTexture || texture.isFramebufferTexture; - const backend = this.backend; + if ( this.needsUpdate ) this.dispose(); + if ( this._method !== null ) return this._method; - if ( isRenderTarget && textureData.initialized === true ) { + // - // it's an update + const parametersProps = [ 'parameters', 'local', 'global', 'refresh', 'setOutput', 'THREE', 'TSL' ]; + const interfaceProps = [ 'layout', 'init', 'main', 'dispose' ]; - backend.destroySampler( texture ); - backend.destroyTexture( texture ); + const properties = interfaceProps.join( ', ' ); + const declarations = 'var ' + properties + '; var output = {};\n'; + const returns = '\nreturn { ...output, ' + properties + ' };'; - } + const code = declarations + this.codeNode.code + returns; // - if ( texture.isFramebufferTexture ) { + this._method = new Function( ...parametersProps, code ); - const renderer = this.renderer; - const renderTarget = renderer.getRenderTarget(); + return this._method; - if ( renderTarget ) { + } - texture.type = renderTarget.texture.type; + dispose() { - } else { + if ( this._method === null ) return; - texture.type = UnsignedByteType; + if ( this._object && typeof this._object.dispose === 'function' ) { - } + this._object.dispose(); } - // + this._method = null; + this._object = null; + this._source = null; + this._value = null; + this._needsOutputUpdate = true; + this._output.value = null; + this._outputs = {}; - const { width, height, depth } = this.getSize( texture ); + } - options.width = width; - options.height = height; - options.depth = depth; - options.needsMipmaps = this.needsMipmaps( texture ); - options.levels = options.needsMipmaps ? this.getMipLevels( texture, width, height ) : 1; + setup() { - // + return this.getDefaultOutputNode(); - if ( isRenderTarget || texture.isStorageTexture === true ) { + } - backend.createSampler( texture ); - backend.createTexture( texture, options ); + getCacheKey( force ) { - textureData.generation = texture.version; + const values = [ hashString( this.source ), this.getDefaultOutputNode().getCacheKey( force ) ]; - } else { + for ( const param in this.parameters ) { - const needsCreate = textureData.initialized !== true; + values.push( this.parameters[ param ].getCacheKey( force ) ); - if ( needsCreate ) backend.createSampler( texture ); + } - if ( texture.version > 0 ) { + return hashArray( values ); - const image = texture.image; + } - if ( image === undefined ) { + set needsUpdate( value ) { - console.warn( 'THREE.Renderer: Texture marked for update but image is undefined.' ); - - } else if ( image.complete === false ) { - - console.warn( 'THREE.Renderer: Texture marked for update but image is incomplete.' ); - - } else { + if ( value === true ) this.dispose(); - if ( texture.images ) { + } - const images = []; + get needsUpdate() { - for ( const image of texture.images ) { + return this.source !== this._source; - images.push( image ); + } - } + _exec() { - options.images = images; + if ( this.codeNode === null ) return this; - } else { + if ( this._needsOutputUpdate === true ) { - options.image = image; + this._value = this.call( 'main' ); - } + this._needsOutputUpdate = false; - if ( textureData.isDefaultTexture === undefined || textureData.isDefaultTexture === true ) { + } - backend.createTexture( texture, options ); + this._output.value = this._value; - textureData.isDefaultTexture = false; - textureData.generation = texture.version; + return this; - } + } - if ( texture.source.dataReady === true ) backend.updateTexture( texture, options ); + _refresh() { - if ( options.needsMipmaps && texture.mipmaps.length === 0 ) backend.generateMipmaps( texture ); + this.needsUpdate = true; - } + this._exec(); - } else { + this._output.refresh(); - // async update + } - backend.createDefaultTexture( texture ); +} - textureData.isDefaultTexture = true; - textureData.generation = texture.version; +const scriptable = /*@__PURE__*/ nodeProxy( ScriptableNode ); - } +class FogNode extends Node { - } + static get type() { - // dispose handler + return 'FogNode'; - if ( textureData.initialized !== true ) { + } - textureData.initialized = true; - textureData.generation = texture.version; + constructor( colorNode, factorNode ) { - // + super( 'float' ); - this.info.memory.textures ++; + this.isFogNode = true; - // dispose + this.colorNode = colorNode; + this.factorNode = factorNode; - const onDispose = () => { + } - texture.removeEventListener( 'dispose', onDispose ); + getViewZNode( builder ) { - this._destroyTexture( texture ); + let viewZ; - this.info.memory.textures --; + const getViewZ = builder.context.getViewZ; - }; + if ( getViewZ !== undefined ) { - texture.addEventListener( 'dispose', onDispose ); + viewZ = getViewZ( this ); } - // - - textureData.version = texture.version; + return ( viewZ || positionView.z ).negate(); } - getSize( texture, target = _size ) { - - let image = texture.images ? texture.images[ 0 ] : texture.image; + setup() { - if ( image ) { + return this.factorNode; - if ( image.image !== undefined ) image = image.image; + } - target.width = image.width; - target.height = image.height; - target.depth = texture.isCubeTexture ? 6 : ( image.depth || 1 ); +} - } else { +const fog = /*@__PURE__*/ nodeProxy( FogNode ); - target.width = target.height = target.depth = 1; +class FogRangeNode extends FogNode { - } + static get type() { - return target; + return 'FogRangeNode'; } - getMipLevels( texture, width, height ) { + constructor( colorNode, nearNode, farNode ) { - let mipLevelCount; + super( colorNode ); - if ( texture.isCompressedTexture ) { + this.isFogRangeNode = true; - mipLevelCount = texture.mipmaps.length; + this.nearNode = nearNode; + this.farNode = farNode; - } else { + } - mipLevelCount = Math.floor( Math.log2( Math.max( width, height ) ) ) + 1; + setup( builder ) { - } + const viewZ = this.getViewZNode( builder ); - return mipLevelCount; + return smoothstep( this.nearNode, this.farNode, viewZ ); } - needsMipmaps( texture ) { +} - if ( this.isEnvironmentTexture( texture ) ) return true; +const rangeFog = /*@__PURE__*/ nodeProxy( FogRangeNode ); - return ( texture.isCompressedTexture === true ) || ( ( texture.minFilter !== NearestFilter ) && ( texture.minFilter !== LinearFilter ) ); +class FogExp2Node extends FogNode { + + static get type() { + + return 'FogExp2Node'; } - isEnvironmentTexture( texture ) { + constructor( colorNode, densityNode ) { - const mapping = texture.mapping; + super( colorNode ); - return ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) || ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping ); + this.isFogExp2Node = true; + + this.densityNode = densityNode; } - _destroyTexture( texture ) { + setup( builder ) { - this.backend.destroySampler( texture ); - this.backend.destroyTexture( texture ); + const viewZ = this.getViewZNode( builder ); + const density = this.densityNode; - this.delete( texture ); + return density.mul( density, viewZ, viewZ ).negate().exp().oneMinus(); } } -class Color4 extends Color { +const densityFog = /*@__PURE__*/ nodeProxy( FogExp2Node ); - constructor( r, g, b, a = 1 ) { +let min = null; +let max = null; - super( r, g, b ); +class RangeNode extends Node { - this.a = a; + static get type() { + + return 'RangeNode'; } - set( r, g, b, a = 1 ) { + constructor( minNode = float(), maxNode = float() ) { - this.a = a; + super(); - return super.set( r, g, b ); + this.minNode = minNode; + this.maxNode = maxNode; } - copy( color ) { + getVectorLength( builder ) { - if ( color.a !== undefined ) this.a = color.a; + const minLength = builder.getTypeLength( getValueType( this.minNode.value ) ); + const maxLength = builder.getTypeLength( getValueType( this.maxNode.value ) ); - return super.copy( color ); + return minLength > maxLength ? minLength : maxLength; } - clone() { + getNodeType( builder ) { - return new this.constructor( this.r, this.g, this.b, this.a ); + return builder.object.count > 1 ? builder.getTypeFromLength( this.getVectorLength( builder ) ) : 'float'; } -} + setup( builder ) { -const hash = /*@__PURE__*/ Fn( ( [ seed ] ) => { + const object = builder.object; - // Taken from https://www.shadertoy.com/view/XlGcRh, originally from pcg-random.org + let output = null; - const state = seed.toUint().mul( 747796405 ).add( 2891336453 ); - const word = state.shiftRight( state.shiftRight( 28 ).add( 4 ) ).bitXor( state ).mul( 277803737 ); - const result = word.shiftRight( 22 ).bitXor( word ); + if ( object.count > 1 ) { - return result.toFloat().mul( 1 / 2 ** 32 ); // Convert to range [0, 1) + const minValue = this.minNode.value; + const maxValue = this.maxNode.value; -} ); + const minLength = builder.getTypeLength( getValueType( minValue ) ); + const maxLength = builder.getTypeLength( getValueType( maxValue ) ); -// remapping functions https://iquilezles.org/articles/functions/ -const parabola = ( x, k ) => pow( mul( 4.0, x.mul( sub( 1.0, x ) ) ), k ); -const gain = ( x, k ) => x.lessThan( 0.5 ) ? parabola( x.mul( 2.0 ), k ).div( 2.0 ) : sub( 1.0, parabola( mul( sub( 1.0, x ), 2.0 ), k ).div( 2.0 ) ); -const pcurve = ( x, a, b ) => pow( div( pow( x, a ), add( pow( x, a ), pow( sub( 1.0, x ), b ) ) ), 1.0 / a ); -const sinc = ( x, k ) => sin( PI.mul( k.mul( x ).sub( 1.0 ) ) ).div( PI.mul( k.mul( x ).sub( 1.0 ) ) ); + min = min || new Vector4(); + max = max || new Vector4(); -// https://github.com/cabbibo/glsl-tri-noise-3d + min.setScalar( 0 ); + max.setScalar( 0 ); + if ( minLength === 1 ) min.setScalar( minValue ); + else if ( minValue.isColor ) min.set( minValue.r, minValue.g, minValue.b ); + else min.set( minValue.x, minValue.y, minValue.z || 0, minValue.w || 0 ); -const tri = /*@__PURE__*/ Fn( ( [ x ] ) => { + if ( maxLength === 1 ) max.setScalar( maxValue ); + else if ( maxValue.isColor ) max.set( maxValue.r, maxValue.g, maxValue.b ); + else max.set( maxValue.x, maxValue.y, maxValue.z || 0, maxValue.w || 0 ); - return x.fract().sub( .5 ).abs(); + const stride = 4; -} ).setLayout( { - name: 'tri', - type: 'float', - inputs: [ - { name: 'x', type: 'float' } - ] -} ); + const length = stride * object.count; + const array = new Float32Array( length ); -const tri3 = /*@__PURE__*/ Fn( ( [ p ] ) => { + for ( let i = 0; i < length; i ++ ) { - return vec3( tri( p.z.add( tri( p.y.mul( 1. ) ) ) ), tri( p.z.add( tri( p.x.mul( 1. ) ) ) ), tri( p.y.add( tri( p.x.mul( 1. ) ) ) ) ); + const index = i % stride; -} ).setLayout( { - name: 'tri3', - type: 'vec3', - inputs: [ - { name: 'p', type: 'vec3' } - ] -} ); + const minElementValue = min.getComponent( index ); + const maxElementValue = max.getComponent( index ); -const triNoise3D = /*@__PURE__*/ Fn( ( [ p_immutable, spd, time ] ) => { + array[ i ] = MathUtils.lerp( minElementValue, maxElementValue, Math.random() ); - const p = vec3( p_immutable ).toVar(); - const z = float( 1.4 ).toVar(); - const rz = float( 0.0 ).toVar(); - const bp = vec3( p ).toVar(); + } - Loop( { start: float( 0.0 ), end: float( 3.0 ), type: 'float', condition: '<=' }, () => { + const nodeType = this.getNodeType( builder ); - const dg = vec3( tri3( bp.mul( 2.0 ) ) ).toVar(); - p.addAssign( dg.add( time.mul( float( 0.1 ).mul( spd ) ) ) ); - bp.mulAssign( 1.8 ); - z.mulAssign( 1.5 ); - p.mulAssign( 1.2 ); + if ( object.count <= 4096 ) { - const t = float( tri( p.z.add( tri( p.x.add( tri( p.y ) ) ) ) ) ).toVar(); - rz.addAssign( t.div( z ) ); - bp.addAssign( 0.14 ); + output = buffer( array, 'vec4', object.count ).element( instanceIndex ).convert( nodeType ); - } ); + } else { - return rz; + // TODO: Improve anonymous buffer attribute creation removing this part + const bufferAttribute = new InstancedBufferAttribute( array, 4 ); + builder.geometry.setAttribute( '__range' + this.id, bufferAttribute ); -} ).setLayout( { - name: 'triNoise3D', - type: 'float', - inputs: [ - { name: 'p', type: 'vec3' }, - { name: 'spd', type: 'float' }, - { name: 'time', type: 'float' } - ] -} ); + output = instancedBufferAttribute( bufferAttribute ).convert( nodeType ); -const rotateUV = /*@__PURE__*/ Fn( ( [ uv, rotation, center = vec2( 0.5 ) ] ) => { + } - return rotate( uv.sub( center ), rotation ).add( center ); + } else { -} ); + output = float( 0 ); -const spherizeUV = /*@__PURE__*/ Fn( ( [ uv, strength, center = vec2( 0.5 ) ] ) => { + } - const delta = uv.sub( center ); - const delta2 = delta.dot( delta ); - const delta4 = delta2.mul( delta2 ); - const deltaOffset = delta4.mul( strength ); + return output; - return uv.add( delta.mul( deltaOffset ) ); + } -} ); +} -const billboarding = /*@__PURE__*/ Fn( ( { position = null, horizontal = true, vertical = false } ) => { +const range = /*@__PURE__*/ nodeProxy( RangeNode ); - let worldMatrix; +const BasicShadowMap = Fn( ( { depthTexture, shadowCoord } ) => { - if ( position !== null ) { + return texture( depthTexture, shadowCoord.xy ).compare( shadowCoord.z ); - worldMatrix = modelWorldMatrix.toVar(); - worldMatrix[ 3 ][ 0 ] = position.x; - worldMatrix[ 3 ][ 1 ] = position.y; - worldMatrix[ 3 ][ 2 ] = position.z; +} ); - } else { +const PCFShadowMap = Fn( ( { depthTexture, shadowCoord, shadow } ) => { - worldMatrix = modelWorldMatrix; + const depthCompare = ( uv, compare ) => texture( depthTexture, uv ).compare( compare ); - } + const mapSize = reference( 'mapSize', 'vec2', shadow ).setGroup( renderGroup ); + const radius = reference( 'radius', 'float', shadow ).setGroup( renderGroup ); - const modelViewMatrix = cameraViewMatrix.mul( worldMatrix ); + const texelSize = vec2( 1 ).div( mapSize ); + const dx0 = texelSize.x.negate().mul( radius ); + const dy0 = texelSize.y.negate().mul( radius ); + const dx1 = texelSize.x.mul( radius ); + const dy1 = texelSize.y.mul( radius ); + const dx2 = dx0.div( 2 ); + const dy2 = dy0.div( 2 ); + const dx3 = dx1.div( 2 ); + const dy3 = dy1.div( 2 ); - if ( defined( horizontal ) ) { + return add( + depthCompare( shadowCoord.xy.add( vec2( dx0, dy0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( 0, dy0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx1, dy0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx2, dy2 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( 0, dy2 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx3, dy2 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx0, 0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx2, 0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy, shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx3, 0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx1, 0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx2, dy3 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( 0, dy3 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx3, dy3 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx0, dy1 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( 0, dy1 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx1, dy1 ) ), shadowCoord.z ) + ).mul( 1 / 17 ); - modelViewMatrix[ 0 ][ 0 ] = modelWorldMatrix[ 0 ].length(); - modelViewMatrix[ 0 ][ 1 ] = 0; - modelViewMatrix[ 0 ][ 2 ] = 0; +} ); - } +const PCFSoftShadowMap = Fn( ( { depthTexture, shadowCoord, shadow } ) => { - if ( defined( vertical ) ) { + const depthCompare = ( uv, compare ) => texture( depthTexture, uv ).compare( compare ); - modelViewMatrix[ 1 ][ 0 ] = 0; - modelViewMatrix[ 1 ][ 1 ] = modelWorldMatrix[ 1 ].length(); - modelViewMatrix[ 1 ][ 2 ] = 0; + const mapSize = reference( 'mapSize', 'vec2', shadow ).setGroup( renderGroup ); - } + const texelSize = vec2( 1 ).div( mapSize ); + const dx = texelSize.x; + const dy = texelSize.y; - modelViewMatrix[ 2 ][ 0 ] = 0; - modelViewMatrix[ 2 ][ 1 ] = 0; - modelViewMatrix[ 2 ][ 2 ] = 1; + const uv = shadowCoord.xy; + const f = fract( uv.mul( mapSize ).add( 0.5 ) ); + uv.subAssign( f.mul( texelSize ) ); - return cameraProjectionMatrix.mul( modelViewMatrix ).mul( positionLocal ); + return add( + depthCompare( uv, shadowCoord.z ), + depthCompare( uv.add( vec2( dx, 0 ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( 0, dy ) ), shadowCoord.z ), + depthCompare( uv.add( texelSize ), shadowCoord.z ), + mix( + depthCompare( uv.add( vec2( dx.negate(), 0 ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( dx.mul( 2 ), 0 ) ), shadowCoord.z ), + f.x + ), + mix( + depthCompare( uv.add( vec2( dx.negate(), dy ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( dx.mul( 2 ), dy ) ), shadowCoord.z ), + f.x + ), + mix( + depthCompare( uv.add( vec2( 0, dy.negate() ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( 0, dy.mul( 2 ) ) ), shadowCoord.z ), + f.y + ), + mix( + depthCompare( uv.add( vec2( dx, dy.negate() ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( dx, dy.mul( 2 ) ) ), shadowCoord.z ), + f.y + ), + mix( + mix( + depthCompare( uv.add( vec2( dx.negate(), dy.negate() ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( dx.mul( 2 ), dy.negate() ) ), shadowCoord.z ), + f.x + ), + mix( + depthCompare( uv.add( vec2( dx.negate(), dy.mul( 2 ) ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( dx.mul( 2 ), dy.mul( 2 ) ) ), shadowCoord.z ), + f.x + ), + f.y + ) + ).mul( 1 / 9 ); } ); -const viewportSafeUV = /*@__PURE__*/ Fn( ( [ uv = null ] ) => { +// VSM - const depth = linearDepth(); - const depthDiff = linearDepth( viewportDepthTexture( uv ) ).sub( depth ); - const finalUV = depthDiff.lessThan( 0 ).select( viewportUV, uv ); +const VSMShadowMapNode = Fn( ( { depthTexture, shadowCoord } ) => { - return finalUV; + const occlusion = float( 1 ).toVar(); -} ); + const distribution = texture( depthTexture ).uv( shadowCoord.xy ).rg; -const _matrixCache = new WeakMap(); + const hardShadow = step( shadowCoord.z, distribution.x ); -class VelocityNode extends TempNode { + If( hardShadow.notEqual( float( 1.0 ) ), () => { - constructor() { + const distance = shadowCoord.z.sub( distribution.x ); + const variance = max$1( 0, distribution.y.mul( distribution.y ) ); + let softnessProbability = variance.div( variance.add( distance.mul( distance ) ) ); // Chebeyshevs inequality + softnessProbability = clamp( sub( softnessProbability, 0.3 ).div( 0.95 - 0.3 ) ); + occlusion.assign( clamp( max$1( hardShadow, softnessProbability ) ) ); - super( 'vec2' ); + } ); - this.updateType = NodeUpdateType.OBJECT; - this.updateAfterType = NodeUpdateType.OBJECT; + return occlusion; - this.previousProjectionMatrix = uniform( new Matrix4() ); - this.previousModelViewMatrix = uniform( new Matrix4() ); +} ); - } +const VSMPassVertical = Fn( ( { samples, radius, size, shadowPass } ) => { - update( { camera, object } ) { + const mean = float( 0 ).toVar(); + const squaredMean = float( 0 ).toVar(); - const previousModelMatrix = getPreviousMatrix( object ); - const previousCameraMatrix = getPreviousMatrix( camera ); + const uvStride = samples.lessThanEqual( float( 1 ) ).select( float( 0 ), float( 2 ).div( samples.sub( 1 ) ) ); + const uvStart = samples.lessThanEqual( float( 1 ) ).select( float( 0 ), float( - 1 ) ); - this.previousModelViewMatrix.value.copy( previousModelMatrix ); - this.previousProjectionMatrix.value.copy( previousCameraMatrix ); + Loop( { start: int( 0 ), end: int( samples ), type: 'int', condition: '<' }, ( { i } ) => { - } + const uvOffset = uvStart.add( float( i ).mul( uvStride ) ); - updateAfter( { camera, object } ) { + const depth = shadowPass.uv( add( screenCoordinate.xy, vec2( 0, uvOffset ).mul( radius ) ).div( size ) ).x; + mean.addAssign( depth ); + squaredMean.addAssign( depth.mul( depth ) ); - const previousModelMatrix = getPreviousMatrix( object ); - const previousCameraMatrix = getPreviousMatrix( camera ); + } ); - previousModelMatrix.copy( object.modelViewMatrix ); - previousCameraMatrix.copy( camera.projectionMatrix ); + mean.divAssign( samples ); + squaredMean.divAssign( samples ); - } + const std_dev = sqrt( squaredMean.sub( mean.mul( mean ) ) ); + return vec2( mean, std_dev ); - setup( /*builder*/ ) { +} ); - const clipPositionCurrent = cameraProjectionMatrix.mul( modelViewMatrix ).mul( positionLocal ); - const clipPositionPrevious = this.previousProjectionMatrix.mul( this.previousModelViewMatrix ).mul( positionPrevious ); +const VSMPassHorizontal = Fn( ( { samples, radius, size, shadowPass } ) => { - const ndcPositionCurrent = clipPositionCurrent.xy.div( clipPositionCurrent.w ); - const ndcPositionPrevious = clipPositionPrevious.xy.div( clipPositionPrevious.w ); + const mean = float( 0 ).toVar(); + const squaredMean = float( 0 ).toVar(); - const velocity = sub( ndcPositionCurrent, ndcPositionPrevious ); + const uvStride = samples.lessThanEqual( float( 1 ) ).select( float( 0 ), float( 2 ).div( samples.sub( 1 ) ) ); + const uvStart = samples.lessThanEqual( float( 1 ) ).select( float( 0 ), float( - 1 ) ); - return velocity; + Loop( { start: int( 0 ), end: int( samples ), type: 'int', condition: '<' }, ( { i } ) => { - } + const uvOffset = uvStart.add( float( i ).mul( uvStride ) ); -} + const distribution = shadowPass.uv( add( screenCoordinate.xy, vec2( uvOffset, 0 ).mul( radius ) ).div( size ) ); + mean.addAssign( distribution.x ); + squaredMean.addAssign( add( distribution.y.mul( distribution.y ), distribution.x.mul( distribution.x ) ) ); -function getPreviousMatrix( object ) { + } ); - let previousMatrix = _matrixCache.get( object ); + mean.divAssign( samples ); + squaredMean.divAssign( samples ); - if ( previousMatrix === undefined ) { + const std_dev = sqrt( squaredMean.sub( mean.mul( mean ) ) ); + return vec2( mean, std_dev ); - previousMatrix = new Matrix4(); - _matrixCache.set( object, previousMatrix ); +} ); - } +const _shadowFilterLib = [ BasicShadowMap, PCFShadowMap, PCFSoftShadowMap, VSMShadowMapNode ]; - return previousMatrix; +// -} +let _overrideMaterial = null; +const _quadMesh$1 = /*@__PURE__*/ new QuadMesh(); -VelocityNode.type = /*@__PURE__*/ registerNode( 'Velocity', VelocityNode ); +class AnalyticLightNode extends LightingNode { -const velocity = /*@__PURE__*/ nodeImmutable( VelocityNode ); + static get type() { -const burn = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { + return 'AnalyticLightNode'; - return min$1( 1.0, base.oneMinus().div( blend ) ).oneMinus(); + } -} ).setLayout( { - name: 'burnBlend', - type: 'vec3', - inputs: [ - { name: 'base', type: 'vec3' }, - { name: 'blend', type: 'vec3' } - ] -} ); + constructor( light = null ) { -const dodge = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { + super(); - return min$1( base.div( blend.oneMinus() ), 1.0 ); + this.updateType = NodeUpdateType.FRAME; -} ).setLayout( { - name: 'dodgeBlend', - type: 'vec3', - inputs: [ - { name: 'base', type: 'vec3' }, - { name: 'blend', type: 'vec3' } - ] -} ); + this.light = light; -const screen = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { + this.color = new Color(); + this.colorNode = uniform( this.color ).setGroup( renderGroup ); - return base.oneMinus().mul( blend.oneMinus() ).oneMinus(); + this.baseColorNode = null; -} ).setLayout( { - name: 'screenBlend', - type: 'vec3', - inputs: [ - { name: 'base', type: 'vec3' }, - { name: 'blend', type: 'vec3' } - ] -} ); + this.shadowMap = null; + this.shadowNode = null; + this.shadowColorNode = null; -const overlay = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { + this.vsmShadowMapVertical = null; + this.vsmShadowMapHorizontal = null; - return mix( base.mul( 2.0 ).mul( blend ), base.oneMinus().mul( 2.0 ).mul( blend.oneMinus() ).oneMinus(), step( 0.5, base ) ); + this.vsmMaterialVertical = null; + this.vsmMaterialHorizontal = null; -} ).setLayout( { - name: 'overlayBlend', - type: 'vec3', - inputs: [ - { name: 'base', type: 'vec3' }, - { name: 'blend', type: 'vec3' } - ] -} ); + this.isAnalyticLightNode = true; -const motionBlur = /*@__PURE__*/ Fn( ( [ inputNode, velocity, numSamples = int( 16 ) ] ) => { + } - const sampleColor = ( uv ) => inputNode.uv( uv ); + getCacheKey() { - const uvs = uv(); + return hash$1( super.getCacheKey(), this.light.id, this.light.castShadow ? 1 : 0 ); - const colorResult = sampleColor( uvs ).toVar(); - const fSamples = float( numSamples ); + } - Loop( { start: int( 1 ), end: numSamples, type: 'int', condition: '<=' }, ( { i } ) => { + getHash() { - const offset = velocity.mul( float( i ).div( fSamples.sub( 1 ) ).sub( 0.5 ) ); - colorResult.addAssign( sampleColor( uvs.add( offset ) ) ); + return this.light.uuid; - } ); + } - colorResult.divAssign( fSamples ); + setupShadow( builder ) { - return colorResult; + const { object, renderer } = builder; -} ); + if ( renderer.shadowMap.enabled === false ) return; -const bleach = /*@__PURE__*/ Fn( ( [ color, opacity = 1 ] ) => { + let shadowColorNode = this.shadowColorNode; - const base = color; - const lum = luminance( base.rgb ); - const blend = vec3( lum ); + if ( shadowColorNode === null ) { - const L = min$1( 1.0, max$1( 0.0, float( 10.0 ).mul( lum.sub( 0.45 ) ) ) ); + if ( _overrideMaterial === null ) { - const result1 = blend.mul( base.rgb ).mul( 2.0 ); - const result2 = float( 2.0 ).mul( blend.oneMinus() ).mul( base.rgb.oneMinus() ).oneMinus(); + _overrideMaterial = new NodeMaterial(); + _overrideMaterial.fragmentNode = vec4( 0, 0, 0, 1 ); + _overrideMaterial.isShadowNodeMaterial = true; // Use to avoid other overrideMaterial override material.fragmentNode unintentionally when using material.shadowNode + _overrideMaterial.name = 'ShadowMaterial'; - const newColor = mix( result1, result2, L ); + } - const A2 = base.a.mul( opacity ); + const shadowMapType = renderer.shadowMap.type; + const shadow = this.light.shadow; - const mixRGB = A2.mul( newColor.rgb ); + const depthTexture = new DepthTexture(); + depthTexture.compareFunction = LessCompare; - mixRGB.addAssign( base.rgb.mul( A2.oneMinus() ) ); + const shadowMap = builder.createRenderTarget( shadow.mapSize.width, shadow.mapSize.height ); + shadowMap.depthTexture = depthTexture; - return vec4( mixRGB, base.a ); + shadow.camera.updateProjectionMatrix(); -} ); + // VSM -const sepia = /*@__PURE__*/ Fn( ( [ color ] ) => { + if ( shadowMapType === VSMShadowMap ) { - const c = vec3( color ); + depthTexture.compareFunction = null; // VSM does not use textureSampleCompare()/texture2DCompare() - // https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/sepia.js + this.vsmShadowMapVertical = builder.createRenderTarget( shadow.mapSize.width, shadow.mapSize.height, { format: RGFormat, type: HalfFloatType } ); + this.vsmShadowMapHorizontal = builder.createRenderTarget( shadow.mapSize.width, shadow.mapSize.height, { format: RGFormat, type: HalfFloatType } ); - return vec4( - dot( c, vec3( 0.393, 0.769, 0.189 ) ), - dot( c, vec3( 0.349, 0.686, 0.168 ) ), - dot( c, vec3( 0.272, 0.534, 0.131 ) ), - color.a - ); + const shadowPassVertical = texture( depthTexture ); + const shadowPassHorizontal = texture( this.vsmShadowMapVertical.texture ); -} ); + const samples = reference( 'blurSamples', 'float', shadow ).setGroup( renderGroup ); + const radius = reference( 'radius', 'float', shadow ).setGroup( renderGroup ); + const size = reference( 'mapSize', 'vec2', shadow ).setGroup( renderGroup ); -const sRGBToLinear = /*@__PURE__*/ Fn( ( [ color ] ) => { + let material = this.vsmMaterialVertical || ( this.vsmMaterialVertical = new NodeMaterial() ); + material.fragmentNode = VSMPassVertical( { samples, radius, size, shadowPass: shadowPassVertical } ).context( builder.getSharedContext() ); + material.name = 'VSMVertical'; - const a = color.mul( 0.9478672986 ).add( 0.0521327014 ).pow( 2.4 ); - const b = color.mul( 0.0773993808 ); - const factor = color.lessThanEqual( 0.04045 ); + material = this.vsmMaterialHorizontal || ( this.vsmMaterialHorizontal = new NodeMaterial() ); + material.fragmentNode = VSMPassHorizontal( { samples, radius, size, shadowPass: shadowPassHorizontal } ).context( builder.getSharedContext() ); + material.name = 'VSMHorizontal'; - const rgbResult = mix( a, b, factor ); + } - return rgbResult; + // -} ).setLayout( { - name: 'sRGBToLinear', - type: 'vec3', - inputs: [ - { name: 'color', type: 'vec3' } - ] -} ); + const shadowIntensity = reference( 'intensity', 'float', shadow ).setGroup( renderGroup ); + const bias = reference( 'bias', 'float', shadow ).setGroup( renderGroup ); + const normalBias = reference( 'normalBias', 'float', shadow ).setGroup( renderGroup ); -const LinearTosRGB = /*@__PURE__*/ Fn( ( [ color ] ) => { + const position = object.material.shadowPositionNode || positionWorld; - const a = color.pow( 0.41666 ).mul( 1.055 ).sub( 0.055 ); - const b = color.mul( 12.92 ); - const factor = color.lessThanEqual( 0.0031308 ); + let shadowCoord = uniform( shadow.matrix ).setGroup( renderGroup ).mul( position.add( normalWorld.mul( normalBias ) ) ); + shadowCoord = shadowCoord.xyz.div( shadowCoord.w ); - const rgbResult = mix( a, b, factor ); + let coordZ = shadowCoord.z.add( bias ); - return rgbResult; + if ( renderer.coordinateSystem === WebGPUCoordinateSystem ) { -} ).setLayout( { - name: 'LinearTosRGB', - type: 'vec3', - inputs: [ - { name: 'color', type: 'vec3' } - ] -} ); + coordZ = coordZ.mul( 2 ).sub( 1 ); // WebGPU: Convertion [ 0, 1 ] to [ - 1, 1 ] -var ColorSpaceFunctions = /*#__PURE__*/Object.freeze({ - __proto__: null, - LinearTosRGB: LinearTosRGB, - sRGBToLinear: sRGBToLinear -}); + } -// exposure only + shadowCoord = vec3( + shadowCoord.x, + shadowCoord.y.oneMinus(), // follow webgpu standards + coordZ + ); -const LinearToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { + const frustumTest = shadowCoord.x.greaterThanEqual( 0 ) + .and( shadowCoord.x.lessThanEqual( 1 ) ) + .and( shadowCoord.y.greaterThanEqual( 0 ) ) + .and( shadowCoord.y.lessThanEqual( 1 ) ) + .and( shadowCoord.z.lessThanEqual( 1 ) ); - return color.mul( exposure ).clamp(); + // -} ).setLayout( { - name: 'LinearToneMapping', - type: 'vec3', - inputs: [ - { name: 'color', type: 'vec3' }, - { name: 'exposure', type: 'float' } - ] -} ); + const filterFn = shadow.filterNode || _shadowFilterLib[ renderer.shadowMap.type ] || null; -// source: https://www.cs.utah.edu/docs/techreports/2002/pdf/UUCS-02-001.pdf + if ( filterFn === null ) { -const ReinhardToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { + throw new Error( 'THREE.WebGPURenderer: Shadow map type not supported yet.' ); - color = color.mul( exposure ); + } - return color.div( color.add( 1.0 ) ).clamp(); + const shadowColor = texture( shadowMap.texture, shadowCoord ); + const shadowNode = frustumTest.select( filterFn( { depthTexture: ( shadowMapType === VSMShadowMap ) ? this.vsmShadowMapHorizontal.texture : depthTexture, shadowCoord, shadow } ), float( 1 ) ); -} ).setLayout( { - name: 'ReinhardToneMapping', - type: 'vec3', - inputs: [ - { name: 'color', type: 'vec3' }, - { name: 'exposure', type: 'float' } - ] -} ); + this.shadowMap = shadowMap; + this.light.shadow.map = shadowMap; -// source: http://filmicworlds.com/blog/filmic-tonemapping-operators/ + this.shadowNode = shadowNode; + this.shadowColorNode = shadowColorNode = this.colorNode.mul( mix( 1, shadowNode.rgb.mix( shadowColor, 1 ), shadowIntensity.mul( shadowColor.a ) ) ); -const CineonToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { + this.baseColorNode = this.colorNode; - // filmic operator by Jim Hejl and Richard Burgess-Dawson - color = color.mul( exposure ); - color = color.sub( 0.004 ).max( 0.0 ); + } - const a = color.mul( color.mul( 6.2 ).add( 0.5 ) ); - const b = color.mul( color.mul( 6.2 ).add( 1.7 ) ).add( 0.06 ); + // - return a.div( b ).pow( 2.2 ); + this.colorNode = shadowColorNode; -} ).setLayout( { - name: 'CineonToneMapping', - type: 'vec3', - inputs: [ - { name: 'color', type: 'vec3' }, - { name: 'exposure', type: 'float' } - ] -} ); + this.updateBeforeType = NodeUpdateType.RENDER; -// source: https://github.com/selfshadow/ltc_code/blob/master/webgl/shaders/ltc/ltc_blit.fs + } -const RRTAndODTFit = /*@__PURE__*/ Fn( ( [ color ] ) => { + setup( builder ) { - const a = color.mul( color.add( 0.0245786 ) ).sub( 0.000090537 ); - const b = color.mul( color.add( 0.4329510 ).mul( 0.983729 ) ).add( 0.238081 ); + this.colorNode = this.baseColorNode || this.colorNode; - return a.div( b ); + if ( this.light.castShadow ) { -} ); + if ( builder.object.receiveShadow ) { -// source: https://github.com/selfshadow/ltc_code/blob/master/webgl/shaders/ltc/ltc_blit.fs + this.setupShadow( builder ); -const ACESFilmicToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { + } - // sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT - const ACESInputMat = mat3( - 0.59719, 0.35458, 0.04823, - 0.07600, 0.90834, 0.01566, - 0.02840, 0.13383, 0.83777 - ); + } else if ( this.shadowNode !== null ) { - // ODT_SAT => XYZ => D60_2_D65 => sRGB - const ACESOutputMat = mat3( - 1.60475, - 0.53108, - 0.07367, - - 0.10208, 1.10813, - 0.00605, - - 0.00327, - 0.07276, 1.07602 - ); + this.disposeShadow(); - color = color.mul( exposure ).div( 0.6 ); + } - color = ACESInputMat.mul( color ); + } - // Apply RRT and ODT - color = RRTAndODTFit( color ); + updateShadow( frame ) { - color = ACESOutputMat.mul( color ); + const { shadowMap, light } = this; + const { renderer, scene, camera } = frame; - // Clamp to [0, 1] - return color.clamp(); + const shadowType = renderer.shadowMap.type; -} ).setLayout( { - name: 'ACESFilmicToneMapping', - type: 'vec3', - inputs: [ - { name: 'color', type: 'vec3' }, - { name: 'exposure', type: 'float' } - ] -} ); + const depthVersion = shadowMap.depthTexture.version; + this._depthVersionCached = depthVersion; -const LINEAR_REC2020_TO_LINEAR_SRGB = /*@__PURE__*/ mat3( vec3( 1.6605, - 0.1246, - 0.0182 ), vec3( - 0.5876, 1.1329, - 0.1006 ), vec3( - 0.0728, - 0.0083, 1.1187 ) ); -const LINEAR_SRGB_TO_LINEAR_REC2020 = /*@__PURE__*/ mat3( vec3( 0.6274, 0.0691, 0.0164 ), vec3( 0.3293, 0.9195, 0.0880 ), vec3( 0.0433, 0.0113, 0.8956 ) ); + const currentOverrideMaterial = scene.overrideMaterial; -const agxDefaultContrastApprox = /*@__PURE__*/ Fn( ( [ x_immutable ] ) => { + scene.overrideMaterial = _overrideMaterial; - const x = vec3( x_immutable ).toVar(); - const x2 = vec3( x.mul( x ) ).toVar(); - const x4 = vec3( x2.mul( x2 ) ).toVar(); + shadowMap.setSize( light.shadow.mapSize.width, light.shadow.mapSize.height ); - return float( 15.5 ).mul( x4.mul( x2 ) ).sub( mul( 40.14, x4.mul( x ) ) ).add( mul( 31.96, x4 ).sub( mul( 6.868, x2.mul( x ) ) ).add( mul( 0.4298, x2 ).add( mul( 0.1191, x ).sub( 0.00232 ) ) ) ); + light.shadow.updateMatrices( light ); + light.shadow.camera.layers.mask = camera.layers.mask; -} ); + const currentRenderTarget = renderer.getRenderTarget(); + const currentRenderObjectFunction = renderer.getRenderObjectFunction(); -const AgXToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { + renderer.setRenderObjectFunction( ( object, ...params ) => { - const colortone = vec3( color ).toVar(); - const AgXInsetMatrix = mat3( vec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ), vec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ), vec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 ) ); - const AgXOutsetMatrix = mat3( vec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ), vec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ), vec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 ) ); - const AgxMinEv = float( - 12.47393 ); - const AgxMaxEv = float( 4.026069 ); - colortone.mulAssign( exposure ); - colortone.assign( LINEAR_SRGB_TO_LINEAR_REC2020.mul( colortone ) ); - colortone.assign( AgXInsetMatrix.mul( colortone ) ); - colortone.assign( max$1( colortone, 1e-10 ) ); - colortone.assign( log2( colortone ) ); - colortone.assign( colortone.sub( AgxMinEv ).div( AgxMaxEv.sub( AgxMinEv ) ) ); - colortone.assign( clamp( colortone, 0.0, 1.0 ) ); - colortone.assign( agxDefaultContrastApprox( colortone ) ); - colortone.assign( AgXOutsetMatrix.mul( colortone ) ); - colortone.assign( pow( max$1( vec3( 0.0 ), colortone ), vec3( 2.2 ) ) ); - colortone.assign( LINEAR_REC2020_TO_LINEAR_SRGB.mul( colortone ) ); - colortone.assign( clamp( colortone, 0.0, 1.0 ) ); + if ( object.castShadow === true || ( object.receiveShadow && shadowType === VSMShadowMap ) ) { - return colortone; + renderer.renderObject( object, ...params ); -} ).setLayout( { - name: 'AgXToneMapping', - type: 'vec3', - inputs: [ - { name: 'color', type: 'vec3' }, - { name: 'exposure', type: 'float' } - ] -} ); + } -// https://modelviewer.dev/examples/tone-mapping + } ); -const NeutralToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { + renderer.setRenderTarget( shadowMap ); + renderer.render( scene, light.shadow.camera ); - const StartCompression = float( 0.8 - 0.04 ); - const Desaturation = float( 0.15 ); + renderer.setRenderObjectFunction( currentRenderObjectFunction ); - color = color.mul( exposure ); + // vsm blur pass - const x = min$1( color.r, min$1( color.g, color.b ) ); - const offset = select( x.lessThan( 0.08 ), x.sub( mul( 6.25, x.mul( x ) ) ), 0.04 ); + if ( light.isPointLight !== true && shadowType === VSMShadowMap ) { - color.subAssign( offset ); + this.vsmPass( frame, light ); - const peak = max$1( color.r, max$1( color.g, color.b ) ); + } - If( peak.lessThan( StartCompression ), () => { + renderer.setRenderTarget( currentRenderTarget ); - return color; + scene.overrideMaterial = currentOverrideMaterial; - } ); + } - const d = sub( 1, StartCompression ); - const newPeak = sub( 1, d.mul( d ).div( peak.add( d.sub( StartCompression ) ) ) ); - color.mulAssign( newPeak.div( peak ) ); - const g = sub( 1, div( 1, Desaturation.mul( peak.sub( newPeak ) ).add( 1 ) ) ); + vsmPass( frame, light ) { - return mix( color, vec3( newPeak ), g ); + const { renderer } = frame; -} ).setLayout( { - name: 'NeutralToneMapping', - type: 'vec3', - inputs: [ - { name: 'color', type: 'vec3' }, - { name: 'exposure', type: 'float' } - ] -} ); + this.vsmShadowMapVertical.setSize( light.shadow.mapSize.width, light.shadow.mapSize.height ); + this.vsmShadowMapHorizontal.setSize( light.shadow.mapSize.width, light.shadow.mapSize.height ); -var ToneMappingFunctions = /*#__PURE__*/Object.freeze({ - __proto__: null, - ACESFilmicToneMapping: ACESFilmicToneMapping, - AgXToneMapping: AgXToneMapping, - CineonToneMapping: CineonToneMapping, - LinearToneMapping: LinearToneMapping, - NeutralToneMapping: NeutralToneMapping, - ReinhardToneMapping: ReinhardToneMapping -}); + renderer.setRenderTarget( this.vsmShadowMapVertical ); + _quadMesh$1.material = this.vsmMaterialVertical; + _quadMesh$1.render( renderer ); -const checker = /*@__PURE__*/ Fn( ( [ coord = uv() ] ) => { + renderer.setRenderTarget( this.vsmShadowMapHorizontal ); + _quadMesh$1.material = this.vsmMaterialHorizontal; + _quadMesh$1.render( renderer ); - const uv = coord.mul( 2.0 ); + } - const cx = uv.x.floor(); - const cy = uv.y.floor(); - const result = cx.add( cy ).mod( 2.0 ); + disposeShadow() { - return result.sign(); + this.shadowMap.dispose(); + this.shadowMap = null; -} ); + if ( this.vsmShadowMapVertical !== null ) { -// Three.js Transpiler -// https://raw.githubusercontent.com/AcademySoftwareFoundation/MaterialX/main/libraries/stdlib/genglsl/lib/mx_noise.glsl + this.vsmShadowMapVertical.dispose(); + this.vsmShadowMapVertical = null; + this.vsmMaterialVertical.dispose(); + this.vsmMaterialVertical = null; + } -const mx_select = /*@__PURE__*/ Fn( ( [ b_immutable, t_immutable, f_immutable ] ) => { + if ( this.vsmShadowMapHorizontal !== null ) { - const f = float( f_immutable ).toVar(); - const t = float( t_immutable ).toVar(); - const b = bool( b_immutable ).toVar(); + this.vsmShadowMapHorizontal.dispose(); + this.vsmShadowMapHorizontal = null; - return select( b, t, f ); + this.vsmMaterialHorizontal.dispose(); + this.vsmMaterialHorizontal = null; -} ).setLayout( { - name: 'mx_select', - type: 'float', - inputs: [ - { name: 'b', type: 'bool' }, - { name: 't', type: 'float' }, - { name: 'f', type: 'float' } - ] -} ); + } -const mx_negate_if = /*@__PURE__*/ Fn( ( [ val_immutable, b_immutable ] ) => { + this.shadowNode = null; + this.shadowColorNode = null; - const b = bool( b_immutable ).toVar(); - const val = float( val_immutable ).toVar(); + this.baseColorNode = null; - return select( b, val.negate(), val ); + this.updateBeforeType = NodeUpdateType.NONE; -} ).setLayout( { - name: 'mx_negate_if', - type: 'float', - inputs: [ - { name: 'val', type: 'float' }, - { name: 'b', type: 'bool' } - ] -} ); + } -const mx_floor = /*@__PURE__*/ Fn( ( [ x_immutable ] ) => { + updateBefore( frame ) { - const x = float( x_immutable ).toVar(); + const shadow = this.light.shadow; - return int( floor( x ) ); + const needsUpdate = shadow.needsUpdate || shadow.autoUpdate; -} ).setLayout( { - name: 'mx_floor', - type: 'int', - inputs: [ - { name: 'x', type: 'float' } - ] -} ); + if ( needsUpdate ) { -const mx_floorfrac = /*@__PURE__*/ Fn( ( [ x_immutable, i ] ) => { + this.updateShadow( frame ); - const x = float( x_immutable ).toVar(); - i.assign( mx_floor( x ) ); + if ( this.shadowMap.depthTexture.version === this._depthVersionCached ) { - return x.sub( float( i ) ); + shadow.needsUpdate = false; -} ); + } -const mx_bilerp_0 = /*@__PURE__*/ Fn( ( [ v0_immutable, v1_immutable, v2_immutable, v3_immutable, s_immutable, t_immutable ] ) => { + } - const t = float( t_immutable ).toVar(); - const s = float( s_immutable ).toVar(); - const v3 = float( v3_immutable ).toVar(); - const v2 = float( v2_immutable ).toVar(); - const v1 = float( v1_immutable ).toVar(); - const v0 = float( v0_immutable ).toVar(); - const s1 = float( sub( 1.0, s ) ).toVar(); + } - return sub( 1.0, t ).mul( v0.mul( s1 ).add( v1.mul( s ) ) ).add( t.mul( v2.mul( s1 ).add( v3.mul( s ) ) ) ); + update( /*frame*/ ) { -} ).setLayout( { - name: 'mx_bilerp_0', - type: 'float', - inputs: [ - { name: 'v0', type: 'float' }, - { name: 'v1', type: 'float' }, - { name: 'v2', type: 'float' }, - { name: 'v3', type: 'float' }, - { name: 's', type: 'float' }, - { name: 't', type: 'float' } - ] -} ); + const { light } = this; -const mx_bilerp_1 = /*@__PURE__*/ Fn( ( [ v0_immutable, v1_immutable, v2_immutable, v3_immutable, s_immutable, t_immutable ] ) => { + this.color.copy( light.color ).multiplyScalar( light.intensity ); - const t = float( t_immutable ).toVar(); - const s = float( s_immutable ).toVar(); - const v3 = vec3( v3_immutable ).toVar(); - const v2 = vec3( v2_immutable ).toVar(); - const v1 = vec3( v1_immutable ).toVar(); - const v0 = vec3( v0_immutable ).toVar(); - const s1 = float( sub( 1.0, s ) ).toVar(); + } - return sub( 1.0, t ).mul( v0.mul( s1 ).add( v1.mul( s ) ) ).add( t.mul( v2.mul( s1 ).add( v3.mul( s ) ) ) ); +} -} ).setLayout( { - name: 'mx_bilerp_1', - type: 'vec3', - inputs: [ - { name: 'v0', type: 'vec3' }, - { name: 'v1', type: 'vec3' }, - { name: 'v2', type: 'vec3' }, - { name: 'v3', type: 'vec3' }, - { name: 's', type: 'float' }, - { name: 't', type: 'float' } - ] -} ); +const getDistanceAttenuation = /*@__PURE__*/ Fn( ( inputs ) => { -const mx_bilerp = /*@__PURE__*/ overloadingFn( [ mx_bilerp_0, mx_bilerp_1 ] ); + const { lightDistance, cutoffDistance, decayExponent } = inputs; -const mx_trilerp_0 = /*@__PURE__*/ Fn( ( [ v0_immutable, v1_immutable, v2_immutable, v3_immutable, v4_immutable, v5_immutable, v6_immutable, v7_immutable, s_immutable, t_immutable, r_immutable ] ) => { + // based upon Frostbite 3 Moving to Physically-based Rendering + // page 32, equation 26: E[window1] + // https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf + const distanceFalloff = lightDistance.pow( decayExponent ).max( 0.01 ).reciprocal(); - const r = float( r_immutable ).toVar(); - const t = float( t_immutable ).toVar(); - const s = float( s_immutable ).toVar(); - const v7 = float( v7_immutable ).toVar(); - const v6 = float( v6_immutable ).toVar(); - const v5 = float( v5_immutable ).toVar(); - const v4 = float( v4_immutable ).toVar(); - const v3 = float( v3_immutable ).toVar(); - const v2 = float( v2_immutable ).toVar(); - const v1 = float( v1_immutable ).toVar(); - const v0 = float( v0_immutable ).toVar(); - const s1 = float( sub( 1.0, s ) ).toVar(); - const t1 = float( sub( 1.0, t ) ).toVar(); - const r1 = float( sub( 1.0, r ) ).toVar(); + return cutoffDistance.greaterThan( 0 ).select( + distanceFalloff.mul( lightDistance.div( cutoffDistance ).pow4().oneMinus().clamp().pow2() ), + distanceFalloff + ); - return r1.mul( t1.mul( v0.mul( s1 ).add( v1.mul( s ) ) ).add( t.mul( v2.mul( s1 ).add( v3.mul( s ) ) ) ) ).add( r.mul( t1.mul( v4.mul( s1 ).add( v5.mul( s ) ) ).add( t.mul( v6.mul( s1 ).add( v7.mul( s ) ) ) ) ) ); +} ); // validated -} ).setLayout( { - name: 'mx_trilerp_0', - type: 'float', - inputs: [ - { name: 'v0', type: 'float' }, - { name: 'v1', type: 'float' }, - { name: 'v2', type: 'float' }, - { name: 'v3', type: 'float' }, - { name: 'v4', type: 'float' }, - { name: 'v5', type: 'float' }, - { name: 'v6', type: 'float' }, - { name: 'v7', type: 'float' }, - { name: 's', type: 'float' }, - { name: 't', type: 'float' }, - { name: 'r', type: 'float' } - ] -} ); +let uniformsLib; -const mx_trilerp_1 = /*@__PURE__*/ Fn( ( [ v0_immutable, v1_immutable, v2_immutable, v3_immutable, v4_immutable, v5_immutable, v6_immutable, v7_immutable, s_immutable, t_immutable, r_immutable ] ) => { +function getLightData( light ) { - const r = float( r_immutable ).toVar(); - const t = float( t_immutable ).toVar(); - const s = float( s_immutable ).toVar(); - const v7 = vec3( v7_immutable ).toVar(); - const v6 = vec3( v6_immutable ).toVar(); - const v5 = vec3( v5_immutable ).toVar(); - const v4 = vec3( v4_immutable ).toVar(); - const v3 = vec3( v3_immutable ).toVar(); - const v2 = vec3( v2_immutable ).toVar(); - const v1 = vec3( v1_immutable ).toVar(); - const v0 = vec3( v0_immutable ).toVar(); - const s1 = float( sub( 1.0, s ) ).toVar(); - const t1 = float( sub( 1.0, t ) ).toVar(); - const r1 = float( sub( 1.0, r ) ).toVar(); + uniformsLib = uniformsLib || new WeakMap(); - return r1.mul( t1.mul( v0.mul( s1 ).add( v1.mul( s ) ) ).add( t.mul( v2.mul( s1 ).add( v3.mul( s ) ) ) ) ).add( r.mul( t1.mul( v4.mul( s1 ).add( v5.mul( s ) ) ).add( t.mul( v6.mul( s1 ).add( v7.mul( s ) ) ) ) ) ); + let uniforms = uniformsLib.get( light ); -} ).setLayout( { - name: 'mx_trilerp_1', - type: 'vec3', - inputs: [ - { name: 'v0', type: 'vec3' }, - { name: 'v1', type: 'vec3' }, - { name: 'v2', type: 'vec3' }, - { name: 'v3', type: 'vec3' }, - { name: 'v4', type: 'vec3' }, - { name: 'v5', type: 'vec3' }, - { name: 'v6', type: 'vec3' }, - { name: 'v7', type: 'vec3' }, - { name: 's', type: 'float' }, - { name: 't', type: 'float' }, - { name: 'r', type: 'float' } - ] -} ); + if ( uniforms === undefined ) uniformsLib.set( light, uniforms = {} ); -const mx_trilerp = /*@__PURE__*/ overloadingFn( [ mx_trilerp_0, mx_trilerp_1 ] ); + return uniforms; -const mx_gradient_float_0 = /*@__PURE__*/ Fn( ( [ hash_immutable, x_immutable, y_immutable ] ) => { +} - const y = float( y_immutable ).toVar(); - const x = float( x_immutable ).toVar(); - const hash = uint( hash_immutable ).toVar(); - const h = uint( hash.bitAnd( uint( 7 ) ) ).toVar(); - const u = float( mx_select( h.lessThan( uint( 4 ) ), x, y ) ).toVar(); - const v = float( mul( 2.0, mx_select( h.lessThan( uint( 4 ) ), y, x ) ) ).toVar(); +function lightPosition( light ) { - return mx_negate_if( u, bool( h.bitAnd( uint( 1 ) ) ) ).add( mx_negate_if( v, bool( h.bitAnd( uint( 2 ) ) ) ) ); + const data = getLightData( light ); -} ).setLayout( { - name: 'mx_gradient_float_0', - type: 'float', - inputs: [ - { name: 'hash', type: 'uint' }, - { name: 'x', type: 'float' }, - { name: 'y', type: 'float' } - ] -} ); + return data.position || ( data.position = uniform( new Vector3() ).setGroup( renderGroup ).onRenderUpdate( ( _, self ) => self.value.setFromMatrixPosition( light.matrixWorld ) ) ); -const mx_gradient_float_1 = /*@__PURE__*/ Fn( ( [ hash_immutable, x_immutable, y_immutable, z_immutable ] ) => { +} - const z = float( z_immutable ).toVar(); - const y = float( y_immutable ).toVar(); - const x = float( x_immutable ).toVar(); - const hash = uint( hash_immutable ).toVar(); - const h = uint( hash.bitAnd( uint( 15 ) ) ).toVar(); - const u = float( mx_select( h.lessThan( uint( 8 ) ), x, y ) ).toVar(); - const v = float( mx_select( h.lessThan( uint( 4 ) ), y, mx_select( h.equal( uint( 12 ) ).or( h.equal( uint( 14 ) ) ), x, z ) ) ).toVar(); +function lightTargetPosition( light ) { - return mx_negate_if( u, bool( h.bitAnd( uint( 1 ) ) ) ).add( mx_negate_if( v, bool( h.bitAnd( uint( 2 ) ) ) ) ); + const data = getLightData( light ); -} ).setLayout( { - name: 'mx_gradient_float_1', - type: 'float', - inputs: [ - { name: 'hash', type: 'uint' }, - { name: 'x', type: 'float' }, - { name: 'y', type: 'float' }, - { name: 'z', type: 'float' } - ] -} ); + return data.targetPosition || ( data.targetPosition = uniform( new Vector3() ).setGroup( renderGroup ).onRenderUpdate( ( _, self ) => self.value.setFromMatrixPosition( light.target.matrixWorld ) ) ); -const mx_gradient_float = /*@__PURE__*/ overloadingFn( [ mx_gradient_float_0, mx_gradient_float_1 ] ); +} -const mx_gradient_vec3_0 = /*@__PURE__*/ Fn( ( [ hash_immutable, x_immutable, y_immutable ] ) => { +function lightViewPosition( light ) { - const y = float( y_immutable ).toVar(); - const x = float( x_immutable ).toVar(); - const hash = uvec3( hash_immutable ).toVar(); + const data = getLightData( light ); - return vec3( mx_gradient_float( hash.x, x, y ), mx_gradient_float( hash.y, x, y ), mx_gradient_float( hash.z, x, y ) ); + return data.viewPosition || ( data.viewPosition = uniform( new Vector3() ).setGroup( renderGroup ).onRenderUpdate( ( { camera }, self ) => { -} ).setLayout( { - name: 'mx_gradient_vec3_0', - type: 'vec3', - inputs: [ - { name: 'hash', type: 'uvec3' }, - { name: 'x', type: 'float' }, - { name: 'y', type: 'float' } - ] -} ); + self.value = self.value || new Vector3(); + self.value.setFromMatrixPosition( light.matrixWorld ); -const mx_gradient_vec3_1 = /*@__PURE__*/ Fn( ( [ hash_immutable, x_immutable, y_immutable, z_immutable ] ) => { + self.value.applyMatrix4( camera.matrixWorldInverse ); - const z = float( z_immutable ).toVar(); - const y = float( y_immutable ).toVar(); - const x = float( x_immutable ).toVar(); - const hash = uvec3( hash_immutable ).toVar(); + } ) ); - return vec3( mx_gradient_float( hash.x, x, y, z ), mx_gradient_float( hash.y, x, y, z ), mx_gradient_float( hash.z, x, y, z ) ); +} -} ).setLayout( { - name: 'mx_gradient_vec3_1', - type: 'vec3', - inputs: [ - { name: 'hash', type: 'uvec3' }, - { name: 'x', type: 'float' }, - { name: 'y', type: 'float' }, - { name: 'z', type: 'float' } - ] -} ); +const lightTargetDirection = ( light ) => cameraViewMatrix.transformDirection( lightPosition( light ).sub( lightTargetPosition( light ) ) ); -const mx_gradient_vec3 = /*@__PURE__*/ overloadingFn( [ mx_gradient_vec3_0, mx_gradient_vec3_1 ] ); +const hash = /*@__PURE__*/ Fn( ( [ seed ] ) => { -const mx_gradient_scale2d_0 = /*@__PURE__*/ Fn( ( [ v_immutable ] ) => { + // Taken from https://www.shadertoy.com/view/XlGcRh, originally from pcg-random.org - const v = float( v_immutable ).toVar(); + const state = seed.toUint().mul( 747796405 ).add( 2891336453 ); + const word = state.shiftRight( state.shiftRight( 28 ).add( 4 ) ).bitXor( state ).mul( 277803737 ); + const result = word.shiftRight( 22 ).bitXor( word ); - return mul( 0.6616, v ); + return result.toFloat().mul( 1 / 2 ** 32 ); // Convert to range [0, 1) -} ).setLayout( { - name: 'mx_gradient_scale2d_0', - type: 'float', - inputs: [ - { name: 'v', type: 'float' } - ] } ); -const mx_gradient_scale3d_0 = /*@__PURE__*/ Fn( ( [ v_immutable ] ) => { - - const v = float( v_immutable ).toVar(); +// remapping functions https://iquilezles.org/articles/functions/ +const parabola = ( x, k ) => pow( mul( 4.0, x.mul( sub( 1.0, x ) ) ), k ); +const gain = ( x, k ) => x.lessThan( 0.5 ) ? parabola( x.mul( 2.0 ), k ).div( 2.0 ) : sub( 1.0, parabola( mul( sub( 1.0, x ), 2.0 ), k ).div( 2.0 ) ); +const pcurve = ( x, a, b ) => pow( div( pow( x, a ), add( pow( x, a ), pow( sub( 1.0, x ), b ) ) ), 1.0 / a ); +const sinc = ( x, k ) => sin( PI.mul( k.mul( x ).sub( 1.0 ) ) ).div( PI.mul( k.mul( x ).sub( 1.0 ) ) ); - return mul( 0.9820, v ); +// https://github.com/cabbibo/glsl-tri-noise-3d + + +const tri = /*@__PURE__*/ Fn( ( [ x ] ) => { + + return x.fract().sub( .5 ).abs(); } ).setLayout( { - name: 'mx_gradient_scale3d_0', + name: 'tri', type: 'float', inputs: [ - { name: 'v', type: 'float' } + { name: 'x', type: 'float' } ] } ); -const mx_gradient_scale2d_1 = /*@__PURE__*/ Fn( ( [ v_immutable ] ) => { - - const v = vec3( v_immutable ).toVar(); +const tri3 = /*@__PURE__*/ Fn( ( [ p ] ) => { - return mul( 0.6616, v ); + return vec3( tri( p.z.add( tri( p.y.mul( 1. ) ) ) ), tri( p.z.add( tri( p.x.mul( 1. ) ) ) ), tri( p.y.add( tri( p.x.mul( 1. ) ) ) ) ); } ).setLayout( { - name: 'mx_gradient_scale2d_1', + name: 'tri3', type: 'vec3', inputs: [ - { name: 'v', type: 'vec3' } + { name: 'p', type: 'vec3' } ] } ); -const mx_gradient_scale2d = /*@__PURE__*/ overloadingFn( [ mx_gradient_scale2d_0, mx_gradient_scale2d_1 ] ); - -const mx_gradient_scale3d_1 = /*@__PURE__*/ Fn( ( [ v_immutable ] ) => { - - const v = vec3( v_immutable ).toVar(); +const triNoise3D = /*@__PURE__*/ Fn( ( [ p_immutable, spd, time ] ) => { - return mul( 0.9820, v ); + const p = vec3( p_immutable ).toVar(); + const z = float( 1.4 ).toVar(); + const rz = float( 0.0 ).toVar(); + const bp = vec3( p ).toVar(); -} ).setLayout( { - name: 'mx_gradient_scale3d_1', - type: 'vec3', - inputs: [ - { name: 'v', type: 'vec3' } - ] -} ); + Loop( { start: float( 0.0 ), end: float( 3.0 ), type: 'float', condition: '<=' }, () => { -const mx_gradient_scale3d = /*@__PURE__*/ overloadingFn( [ mx_gradient_scale3d_0, mx_gradient_scale3d_1 ] ); + const dg = vec3( tri3( bp.mul( 2.0 ) ) ).toVar(); + p.addAssign( dg.add( time.mul( float( 0.1 ).mul( spd ) ) ) ); + bp.mulAssign( 1.8 ); + z.mulAssign( 1.5 ); + p.mulAssign( 1.2 ); -const mx_rotl32 = /*@__PURE__*/ Fn( ( [ x_immutable, k_immutable ] ) => { + const t = float( tri( p.z.add( tri( p.x.add( tri( p.y ) ) ) ) ) ).toVar(); + rz.addAssign( t.div( z ) ); + bp.addAssign( 0.14 ); - const k = int( k_immutable ).toVar(); - const x = uint( x_immutable ).toVar(); + } ); - return x.shiftLeft( k ).bitOr( x.shiftRight( int( 32 ).sub( k ) ) ); + return rz; } ).setLayout( { - name: 'mx_rotl32', - type: 'uint', + name: 'triNoise3D', + type: 'float', inputs: [ - { name: 'x', type: 'uint' }, - { name: 'k', type: 'int' } + { name: 'p', type: 'vec3' }, + { name: 'spd', type: 'float' }, + { name: 'time', type: 'float' } ] } ); -const mx_bjmix = /*@__PURE__*/ Fn( ( [ a, b, c ] ) => { +const rotateUV = /*@__PURE__*/ Fn( ( [ uv, rotation, center = vec2( 0.5 ) ] ) => { - a.subAssign( c ); - a.bitXorAssign( mx_rotl32( c, int( 4 ) ) ); - c.addAssign( b ); - b.subAssign( a ); - b.bitXorAssign( mx_rotl32( a, int( 6 ) ) ); - a.addAssign( c ); - c.subAssign( b ); - c.bitXorAssign( mx_rotl32( b, int( 8 ) ) ); - b.addAssign( a ); - a.subAssign( c ); - a.bitXorAssign( mx_rotl32( c, int( 16 ) ) ); - c.addAssign( b ); - b.subAssign( a ); - b.bitXorAssign( mx_rotl32( a, int( 19 ) ) ); - a.addAssign( c ); - c.subAssign( b ); - c.bitXorAssign( mx_rotl32( b, int( 4 ) ) ); - b.addAssign( a ); + return rotate( uv.sub( center ), rotation ).add( center ); } ); -const mx_bjfinal = /*@__PURE__*/ Fn( ( [ a_immutable, b_immutable, c_immutable ] ) => { +const spherizeUV = /*@__PURE__*/ Fn( ( [ uv, strength, center = vec2( 0.5 ) ] ) => { - const c = uint( c_immutable ).toVar(); - const b = uint( b_immutable ).toVar(); - const a = uint( a_immutable ).toVar(); - c.bitXorAssign( b ); - c.subAssign( mx_rotl32( b, int( 14 ) ) ); - a.bitXorAssign( c ); - a.subAssign( mx_rotl32( c, int( 11 ) ) ); - b.bitXorAssign( a ); - b.subAssign( mx_rotl32( a, int( 25 ) ) ); - c.bitXorAssign( b ); - c.subAssign( mx_rotl32( b, int( 16 ) ) ); - a.bitXorAssign( c ); - a.subAssign( mx_rotl32( c, int( 4 ) ) ); - b.bitXorAssign( a ); - b.subAssign( mx_rotl32( a, int( 14 ) ) ); - c.bitXorAssign( b ); - c.subAssign( mx_rotl32( b, int( 24 ) ) ); + const delta = uv.sub( center ); + const delta2 = delta.dot( delta ); + const delta4 = delta2.mul( delta2 ); + const deltaOffset = delta4.mul( strength ); - return c; + return uv.add( delta.mul( deltaOffset ) ); -} ).setLayout( { - name: 'mx_bjfinal', - type: 'uint', - inputs: [ - { name: 'a', type: 'uint' }, - { name: 'b', type: 'uint' }, - { name: 'c', type: 'uint' } - ] } ); -const mx_bits_to_01 = /*@__PURE__*/ Fn( ( [ bits_immutable ] ) => { +const billboarding = /*@__PURE__*/ Fn( ( { position = null, horizontal = true, vertical = false } ) => { - const bits = uint( bits_immutable ).toVar(); + let worldMatrix; - return float( bits ).div( float( uint( int( 0xffffffff ) ) ) ); + if ( position !== null ) { -} ).setLayout( { - name: 'mx_bits_to_01', - type: 'float', - inputs: [ - { name: 'bits', type: 'uint' } - ] -} ); + worldMatrix = modelWorldMatrix.toVar(); + worldMatrix[ 3 ][ 0 ] = position.x; + worldMatrix[ 3 ][ 1 ] = position.y; + worldMatrix[ 3 ][ 2 ] = position.z; -const mx_fade = /*@__PURE__*/ Fn( ( [ t_immutable ] ) => { + } else { - const t = float( t_immutable ).toVar(); + worldMatrix = modelWorldMatrix; - return t.mul( t ).mul( t ).mul( t.mul( t.mul( 6.0 ).sub( 15.0 ) ).add( 10.0 ) ); + } -} ).setLayout( { - name: 'mx_fade', - type: 'float', - inputs: [ - { name: 't', type: 'float' } - ] -} ); + const modelViewMatrix = cameraViewMatrix.mul( worldMatrix ); -const mx_hash_int_0 = /*@__PURE__*/ Fn( ( [ x_immutable ] ) => { + if ( defined( horizontal ) ) { - const x = int( x_immutable ).toVar(); - const len = uint( uint( 1 ) ).toVar(); - const seed = uint( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ).toVar(); + modelViewMatrix[ 0 ][ 0 ] = modelWorldMatrix[ 0 ].length(); + modelViewMatrix[ 0 ][ 1 ] = 0; + modelViewMatrix[ 0 ][ 2 ] = 0; - return mx_bjfinal( seed.add( uint( x ) ), seed, seed ); + } -} ).setLayout( { - name: 'mx_hash_int_0', - type: 'uint', - inputs: [ - { name: 'x', type: 'int' } - ] -} ); + if ( defined( vertical ) ) { -const mx_hash_int_1 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable ] ) => { + modelViewMatrix[ 1 ][ 0 ] = 0; + modelViewMatrix[ 1 ][ 1 ] = modelWorldMatrix[ 1 ].length(); + modelViewMatrix[ 1 ][ 2 ] = 0; - const y = int( y_immutable ).toVar(); - const x = int( x_immutable ).toVar(); - const len = uint( uint( 2 ) ).toVar(); - const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); - a.assign( b.assign( c.assign( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ) ) ); - a.addAssign( uint( x ) ); - b.addAssign( uint( y ) ); + } - return mx_bjfinal( a, b, c ); + modelViewMatrix[ 2 ][ 0 ] = 0; + modelViewMatrix[ 2 ][ 1 ] = 0; + modelViewMatrix[ 2 ][ 2 ] = 1; + + return cameraProjectionMatrix.mul( modelViewMatrix ).mul( positionLocal ); -} ).setLayout( { - name: 'mx_hash_int_1', - type: 'uint', - inputs: [ - { name: 'x', type: 'int' }, - { name: 'y', type: 'int' } - ] } ); -const mx_hash_int_2 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable, z_immutable ] ) => { +const viewportSafeUV = /*@__PURE__*/ Fn( ( [ uv = null ] ) => { - const z = int( z_immutable ).toVar(); - const y = int( y_immutable ).toVar(); - const x = int( x_immutable ).toVar(); - const len = uint( uint( 3 ) ).toVar(); - const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); - a.assign( b.assign( c.assign( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ) ) ); - a.addAssign( uint( x ) ); - b.addAssign( uint( y ) ); - c.addAssign( uint( z ) ); + const depth = linearDepth(); + const depthDiff = linearDepth( viewportDepthTexture( uv ) ).sub( depth ); + const finalUV = depthDiff.lessThan( 0 ).select( screenUV, uv ); - return mx_bjfinal( a, b, c ); + return finalUV; -} ).setLayout( { - name: 'mx_hash_int_2', - type: 'uint', - inputs: [ - { name: 'x', type: 'int' }, - { name: 'y', type: 'int' }, - { name: 'z', type: 'int' } - ] } ); -const mx_hash_int_3 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable, z_immutable, xx_immutable ] ) => { +const _objectData = new WeakMap(); - const xx = int( xx_immutable ).toVar(); - const z = int( z_immutable ).toVar(); - const y = int( y_immutable ).toVar(); - const x = int( x_immutable ).toVar(); - const len = uint( uint( 4 ) ).toVar(); - const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); - a.assign( b.assign( c.assign( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ) ) ); - a.addAssign( uint( x ) ); - b.addAssign( uint( y ) ); - c.addAssign( uint( z ) ); - mx_bjmix( a, b, c ); - a.addAssign( uint( xx ) ); +class VelocityNode extends TempNode { - return mx_bjfinal( a, b, c ); + static get type() { -} ).setLayout( { - name: 'mx_hash_int_3', - type: 'uint', - inputs: [ - { name: 'x', type: 'int' }, - { name: 'y', type: 'int' }, - { name: 'z', type: 'int' }, - { name: 'xx', type: 'int' } - ] -} ); + return 'VelocityNode'; -const mx_hash_int_4 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable, z_immutable, xx_immutable, yy_immutable ] ) => { + } - const yy = int( yy_immutable ).toVar(); - const xx = int( xx_immutable ).toVar(); - const z = int( z_immutable ).toVar(); - const y = int( y_immutable ).toVar(); - const x = int( x_immutable ).toVar(); - const len = uint( uint( 5 ) ).toVar(); - const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); - a.assign( b.assign( c.assign( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ) ) ); - a.addAssign( uint( x ) ); - b.addAssign( uint( y ) ); - c.addAssign( uint( z ) ); - mx_bjmix( a, b, c ); - a.addAssign( uint( xx ) ); - b.addAssign( uint( yy ) ); + constructor() { - return mx_bjfinal( a, b, c ); + super( 'vec2' ); -} ).setLayout( { - name: 'mx_hash_int_4', - type: 'uint', - inputs: [ - { name: 'x', type: 'int' }, - { name: 'y', type: 'int' }, - { name: 'z', type: 'int' }, - { name: 'xx', type: 'int' }, - { name: 'yy', type: 'int' } - ] -} ); + this.updateType = NodeUpdateType.OBJECT; + this.updateAfterType = NodeUpdateType.OBJECT; -const mx_hash_int = /*@__PURE__*/ overloadingFn( [ mx_hash_int_0, mx_hash_int_1, mx_hash_int_2, mx_hash_int_3, mx_hash_int_4 ] ); + this.previousModelWorldMatrix = uniform( new Matrix4() ); + this.previousProjectionMatrix = uniform( new Matrix4() ).setGroup( renderGroup ); + this.previousCameraViewMatrix = uniform( new Matrix4() ); -const mx_hash_vec3_0 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable ] ) => { + } - const y = int( y_immutable ).toVar(); - const x = int( x_immutable ).toVar(); - const h = uint( mx_hash_int( x, y ) ).toVar(); - const result = uvec3().toVar(); - result.x.assign( h.bitAnd( int( 0xFF ) ) ); - result.y.assign( h.shiftRight( int( 8 ) ).bitAnd( int( 0xFF ) ) ); - result.z.assign( h.shiftRight( int( 16 ) ).bitAnd( int( 0xFF ) ) ); + update( { frameId, camera, object } ) { - return result; + const previousModelMatrix = getPreviousMatrix( object ); -} ).setLayout( { - name: 'mx_hash_vec3_0', - type: 'uvec3', - inputs: [ - { name: 'x', type: 'int' }, - { name: 'y', type: 'int' } - ] -} ); + this.previousModelWorldMatrix.value.copy( previousModelMatrix ); -const mx_hash_vec3_1 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable, z_immutable ] ) => { + // - const z = int( z_immutable ).toVar(); - const y = int( y_immutable ).toVar(); - const x = int( x_immutable ).toVar(); - const h = uint( mx_hash_int( x, y, z ) ).toVar(); - const result = uvec3().toVar(); - result.x.assign( h.bitAnd( int( 0xFF ) ) ); - result.y.assign( h.shiftRight( int( 8 ) ).bitAnd( int( 0xFF ) ) ); - result.z.assign( h.shiftRight( int( 16 ) ).bitAnd( int( 0xFF ) ) ); + const cameraData = getData( camera ); - return result; + if ( cameraData.frameId !== frameId ) { -} ).setLayout( { - name: 'mx_hash_vec3_1', - type: 'uvec3', - inputs: [ - { name: 'x', type: 'int' }, - { name: 'y', type: 'int' }, - { name: 'z', type: 'int' } - ] -} ); + cameraData.frameId = frameId; -const mx_hash_vec3 = /*@__PURE__*/ overloadingFn( [ mx_hash_vec3_0, mx_hash_vec3_1 ] ); + if ( cameraData.previousProjectionMatrix === undefined ) { -const mx_perlin_noise_float_0 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + cameraData.previousProjectionMatrix = new Matrix4(); + cameraData.previousCameraViewMatrix = new Matrix4(); - const p = vec2( p_immutable ).toVar(); - const X = int().toVar(), Y = int().toVar(); - const fx = float( mx_floorfrac( p.x, X ) ).toVar(); - const fy = float( mx_floorfrac( p.y, Y ) ).toVar(); - const u = float( mx_fade( fx ) ).toVar(); - const v = float( mx_fade( fy ) ).toVar(); - const result = float( mx_bilerp( mx_gradient_float( mx_hash_int( X, Y ), fx, fy ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y ), fx.sub( 1.0 ), fy ), mx_gradient_float( mx_hash_int( X, Y.add( int( 1 ) ) ), fx, fy.sub( 1.0 ) ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y.add( int( 1 ) ) ), fx.sub( 1.0 ), fy.sub( 1.0 ) ), u, v ) ).toVar(); + cameraData.currentProjectionMatrix = new Matrix4(); + cameraData.currentCameraViewMatrix = new Matrix4(); - return mx_gradient_scale2d( result ); + cameraData.previousProjectionMatrix.copy( camera.projectionMatrix ); + cameraData.previousCameraViewMatrix.copy( camera.matrixWorldInverse ); -} ).setLayout( { - name: 'mx_perlin_noise_float_0', - type: 'float', - inputs: [ - { name: 'p', type: 'vec2' } - ] -} ); + } else { -const mx_perlin_noise_float_1 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + cameraData.previousProjectionMatrix.copy( cameraData.currentProjectionMatrix ); + cameraData.previousCameraViewMatrix.copy( cameraData.currentCameraViewMatrix ); - const p = vec3( p_immutable ).toVar(); - const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); - const fx = float( mx_floorfrac( p.x, X ) ).toVar(); - const fy = float( mx_floorfrac( p.y, Y ) ).toVar(); - const fz = float( mx_floorfrac( p.z, Z ) ).toVar(); - const u = float( mx_fade( fx ) ).toVar(); - const v = float( mx_fade( fy ) ).toVar(); - const w = float( mx_fade( fz ) ).toVar(); - const result = float( mx_trilerp( mx_gradient_float( mx_hash_int( X, Y, Z ), fx, fy, fz ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y, Z ), fx.sub( 1.0 ), fy, fz ), mx_gradient_float( mx_hash_int( X, Y.add( int( 1 ) ), Z ), fx, fy.sub( 1.0 ), fz ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y.add( int( 1 ) ), Z ), fx.sub( 1.0 ), fy.sub( 1.0 ), fz ), mx_gradient_float( mx_hash_int( X, Y, Z.add( int( 1 ) ) ), fx, fy, fz.sub( 1.0 ) ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y, Z.add( int( 1 ) ) ), fx.sub( 1.0 ), fy, fz.sub( 1.0 ) ), mx_gradient_float( mx_hash_int( X, Y.add( int( 1 ) ), Z.add( int( 1 ) ) ), fx, fy.sub( 1.0 ), fz.sub( 1.0 ) ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y.add( int( 1 ) ), Z.add( int( 1 ) ) ), fx.sub( 1.0 ), fy.sub( 1.0 ), fz.sub( 1.0 ) ), u, v, w ) ).toVar(); + } - return mx_gradient_scale3d( result ); + cameraData.currentProjectionMatrix.copy( camera.projectionMatrix ); + cameraData.currentCameraViewMatrix.copy( camera.matrixWorldInverse ); -} ).setLayout( { - name: 'mx_perlin_noise_float_1', - type: 'float', - inputs: [ - { name: 'p', type: 'vec3' } - ] -} ); + this.previousProjectionMatrix.value.copy( cameraData.previousProjectionMatrix ); + this.previousCameraViewMatrix.value.copy( cameraData.previousCameraViewMatrix ); -const mx_perlin_noise_float = /*@__PURE__*/ overloadingFn( [ mx_perlin_noise_float_0, mx_perlin_noise_float_1 ] ); + } -const mx_perlin_noise_vec3_0 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + } - const p = vec2( p_immutable ).toVar(); - const X = int().toVar(), Y = int().toVar(); - const fx = float( mx_floorfrac( p.x, X ) ).toVar(); - const fy = float( mx_floorfrac( p.y, Y ) ).toVar(); - const u = float( mx_fade( fx ) ).toVar(); - const v = float( mx_fade( fy ) ).toVar(); - const result = vec3( mx_bilerp( mx_gradient_vec3( mx_hash_vec3( X, Y ), fx, fy ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y ), fx.sub( 1.0 ), fy ), mx_gradient_vec3( mx_hash_vec3( X, Y.add( int( 1 ) ) ), fx, fy.sub( 1.0 ) ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y.add( int( 1 ) ) ), fx.sub( 1.0 ), fy.sub( 1.0 ) ), u, v ) ).toVar(); + updateAfter( { object } ) { - return mx_gradient_scale2d( result ); + getPreviousMatrix( object ).copy( object.matrixWorld ); -} ).setLayout( { - name: 'mx_perlin_noise_vec3_0', - type: 'vec3', - inputs: [ - { name: 'p', type: 'vec2' } - ] -} ); + } -const mx_perlin_noise_vec3_1 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + setup( /*builder*/ ) { - const p = vec3( p_immutable ).toVar(); - const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); - const fx = float( mx_floorfrac( p.x, X ) ).toVar(); - const fy = float( mx_floorfrac( p.y, Y ) ).toVar(); - const fz = float( mx_floorfrac( p.z, Z ) ).toVar(); - const u = float( mx_fade( fx ) ).toVar(); - const v = float( mx_fade( fy ) ).toVar(); - const w = float( mx_fade( fz ) ).toVar(); - const result = vec3( mx_trilerp( mx_gradient_vec3( mx_hash_vec3( X, Y, Z ), fx, fy, fz ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y, Z ), fx.sub( 1.0 ), fy, fz ), mx_gradient_vec3( mx_hash_vec3( X, Y.add( int( 1 ) ), Z ), fx, fy.sub( 1.0 ), fz ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y.add( int( 1 ) ), Z ), fx.sub( 1.0 ), fy.sub( 1.0 ), fz ), mx_gradient_vec3( mx_hash_vec3( X, Y, Z.add( int( 1 ) ) ), fx, fy, fz.sub( 1.0 ) ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y, Z.add( int( 1 ) ) ), fx.sub( 1.0 ), fy, fz.sub( 1.0 ) ), mx_gradient_vec3( mx_hash_vec3( X, Y.add( int( 1 ) ), Z.add( int( 1 ) ) ), fx, fy.sub( 1.0 ), fz.sub( 1.0 ) ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y.add( int( 1 ) ), Z.add( int( 1 ) ) ), fx.sub( 1.0 ), fy.sub( 1.0 ), fz.sub( 1.0 ) ), u, v, w ) ).toVar(); + const previousModelViewMatrix = this.previousCameraViewMatrix.mul( this.previousModelWorldMatrix ); - return mx_gradient_scale3d( result ); + const clipPositionCurrent = cameraProjectionMatrix.mul( modelViewMatrix ).mul( positionLocal ); + const clipPositionPrevious = this.previousProjectionMatrix.mul( previousModelViewMatrix ).mul( positionPrevious ); -} ).setLayout( { - name: 'mx_perlin_noise_vec3_1', - type: 'vec3', - inputs: [ - { name: 'p', type: 'vec3' } - ] -} ); + const ndcPositionCurrent = clipPositionCurrent.xy.div( clipPositionCurrent.w ); + const ndcPositionPrevious = clipPositionPrevious.xy.div( clipPositionPrevious.w ); -const mx_perlin_noise_vec3 = /*@__PURE__*/ overloadingFn( [ mx_perlin_noise_vec3_0, mx_perlin_noise_vec3_1 ] ); + const velocity = sub( ndcPositionCurrent, ndcPositionPrevious ); -const mx_cell_noise_float_0 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + return velocity; - const p = float( p_immutable ).toVar(); - const ix = int( mx_floor( p ) ).toVar(); + } - return mx_bits_to_01( mx_hash_int( ix ) ); +} -} ).setLayout( { - name: 'mx_cell_noise_float_0', - type: 'float', - inputs: [ - { name: 'p', type: 'float' } - ] -} ); +function getData( object ) { -const mx_cell_noise_float_1 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + let objectData = _objectData.get( object ); - const p = vec2( p_immutable ).toVar(); - const ix = int( mx_floor( p.x ) ).toVar(); - const iy = int( mx_floor( p.y ) ).toVar(); + if ( objectData === undefined ) { - return mx_bits_to_01( mx_hash_int( ix, iy ) ); + objectData = {}; + _objectData.set( object, objectData ); -} ).setLayout( { - name: 'mx_cell_noise_float_1', - type: 'float', - inputs: [ - { name: 'p', type: 'vec2' } - ] -} ); + } -const mx_cell_noise_float_2 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + return objectData; - const p = vec3( p_immutable ).toVar(); - const ix = int( mx_floor( p.x ) ).toVar(); - const iy = int( mx_floor( p.y ) ).toVar(); - const iz = int( mx_floor( p.z ) ).toVar(); +} - return mx_bits_to_01( mx_hash_int( ix, iy, iz ) ); +function getPreviousMatrix( object, index = 0 ) { -} ).setLayout( { - name: 'mx_cell_noise_float_2', - type: 'float', - inputs: [ - { name: 'p', type: 'vec3' } - ] -} ); + const objectData = getData( object ); -const mx_cell_noise_float_3 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + let matrix = objectData[ index ]; - const p = vec4( p_immutable ).toVar(); - const ix = int( mx_floor( p.x ) ).toVar(); - const iy = int( mx_floor( p.y ) ).toVar(); - const iz = int( mx_floor( p.z ) ).toVar(); - const iw = int( mx_floor( p.w ) ).toVar(); + if ( matrix === undefined ) { - return mx_bits_to_01( mx_hash_int( ix, iy, iz, iw ) ); + objectData[ index ] = matrix = new Matrix4(); -} ).setLayout( { - name: 'mx_cell_noise_float_3', - type: 'float', - inputs: [ - { name: 'p', type: 'vec4' } - ] -} ); + } -const mx_cell_noise_float$1 = /*@__PURE__*/ overloadingFn( [ mx_cell_noise_float_0, mx_cell_noise_float_1, mx_cell_noise_float_2, mx_cell_noise_float_3 ] ); + return matrix; -const mx_cell_noise_vec3_0 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { +} - const p = float( p_immutable ).toVar(); - const ix = int( mx_floor( p ) ).toVar(); +const velocity = /*@__PURE__*/ nodeImmutable( VelocityNode ); - return vec3( mx_bits_to_01( mx_hash_int( ix, int( 0 ) ) ), mx_bits_to_01( mx_hash_int( ix, int( 1 ) ) ), mx_bits_to_01( mx_hash_int( ix, int( 2 ) ) ) ); +const burn = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { + + return min$1( 1.0, base.oneMinus().div( blend ) ).oneMinus(); } ).setLayout( { - name: 'mx_cell_noise_vec3_0', + name: 'burnBlend', type: 'vec3', inputs: [ - { name: 'p', type: 'float' } + { name: 'base', type: 'vec3' }, + { name: 'blend', type: 'vec3' } ] } ); -const mx_cell_noise_vec3_1 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { - - const p = vec2( p_immutable ).toVar(); - const ix = int( mx_floor( p.x ) ).toVar(); - const iy = int( mx_floor( p.y ) ).toVar(); +const dodge = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { - return vec3( mx_bits_to_01( mx_hash_int( ix, iy, int( 0 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, int( 1 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, int( 2 ) ) ) ); + return min$1( base.div( blend.oneMinus() ), 1.0 ); } ).setLayout( { - name: 'mx_cell_noise_vec3_1', + name: 'dodgeBlend', type: 'vec3', inputs: [ - { name: 'p', type: 'vec2' } + { name: 'base', type: 'vec3' }, + { name: 'blend', type: 'vec3' } ] } ); -const mx_cell_noise_vec3_2 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { - - const p = vec3( p_immutable ).toVar(); - const ix = int( mx_floor( p.x ) ).toVar(); - const iy = int( mx_floor( p.y ) ).toVar(); - const iz = int( mx_floor( p.z ) ).toVar(); +const screen = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { - return vec3( mx_bits_to_01( mx_hash_int( ix, iy, iz, int( 0 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, iz, int( 1 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, iz, int( 2 ) ) ) ); + return base.oneMinus().mul( blend.oneMinus() ).oneMinus(); } ).setLayout( { - name: 'mx_cell_noise_vec3_2', + name: 'screenBlend', type: 'vec3', inputs: [ - { name: 'p', type: 'vec3' } + { name: 'base', type: 'vec3' }, + { name: 'blend', type: 'vec3' } ] } ); -const mx_cell_noise_vec3_3 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { - - const p = vec4( p_immutable ).toVar(); - const ix = int( mx_floor( p.x ) ).toVar(); - const iy = int( mx_floor( p.y ) ).toVar(); - const iz = int( mx_floor( p.z ) ).toVar(); - const iw = int( mx_floor( p.w ) ).toVar(); +const overlay = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { - return vec3( mx_bits_to_01( mx_hash_int( ix, iy, iz, iw, int( 0 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, iz, iw, int( 1 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, iz, iw, int( 2 ) ) ) ); + return mix( base.mul( 2.0 ).mul( blend ), base.oneMinus().mul( 2.0 ).mul( blend.oneMinus() ).oneMinus(), step( 0.5, base ) ); } ).setLayout( { - name: 'mx_cell_noise_vec3_3', + name: 'overlayBlend', type: 'vec3', inputs: [ - { name: 'p', type: 'vec4' } + { name: 'base', type: 'vec3' }, + { name: 'blend', type: 'vec3' } ] } ); -const mx_cell_noise_vec3 = /*@__PURE__*/ overloadingFn( [ mx_cell_noise_vec3_0, mx_cell_noise_vec3_1, mx_cell_noise_vec3_2, mx_cell_noise_vec3_3 ] ); +const motionBlur = /*@__PURE__*/ Fn( ( [ inputNode, velocity, numSamples = int( 16 ) ] ) => { -const mx_fractal_noise_float$1 = /*@__PURE__*/ Fn( ( [ p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable ] ) => { + const sampleColor = ( uv ) => inputNode.uv( uv ); - const diminish = float( diminish_immutable ).toVar(); - const lacunarity = float( lacunarity_immutable ).toVar(); - const octaves = int( octaves_immutable ).toVar(); - const p = vec3( p_immutable ).toVar(); - const result = float( 0.0 ).toVar(); - const amplitude = float( 1.0 ).toVar(); + const uvs = uv(); - Loop( octaves, () => { + const colorResult = sampleColor( uvs ).toVar(); + const fSamples = float( numSamples ); - result.addAssign( amplitude.mul( mx_perlin_noise_float( p ) ) ); - amplitude.mulAssign( diminish ); - p.mulAssign( lacunarity ); + Loop( { start: int( 1 ), end: numSamples, type: 'int', condition: '<=' }, ( { i } ) => { + + const offset = velocity.mul( float( i ).div( fSamples.sub( 1 ) ).sub( 0.5 ) ); + colorResult.addAssign( sampleColor( uvs.add( offset ) ) ); } ); - return result; + colorResult.divAssign( fSamples ); + + return colorResult; + +} ); + +const bleach = /*@__PURE__*/ Fn( ( [ color, opacity = 1 ] ) => { + + const base = color; + const lum = luminance( base.rgb ); + const blend = vec3( lum ); + + const L = min$1( 1.0, max$1( 0.0, float( 10.0 ).mul( lum.sub( 0.45 ) ) ) ); + + const result1 = blend.mul( base.rgb ).mul( 2.0 ); + const result2 = float( 2.0 ).mul( blend.oneMinus() ).mul( base.rgb.oneMinus() ).oneMinus(); + + const newColor = mix( result1, result2, L ); + + const A2 = base.a.mul( opacity ); + + const mixRGB = A2.mul( newColor.rgb ); + + mixRGB.addAssign( base.rgb.mul( A2.oneMinus() ) ); + + return vec4( mixRGB, base.a ); + +} ); + +const sepia = /*@__PURE__*/ Fn( ( [ color ] ) => { + + const c = vec3( color ); + + // https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/sepia.js + + return vec4( + dot( c, vec3( 0.393, 0.769, 0.189 ) ), + dot( c, vec3( 0.349, 0.686, 0.168 ) ), + dot( c, vec3( 0.272, 0.534, 0.131 ) ), + color.a + ); + +} ); + +const sRGBToLinearSRGB = /*@__PURE__*/ Fn( ( [ color ] ) => { + + const a = color.mul( 0.9478672986 ).add( 0.0521327014 ).pow( 2.4 ); + const b = color.mul( 0.0773993808 ); + const factor = color.lessThanEqual( 0.04045 ); + + const rgbResult = mix( a, b, factor ); + + return rgbResult; } ).setLayout( { - name: 'mx_fractal_noise_float', - type: 'float', + name: 'sRGBToLinearSRGB', + type: 'vec3', inputs: [ - { name: 'p', type: 'vec3' }, - { name: 'octaves', type: 'int' }, - { name: 'lacunarity', type: 'float' }, - { name: 'diminish', type: 'float' } + { name: 'color', type: 'vec3' } ] } ); -const mx_fractal_noise_vec3$1 = /*@__PURE__*/ Fn( ( [ p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable ] ) => { +const linearSRGBTosRGB = /*@__PURE__*/ Fn( ( [ color ] ) => { - const diminish = float( diminish_immutable ).toVar(); - const lacunarity = float( lacunarity_immutable ).toVar(); - const octaves = int( octaves_immutable ).toVar(); - const p = vec3( p_immutable ).toVar(); - const result = vec3( 0.0 ).toVar(); - const amplitude = float( 1.0 ).toVar(); + const a = color.pow( 0.41666 ).mul( 1.055 ).sub( 0.055 ); + const b = color.mul( 12.92 ); + const factor = color.lessThanEqual( 0.0031308 ); - Loop( octaves, () => { + const rgbResult = mix( a, b, factor ); - result.addAssign( amplitude.mul( mx_perlin_noise_vec3( p ) ) ); - amplitude.mulAssign( diminish ); - p.mulAssign( lacunarity ); + return rgbResult; - } ); +} ).setLayout( { + name: 'linearSRGBTosRGB', + type: 'vec3', + inputs: [ + { name: 'color', type: 'vec3' } + ] +} ); - return result; +// exposure only + +const linearToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { + + return color.mul( exposure ).clamp(); } ).setLayout( { - name: 'mx_fractal_noise_vec3', + name: 'linearToneMapping', type: 'vec3', inputs: [ - { name: 'p', type: 'vec3' }, - { name: 'octaves', type: 'int' }, - { name: 'lacunarity', type: 'float' }, - { name: 'diminish', type: 'float' } + { name: 'color', type: 'vec3' }, + { name: 'exposure', type: 'float' } ] } ); -const mx_fractal_noise_vec2$1 = /*@__PURE__*/ Fn( ( [ p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable ] ) => { +// source: https://www.cs.utah.edu/docs/techreports/2002/pdf/UUCS-02-001.pdf - const diminish = float( diminish_immutable ).toVar(); - const lacunarity = float( lacunarity_immutable ).toVar(); - const octaves = int( octaves_immutable ).toVar(); - const p = vec3( p_immutable ).toVar(); +const reinhardToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { - return vec2( mx_fractal_noise_float$1( p, octaves, lacunarity, diminish ), mx_fractal_noise_float$1( p.add( vec3( int( 19 ), int( 193 ), int( 17 ) ) ), octaves, lacunarity, diminish ) ); + color = color.mul( exposure ); + + return color.div( color.add( 1.0 ) ).clamp(); } ).setLayout( { - name: 'mx_fractal_noise_vec2', - type: 'vec2', + name: 'reinhardToneMapping', + type: 'vec3', inputs: [ - { name: 'p', type: 'vec3' }, - { name: 'octaves', type: 'int' }, - { name: 'lacunarity', type: 'float' }, - { name: 'diminish', type: 'float' } + { name: 'color', type: 'vec3' }, + { name: 'exposure', type: 'float' } ] } ); -const mx_fractal_noise_vec4$1 = /*@__PURE__*/ Fn( ( [ p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable ] ) => { +// source: http://filmicworlds.com/blog/filmic-tonemapping-operators/ - const diminish = float( diminish_immutable ).toVar(); - const lacunarity = float( lacunarity_immutable ).toVar(); - const octaves = int( octaves_immutable ).toVar(); - const p = vec3( p_immutable ).toVar(); - const c = vec3( mx_fractal_noise_vec3$1( p, octaves, lacunarity, diminish ) ).toVar(); - const f = float( mx_fractal_noise_float$1( p.add( vec3( int( 19 ), int( 193 ), int( 17 ) ) ), octaves, lacunarity, diminish ) ).toVar(); +const cineonToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { - return vec4( c, f ); + // filmic operator by Jim Hejl and Richard Burgess-Dawson + color = color.mul( exposure ); + color = color.sub( 0.004 ).max( 0.0 ); + + const a = color.mul( color.mul( 6.2 ).add( 0.5 ) ); + const b = color.mul( color.mul( 6.2 ).add( 1.7 ) ).add( 0.06 ); + + return a.div( b ).pow( 2.2 ); } ).setLayout( { - name: 'mx_fractal_noise_vec4', - type: 'vec4', + name: 'cineonToneMapping', + type: 'vec3', inputs: [ - { name: 'p', type: 'vec3' }, - { name: 'octaves', type: 'int' }, - { name: 'lacunarity', type: 'float' }, - { name: 'diminish', type: 'float' } + { name: 'color', type: 'vec3' }, + { name: 'exposure', type: 'float' } ] } ); -const mx_worley_distance_0 = /*@__PURE__*/ Fn( ( [ p_immutable, x_immutable, y_immutable, xoff_immutable, yoff_immutable, jitter_immutable, metric_immutable ] ) => { +// source: https://github.com/selfshadow/ltc_code/blob/master/webgl/shaders/ltc/ltc_blit.fs - const metric = int( metric_immutable ).toVar(); - const jitter = float( jitter_immutable ).toVar(); - const yoff = int( yoff_immutable ).toVar(); - const xoff = int( xoff_immutable ).toVar(); - const y = int( y_immutable ).toVar(); - const x = int( x_immutable ).toVar(); - const p = vec2( p_immutable ).toVar(); - const tmp = vec3( mx_cell_noise_vec3( vec2( x.add( xoff ), y.add( yoff ) ) ) ).toVar(); - const off = vec2( tmp.x, tmp.y ).toVar(); - off.subAssign( 0.5 ); - off.mulAssign( jitter ); - off.addAssign( 0.5 ); - const cellpos = vec2( vec2( float( x ), float( y ) ).add( off ) ).toVar(); - const diff = vec2( cellpos.sub( p ) ).toVar(); +const RRTAndODTFit = /*@__PURE__*/ Fn( ( [ color ] ) => { - If( metric.equal( int( 2 ) ), () => { + const a = color.mul( color.add( 0.0245786 ) ).sub( 0.000090537 ); + const b = color.mul( color.add( 0.4329510 ).mul( 0.983729 ) ).add( 0.238081 ); - return abs( diff.x ).add( abs( diff.y ) ); + return a.div( b ); - } ); +} ); - If( metric.equal( int( 3 ) ), () => { +// source: https://github.com/selfshadow/ltc_code/blob/master/webgl/shaders/ltc/ltc_blit.fs - return max$1( abs( diff.x ), abs( diff.y ) ); +const acesFilmicToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { - } ); + // sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT + const ACESInputMat = mat3( + 0.59719, 0.35458, 0.04823, + 0.07600, 0.90834, 0.01566, + 0.02840, 0.13383, 0.83777 + ); - return dot( diff, diff ); + // ODT_SAT => XYZ => D60_2_D65 => sRGB + const ACESOutputMat = mat3( + 1.60475, - 0.53108, - 0.07367, + - 0.10208, 1.10813, - 0.00605, + - 0.00327, - 0.07276, 1.07602 + ); + + color = color.mul( exposure ).div( 0.6 ); + + color = ACESInputMat.mul( color ); + + // Apply RRT and ODT + color = RRTAndODTFit( color ); + + color = ACESOutputMat.mul( color ); + + // Clamp to [0, 1] + return color.clamp(); } ).setLayout( { - name: 'mx_worley_distance_0', - type: 'float', + name: 'acesFilmicToneMapping', + type: 'vec3', inputs: [ - { name: 'p', type: 'vec2' }, - { name: 'x', type: 'int' }, - { name: 'y', type: 'int' }, - { name: 'xoff', type: 'int' }, - { name: 'yoff', type: 'int' }, - { name: 'jitter', type: 'float' }, - { name: 'metric', type: 'int' } + { name: 'color', type: 'vec3' }, + { name: 'exposure', type: 'float' } ] } ); -const mx_worley_distance_1 = /*@__PURE__*/ Fn( ( [ p_immutable, x_immutable, y_immutable, z_immutable, xoff_immutable, yoff_immutable, zoff_immutable, jitter_immutable, metric_immutable ] ) => { - - const metric = int( metric_immutable ).toVar(); - const jitter = float( jitter_immutable ).toVar(); - const zoff = int( zoff_immutable ).toVar(); - const yoff = int( yoff_immutable ).toVar(); - const xoff = int( xoff_immutable ).toVar(); - const z = int( z_immutable ).toVar(); - const y = int( y_immutable ).toVar(); - const x = int( x_immutable ).toVar(); - const p = vec3( p_immutable ).toVar(); - const off = vec3( mx_cell_noise_vec3( vec3( x.add( xoff ), y.add( yoff ), z.add( zoff ) ) ) ).toVar(); - off.subAssign( 0.5 ); - off.mulAssign( jitter ); - off.addAssign( 0.5 ); - const cellpos = vec3( vec3( float( x ), float( y ), float( z ) ).add( off ) ).toVar(); - const diff = vec3( cellpos.sub( p ) ).toVar(); +const LINEAR_REC2020_TO_LINEAR_SRGB = /*@__PURE__*/ mat3( vec3( 1.6605, - 0.1246, - 0.0182 ), vec3( - 0.5876, 1.1329, - 0.1006 ), vec3( - 0.0728, - 0.0083, 1.1187 ) ); +const LINEAR_SRGB_TO_LINEAR_REC2020 = /*@__PURE__*/ mat3( vec3( 0.6274, 0.0691, 0.0164 ), vec3( 0.3293, 0.9195, 0.0880 ), vec3( 0.0433, 0.0113, 0.8956 ) ); - If( metric.equal( int( 2 ) ), () => { +const agxDefaultContrastApprox = /*@__PURE__*/ Fn( ( [ x_immutable ] ) => { - return abs( diff.x ).add( abs( diff.y ) ).add( abs( diff.z ) ); + const x = vec3( x_immutable ).toVar(); + const x2 = vec3( x.mul( x ) ).toVar(); + const x4 = vec3( x2.mul( x2 ) ).toVar(); - } ); + return float( 15.5 ).mul( x4.mul( x2 ) ).sub( mul( 40.14, x4.mul( x ) ) ).add( mul( 31.96, x4 ).sub( mul( 6.868, x2.mul( x ) ) ).add( mul( 0.4298, x2 ).add( mul( 0.1191, x ).sub( 0.00232 ) ) ) ); - If( metric.equal( int( 3 ) ), () => { +} ); - return max$1( max$1( abs( diff.x ), abs( diff.y ) ), abs( diff.z ) ); +const agxToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { - } ); + const colortone = vec3( color ).toVar(); + const AgXInsetMatrix = mat3( vec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ), vec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ), vec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 ) ); + const AgXOutsetMatrix = mat3( vec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ), vec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ), vec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 ) ); + const AgxMinEv = float( - 12.47393 ); + const AgxMaxEv = float( 4.026069 ); + colortone.mulAssign( exposure ); + colortone.assign( LINEAR_SRGB_TO_LINEAR_REC2020.mul( colortone ) ); + colortone.assign( AgXInsetMatrix.mul( colortone ) ); + colortone.assign( max$1( colortone, 1e-10 ) ); + colortone.assign( log2( colortone ) ); + colortone.assign( colortone.sub( AgxMinEv ).div( AgxMaxEv.sub( AgxMinEv ) ) ); + colortone.assign( clamp( colortone, 0.0, 1.0 ) ); + colortone.assign( agxDefaultContrastApprox( colortone ) ); + colortone.assign( AgXOutsetMatrix.mul( colortone ) ); + colortone.assign( pow( max$1( vec3( 0.0 ), colortone ), vec3( 2.2 ) ) ); + colortone.assign( LINEAR_REC2020_TO_LINEAR_SRGB.mul( colortone ) ); + colortone.assign( clamp( colortone, 0.0, 1.0 ) ); - return dot( diff, diff ); + return colortone; } ).setLayout( { - name: 'mx_worley_distance_1', - type: 'float', + name: 'agxToneMapping', + type: 'vec3', inputs: [ - { name: 'p', type: 'vec3' }, - { name: 'x', type: 'int' }, - { name: 'y', type: 'int' }, - { name: 'z', type: 'int' }, - { name: 'xoff', type: 'int' }, - { name: 'yoff', type: 'int' }, - { name: 'zoff', type: 'int' }, - { name: 'jitter', type: 'float' }, - { name: 'metric', type: 'int' } + { name: 'color', type: 'vec3' }, + { name: 'exposure', type: 'float' } ] } ); -const mx_worley_distance = /*@__PURE__*/ overloadingFn( [ mx_worley_distance_0, mx_worley_distance_1 ] ); - -const mx_worley_noise_float_0 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { +// https://modelviewer.dev/examples/tone-mapping - const metric = int( metric_immutable ).toVar(); - const jitter = float( jitter_immutable ).toVar(); - const p = vec2( p_immutable ).toVar(); - const X = int().toVar(), Y = int().toVar(); - const localpos = vec2( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ) ).toVar(); - const sqdist = float( 1e6 ).toVar(); +const neutralToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { - Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + const StartCompression = float( 0.8 - 0.04 ); + const Desaturation = float( 0.15 ); - Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + color = color.mul( exposure ); - const dist = float( mx_worley_distance( localpos, x, y, X, Y, jitter, metric ) ).toVar(); - sqdist.assign( min$1( sqdist, dist ) ); + const x = min$1( color.r, min$1( color.g, color.b ) ); + const offset = select( x.lessThan( 0.08 ), x.sub( mul( 6.25, x.mul( x ) ) ), 0.04 ); - } ); + color.subAssign( offset ); - } ); + const peak = max$1( color.r, max$1( color.g, color.b ) ); - If( metric.equal( int( 0 ) ), () => { + If( peak.lessThan( StartCompression ), () => { - sqdist.assign( sqrt( sqdist ) ); + return color; } ); - return sqdist; + const d = sub( 1, StartCompression ); + const newPeak = sub( 1, d.mul( d ).div( peak.add( d.sub( StartCompression ) ) ) ); + color.mulAssign( newPeak.div( peak ) ); + const g = sub( 1, div( 1, Desaturation.mul( peak.sub( newPeak ) ).add( 1 ) ) ); + + return mix( color, vec3( newPeak ), g ); } ).setLayout( { - name: 'mx_worley_noise_float_0', - type: 'float', + name: 'neutralToneMapping', + type: 'vec3', inputs: [ - { name: 'p', type: 'vec2' }, - { name: 'jitter', type: 'float' }, - { name: 'metric', type: 'int' } + { name: 'color', type: 'vec3' }, + { name: 'exposure', type: 'float' } ] } ); -const mx_worley_noise_vec2_0 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { +class ComputeBuiltinNode extends Node { - const metric = int( metric_immutable ).toVar(); - const jitter = float( jitter_immutable ).toVar(); - const p = vec2( p_immutable ).toVar(); - const X = int().toVar(), Y = int().toVar(); - const localpos = vec2( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ) ).toVar(); - const sqdist = vec2( 1e6, 1e6 ).toVar(); + static get type() { - Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + return 'ComputeBuiltinNode'; - Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + } - const dist = float( mx_worley_distance( localpos, x, y, X, Y, jitter, metric ) ).toVar(); + constructor( builtinName, nodeType ) { - If( dist.lessThan( sqdist.x ), () => { + super( nodeType ); - sqdist.y.assign( sqdist.x ); - sqdist.x.assign( dist ); + this._builtinName = builtinName; - } ).ElseIf( dist.lessThan( sqdist.y ), () => { + } - sqdist.y.assign( dist ); + getHash( builder ) { - } ); + return this.getBuiltinName( builder ); - } ); + } - } ); + getNodeType( /*builder*/ ) { - If( metric.equal( int( 0 ) ), () => { + return this.nodeType; - sqdist.assign( sqrt( sqdist ) ); + } - } ); + setBuiltinName( builtinName ) { - return sqdist; + this._builtinName = builtinName; -} ).setLayout( { - name: 'mx_worley_noise_vec2_0', - type: 'vec2', - inputs: [ - { name: 'p', type: 'vec2' }, - { name: 'jitter', type: 'float' }, - { name: 'metric', type: 'int' } - ] -} ); + return this; -const mx_worley_noise_vec3_0 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + } - const metric = int( metric_immutable ).toVar(); - const jitter = float( jitter_immutable ).toVar(); - const p = vec2( p_immutable ).toVar(); - const X = int().toVar(), Y = int().toVar(); - const localpos = vec2( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ) ).toVar(); - const sqdist = vec3( 1e6, 1e6, 1e6 ).toVar(); + getBuiltinName( /*builder*/ ) { - Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + return this._builtinName; - Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + } - const dist = float( mx_worley_distance( localpos, x, y, X, Y, jitter, metric ) ).toVar(); + hasBuiltin( builder ) { - If( dist.lessThan( sqdist.x ), () => { + builder.hasBuiltin( this._builtinName ); - sqdist.z.assign( sqdist.y ); - sqdist.y.assign( sqdist.x ); - sqdist.x.assign( dist ); + } + + generate( builder, output ) { + + const builtinName = this.getBuiltinName( builder ); + const nodeType = this.getNodeType( builder ); + + if ( builder.shaderStage === 'compute' ) { + + return builder.format( builtinName, nodeType, output ); + + } else { + + console.warn( `ComputeBuiltinNode: Compute built-in value ${builtinName} can not be accessed in the ${builder.shaderStage} stage` ); + return builder.generateConst( nodeType ); + + } + + } + + serialize( data ) { + + super.serialize( data ); + + data.global = this.global; + data._builtinName = this._builtinName; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.global = data.global; + this._builtinName = data._builtinName; + + } + +} + +const computeBuiltin = ( name, nodeType ) => nodeObject( new ComputeBuiltinNode( name, nodeType ) ); + +const numWorkgroups = /*@__PURE__*/ computeBuiltin( 'numWorkgroups', 'uvec3' ); +const workgroupId = /*@__PURE__*/ computeBuiltin( 'workgroupId', 'uvec3' ); +const localId = /*@__PURE__*/ computeBuiltin( 'localId', 'uvec3' ); +const subgroupSize = /*@__PURE__*/ computeBuiltin( 'subgroupSize', 'uint' ); + +class BarrierNode extends Node { + + constructor( scope ) { + + super(); + + this.scope = scope; + + } + + generate( builder ) { + + const { scope } = this; + const { renderer } = builder; + + if ( renderer.backend.isWebGLBackend === true ) { + + builder.addFlowCode( `\t// ${scope}Barrier \n` ); + + } else { + + builder.addLineFlowCode( `${scope}Barrier()`, this ); + + } + + } + +} + +const barrier = nodeProxy( BarrierNode ); + +const workgroupBarrier = () => barrier( 'workgroup' ).append(); +const storageBarrier = () => barrier( 'storage' ).append(); +const textureBarrier = () => barrier( 'texture' ).append(); + +class WorkgroupInfoElementNode extends ArrayElementNode { + + constructor( workgroupInfoNode, indexNode ) { + + super( workgroupInfoNode, indexNode ); + + this.isWorkgroupInfoElementNode = true; + + } + + generate( builder, output ) { + + let snippet; + + const isAssignContext = builder.context.assign; + snippet = super.generate( builder ); + + if ( isAssignContext !== true ) { + + const type = this.getNodeType( builder ); + + snippet = builder.format( snippet, type, output ); + + } + + // TODO: Possibly activate clip distance index on index access rather than from clipping context + + return snippet; + + } + +} + + +class WorkgroupInfoNode extends Node { + + constructor( scope, bufferType, bufferCount = 0 ) { + + super( bufferType ); + + this.bufferType = bufferType; + this.bufferCount = bufferCount; + + this.isWorkgroupInfoNode = true; + + this.scope = scope; + + } + + label( name ) { + + this.name = name; + + return this; + + } + + getHash() { + + return this.uuid; + + } + + setScope( scope ) { + + this.scope = scope; + + return this; + + } + + getInputType( /*builder*/ ) { + + return `${this.scope}Array`; + + } + + element( indexNode ) { + + return nodeObject( new WorkgroupInfoElementNode( this, indexNode ) ); + + } + + generate( builder ) { + + return builder.getScopedArray( this.name || `${this.scope}Array_${this.id}`, this.scope.toLowerCase(), this.bufferType, this.bufferCount ); + + } + +} + +const workgroupArray = ( type, count ) => nodeObject( new WorkgroupInfoNode( 'Workgroup', type, count ) ); + +class AtomicFunctionNode extends TempNode { + + static get type() { + + return 'AtomicFunctionNode'; + + } + + constructor( method, pointerNode, valueNode, storeNode = null ) { + + super( 'uint' ); + + this.method = method; + + this.pointerNode = pointerNode; + this.valueNode = valueNode; + this.storeNode = storeNode; + + } + + getInputType( builder ) { + + return this.pointerNode.getNodeType( builder ); + + } + + getNodeType( builder ) { + + return this.getInputType( builder ); + + } + + generate( builder ) { + + const method = this.method; + + const type = this.getNodeType( builder ); + const inputType = this.getInputType( builder ); + + const a = this.pointerNode; + const b = this.valueNode; + + const params = []; + + params.push( `&${ a.build( builder, inputType ) }` ); + params.push( b.build( builder, inputType ) ); + + const methodSnippet = `${ builder.getMethod( method, type ) }( ${params.join( ', ' )} )`; + + if ( this.storeNode !== null ) { + + const varSnippet = this.storeNode.build( builder, inputType ); + + builder.addLineFlowCode( `${varSnippet} = ${methodSnippet}`, this ); + + } else { + + builder.addLineFlowCode( methodSnippet, this ); + + } + + } + +} + +AtomicFunctionNode.ATOMIC_LOAD = 'atomicLoad'; +AtomicFunctionNode.ATOMIC_STORE = 'atomicStore'; +AtomicFunctionNode.ATOMIC_ADD = 'atomicAdd'; +AtomicFunctionNode.ATOMIC_SUB = 'atomicSub'; +AtomicFunctionNode.ATOMIC_MAX = 'atomicMax'; +AtomicFunctionNode.ATOMIC_MIN = 'atomicMin'; +AtomicFunctionNode.ATOMIC_AND = 'atomicAnd'; +AtomicFunctionNode.ATOMIC_OR = 'atomicOr'; +AtomicFunctionNode.ATOMIC_XOR = 'atomicXor'; + +const atomicNode = nodeProxy( AtomicFunctionNode ); + +const atomicFunc = ( method, pointerNode, valueNode, storeNode ) => { + + const node = atomicNode( method, pointerNode, valueNode, storeNode ); + node.append(); + + return node; + +}; + +const atomicStore = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_STORE, pointerNode, valueNode, storeNode ); +const atomicAdd = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_ADD, pointerNode, valueNode, storeNode ); +const atomicSub = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_SUB, pointerNode, valueNode, storeNode ); +const atomicMax = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_MAX, pointerNode, valueNode, storeNode ); +const atomicMin = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_MIN, pointerNode, valueNode, storeNode ); +const atomicAnd = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_AND, pointerNode, valueNode, storeNode ); +const atomicOr = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_OR, pointerNode, valueNode, storeNode ); +const atomicXor = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_XOR, pointerNode, valueNode, storeNode ); + +const checker = /*@__PURE__*/ Fn( ( [ coord = uv() ] ) => { + + const uv = coord.mul( 2.0 ); + + const cx = uv.x.floor(); + const cy = uv.y.floor(); + const result = cx.add( cy ).mod( 2.0 ); + + return result.sign(); + +} ); + +// Three.js Transpiler +// https://raw.githubusercontent.com/AcademySoftwareFoundation/MaterialX/main/libraries/stdlib/genglsl/lib/mx_noise.glsl + + + +const mx_select = /*@__PURE__*/ Fn( ( [ b_immutable, t_immutable, f_immutable ] ) => { + + const f = float( f_immutable ).toVar(); + const t = float( t_immutable ).toVar(); + const b = bool( b_immutable ).toVar(); + + return select( b, t, f ); + +} ).setLayout( { + name: 'mx_select', + type: 'float', + inputs: [ + { name: 'b', type: 'bool' }, + { name: 't', type: 'float' }, + { name: 'f', type: 'float' } + ] +} ); + +const mx_negate_if = /*@__PURE__*/ Fn( ( [ val_immutable, b_immutable ] ) => { + + const b = bool( b_immutable ).toVar(); + const val = float( val_immutable ).toVar(); + + return select( b, val.negate(), val ); + +} ).setLayout( { + name: 'mx_negate_if', + type: 'float', + inputs: [ + { name: 'val', type: 'float' }, + { name: 'b', type: 'bool' } + ] +} ); + +const mx_floor = /*@__PURE__*/ Fn( ( [ x_immutable ] ) => { + + const x = float( x_immutable ).toVar(); + + return int( floor( x ) ); + +} ).setLayout( { + name: 'mx_floor', + type: 'int', + inputs: [ + { name: 'x', type: 'float' } + ] +} ); + +const mx_floorfrac = /*@__PURE__*/ Fn( ( [ x_immutable, i ] ) => { + + const x = float( x_immutable ).toVar(); + i.assign( mx_floor( x ) ); + + return x.sub( float( i ) ); + +} ); + +const mx_bilerp_0 = /*@__PURE__*/ Fn( ( [ v0_immutable, v1_immutable, v2_immutable, v3_immutable, s_immutable, t_immutable ] ) => { + + const t = float( t_immutable ).toVar(); + const s = float( s_immutable ).toVar(); + const v3 = float( v3_immutable ).toVar(); + const v2 = float( v2_immutable ).toVar(); + const v1 = float( v1_immutable ).toVar(); + const v0 = float( v0_immutable ).toVar(); + const s1 = float( sub( 1.0, s ) ).toVar(); + + return sub( 1.0, t ).mul( v0.mul( s1 ).add( v1.mul( s ) ) ).add( t.mul( v2.mul( s1 ).add( v3.mul( s ) ) ) ); + +} ).setLayout( { + name: 'mx_bilerp_0', + type: 'float', + inputs: [ + { name: 'v0', type: 'float' }, + { name: 'v1', type: 'float' }, + { name: 'v2', type: 'float' }, + { name: 'v3', type: 'float' }, + { name: 's', type: 'float' }, + { name: 't', type: 'float' } + ] +} ); + +const mx_bilerp_1 = /*@__PURE__*/ Fn( ( [ v0_immutable, v1_immutable, v2_immutable, v3_immutable, s_immutable, t_immutable ] ) => { + + const t = float( t_immutable ).toVar(); + const s = float( s_immutable ).toVar(); + const v3 = vec3( v3_immutable ).toVar(); + const v2 = vec3( v2_immutable ).toVar(); + const v1 = vec3( v1_immutable ).toVar(); + const v0 = vec3( v0_immutable ).toVar(); + const s1 = float( sub( 1.0, s ) ).toVar(); + + return sub( 1.0, t ).mul( v0.mul( s1 ).add( v1.mul( s ) ) ).add( t.mul( v2.mul( s1 ).add( v3.mul( s ) ) ) ); + +} ).setLayout( { + name: 'mx_bilerp_1', + type: 'vec3', + inputs: [ + { name: 'v0', type: 'vec3' }, + { name: 'v1', type: 'vec3' }, + { name: 'v2', type: 'vec3' }, + { name: 'v3', type: 'vec3' }, + { name: 's', type: 'float' }, + { name: 't', type: 'float' } + ] +} ); + +const mx_bilerp = /*@__PURE__*/ overloadingFn( [ mx_bilerp_0, mx_bilerp_1 ] ); + +const mx_trilerp_0 = /*@__PURE__*/ Fn( ( [ v0_immutable, v1_immutable, v2_immutable, v3_immutable, v4_immutable, v5_immutable, v6_immutable, v7_immutable, s_immutable, t_immutable, r_immutable ] ) => { + + const r = float( r_immutable ).toVar(); + const t = float( t_immutable ).toVar(); + const s = float( s_immutable ).toVar(); + const v7 = float( v7_immutable ).toVar(); + const v6 = float( v6_immutable ).toVar(); + const v5 = float( v5_immutable ).toVar(); + const v4 = float( v4_immutable ).toVar(); + const v3 = float( v3_immutable ).toVar(); + const v2 = float( v2_immutable ).toVar(); + const v1 = float( v1_immutable ).toVar(); + const v0 = float( v0_immutable ).toVar(); + const s1 = float( sub( 1.0, s ) ).toVar(); + const t1 = float( sub( 1.0, t ) ).toVar(); + const r1 = float( sub( 1.0, r ) ).toVar(); + + return r1.mul( t1.mul( v0.mul( s1 ).add( v1.mul( s ) ) ).add( t.mul( v2.mul( s1 ).add( v3.mul( s ) ) ) ) ).add( r.mul( t1.mul( v4.mul( s1 ).add( v5.mul( s ) ) ).add( t.mul( v6.mul( s1 ).add( v7.mul( s ) ) ) ) ) ); + +} ).setLayout( { + name: 'mx_trilerp_0', + type: 'float', + inputs: [ + { name: 'v0', type: 'float' }, + { name: 'v1', type: 'float' }, + { name: 'v2', type: 'float' }, + { name: 'v3', type: 'float' }, + { name: 'v4', type: 'float' }, + { name: 'v5', type: 'float' }, + { name: 'v6', type: 'float' }, + { name: 'v7', type: 'float' }, + { name: 's', type: 'float' }, + { name: 't', type: 'float' }, + { name: 'r', type: 'float' } + ] +} ); + +const mx_trilerp_1 = /*@__PURE__*/ Fn( ( [ v0_immutable, v1_immutable, v2_immutable, v3_immutable, v4_immutable, v5_immutable, v6_immutable, v7_immutable, s_immutable, t_immutable, r_immutable ] ) => { + + const r = float( r_immutable ).toVar(); + const t = float( t_immutable ).toVar(); + const s = float( s_immutable ).toVar(); + const v7 = vec3( v7_immutable ).toVar(); + const v6 = vec3( v6_immutable ).toVar(); + const v5 = vec3( v5_immutable ).toVar(); + const v4 = vec3( v4_immutable ).toVar(); + const v3 = vec3( v3_immutable ).toVar(); + const v2 = vec3( v2_immutable ).toVar(); + const v1 = vec3( v1_immutable ).toVar(); + const v0 = vec3( v0_immutable ).toVar(); + const s1 = float( sub( 1.0, s ) ).toVar(); + const t1 = float( sub( 1.0, t ) ).toVar(); + const r1 = float( sub( 1.0, r ) ).toVar(); + + return r1.mul( t1.mul( v0.mul( s1 ).add( v1.mul( s ) ) ).add( t.mul( v2.mul( s1 ).add( v3.mul( s ) ) ) ) ).add( r.mul( t1.mul( v4.mul( s1 ).add( v5.mul( s ) ) ).add( t.mul( v6.mul( s1 ).add( v7.mul( s ) ) ) ) ) ); + +} ).setLayout( { + name: 'mx_trilerp_1', + type: 'vec3', + inputs: [ + { name: 'v0', type: 'vec3' }, + { name: 'v1', type: 'vec3' }, + { name: 'v2', type: 'vec3' }, + { name: 'v3', type: 'vec3' }, + { name: 'v4', type: 'vec3' }, + { name: 'v5', type: 'vec3' }, + { name: 'v6', type: 'vec3' }, + { name: 'v7', type: 'vec3' }, + { name: 's', type: 'float' }, + { name: 't', type: 'float' }, + { name: 'r', type: 'float' } + ] +} ); + +const mx_trilerp = /*@__PURE__*/ overloadingFn( [ mx_trilerp_0, mx_trilerp_1 ] ); + +const mx_gradient_float_0 = /*@__PURE__*/ Fn( ( [ hash_immutable, x_immutable, y_immutable ] ) => { + + const y = float( y_immutable ).toVar(); + const x = float( x_immutable ).toVar(); + const hash = uint( hash_immutable ).toVar(); + const h = uint( hash.bitAnd( uint( 7 ) ) ).toVar(); + const u = float( mx_select( h.lessThan( uint( 4 ) ), x, y ) ).toVar(); + const v = float( mul( 2.0, mx_select( h.lessThan( uint( 4 ) ), y, x ) ) ).toVar(); + + return mx_negate_if( u, bool( h.bitAnd( uint( 1 ) ) ) ).add( mx_negate_if( v, bool( h.bitAnd( uint( 2 ) ) ) ) ); + +} ).setLayout( { + name: 'mx_gradient_float_0', + type: 'float', + inputs: [ + { name: 'hash', type: 'uint' }, + { name: 'x', type: 'float' }, + { name: 'y', type: 'float' } + ] +} ); + +const mx_gradient_float_1 = /*@__PURE__*/ Fn( ( [ hash_immutable, x_immutable, y_immutable, z_immutable ] ) => { + + const z = float( z_immutable ).toVar(); + const y = float( y_immutable ).toVar(); + const x = float( x_immutable ).toVar(); + const hash = uint( hash_immutable ).toVar(); + const h = uint( hash.bitAnd( uint( 15 ) ) ).toVar(); + const u = float( mx_select( h.lessThan( uint( 8 ) ), x, y ) ).toVar(); + const v = float( mx_select( h.lessThan( uint( 4 ) ), y, mx_select( h.equal( uint( 12 ) ).or( h.equal( uint( 14 ) ) ), x, z ) ) ).toVar(); + + return mx_negate_if( u, bool( h.bitAnd( uint( 1 ) ) ) ).add( mx_negate_if( v, bool( h.bitAnd( uint( 2 ) ) ) ) ); + +} ).setLayout( { + name: 'mx_gradient_float_1', + type: 'float', + inputs: [ + { name: 'hash', type: 'uint' }, + { name: 'x', type: 'float' }, + { name: 'y', type: 'float' }, + { name: 'z', type: 'float' } + ] +} ); + +const mx_gradient_float = /*@__PURE__*/ overloadingFn( [ mx_gradient_float_0, mx_gradient_float_1 ] ); + +const mx_gradient_vec3_0 = /*@__PURE__*/ Fn( ( [ hash_immutable, x_immutable, y_immutable ] ) => { + + const y = float( y_immutable ).toVar(); + const x = float( x_immutable ).toVar(); + const hash = uvec3( hash_immutable ).toVar(); + + return vec3( mx_gradient_float( hash.x, x, y ), mx_gradient_float( hash.y, x, y ), mx_gradient_float( hash.z, x, y ) ); + +} ).setLayout( { + name: 'mx_gradient_vec3_0', + type: 'vec3', + inputs: [ + { name: 'hash', type: 'uvec3' }, + { name: 'x', type: 'float' }, + { name: 'y', type: 'float' } + ] +} ); + +const mx_gradient_vec3_1 = /*@__PURE__*/ Fn( ( [ hash_immutable, x_immutable, y_immutable, z_immutable ] ) => { + + const z = float( z_immutable ).toVar(); + const y = float( y_immutable ).toVar(); + const x = float( x_immutable ).toVar(); + const hash = uvec3( hash_immutable ).toVar(); + + return vec3( mx_gradient_float( hash.x, x, y, z ), mx_gradient_float( hash.y, x, y, z ), mx_gradient_float( hash.z, x, y, z ) ); + +} ).setLayout( { + name: 'mx_gradient_vec3_1', + type: 'vec3', + inputs: [ + { name: 'hash', type: 'uvec3' }, + { name: 'x', type: 'float' }, + { name: 'y', type: 'float' }, + { name: 'z', type: 'float' } + ] +} ); + +const mx_gradient_vec3 = /*@__PURE__*/ overloadingFn( [ mx_gradient_vec3_0, mx_gradient_vec3_1 ] ); + +const mx_gradient_scale2d_0 = /*@__PURE__*/ Fn( ( [ v_immutable ] ) => { + + const v = float( v_immutable ).toVar(); + + return mul( 0.6616, v ); + +} ).setLayout( { + name: 'mx_gradient_scale2d_0', + type: 'float', + inputs: [ + { name: 'v', type: 'float' } + ] +} ); + +const mx_gradient_scale3d_0 = /*@__PURE__*/ Fn( ( [ v_immutable ] ) => { + + const v = float( v_immutable ).toVar(); + + return mul( 0.9820, v ); + +} ).setLayout( { + name: 'mx_gradient_scale3d_0', + type: 'float', + inputs: [ + { name: 'v', type: 'float' } + ] +} ); + +const mx_gradient_scale2d_1 = /*@__PURE__*/ Fn( ( [ v_immutable ] ) => { + + const v = vec3( v_immutable ).toVar(); + + return mul( 0.6616, v ); + +} ).setLayout( { + name: 'mx_gradient_scale2d_1', + type: 'vec3', + inputs: [ + { name: 'v', type: 'vec3' } + ] +} ); + +const mx_gradient_scale2d = /*@__PURE__*/ overloadingFn( [ mx_gradient_scale2d_0, mx_gradient_scale2d_1 ] ); + +const mx_gradient_scale3d_1 = /*@__PURE__*/ Fn( ( [ v_immutable ] ) => { + + const v = vec3( v_immutable ).toVar(); + + return mul( 0.9820, v ); + +} ).setLayout( { + name: 'mx_gradient_scale3d_1', + type: 'vec3', + inputs: [ + { name: 'v', type: 'vec3' } + ] +} ); + +const mx_gradient_scale3d = /*@__PURE__*/ overloadingFn( [ mx_gradient_scale3d_0, mx_gradient_scale3d_1 ] ); + +const mx_rotl32 = /*@__PURE__*/ Fn( ( [ x_immutable, k_immutable ] ) => { + + const k = int( k_immutable ).toVar(); + const x = uint( x_immutable ).toVar(); + + return x.shiftLeft( k ).bitOr( x.shiftRight( int( 32 ).sub( k ) ) ); + +} ).setLayout( { + name: 'mx_rotl32', + type: 'uint', + inputs: [ + { name: 'x', type: 'uint' }, + { name: 'k', type: 'int' } + ] +} ); + +const mx_bjmix = /*@__PURE__*/ Fn( ( [ a, b, c ] ) => { + + a.subAssign( c ); + a.bitXorAssign( mx_rotl32( c, int( 4 ) ) ); + c.addAssign( b ); + b.subAssign( a ); + b.bitXorAssign( mx_rotl32( a, int( 6 ) ) ); + a.addAssign( c ); + c.subAssign( b ); + c.bitXorAssign( mx_rotl32( b, int( 8 ) ) ); + b.addAssign( a ); + a.subAssign( c ); + a.bitXorAssign( mx_rotl32( c, int( 16 ) ) ); + c.addAssign( b ); + b.subAssign( a ); + b.bitXorAssign( mx_rotl32( a, int( 19 ) ) ); + a.addAssign( c ); + c.subAssign( b ); + c.bitXorAssign( mx_rotl32( b, int( 4 ) ) ); + b.addAssign( a ); + +} ); + +const mx_bjfinal = /*@__PURE__*/ Fn( ( [ a_immutable, b_immutable, c_immutable ] ) => { + + const c = uint( c_immutable ).toVar(); + const b = uint( b_immutable ).toVar(); + const a = uint( a_immutable ).toVar(); + c.bitXorAssign( b ); + c.subAssign( mx_rotl32( b, int( 14 ) ) ); + a.bitXorAssign( c ); + a.subAssign( mx_rotl32( c, int( 11 ) ) ); + b.bitXorAssign( a ); + b.subAssign( mx_rotl32( a, int( 25 ) ) ); + c.bitXorAssign( b ); + c.subAssign( mx_rotl32( b, int( 16 ) ) ); + a.bitXorAssign( c ); + a.subAssign( mx_rotl32( c, int( 4 ) ) ); + b.bitXorAssign( a ); + b.subAssign( mx_rotl32( a, int( 14 ) ) ); + c.bitXorAssign( b ); + c.subAssign( mx_rotl32( b, int( 24 ) ) ); + + return c; + +} ).setLayout( { + name: 'mx_bjfinal', + type: 'uint', + inputs: [ + { name: 'a', type: 'uint' }, + { name: 'b', type: 'uint' }, + { name: 'c', type: 'uint' } + ] +} ); + +const mx_bits_to_01 = /*@__PURE__*/ Fn( ( [ bits_immutable ] ) => { + + const bits = uint( bits_immutable ).toVar(); + + return float( bits ).div( float( uint( int( 0xffffffff ) ) ) ); + +} ).setLayout( { + name: 'mx_bits_to_01', + type: 'float', + inputs: [ + { name: 'bits', type: 'uint' } + ] +} ); + +const mx_fade = /*@__PURE__*/ Fn( ( [ t_immutable ] ) => { + + const t = float( t_immutable ).toVar(); + + return t.mul( t ).mul( t ).mul( t.mul( t.mul( 6.0 ).sub( 15.0 ) ).add( 10.0 ) ); + +} ).setLayout( { + name: 'mx_fade', + type: 'float', + inputs: [ + { name: 't', type: 'float' } + ] +} ); + +const mx_hash_int_0 = /*@__PURE__*/ Fn( ( [ x_immutable ] ) => { + + const x = int( x_immutable ).toVar(); + const len = uint( uint( 1 ) ).toVar(); + const seed = uint( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ).toVar(); + + return mx_bjfinal( seed.add( uint( x ) ), seed, seed ); + +} ).setLayout( { + name: 'mx_hash_int_0', + type: 'uint', + inputs: [ + { name: 'x', type: 'int' } + ] +} ); + +const mx_hash_int_1 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable ] ) => { + + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const len = uint( uint( 2 ) ).toVar(); + const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); + a.assign( b.assign( c.assign( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ) ) ); + a.addAssign( uint( x ) ); + b.addAssign( uint( y ) ); + + return mx_bjfinal( a, b, c ); + +} ).setLayout( { + name: 'mx_hash_int_1', + type: 'uint', + inputs: [ + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' } + ] +} ); + +const mx_hash_int_2 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable, z_immutable ] ) => { + + const z = int( z_immutable ).toVar(); + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const len = uint( uint( 3 ) ).toVar(); + const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); + a.assign( b.assign( c.assign( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ) ) ); + a.addAssign( uint( x ) ); + b.addAssign( uint( y ) ); + c.addAssign( uint( z ) ); + + return mx_bjfinal( a, b, c ); + +} ).setLayout( { + name: 'mx_hash_int_2', + type: 'uint', + inputs: [ + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' }, + { name: 'z', type: 'int' } + ] +} ); + +const mx_hash_int_3 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable, z_immutable, xx_immutable ] ) => { + + const xx = int( xx_immutable ).toVar(); + const z = int( z_immutable ).toVar(); + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const len = uint( uint( 4 ) ).toVar(); + const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); + a.assign( b.assign( c.assign( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ) ) ); + a.addAssign( uint( x ) ); + b.addAssign( uint( y ) ); + c.addAssign( uint( z ) ); + mx_bjmix( a, b, c ); + a.addAssign( uint( xx ) ); + + return mx_bjfinal( a, b, c ); + +} ).setLayout( { + name: 'mx_hash_int_3', + type: 'uint', + inputs: [ + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' }, + { name: 'z', type: 'int' }, + { name: 'xx', type: 'int' } + ] +} ); + +const mx_hash_int_4 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable, z_immutable, xx_immutable, yy_immutable ] ) => { + + const yy = int( yy_immutable ).toVar(); + const xx = int( xx_immutable ).toVar(); + const z = int( z_immutable ).toVar(); + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const len = uint( uint( 5 ) ).toVar(); + const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); + a.assign( b.assign( c.assign( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ) ) ); + a.addAssign( uint( x ) ); + b.addAssign( uint( y ) ); + c.addAssign( uint( z ) ); + mx_bjmix( a, b, c ); + a.addAssign( uint( xx ) ); + b.addAssign( uint( yy ) ); + + return mx_bjfinal( a, b, c ); + +} ).setLayout( { + name: 'mx_hash_int_4', + type: 'uint', + inputs: [ + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' }, + { name: 'z', type: 'int' }, + { name: 'xx', type: 'int' }, + { name: 'yy', type: 'int' } + ] +} ); + +const mx_hash_int = /*@__PURE__*/ overloadingFn( [ mx_hash_int_0, mx_hash_int_1, mx_hash_int_2, mx_hash_int_3, mx_hash_int_4 ] ); + +const mx_hash_vec3_0 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable ] ) => { + + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const h = uint( mx_hash_int( x, y ) ).toVar(); + const result = uvec3().toVar(); + result.x.assign( h.bitAnd( int( 0xFF ) ) ); + result.y.assign( h.shiftRight( int( 8 ) ).bitAnd( int( 0xFF ) ) ); + result.z.assign( h.shiftRight( int( 16 ) ).bitAnd( int( 0xFF ) ) ); + + return result; + +} ).setLayout( { + name: 'mx_hash_vec3_0', + type: 'uvec3', + inputs: [ + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' } + ] +} ); + +const mx_hash_vec3_1 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable, z_immutable ] ) => { + + const z = int( z_immutable ).toVar(); + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const h = uint( mx_hash_int( x, y, z ) ).toVar(); + const result = uvec3().toVar(); + result.x.assign( h.bitAnd( int( 0xFF ) ) ); + result.y.assign( h.shiftRight( int( 8 ) ).bitAnd( int( 0xFF ) ) ); + result.z.assign( h.shiftRight( int( 16 ) ).bitAnd( int( 0xFF ) ) ); + + return result; + +} ).setLayout( { + name: 'mx_hash_vec3_1', + type: 'uvec3', + inputs: [ + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' }, + { name: 'z', type: 'int' } + ] +} ); + +const mx_hash_vec3 = /*@__PURE__*/ overloadingFn( [ mx_hash_vec3_0, mx_hash_vec3_1 ] ); + +const mx_perlin_noise_float_0 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec2( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(); + const fx = float( mx_floorfrac( p.x, X ) ).toVar(); + const fy = float( mx_floorfrac( p.y, Y ) ).toVar(); + const u = float( mx_fade( fx ) ).toVar(); + const v = float( mx_fade( fy ) ).toVar(); + const result = float( mx_bilerp( mx_gradient_float( mx_hash_int( X, Y ), fx, fy ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y ), fx.sub( 1.0 ), fy ), mx_gradient_float( mx_hash_int( X, Y.add( int( 1 ) ) ), fx, fy.sub( 1.0 ) ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y.add( int( 1 ) ) ), fx.sub( 1.0 ), fy.sub( 1.0 ) ), u, v ) ).toVar(); + + return mx_gradient_scale2d( result ); + +} ).setLayout( { + name: 'mx_perlin_noise_float_0', + type: 'float', + inputs: [ + { name: 'p', type: 'vec2' } + ] +} ); + +const mx_perlin_noise_float_1 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec3( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); + const fx = float( mx_floorfrac( p.x, X ) ).toVar(); + const fy = float( mx_floorfrac( p.y, Y ) ).toVar(); + const fz = float( mx_floorfrac( p.z, Z ) ).toVar(); + const u = float( mx_fade( fx ) ).toVar(); + const v = float( mx_fade( fy ) ).toVar(); + const w = float( mx_fade( fz ) ).toVar(); + const result = float( mx_trilerp( mx_gradient_float( mx_hash_int( X, Y, Z ), fx, fy, fz ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y, Z ), fx.sub( 1.0 ), fy, fz ), mx_gradient_float( mx_hash_int( X, Y.add( int( 1 ) ), Z ), fx, fy.sub( 1.0 ), fz ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y.add( int( 1 ) ), Z ), fx.sub( 1.0 ), fy.sub( 1.0 ), fz ), mx_gradient_float( mx_hash_int( X, Y, Z.add( int( 1 ) ) ), fx, fy, fz.sub( 1.0 ) ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y, Z.add( int( 1 ) ) ), fx.sub( 1.0 ), fy, fz.sub( 1.0 ) ), mx_gradient_float( mx_hash_int( X, Y.add( int( 1 ) ), Z.add( int( 1 ) ) ), fx, fy.sub( 1.0 ), fz.sub( 1.0 ) ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y.add( int( 1 ) ), Z.add( int( 1 ) ) ), fx.sub( 1.0 ), fy.sub( 1.0 ), fz.sub( 1.0 ) ), u, v, w ) ).toVar(); + + return mx_gradient_scale3d( result ); + +} ).setLayout( { + name: 'mx_perlin_noise_float_1', + type: 'float', + inputs: [ + { name: 'p', type: 'vec3' } + ] +} ); + +const mx_perlin_noise_float = /*@__PURE__*/ overloadingFn( [ mx_perlin_noise_float_0, mx_perlin_noise_float_1 ] ); + +const mx_perlin_noise_vec3_0 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec2( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(); + const fx = float( mx_floorfrac( p.x, X ) ).toVar(); + const fy = float( mx_floorfrac( p.y, Y ) ).toVar(); + const u = float( mx_fade( fx ) ).toVar(); + const v = float( mx_fade( fy ) ).toVar(); + const result = vec3( mx_bilerp( mx_gradient_vec3( mx_hash_vec3( X, Y ), fx, fy ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y ), fx.sub( 1.0 ), fy ), mx_gradient_vec3( mx_hash_vec3( X, Y.add( int( 1 ) ) ), fx, fy.sub( 1.0 ) ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y.add( int( 1 ) ) ), fx.sub( 1.0 ), fy.sub( 1.0 ) ), u, v ) ).toVar(); + + return mx_gradient_scale2d( result ); + +} ).setLayout( { + name: 'mx_perlin_noise_vec3_0', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec2' } + ] +} ); + +const mx_perlin_noise_vec3_1 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec3( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); + const fx = float( mx_floorfrac( p.x, X ) ).toVar(); + const fy = float( mx_floorfrac( p.y, Y ) ).toVar(); + const fz = float( mx_floorfrac( p.z, Z ) ).toVar(); + const u = float( mx_fade( fx ) ).toVar(); + const v = float( mx_fade( fy ) ).toVar(); + const w = float( mx_fade( fz ) ).toVar(); + const result = vec3( mx_trilerp( mx_gradient_vec3( mx_hash_vec3( X, Y, Z ), fx, fy, fz ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y, Z ), fx.sub( 1.0 ), fy, fz ), mx_gradient_vec3( mx_hash_vec3( X, Y.add( int( 1 ) ), Z ), fx, fy.sub( 1.0 ), fz ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y.add( int( 1 ) ), Z ), fx.sub( 1.0 ), fy.sub( 1.0 ), fz ), mx_gradient_vec3( mx_hash_vec3( X, Y, Z.add( int( 1 ) ) ), fx, fy, fz.sub( 1.0 ) ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y, Z.add( int( 1 ) ) ), fx.sub( 1.0 ), fy, fz.sub( 1.0 ) ), mx_gradient_vec3( mx_hash_vec3( X, Y.add( int( 1 ) ), Z.add( int( 1 ) ) ), fx, fy.sub( 1.0 ), fz.sub( 1.0 ) ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y.add( int( 1 ) ), Z.add( int( 1 ) ) ), fx.sub( 1.0 ), fy.sub( 1.0 ), fz.sub( 1.0 ) ), u, v, w ) ).toVar(); + + return mx_gradient_scale3d( result ); + +} ).setLayout( { + name: 'mx_perlin_noise_vec3_1', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec3' } + ] +} ); + +const mx_perlin_noise_vec3 = /*@__PURE__*/ overloadingFn( [ mx_perlin_noise_vec3_0, mx_perlin_noise_vec3_1 ] ); + +const mx_cell_noise_float_0 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = float( p_immutable ).toVar(); + const ix = int( mx_floor( p ) ).toVar(); + + return mx_bits_to_01( mx_hash_int( ix ) ); + +} ).setLayout( { + name: 'mx_cell_noise_float_0', + type: 'float', + inputs: [ + { name: 'p', type: 'float' } + ] +} ); + +const mx_cell_noise_float_1 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec2( p_immutable ).toVar(); + const ix = int( mx_floor( p.x ) ).toVar(); + const iy = int( mx_floor( p.y ) ).toVar(); + + return mx_bits_to_01( mx_hash_int( ix, iy ) ); + +} ).setLayout( { + name: 'mx_cell_noise_float_1', + type: 'float', + inputs: [ + { name: 'p', type: 'vec2' } + ] +} ); + +const mx_cell_noise_float_2 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec3( p_immutable ).toVar(); + const ix = int( mx_floor( p.x ) ).toVar(); + const iy = int( mx_floor( p.y ) ).toVar(); + const iz = int( mx_floor( p.z ) ).toVar(); + + return mx_bits_to_01( mx_hash_int( ix, iy, iz ) ); + +} ).setLayout( { + name: 'mx_cell_noise_float_2', + type: 'float', + inputs: [ + { name: 'p', type: 'vec3' } + ] +} ); + +const mx_cell_noise_float_3 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec4( p_immutable ).toVar(); + const ix = int( mx_floor( p.x ) ).toVar(); + const iy = int( mx_floor( p.y ) ).toVar(); + const iz = int( mx_floor( p.z ) ).toVar(); + const iw = int( mx_floor( p.w ) ).toVar(); + + return mx_bits_to_01( mx_hash_int( ix, iy, iz, iw ) ); + +} ).setLayout( { + name: 'mx_cell_noise_float_3', + type: 'float', + inputs: [ + { name: 'p', type: 'vec4' } + ] +} ); + +const mx_cell_noise_float$1 = /*@__PURE__*/ overloadingFn( [ mx_cell_noise_float_0, mx_cell_noise_float_1, mx_cell_noise_float_2, mx_cell_noise_float_3 ] ); + +const mx_cell_noise_vec3_0 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = float( p_immutable ).toVar(); + const ix = int( mx_floor( p ) ).toVar(); + + return vec3( mx_bits_to_01( mx_hash_int( ix, int( 0 ) ) ), mx_bits_to_01( mx_hash_int( ix, int( 1 ) ) ), mx_bits_to_01( mx_hash_int( ix, int( 2 ) ) ) ); + +} ).setLayout( { + name: 'mx_cell_noise_vec3_0', + type: 'vec3', + inputs: [ + { name: 'p', type: 'float' } + ] +} ); + +const mx_cell_noise_vec3_1 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec2( p_immutable ).toVar(); + const ix = int( mx_floor( p.x ) ).toVar(); + const iy = int( mx_floor( p.y ) ).toVar(); + + return vec3( mx_bits_to_01( mx_hash_int( ix, iy, int( 0 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, int( 1 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, int( 2 ) ) ) ); + +} ).setLayout( { + name: 'mx_cell_noise_vec3_1', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec2' } + ] +} ); + +const mx_cell_noise_vec3_2 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec3( p_immutable ).toVar(); + const ix = int( mx_floor( p.x ) ).toVar(); + const iy = int( mx_floor( p.y ) ).toVar(); + const iz = int( mx_floor( p.z ) ).toVar(); + + return vec3( mx_bits_to_01( mx_hash_int( ix, iy, iz, int( 0 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, iz, int( 1 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, iz, int( 2 ) ) ) ); + +} ).setLayout( { + name: 'mx_cell_noise_vec3_2', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec3' } + ] +} ); + +const mx_cell_noise_vec3_3 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec4( p_immutable ).toVar(); + const ix = int( mx_floor( p.x ) ).toVar(); + const iy = int( mx_floor( p.y ) ).toVar(); + const iz = int( mx_floor( p.z ) ).toVar(); + const iw = int( mx_floor( p.w ) ).toVar(); + + return vec3( mx_bits_to_01( mx_hash_int( ix, iy, iz, iw, int( 0 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, iz, iw, int( 1 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, iz, iw, int( 2 ) ) ) ); + +} ).setLayout( { + name: 'mx_cell_noise_vec3_3', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec4' } + ] +} ); + +const mx_cell_noise_vec3 = /*@__PURE__*/ overloadingFn( [ mx_cell_noise_vec3_0, mx_cell_noise_vec3_1, mx_cell_noise_vec3_2, mx_cell_noise_vec3_3 ] ); + +const mx_fractal_noise_float$1 = /*@__PURE__*/ Fn( ( [ p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable ] ) => { + + const diminish = float( diminish_immutable ).toVar(); + const lacunarity = float( lacunarity_immutable ).toVar(); + const octaves = int( octaves_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const result = float( 0.0 ).toVar(); + const amplitude = float( 1.0 ).toVar(); + + Loop( octaves, () => { + + result.addAssign( amplitude.mul( mx_perlin_noise_float( p ) ) ); + amplitude.mulAssign( diminish ); + p.mulAssign( lacunarity ); + + } ); + + return result; + +} ).setLayout( { + name: 'mx_fractal_noise_float', + type: 'float', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'octaves', type: 'int' }, + { name: 'lacunarity', type: 'float' }, + { name: 'diminish', type: 'float' } + ] +} ); + +const mx_fractal_noise_vec3$1 = /*@__PURE__*/ Fn( ( [ p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable ] ) => { + + const diminish = float( diminish_immutable ).toVar(); + const lacunarity = float( lacunarity_immutable ).toVar(); + const octaves = int( octaves_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const result = vec3( 0.0 ).toVar(); + const amplitude = float( 1.0 ).toVar(); + + Loop( octaves, () => { + + result.addAssign( amplitude.mul( mx_perlin_noise_vec3( p ) ) ); + amplitude.mulAssign( diminish ); + p.mulAssign( lacunarity ); + + } ); + + return result; + +} ).setLayout( { + name: 'mx_fractal_noise_vec3', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'octaves', type: 'int' }, + { name: 'lacunarity', type: 'float' }, + { name: 'diminish', type: 'float' } + ] +} ); + +const mx_fractal_noise_vec2$1 = /*@__PURE__*/ Fn( ( [ p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable ] ) => { + + const diminish = float( diminish_immutable ).toVar(); + const lacunarity = float( lacunarity_immutable ).toVar(); + const octaves = int( octaves_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + + return vec2( mx_fractal_noise_float$1( p, octaves, lacunarity, diminish ), mx_fractal_noise_float$1( p.add( vec3( int( 19 ), int( 193 ), int( 17 ) ) ), octaves, lacunarity, diminish ) ); + +} ).setLayout( { + name: 'mx_fractal_noise_vec2', + type: 'vec2', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'octaves', type: 'int' }, + { name: 'lacunarity', type: 'float' }, + { name: 'diminish', type: 'float' } + ] +} ); + +const mx_fractal_noise_vec4$1 = /*@__PURE__*/ Fn( ( [ p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable ] ) => { + + const diminish = float( diminish_immutable ).toVar(); + const lacunarity = float( lacunarity_immutable ).toVar(); + const octaves = int( octaves_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const c = vec3( mx_fractal_noise_vec3$1( p, octaves, lacunarity, diminish ) ).toVar(); + const f = float( mx_fractal_noise_float$1( p.add( vec3( int( 19 ), int( 193 ), int( 17 ) ) ), octaves, lacunarity, diminish ) ).toVar(); + + return vec4( c, f ); + +} ).setLayout( { + name: 'mx_fractal_noise_vec4', + type: 'vec4', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'octaves', type: 'int' }, + { name: 'lacunarity', type: 'float' }, + { name: 'diminish', type: 'float' } + ] +} ); + +const mx_worley_distance_0 = /*@__PURE__*/ Fn( ( [ p_immutable, x_immutable, y_immutable, xoff_immutable, yoff_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const yoff = int( yoff_immutable ).toVar(); + const xoff = int( xoff_immutable ).toVar(); + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const p = vec2( p_immutable ).toVar(); + const tmp = vec3( mx_cell_noise_vec3( vec2( x.add( xoff ), y.add( yoff ) ) ) ).toVar(); + const off = vec2( tmp.x, tmp.y ).toVar(); + off.subAssign( 0.5 ); + off.mulAssign( jitter ); + off.addAssign( 0.5 ); + const cellpos = vec2( vec2( float( x ), float( y ) ).add( off ) ).toVar(); + const diff = vec2( cellpos.sub( p ) ).toVar(); + + If( metric.equal( int( 2 ) ), () => { + + return abs( diff.x ).add( abs( diff.y ) ); + + } ); + + If( metric.equal( int( 3 ) ), () => { + + return max$1( abs( diff.x ), abs( diff.y ) ); + + } ); + + return dot( diff, diff ); + +} ).setLayout( { + name: 'mx_worley_distance_0', + type: 'float', + inputs: [ + { name: 'p', type: 'vec2' }, + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' }, + { name: 'xoff', type: 'int' }, + { name: 'yoff', type: 'int' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_distance_1 = /*@__PURE__*/ Fn( ( [ p_immutable, x_immutable, y_immutable, z_immutable, xoff_immutable, yoff_immutable, zoff_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const zoff = int( zoff_immutable ).toVar(); + const yoff = int( yoff_immutable ).toVar(); + const xoff = int( xoff_immutable ).toVar(); + const z = int( z_immutable ).toVar(); + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const off = vec3( mx_cell_noise_vec3( vec3( x.add( xoff ), y.add( yoff ), z.add( zoff ) ) ) ).toVar(); + off.subAssign( 0.5 ); + off.mulAssign( jitter ); + off.addAssign( 0.5 ); + const cellpos = vec3( vec3( float( x ), float( y ), float( z ) ).add( off ) ).toVar(); + const diff = vec3( cellpos.sub( p ) ).toVar(); + + If( metric.equal( int( 2 ) ), () => { + + return abs( diff.x ).add( abs( diff.y ) ).add( abs( diff.z ) ); + + } ); + + If( metric.equal( int( 3 ) ), () => { + + return max$1( max$1( abs( diff.x ), abs( diff.y ) ), abs( diff.z ) ); + + } ); + + return dot( diff, diff ); + +} ).setLayout( { + name: 'mx_worley_distance_1', + type: 'float', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' }, + { name: 'z', type: 'int' }, + { name: 'xoff', type: 'int' }, + { name: 'yoff', type: 'int' }, + { name: 'zoff', type: 'int' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_distance = /*@__PURE__*/ overloadingFn( [ mx_worley_distance_0, mx_worley_distance_1 ] ); + +const mx_worley_noise_float_0 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const p = vec2( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(); + const localpos = vec2( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ) ).toVar(); + const sqdist = float( 1e6 ).toVar(); + + Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + + const dist = float( mx_worley_distance( localpos, x, y, X, Y, jitter, metric ) ).toVar(); + sqdist.assign( min$1( sqdist, dist ) ); + + } ); + + } ); + + If( metric.equal( int( 0 ) ), () => { + + sqdist.assign( sqrt( sqdist ) ); + + } ); + + return sqdist; + +} ).setLayout( { + name: 'mx_worley_noise_float_0', + type: 'float', + inputs: [ + { name: 'p', type: 'vec2' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_noise_vec2_0 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const p = vec2( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(); + const localpos = vec2( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ) ).toVar(); + const sqdist = vec2( 1e6, 1e6 ).toVar(); + + Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + + const dist = float( mx_worley_distance( localpos, x, y, X, Y, jitter, metric ) ).toVar(); + + If( dist.lessThan( sqdist.x ), () => { + + sqdist.y.assign( sqdist.x ); + sqdist.x.assign( dist ); + + } ).ElseIf( dist.lessThan( sqdist.y ), () => { + + sqdist.y.assign( dist ); + + } ); + + } ); + + } ); + + If( metric.equal( int( 0 ) ), () => { + + sqdist.assign( sqrt( sqdist ) ); + + } ); + + return sqdist; + +} ).setLayout( { + name: 'mx_worley_noise_vec2_0', + type: 'vec2', + inputs: [ + { name: 'p', type: 'vec2' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_noise_vec3_0 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const p = vec2( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(); + const localpos = vec2( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ) ).toVar(); + const sqdist = vec3( 1e6, 1e6, 1e6 ).toVar(); + + Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + + const dist = float( mx_worley_distance( localpos, x, y, X, Y, jitter, metric ) ).toVar(); + + If( dist.lessThan( sqdist.x ), () => { + + sqdist.z.assign( sqdist.y ); + sqdist.y.assign( sqdist.x ); + sqdist.x.assign( dist ); + + } ).ElseIf( dist.lessThan( sqdist.y ), () => { + + sqdist.z.assign( sqdist.y ); + sqdist.y.assign( dist ); + + } ).ElseIf( dist.lessThan( sqdist.z ), () => { + + sqdist.z.assign( dist ); + + } ); + + } ); + + } ); + + If( metric.equal( int( 0 ) ), () => { + + sqdist.assign( sqrt( sqdist ) ); + + } ); + + return sqdist; + +} ).setLayout( { + name: 'mx_worley_noise_vec3_0', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec2' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_noise_float_1 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); + const localpos = vec3( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ), mx_floorfrac( p.z, Z ) ).toVar(); + const sqdist = float( 1e6 ).toVar(); + + Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'z', condition: '<=' }, ( { z } ) => { + + const dist = float( mx_worley_distance( localpos, x, y, z, X, Y, Z, jitter, metric ) ).toVar(); + sqdist.assign( min$1( sqdist, dist ) ); + + } ); + + } ); + + } ); + + If( metric.equal( int( 0 ) ), () => { + + sqdist.assign( sqrt( sqdist ) ); + + } ); + + return sqdist; + +} ).setLayout( { + name: 'mx_worley_noise_float_1', + type: 'float', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_noise_float$1 = /*@__PURE__*/ overloadingFn( [ mx_worley_noise_float_0, mx_worley_noise_float_1 ] ); + +const mx_worley_noise_vec2_1 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); + const localpos = vec3( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ), mx_floorfrac( p.z, Z ) ).toVar(); + const sqdist = vec2( 1e6, 1e6 ).toVar(); + + Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'z', condition: '<=' }, ( { z } ) => { + + const dist = float( mx_worley_distance( localpos, x, y, z, X, Y, Z, jitter, metric ) ).toVar(); + + If( dist.lessThan( sqdist.x ), () => { + + sqdist.y.assign( sqdist.x ); + sqdist.x.assign( dist ); + + } ).ElseIf( dist.lessThan( sqdist.y ), () => { + + sqdist.y.assign( dist ); + + } ); + + } ); + + } ); + + } ); + + If( metric.equal( int( 0 ) ), () => { + + sqdist.assign( sqrt( sqdist ) ); + + } ); + + return sqdist; + +} ).setLayout( { + name: 'mx_worley_noise_vec2_1', + type: 'vec2', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_noise_vec2$1 = /*@__PURE__*/ overloadingFn( [ mx_worley_noise_vec2_0, mx_worley_noise_vec2_1 ] ); + +const mx_worley_noise_vec3_1 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); + const localpos = vec3( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ), mx_floorfrac( p.z, Z ) ).toVar(); + const sqdist = vec3( 1e6, 1e6, 1e6 ).toVar(); + + Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'z', condition: '<=' }, ( { z } ) => { + + const dist = float( mx_worley_distance( localpos, x, y, z, X, Y, Z, jitter, metric ) ).toVar(); + + If( dist.lessThan( sqdist.x ), () => { + + sqdist.z.assign( sqdist.y ); + sqdist.y.assign( sqdist.x ); + sqdist.x.assign( dist ); + + } ).ElseIf( dist.lessThan( sqdist.y ), () => { + + sqdist.z.assign( sqdist.y ); + sqdist.y.assign( dist ); + + } ).ElseIf( dist.lessThan( sqdist.z ), () => { + + sqdist.z.assign( dist ); + + } ); + + } ); + + } ); + + } ); + + If( metric.equal( int( 0 ) ), () => { + + sqdist.assign( sqrt( sqdist ) ); + + } ); + + return sqdist; + +} ).setLayout( { + name: 'mx_worley_noise_vec3_1', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_noise_vec3$1 = /*@__PURE__*/ overloadingFn( [ mx_worley_noise_vec3_0, mx_worley_noise_vec3_1 ] ); + +// Three.js Transpiler +// https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/stdlib/genglsl/lib/mx_hsv.glsl + + +const mx_hsvtorgb = /*@__PURE__*/ Fn( ( [ hsv ] ) => { + + const s = hsv.y; + const v = hsv.z; + + const result = vec3().toVar(); + + If( s.lessThan( 0.0001 ), () => { + + result.assign( vec3( v, v, v ) ); + + } ).Else( () => { + + let h = hsv.x; + h = h.sub( floor( h ) ).mul( 6.0 ).toVar(); // TODO: check what .toVar() is needed in node system cache + const hi = int( trunc( h ) ); + const f = h.sub( float( hi ) ); + const p = v.mul( s.oneMinus() ); + const q = v.mul( s.mul( f ).oneMinus() ); + const t = v.mul( s.mul( f.oneMinus() ).oneMinus() ); + + If( hi.equal( int( 0 ) ), () => { + + result.assign( vec3( v, t, p ) ); + + } ).ElseIf( hi.equal( int( 1 ) ), () => { + + result.assign( vec3( q, v, p ) ); + + } ).ElseIf( hi.equal( int( 2 ) ), () => { + + result.assign( vec3( p, v, t ) ); + + } ).ElseIf( hi.equal( int( 3 ) ), () => { + + result.assign( vec3( p, q, v ) ); + + } ).ElseIf( hi.equal( int( 4 ) ), () => { + + result.assign( vec3( t, p, v ) ); + + } ).Else( () => { + + result.assign( vec3( v, p, q ) ); + + } ); + + } ); + + return result; + +} ).setLayout( { + name: 'mx_hsvtorgb', + type: 'vec3', + inputs: [ + { name: 'hsv', type: 'vec3' } + ] +} ); + +const mx_rgbtohsv = /*@__PURE__*/ Fn( ( [ c_immutable ] ) => { + + const c = vec3( c_immutable ).toVar(); + const r = float( c.x ).toVar(); + const g = float( c.y ).toVar(); + const b = float( c.z ).toVar(); + const mincomp = float( min$1( r, min$1( g, b ) ) ).toVar(); + const maxcomp = float( max$1( r, max$1( g, b ) ) ).toVar(); + const delta = float( maxcomp.sub( mincomp ) ).toVar(); + const h = float().toVar(), s = float().toVar(), v = float().toVar(); + v.assign( maxcomp ); + + If( maxcomp.greaterThan( 0.0 ), () => { + + s.assign( delta.div( maxcomp ) ); + + } ).Else( () => { + + s.assign( 0.0 ); + + } ); + + If( s.lessThanEqual( 0.0 ), () => { + + h.assign( 0.0 ); + + } ).Else( () => { + + If( r.greaterThanEqual( maxcomp ), () => { + + h.assign( g.sub( b ).div( delta ) ); + + } ).ElseIf( g.greaterThanEqual( maxcomp ), () => { + + h.assign( add( 2.0, b.sub( r ).div( delta ) ) ); + + } ).Else( () => { + + h.assign( add( 4.0, r.sub( g ).div( delta ) ) ); + + } ); + + h.mulAssign( 1.0 / 6.0 ); + + If( h.lessThan( 0.0 ), () => { + + h.addAssign( 1.0 ); + + } ); + + } ); + + return vec3( h, s, v ); + +} ).setLayout( { + name: 'mx_rgbtohsv', + type: 'vec3', + inputs: [ + { name: 'c', type: 'vec3' } + ] +} ); + +// Three.js Transpiler +// https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/stdlib/genglsl/lib/mx_transform_color.glsl + + +const mx_srgb_texture_to_lin_rec709 = /*@__PURE__*/ Fn( ( [ color_immutable ] ) => { + + const color = vec3( color_immutable ).toVar(); + const isAbove = bvec3( greaterThan( color, vec3( 0.04045 ) ) ).toVar(); + const linSeg = vec3( color.div( 12.92 ) ).toVar(); + const powSeg = vec3( pow( max$1( color.add( vec3( 0.055 ) ), vec3( 0.0 ) ).div( 1.055 ), vec3( 2.4 ) ) ).toVar(); + + return mix( linSeg, powSeg, isAbove ); + +} ).setLayout( { + name: 'mx_srgb_texture_to_lin_rec709', + type: 'vec3', + inputs: [ + { name: 'color', type: 'vec3' } + ] +} ); + +const mx_aastep = ( threshold, value ) => { + + threshold = float( threshold ); + value = float( value ); + + const afwidth = vec2( value.dFdx(), value.dFdy() ).length().mul( 0.70710678118654757 ); + + return smoothstep( threshold.sub( afwidth ), threshold.add( afwidth ), value ); + +}; + +const _ramp = ( a, b, uv, p ) => mix( a, b, uv[ p ].clamp() ); +const mx_ramplr = ( valuel, valuer, texcoord = uv() ) => _ramp( valuel, valuer, texcoord, 'x' ); +const mx_ramptb = ( valuet, valueb, texcoord = uv() ) => _ramp( valuet, valueb, texcoord, 'y' ); + +const _split = ( a, b, center, uv, p ) => mix( a, b, mx_aastep( center, uv[ p ] ) ); +const mx_splitlr = ( valuel, valuer, center, texcoord = uv() ) => _split( valuel, valuer, center, texcoord, 'x' ); +const mx_splittb = ( valuet, valueb, center, texcoord = uv() ) => _split( valuet, valueb, center, texcoord, 'y' ); + +const mx_transform_uv = ( uv_scale = 1, uv_offset = 0, uv_geo = uv() ) => uv_geo.mul( uv_scale ).add( uv_offset ); + +const mx_safepower = ( in1, in2 = 1 ) => { + + in1 = float( in1 ); + + return in1.abs().pow( in2 ).mul( in1.sign() ); + +}; + +const mx_contrast = ( input, amount = 1, pivot = .5 ) => float( input ).sub( pivot ).mul( amount ).add( pivot ); + +const mx_noise_float = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_float( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot ); +//export const mx_noise_vec2 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_vec3( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot ); +const mx_noise_vec3 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_vec3( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot ); +const mx_noise_vec4 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => { + + texcoord = texcoord.convert( 'vec2|vec3' ); // overloading type + + const noise_vec4 = vec4( mx_perlin_noise_vec3( texcoord ), mx_perlin_noise_float( texcoord.add( vec2( 19, 73 ) ) ) ); + + return noise_vec4.mul( amplitude ).add( pivot ); + +}; + +const mx_worley_noise_float = ( texcoord = uv(), jitter = 1 ) => mx_worley_noise_float$1( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) ); +const mx_worley_noise_vec2 = ( texcoord = uv(), jitter = 1 ) => mx_worley_noise_vec2$1( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) ); +const mx_worley_noise_vec3 = ( texcoord = uv(), jitter = 1 ) => mx_worley_noise_vec3$1( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) ); + +const mx_cell_noise_float = ( texcoord = uv() ) => mx_cell_noise_float$1( texcoord.convert( 'vec2|vec3' ) ); + +const mx_fractal_noise_float = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mx_fractal_noise_float$1( position, int( octaves ), lacunarity, diminish ).mul( amplitude ); +const mx_fractal_noise_vec2 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mx_fractal_noise_vec2$1( position, int( octaves ), lacunarity, diminish ).mul( amplitude ); +const mx_fractal_noise_vec3 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mx_fractal_noise_vec3$1( position, int( octaves ), lacunarity, diminish ).mul( amplitude ); +const mx_fractal_noise_vec4 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mx_fractal_noise_vec4$1( position, int( octaves ), lacunarity, diminish ).mul( amplitude ); + +const getShIrradianceAt = /*@__PURE__*/ Fn( ( [ normal, shCoefficients ] ) => { + + // normal is assumed to have unit length + + const x = normal.x, y = normal.y, z = normal.z; + + // band 0 + let result = shCoefficients.element( 0 ).mul( 0.886227 ); + + // band 1 + result = result.add( shCoefficients.element( 1 ).mul( 2.0 * 0.511664 ).mul( y ) ); + result = result.add( shCoefficients.element( 2 ).mul( 2.0 * 0.511664 ).mul( z ) ); + result = result.add( shCoefficients.element( 3 ).mul( 2.0 * 0.511664 ).mul( x ) ); + + // band 2 + result = result.add( shCoefficients.element( 4 ).mul( 2.0 * 0.429043 ).mul( x ).mul( y ) ); + result = result.add( shCoefficients.element( 5 ).mul( 2.0 * 0.429043 ).mul( y ).mul( z ) ); + result = result.add( shCoefficients.element( 6 ).mul( z.mul( z ).mul( 0.743125 ).sub( 0.247708 ) ) ); + result = result.add( shCoefficients.element( 7 ).mul( 2.0 * 0.429043 ).mul( x ).mul( z ) ); + result = result.add( shCoefficients.element( 8 ).mul( 0.429043 ).mul( mul( x, x ).sub( mul( y, y ) ) ) ); + + return result; + +} ); + +class PointLightNode extends AnalyticLightNode { + + static get type() { + + return 'PointLightNode'; + + } + + constructor( light = null ) { + + super( light ); + + this.cutoffDistanceNode = uniform( 0 ).setGroup( renderGroup ); + this.decayExponentNode = uniform( 0 ).setGroup( renderGroup ); + + } + + update( frame ) { + + const { light } = this; + + super.update( frame ); + + this.cutoffDistanceNode.value = light.distance; + this.decayExponentNode.value = light.decay; + + } + + setup( builder ) { + + const { colorNode, cutoffDistanceNode, decayExponentNode, light } = this; + + const lightingModel = builder.context.lightingModel; + + const lVector = lightViewPosition( light ).sub( positionView ); // @TODO: Add it into LightNode + + const lightDirection = lVector.normalize(); + const lightDistance = lVector.length(); + + const lightAttenuation = getDistanceAttenuation( { + lightDistance, + cutoffDistance: cutoffDistanceNode, + decayExponent: decayExponentNode + } ); + + const lightColor = colorNode.mul( lightAttenuation ); + + const reflectedLight = builder.context.reflectedLight; + + lightingModel.direct( { + lightDirection, + lightColor, + reflectedLight + }, builder.stack, builder ); + + } + +} + +class DirectionalLightNode extends AnalyticLightNode { + + static get type() { + + return 'DirectionalLightNode'; + + } + + constructor( light = null ) { + + super( light ); + + } + + setup( builder ) { + + super.setup( builder ); + + const lightingModel = builder.context.lightingModel; + + const lightColor = this.colorNode; + const lightDirection = lightTargetDirection( this.light ); + const reflectedLight = builder.context.reflectedLight; + + lightingModel.direct( { + lightDirection, + lightColor, + reflectedLight + }, builder.stack, builder ); + + } + +} + +const _matrix41 = /*@__PURE__*/ new Matrix4(); +const _matrix42 = /*@__PURE__*/ new Matrix4(); + +let ltcLib = null; + +class RectAreaLightNode extends AnalyticLightNode { + + static get type() { + + return 'RectAreaLightNode'; + + } + + constructor( light = null ) { + + super( light ); + + this.halfHeight = uniform( new Vector3() ).setGroup( renderGroup ); + this.halfWidth = uniform( new Vector3() ).setGroup( renderGroup ); + + } + + update( frame ) { + + super.update( frame ); + + const { light } = this; + + const viewMatrix = frame.camera.matrixWorldInverse; + + _matrix42.identity(); + _matrix41.copy( light.matrixWorld ); + _matrix41.premultiply( viewMatrix ); + _matrix42.extractRotation( _matrix41 ); + + this.halfWidth.value.set( light.width * 0.5, 0.0, 0.0 ); + this.halfHeight.value.set( 0.0, light.height * 0.5, 0.0 ); + + this.halfWidth.value.applyMatrix4( _matrix42 ); + this.halfHeight.value.applyMatrix4( _matrix42 ); + + } + + setup( builder ) { + + super.setup( builder ); + + let ltc_1, ltc_2; + + if ( builder.isAvailable( 'float32Filterable' ) ) { + + ltc_1 = texture( ltcLib.LTC_FLOAT_1 ); + ltc_2 = texture( ltcLib.LTC_FLOAT_2 ); + + } else { + + ltc_1 = texture( ltcLib.LTC_HALF_1 ); + ltc_2 = texture( ltcLib.LTC_HALF_2 ); + + } + + const { colorNode, light } = this; + const lightingModel = builder.context.lightingModel; + + const lightPosition = lightViewPosition( light ); + const reflectedLight = builder.context.reflectedLight; + + lightingModel.directRectArea( { + lightColor: colorNode, + lightPosition, + halfWidth: this.halfWidth, + halfHeight: this.halfHeight, + reflectedLight, + ltc_1, + ltc_2 + }, builder.stack, builder ); + + } + + static setLTC( ltc ) { + + ltcLib = ltc; + + } + +} + +class SpotLightNode extends AnalyticLightNode { + + static get type() { + + return 'SpotLightNode'; + + } + + constructor( light = null ) { + + super( light ); + + this.coneCosNode = uniform( 0 ).setGroup( renderGroup ); + this.penumbraCosNode = uniform( 0 ).setGroup( renderGroup ); + + this.cutoffDistanceNode = uniform( 0 ).setGroup( renderGroup ); + this.decayExponentNode = uniform( 0 ).setGroup( renderGroup ); + + } + + update( frame ) { + + super.update( frame ); + + const { light } = this; + + this.coneCosNode.value = Math.cos( light.angle ); + this.penumbraCosNode.value = Math.cos( light.angle * ( 1 - light.penumbra ) ); + + this.cutoffDistanceNode.value = light.distance; + this.decayExponentNode.value = light.decay; + + } + + getSpotAttenuation( angleCosine ) { + + const { coneCosNode, penumbraCosNode } = this; + + return smoothstep( coneCosNode, penumbraCosNode, angleCosine ); + + } + + setup( builder ) { + + super.setup( builder ); + + const lightingModel = builder.context.lightingModel; + + const { colorNode, cutoffDistanceNode, decayExponentNode, light } = this; + + const lVector = lightViewPosition( light ).sub( positionView ); // @TODO: Add it into LightNode + + const lightDirection = lVector.normalize(); + const angleCos = lightDirection.dot( lightTargetDirection( light ) ); + const spotAttenuation = this.getSpotAttenuation( angleCos ); + + const lightDistance = lVector.length(); + + const lightAttenuation = getDistanceAttenuation( { + lightDistance, + cutoffDistance: cutoffDistanceNode, + decayExponent: decayExponentNode + } ); + + const lightColor = colorNode.mul( spotAttenuation ).mul( lightAttenuation ); + + const reflectedLight = builder.context.reflectedLight; + + lightingModel.direct( { + lightDirection, + lightColor, + reflectedLight + }, builder.stack, builder ); + + } + +} + +class IESSpotLightNode extends SpotLightNode { + + static get type() { + + return 'IESSpotLightNode'; + + } + + getSpotAttenuation( angleCosine ) { + + const iesMap = this.light.iesMap; + + let spotAttenuation = null; + + if ( iesMap && iesMap.isTexture === true ) { + + const angle = angleCosine.acos().mul( 1.0 / Math.PI ); + + spotAttenuation = texture( iesMap, vec2( angle, 0 ), 0 ).r; + + } else { + + spotAttenuation = super.getSpotAttenuation( angleCosine ); + + } + + return spotAttenuation; + + } + +} + +class AmbientLightNode extends AnalyticLightNode { + + static get type() { + + return 'AmbientLightNode'; + + } + + constructor( light = null ) { + + super( light ); + + } + + setup( { context } ) { + + context.irradiance.addAssign( this.colorNode ); + + } + +} + +class HemisphereLightNode extends AnalyticLightNode { + + static get type() { + + return 'HemisphereLightNode'; + + } + + constructor( light = null ) { + + super( light ); + + this.lightPositionNode = lightPosition( light ); + this.lightDirectionNode = this.lightPositionNode.normalize(); + + this.groundColorNode = uniform( new Color() ).setGroup( renderGroup ); + + } + + update( frame ) { + + const { light } = this; + + super.update( frame ); + + this.lightPositionNode.object3d = light; + + this.groundColorNode.value.copy( light.groundColor ).multiplyScalar( light.intensity ); + + } + + setup( builder ) { + + const { colorNode, groundColorNode, lightDirectionNode } = this; + + const dotNL = normalView.dot( lightDirectionNode ); + const hemiDiffuseWeight = dotNL.mul( 0.5 ).add( 0.5 ); + + const irradiance = mix( groundColorNode, colorNode, hemiDiffuseWeight ); + + builder.context.irradiance.addAssign( irradiance ); + + } + +} + +class LightProbeNode extends AnalyticLightNode { + + static get type() { + + return 'LightProbeNode'; + + } + + constructor( light = null ) { + + super( light ); + + const array = []; + + for ( let i = 0; i < 9; i ++ ) array.push( new Vector3() ); + + this.lightProbe = uniformArray( array ); + + } + + update( frame ) { + + const { light } = this; + + super.update( frame ); + + // + + for ( let i = 0; i < 9; i ++ ) { + + this.lightProbe.array[ i ].copy( light.sh.coefficients[ i ] ).multiplyScalar( light.intensity ); + + } + + } + + setup( builder ) { + + const irradiance = getShIrradianceAt( normalWorld, this.lightProbe ); + + builder.context.irradiance.addAssign( irradiance ); + + } + +} + +class NodeParser { + + parseFunction( /*source*/ ) { + + console.warn( 'Abstract function.' ); + + } + +} + +class NodeFunction { + + constructor( type, inputs, name = '', precision = '' ) { + + this.type = type; + this.inputs = inputs; + this.name = name; + this.precision = precision; + + } + + getCode( /*name = this.name*/ ) { + + console.warn( 'Abstract function.' ); + + } + +} + +NodeFunction.isNodeFunction = true; + +const declarationRegexp$1 = /^\s*(highp|mediump|lowp)?\s*([a-z_0-9]+)\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)/i; +const propertiesRegexp$1 = /[a-z_0-9]+/ig; + +const pragmaMain = '#pragma main'; + +const parse$1 = ( source ) => { + + source = source.trim(); + + const pragmaMainIndex = source.indexOf( pragmaMain ); + + const mainCode = pragmaMainIndex !== - 1 ? source.slice( pragmaMainIndex + pragmaMain.length ) : source; + + const declaration = mainCode.match( declarationRegexp$1 ); + + if ( declaration !== null && declaration.length === 5 ) { + + // tokenizer + + const inputsCode = declaration[ 4 ]; + const propsMatches = []; + + let nameMatch = null; + + while ( ( nameMatch = propertiesRegexp$1.exec( inputsCode ) ) !== null ) { + + propsMatches.push( nameMatch ); + + } + + // parser + + const inputs = []; + + let i = 0; + + while ( i < propsMatches.length ) { + + const isConst = propsMatches[ i ][ 0 ] === 'const'; + + if ( isConst === true ) { + + i ++; + + } + + let qualifier = propsMatches[ i ][ 0 ]; + + if ( qualifier === 'in' || qualifier === 'out' || qualifier === 'inout' ) { + + i ++; + + } else { + + qualifier = ''; + + } + + const type = propsMatches[ i ++ ][ 0 ]; + + let count = Number.parseInt( propsMatches[ i ][ 0 ] ); + + if ( Number.isNaN( count ) === false ) i ++; + else count = null; + + const name = propsMatches[ i ++ ][ 0 ]; + + inputs.push( new NodeFunctionInput( type, name, count, qualifier, isConst ) ); + + } + + // + + const blockCode = mainCode.substring( declaration[ 0 ].length ); + + const name = declaration[ 3 ] !== undefined ? declaration[ 3 ] : ''; + const type = declaration[ 2 ]; + + const precision = declaration[ 1 ] !== undefined ? declaration[ 1 ] : ''; + + const headerCode = pragmaMainIndex !== - 1 ? source.slice( 0, pragmaMainIndex ) : ''; + + return { + type, + inputs, + name, + precision, + inputsCode, + blockCode, + headerCode + }; + + } else { + + throw new Error( 'FunctionNode: Function is not a GLSL code.' ); + + } + +}; + +class GLSLNodeFunction extends NodeFunction { + + constructor( source ) { + + const { type, inputs, name, precision, inputsCode, blockCode, headerCode } = parse$1( source ); + + super( type, inputs, name, precision ); + + this.inputsCode = inputsCode; + this.blockCode = blockCode; + this.headerCode = headerCode; + + } + + getCode( name = this.name ) { + + let code; + + const blockCode = this.blockCode; + + if ( blockCode !== '' ) { + + const { type, inputsCode, headerCode, precision } = this; + + let declarationCode = `${ type } ${ name } ( ${ inputsCode.trim() } )`; + + if ( precision !== '' ) { + + declarationCode = `${ precision } ${ declarationCode }`; + + } + + code = headerCode + declarationCode + blockCode; + + } else { + + // interface function + + code = ''; + + } + + return code; + + } + +} + +class GLSLNodeParser extends NodeParser { + + parseFunction( source ) { + + return new GLSLNodeFunction( source ); + + } + +} + +function painterSortStable( a, b ) { + + if ( a.groupOrder !== b.groupOrder ) { + + return a.groupOrder - b.groupOrder; + + } else if ( a.renderOrder !== b.renderOrder ) { + + return a.renderOrder - b.renderOrder; + + } else if ( a.material.id !== b.material.id ) { + + return a.material.id - b.material.id; + + } else if ( a.z !== b.z ) { + + return a.z - b.z; + + } else { + + return a.id - b.id; + + } + +} + +function reversePainterSortStable( a, b ) { + + if ( a.groupOrder !== b.groupOrder ) { + + return a.groupOrder - b.groupOrder; + + } else if ( a.renderOrder !== b.renderOrder ) { + + return a.renderOrder - b.renderOrder; + + } else if ( a.z !== b.z ) { + + return b.z - a.z; + + } else { + + return a.id - b.id; + + } + +} + +class RenderList { + + constructor() { + + this.renderItems = []; + this.renderItemsIndex = 0; + + this.opaque = []; + this.transparent = []; + this.bundles = []; + + this.lightsNode = new LightsNode( [] ); + this.lightsArray = []; + + this.occlusionQueryCount = 0; + + } + + begin() { + + this.renderItemsIndex = 0; + + this.opaque.length = 0; + this.transparent.length = 0; + this.bundles.length = 0; + + this.lightsArray.length = 0; + + this.occlusionQueryCount = 0; + + return this; + + } + + getNextRenderItem( object, geometry, material, groupOrder, z, group ) { + + let renderItem = this.renderItems[ this.renderItemsIndex ]; + + if ( renderItem === undefined ) { + + renderItem = { + id: object.id, + object: object, + geometry: geometry, + material: material, + groupOrder: groupOrder, + renderOrder: object.renderOrder, + z: z, + group: group + }; + + this.renderItems[ this.renderItemsIndex ] = renderItem; + + } else { + + renderItem.id = object.id; + renderItem.object = object; + renderItem.geometry = geometry; + renderItem.material = material; + renderItem.groupOrder = groupOrder; + renderItem.renderOrder = object.renderOrder; + renderItem.z = z; + renderItem.group = group; + + } + + this.renderItemsIndex ++; + + return renderItem; + + } + + push( object, geometry, material, groupOrder, z, group ) { + + const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group ); + + if ( object.occlusionTest === true ) this.occlusionQueryCount ++; + + ( material.transparent === true || material.transmission > 0 ? this.transparent : this.opaque ).push( renderItem ); + + } + + unshift( object, geometry, material, groupOrder, z, group ) { + + const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group ); + + ( material.transparent === true ? this.transparent : this.opaque ).unshift( renderItem ); + + } + + pushBundle( group ) { + + this.bundles.push( group ); + + } + + pushLight( light ) { + + this.lightsArray.push( light ); + + } + + getLightsNode() { + + return this.lightsNode.fromLights( this.lightsArray ); + + } + + sort( customOpaqueSort, customTransparentSort ) { + + if ( this.opaque.length > 1 ) this.opaque.sort( customOpaqueSort || painterSortStable ); + if ( this.transparent.length > 1 ) this.transparent.sort( customTransparentSort || reversePainterSortStable ); + + } + + finish() { + + // update lights + + this.lightsNode.setLights( this.lightsArray ); + + // Clear references from inactive renderItems in the list + + for ( let i = this.renderItemsIndex, il = this.renderItems.length; i < il; i ++ ) { + + const renderItem = this.renderItems[ i ]; + + if ( renderItem.id === null ) break; + + renderItem.id = null; + renderItem.object = null; + renderItem.geometry = null; + renderItem.material = null; + renderItem.groupOrder = null; + renderItem.renderOrder = null; + renderItem.z = null; + renderItem.group = null; + + } + + } + +} + +class RenderLists { + + constructor() { + + this.lists = new ChainMap(); + + } + + get( scene, camera ) { + + const lists = this.lists; + const keys = [ scene, camera ]; + + let list = lists.get( keys ); + + if ( list === undefined ) { + + list = new RenderList(); + lists.set( keys, list ); + + } + + return list; + + } + + dispose() { + + this.lists = new ChainMap(); + + } + +} + +let id = 0; + +class RenderContext { + + constructor() { + + this.id = id ++; + + this.color = true; + this.clearColor = true; + this.clearColorValue = { r: 0, g: 0, b: 0, a: 1 }; + + this.depth = true; + this.clearDepth = true; + this.clearDepthValue = 1; + + this.stencil = false; + this.clearStencil = true; + this.clearStencilValue = 1; + + this.viewport = false; + this.viewportValue = new Vector4(); + + this.scissor = false; + this.scissorValue = new Vector4(); + + this.textures = null; + this.depthTexture = null; + this.activeCubeFace = 0; + this.sampleCount = 1; + + this.width = 0; + this.height = 0; + + this.isRenderContext = true; + + } + + getCacheKey() { + + return getCacheKey( this ); + + } + +} + +function getCacheKey( renderContext ) { + + const { textures, activeCubeFace } = renderContext; + + const values = [ activeCubeFace ]; + + for ( const texture of textures ) { + + values.push( texture.id ); + + } + + return hashArray( values ); + +} + +class RenderContexts { + + constructor() { + + this.chainMaps = {}; + + } + + get( scene, camera, renderTarget = null ) { + + const chainKey = [ scene, camera ]; + + let attachmentState; + + if ( renderTarget === null ) { + + attachmentState = 'default'; + + } else { + + const format = renderTarget.texture.format; + const count = renderTarget.textures.length; + + attachmentState = `${ count }:${ format }:${ renderTarget.samples }:${ renderTarget.depthBuffer }:${ renderTarget.stencilBuffer }`; + + } + + const chainMap = this.getChainMap( attachmentState ); + + let renderState = chainMap.get( chainKey ); + + if ( renderState === undefined ) { + + renderState = new RenderContext(); + + chainMap.set( chainKey, renderState ); + + } + + if ( renderTarget !== null ) renderState.sampleCount = renderTarget.samples === 0 ? 1 : renderTarget.samples; + + return renderState; + + } + + getChainMap( attachmentState ) { + + return this.chainMaps[ attachmentState ] || ( this.chainMaps[ attachmentState ] = new ChainMap() ); + + } + + dispose() { + + this.chainMaps = {}; + + } + +} + +const _size = /*@__PURE__*/ new Vector3(); + +class Textures extends DataMap { + + constructor( renderer, backend, info ) { + + super(); + + this.renderer = renderer; + this.backend = backend; + this.info = info; + + } + + updateRenderTarget( renderTarget, activeMipmapLevel = 0 ) { + + const renderTargetData = this.get( renderTarget ); + + const sampleCount = renderTarget.samples === 0 ? 1 : renderTarget.samples; + const depthTextureMips = renderTargetData.depthTextureMips || ( renderTargetData.depthTextureMips = {} ); + + const textures = renderTarget.textures; + + const size = this.getSize( textures[ 0 ] ); + + const mipWidth = size.width >> activeMipmapLevel; + const mipHeight = size.height >> activeMipmapLevel; + + let depthTexture = renderTarget.depthTexture || depthTextureMips[ activeMipmapLevel ]; + let textureNeedsUpdate = false; + + if ( depthTexture === undefined ) { + + depthTexture = new DepthTexture(); + depthTexture.format = renderTarget.stencilBuffer ? DepthStencilFormat : DepthFormat; + depthTexture.type = renderTarget.stencilBuffer ? UnsignedInt248Type : UnsignedIntType; // FloatType + depthTexture.image.width = mipWidth; + depthTexture.image.height = mipHeight; + + depthTextureMips[ activeMipmapLevel ] = depthTexture; + + } + + if ( renderTargetData.width !== size.width || size.height !== renderTargetData.height ) { + + textureNeedsUpdate = true; + depthTexture.needsUpdate = true; + + depthTexture.image.width = mipWidth; + depthTexture.image.height = mipHeight; + + } + + renderTargetData.width = size.width; + renderTargetData.height = size.height; + renderTargetData.textures = textures; + renderTargetData.depthTexture = depthTexture; + renderTargetData.depth = renderTarget.depthBuffer; + renderTargetData.stencil = renderTarget.stencilBuffer; + renderTargetData.renderTarget = renderTarget; + + if ( renderTargetData.sampleCount !== sampleCount ) { + + textureNeedsUpdate = true; + depthTexture.needsUpdate = true; - } ).ElseIf( dist.lessThan( sqdist.y ), () => { + renderTargetData.sampleCount = sampleCount; - sqdist.z.assign( sqdist.y ); - sqdist.y.assign( dist ); + } - } ).ElseIf( dist.lessThan( sqdist.z ), () => { + // - sqdist.z.assign( dist ); + const options = { sampleCount }; - } ); + for ( let i = 0; i < textures.length; i ++ ) { - } ); + const texture = textures[ i ]; - } ); + if ( textureNeedsUpdate ) texture.needsUpdate = true; - If( metric.equal( int( 0 ) ), () => { + this.updateTexture( texture, options ); - sqdist.assign( sqrt( sqdist ) ); + } - } ); + this.updateTexture( depthTexture, options ); - return sqdist; + // dispose handler -} ).setLayout( { - name: 'mx_worley_noise_vec3_0', - type: 'vec3', - inputs: [ - { name: 'p', type: 'vec2' }, - { name: 'jitter', type: 'float' }, - { name: 'metric', type: 'int' } - ] -} ); + if ( renderTargetData.initialized !== true ) { -const mx_worley_noise_float_1 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + renderTargetData.initialized = true; - const metric = int( metric_immutable ).toVar(); - const jitter = float( jitter_immutable ).toVar(); - const p = vec3( p_immutable ).toVar(); - const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); - const localpos = vec3( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ), mx_floorfrac( p.z, Z ) ).toVar(); - const sqdist = float( 1e6 ).toVar(); + // dispose - Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + const onDispose = () => { - Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + renderTarget.removeEventListener( 'dispose', onDispose ); - Loop( { start: - 1, end: int( 1 ), name: 'z', condition: '<=' }, ( { z } ) => { + for ( let i = 0; i < textures.length; i ++ ) { - const dist = float( mx_worley_distance( localpos, x, y, z, X, Y, Z, jitter, metric ) ).toVar(); - sqdist.assign( min$1( sqdist, dist ) ); + this._destroyTexture( textures[ i ] ); - } ); + } - } ); + this._destroyTexture( depthTexture ); - } ); + this.delete( renderTarget ); - If( metric.equal( int( 0 ) ), () => { + }; - sqdist.assign( sqrt( sqdist ) ); + renderTarget.addEventListener( 'dispose', onDispose ); - } ); + } - return sqdist; + } -} ).setLayout( { - name: 'mx_worley_noise_float_1', - type: 'float', - inputs: [ - { name: 'p', type: 'vec3' }, - { name: 'jitter', type: 'float' }, - { name: 'metric', type: 'int' } - ] -} ); + updateTexture( texture, options = {} ) { -const mx_worley_noise_float$1 = /*@__PURE__*/ overloadingFn( [ mx_worley_noise_float_0, mx_worley_noise_float_1 ] ); + const textureData = this.get( texture ); + if ( textureData.initialized === true && textureData.version === texture.version ) return; -const mx_worley_noise_vec2_1 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + const isRenderTarget = texture.isRenderTargetTexture || texture.isDepthTexture || texture.isFramebufferTexture; + const backend = this.backend; - const metric = int( metric_immutable ).toVar(); - const jitter = float( jitter_immutable ).toVar(); - const p = vec3( p_immutable ).toVar(); - const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); - const localpos = vec3( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ), mx_floorfrac( p.z, Z ) ).toVar(); - const sqdist = vec2( 1e6, 1e6 ).toVar(); + if ( isRenderTarget && textureData.initialized === true ) { - Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + // it's an update - Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + backend.destroySampler( texture ); + backend.destroyTexture( texture ); - Loop( { start: - 1, end: int( 1 ), name: 'z', condition: '<=' }, ( { z } ) => { + } - const dist = float( mx_worley_distance( localpos, x, y, z, X, Y, Z, jitter, metric ) ).toVar(); + // - If( dist.lessThan( sqdist.x ), () => { + if ( texture.isFramebufferTexture ) { - sqdist.y.assign( sqdist.x ); - sqdist.x.assign( dist ); + const renderer = this.renderer; + const renderTarget = renderer.getRenderTarget(); - } ).ElseIf( dist.lessThan( sqdist.y ), () => { + if ( renderTarget ) { - sqdist.y.assign( dist ); + texture.type = renderTarget.texture.type; - } ); + } else { - } ); + texture.type = UnsignedByteType; - } ); + } - } ); + } - If( metric.equal( int( 0 ) ), () => { + // - sqdist.assign( sqrt( sqdist ) ); + const { width, height, depth } = this.getSize( texture ); - } ); + options.width = width; + options.height = height; + options.depth = depth; + options.needsMipmaps = this.needsMipmaps( texture ); + options.levels = options.needsMipmaps ? this.getMipLevels( texture, width, height ) : 1; - return sqdist; + // -} ).setLayout( { - name: 'mx_worley_noise_vec2_1', - type: 'vec2', - inputs: [ - { name: 'p', type: 'vec3' }, - { name: 'jitter', type: 'float' }, - { name: 'metric', type: 'int' } - ] -} ); + if ( isRenderTarget || texture.isStorageTexture === true ) { -const mx_worley_noise_vec2$1 = /*@__PURE__*/ overloadingFn( [ mx_worley_noise_vec2_0, mx_worley_noise_vec2_1 ] ); + backend.createSampler( texture ); + backend.createTexture( texture, options ); -const mx_worley_noise_vec3_1 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + textureData.generation = texture.version; - const metric = int( metric_immutable ).toVar(); - const jitter = float( jitter_immutable ).toVar(); - const p = vec3( p_immutable ).toVar(); - const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); - const localpos = vec3( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ), mx_floorfrac( p.z, Z ) ).toVar(); - const sqdist = vec3( 1e6, 1e6, 1e6 ).toVar(); + } else { - Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + const needsCreate = textureData.initialized !== true; - Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + if ( needsCreate ) backend.createSampler( texture ); - Loop( { start: - 1, end: int( 1 ), name: 'z', condition: '<=' }, ( { z } ) => { + if ( texture.version > 0 ) { - const dist = float( mx_worley_distance( localpos, x, y, z, X, Y, Z, jitter, metric ) ).toVar(); + const image = texture.image; - If( dist.lessThan( sqdist.x ), () => { + if ( image === undefined ) { - sqdist.z.assign( sqdist.y ); - sqdist.y.assign( sqdist.x ); - sqdist.x.assign( dist ); + console.warn( 'THREE.Renderer: Texture marked for update but image is undefined.' ); - } ).ElseIf( dist.lessThan( sqdist.y ), () => { + } else if ( image.complete === false ) { - sqdist.z.assign( sqdist.y ); - sqdist.y.assign( dist ); + console.warn( 'THREE.Renderer: Texture marked for update but image is incomplete.' ); - } ).ElseIf( dist.lessThan( sqdist.z ), () => { + } else { - sqdist.z.assign( dist ); + if ( texture.images ) { - } ); + const images = []; - } ); + for ( const image of texture.images ) { - } ); + images.push( image ); - } ); + } - If( metric.equal( int( 0 ) ), () => { + options.images = images; - sqdist.assign( sqrt( sqdist ) ); + } else { - } ); + options.image = image; - return sqdist; + } -} ).setLayout( { - name: 'mx_worley_noise_vec3_1', - type: 'vec3', - inputs: [ - { name: 'p', type: 'vec3' }, - { name: 'jitter', type: 'float' }, - { name: 'metric', type: 'int' } - ] -} ); + if ( textureData.isDefaultTexture === undefined || textureData.isDefaultTexture === true ) { -const mx_worley_noise_vec3$1 = /*@__PURE__*/ overloadingFn( [ mx_worley_noise_vec3_0, mx_worley_noise_vec3_1 ] ); + backend.createTexture( texture, options ); -// Three.js Transpiler -// https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/stdlib/genglsl/lib/mx_hsv.glsl + textureData.isDefaultTexture = false; + textureData.generation = texture.version; + } -const mx_hsvtorgb = /*@__PURE__*/ Fn( ( [ hsv ] ) => { + if ( texture.source.dataReady === true ) backend.updateTexture( texture, options ); - const s = hsv.y; - const v = hsv.z; + if ( options.needsMipmaps && texture.mipmaps.length === 0 ) backend.generateMipmaps( texture ); - const result = vec3().toVar(); + } - If( s.lessThan( 0.0001 ), () => { + } else { - result.assign( vec3( v, v, v ) ); + // async update - } ).Else( () => { + backend.createDefaultTexture( texture ); - let h = hsv.x; - h = h.sub( floor( h ) ).mul( 6.0 ).toVar(); // TODO: check what .toVar() is needed in node system cache - const hi = int( trunc( h ) ); - const f = h.sub( float( hi ) ); - const p = v.mul( s.oneMinus() ); - const q = v.mul( s.mul( f ).oneMinus() ); - const t = v.mul( s.mul( f.oneMinus() ).oneMinus() ); + textureData.isDefaultTexture = true; + textureData.generation = texture.version; - If( hi.equal( int( 0 ) ), () => { + } - result.assign( vec3( v, t, p ) ); + } - } ).ElseIf( hi.equal( int( 1 ) ), () => { + // dispose handler - result.assign( vec3( q, v, p ) ); + if ( textureData.initialized !== true ) { - } ).ElseIf( hi.equal( int( 2 ) ), () => { + textureData.initialized = true; + textureData.generation = texture.version; - result.assign( vec3( p, v, t ) ); + // - } ).ElseIf( hi.equal( int( 3 ) ), () => { + this.info.memory.textures ++; - result.assign( vec3( p, q, v ) ); + // dispose - } ).ElseIf( hi.equal( int( 4 ) ), () => { + const onDispose = () => { - result.assign( vec3( t, p, v ) ); + texture.removeEventListener( 'dispose', onDispose ); - } ).Else( () => { + this._destroyTexture( texture ); - result.assign( vec3( v, p, q ) ); + this.info.memory.textures --; - } ); + }; - } ); + texture.addEventListener( 'dispose', onDispose ); - return result; + } -} ).setLayout( { - name: 'mx_hsvtorgb', - type: 'vec3', - inputs: [ - { name: 'hsv', type: 'vec3' } - ] -} ); + // -const mx_rgbtohsv = /*@__PURE__*/ Fn( ( [ c_immutable ] ) => { + textureData.version = texture.version; - const c = vec3( c_immutable ).toVar(); - const r = float( c.x ).toVar(); - const g = float( c.y ).toVar(); - const b = float( c.z ).toVar(); - const mincomp = float( min$1( r, min$1( g, b ) ) ).toVar(); - const maxcomp = float( max$1( r, max$1( g, b ) ) ).toVar(); - const delta = float( maxcomp.sub( mincomp ) ).toVar(); - const h = float().toVar(), s = float().toVar(), v = float().toVar(); - v.assign( maxcomp ); + } - If( maxcomp.greaterThan( 0.0 ), () => { + getSize( texture, target = _size ) { - s.assign( delta.div( maxcomp ) ); + let image = texture.images ? texture.images[ 0 ] : texture.image; - } ).Else( () => { + if ( image ) { - s.assign( 0.0 ); + if ( image.image !== undefined ) image = image.image; - } ); + target.width = image.width; + target.height = image.height; + target.depth = texture.isCubeTexture ? 6 : ( image.depth || 1 ); - If( s.lessThanEqual( 0.0 ), () => { + } else { - h.assign( 0.0 ); + target.width = target.height = target.depth = 1; - } ).Else( () => { + } - If( r.greaterThanEqual( maxcomp ), () => { + return target; - h.assign( g.sub( b ).div( delta ) ); + } - } ).ElseIf( g.greaterThanEqual( maxcomp ), () => { + getMipLevels( texture, width, height ) { - h.assign( add( 2.0, b.sub( r ).div( delta ) ) ); + let mipLevelCount; - } ).Else( () => { + if ( texture.isCompressedTexture ) { - h.assign( add( 4.0, r.sub( g ).div( delta ) ) ); + mipLevelCount = texture.mipmaps.length; - } ); + } else { - h.mulAssign( 1.0 / 6.0 ); + mipLevelCount = Math.floor( Math.log2( Math.max( width, height ) ) ) + 1; - If( h.lessThan( 0.0 ), () => { + } - h.addAssign( 1.0 ); + return mipLevelCount; - } ); + } - } ); + needsMipmaps( texture ) { - return vec3( h, s, v ); + if ( this.isEnvironmentTexture( texture ) ) return true; -} ).setLayout( { - name: 'mx_rgbtohsv', - type: 'vec3', - inputs: [ - { name: 'c', type: 'vec3' } - ] -} ); + return ( texture.isCompressedTexture === true ) || ( ( texture.minFilter !== NearestFilter ) && ( texture.minFilter !== LinearFilter ) ); -// Three.js Transpiler -// https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/stdlib/genglsl/lib/mx_transform_color.glsl + } + isEnvironmentTexture( texture ) { -const mx_srgb_texture_to_lin_rec709 = /*@__PURE__*/ Fn( ( [ color_immutable ] ) => { + const mapping = texture.mapping; - const color = vec3( color_immutable ).toVar(); - const isAbove = bvec3( greaterThan( color, vec3( 0.04045 ) ) ).toVar(); - const linSeg = vec3( color.div( 12.92 ) ).toVar(); - const powSeg = vec3( pow( max$1( color.add( vec3( 0.055 ) ), vec3( 0.0 ) ).div( 1.055 ), vec3( 2.4 ) ) ).toVar(); + return ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) || ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping ); - return mix( linSeg, powSeg, isAbove ); + } -} ).setLayout( { - name: 'mx_srgb_texture_to_lin_rec709', - type: 'vec3', - inputs: [ - { name: 'color', type: 'vec3' } - ] -} ); + _destroyTexture( texture ) { -const mx_aastep = ( threshold, value ) => { + this.backend.destroySampler( texture ); + this.backend.destroyTexture( texture ); - threshold = float( threshold ); - value = float( value ); + this.delete( texture ); - const afwidth = vec2( value.dFdx(), value.dFdy() ).length().mul( 0.70710678118654757 ); + } - return smoothstep( threshold.sub( afwidth ), threshold.add( afwidth ), value ); +} -}; +class Color4 extends Color { -const _ramp = ( a, b, uv, p ) => mix( a, b, uv[ p ].clamp() ); -const mx_ramplr = ( valuel, valuer, texcoord = uv() ) => _ramp( valuel, valuer, texcoord, 'x' ); -const mx_ramptb = ( valuet, valueb, texcoord = uv() ) => _ramp( valuet, valueb, texcoord, 'y' ); + constructor( r, g, b, a = 1 ) { -const _split = ( a, b, center, uv, p ) => mix( a, b, mx_aastep( center, uv[ p ] ) ); -const mx_splitlr = ( valuel, valuer, center, texcoord = uv() ) => _split( valuel, valuer, center, texcoord, 'x' ); -const mx_splittb = ( valuet, valueb, center, texcoord = uv() ) => _split( valuet, valueb, center, texcoord, 'y' ); + super( r, g, b ); -const mx_transform_uv = ( uv_scale = 1, uv_offset = 0, uv_geo = uv() ) => uv_geo.mul( uv_scale ).add( uv_offset ); + this.a = a; -const mx_safepower = ( in1, in2 = 1 ) => { + } - in1 = float( in1 ); + set( r, g, b, a = 1 ) { - return in1.abs().pow( in2 ).mul( in1.sign() ); + this.a = a; -}; + return super.set( r, g, b ); -const mx_contrast = ( input, amount = 1, pivot = .5 ) => float( input ).sub( pivot ).mul( amount ).add( pivot ); + } -const mx_noise_float = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_float( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot ); -//export const mx_noise_vec2 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_vec3( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot ); -const mx_noise_vec3 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_vec3( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot ); -const mx_noise_vec4 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => { + copy( color ) { - texcoord = texcoord.convert( 'vec2|vec3' ); // overloading type + if ( color.a !== undefined ) this.a = color.a; - const noise_vec4 = vec4( mx_perlin_noise_vec3( texcoord ), mx_perlin_noise_float( texcoord.add( vec2( 19, 73 ) ) ) ); + return super.copy( color ); - return noise_vec4.mul( amplitude ).add( pivot ); + } -}; + clone() { -const mx_worley_noise_float = ( texcoord = uv(), jitter = 1 ) => mx_worley_noise_float$1( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) ); -const mx_worley_noise_vec2 = ( texcoord = uv(), jitter = 1 ) => mx_worley_noise_vec2$1( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) ); -const mx_worley_noise_vec3 = ( texcoord = uv(), jitter = 1 ) => mx_worley_noise_vec3$1( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) ); + return new this.constructor( this.r, this.g, this.b, this.a ); -const mx_cell_noise_float = ( texcoord = uv() ) => mx_cell_noise_float$1( texcoord.convert( 'vec2|vec3' ) ); + } -const mx_fractal_noise_float = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mx_fractal_noise_float$1( position, int( octaves ), lacunarity, diminish ).mul( amplitude ); -const mx_fractal_noise_vec2 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mx_fractal_noise_vec2$1( position, int( octaves ), lacunarity, diminish ).mul( amplitude ); -const mx_fractal_noise_vec3 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mx_fractal_noise_vec3$1( position, int( octaves ), lacunarity, diminish ).mul( amplitude ); -const mx_fractal_noise_vec4 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mx_fractal_noise_vec4$1( position, int( octaves ), lacunarity, diminish ).mul( amplitude ); +} const _clearColor = /*@__PURE__*/ new Color4(); @@ -63266,7 +65288,7 @@ class Background extends DataMap { class NodeBuilderState { - constructor( vertexShader, fragmentShader, computeShader, nodeAttributes, bindings, updateNodes, updateBeforeNodes, updateAfterNodes, instanceBindGroups = true, transforms = [] ) { + constructor( vertexShader, fragmentShader, computeShader, nodeAttributes, bindings, updateNodes, updateBeforeNodes, updateAfterNodes, monitor, transforms = [] ) { this.vertexShader = vertexShader; this.fragmentShader = fragmentShader; @@ -63280,7 +65302,7 @@ class NodeBuilderState { this.updateBeforeNodes = updateBeforeNodes; this.updateAfterNodes = updateAfterNodes; - this.instanceBindGroups = instanceBindGroups; + this.monitor = monitor; this.usedTimes = 0; @@ -63292,7 +65314,7 @@ class NodeBuilderState { for ( const instanceGroup of this.bindings ) { - const shared = this.instanceBindGroups && instanceGroup.bindings[ 0 ].groupNode.shared; + const shared = instanceGroup.bindings[ 0 ].groupNode.shared; if ( shared !== true ) { @@ -63502,7 +65524,7 @@ class Nodes extends DataMap { nodeBuilder.updateNodes, nodeBuilder.updateBeforeNodes, nodeBuilder.updateAfterNodes, - nodeBuilder.instanceBindGroups, + nodeBuilder.monitor, nodeBuilder.transforms ); @@ -63538,15 +65560,17 @@ class Nodes extends DataMap { const environmentNode = this.getEnvironmentNode( scene ); const fogNode = this.getFogNode( scene ); - const cacheKey = []; + const values = []; + + if ( lightsNode ) values.push( lightsNode.getCacheKey( true ) ); + if ( environmentNode ) values.push( environmentNode.getCacheKey() ); + if ( fogNode ) values.push( fogNode.getCacheKey() ); - if ( lightsNode ) cacheKey.push( lightsNode.getCacheKey( true ) ); - if ( environmentNode ) cacheKey.push( environmentNode.getCacheKey() ); - if ( fogNode ) cacheKey.push( fogNode.getCacheKey() ); + values.push( this.renderer.shadowMap.enabled ? 1 : 0 ); cacheKeyData = { callId, - cacheKey: cacheKey.join( ',' ) + cacheKey: hashArray( values ) }; this.callHashCache.set( chain, cacheKeyData ); @@ -63584,9 +65608,9 @@ class Nodes extends DataMap { let backgroundNode = null; - if ( background.isCubeTexture === true || ( background.mapping === EquirectangularReflectionMapping || background.mapping === EquirectangularRefractionMapping ) ) { + if ( background.isCubeTexture === true || ( background.mapping === EquirectangularReflectionMapping || background.mapping === EquirectangularRefractionMapping || background.mapping === CubeUVReflectionMapping ) ) { - if ( scene.backgroundBlurriness > 0 ) { + if ( scene.backgroundBlurriness > 0 || background.mapping === CubeUVReflectionMapping ) { backgroundNode = pmremTexture( background, normalWorld ); @@ -63610,7 +65634,7 @@ class Nodes extends DataMap { } else if ( background.isTexture === true ) { - backgroundNode = texture( background, viewportUV.flipY() ).setUpdateMatrix( true ); + backgroundNode = texture( background, screenUV.flipY() ).setUpdateMatrix( true ); } else if ( background.isColor !== true ) { @@ -63646,11 +65670,18 @@ class Nodes extends DataMap { if ( fog.isFogExp2 ) { - fogNode = densityFog( reference( 'color', 'color', fog ), reference( 'density', 'float', fog ) ); + const color = reference( 'color', 'color', fog ).setGroup( renderGroup ); + const density = reference( 'density', 'float', fog ).setGroup( renderGroup ); + + fogNode = densityFog( color, density ); } else if ( fog.isFog ) { - fogNode = rangeFog( reference( 'color', 'color', fog ), reference( 'near', 'float', fog ), reference( 'far', 'float', fog ) ); + const color = reference( 'color', 'color', fog ).setGroup( renderGroup ); + const near = reference( 'near', 'float', fog ).setGroup( renderGroup ); + const far = reference( 'far', 'float', fog ).setGroup( renderGroup ); + + fogNode = rangeFog( color, near, far ); } else { @@ -63751,7 +65782,7 @@ class Nodes extends DataMap { const renderer = this.renderer; const cacheKey = this.getOutputCacheKey(); - const output = texture( outputTexture, viewportUV ).renderOutput( renderer.toneMapping, renderer.currentColorSpace ); + const output = texture( outputTexture, screenUV ).renderOutput( renderer.toneMapping, renderer.currentColorSpace ); outputNodeMap.set( outputTexture, cacheKey ); @@ -63813,6 +65844,15 @@ class Nodes extends DataMap { } + needsRefresh( renderObject ) { + + const nodeFrame = this.getNodeFrameForRender( renderObject ); + const monitor = renderObject.getMonitor(); + + return monitor.needsRefresh( renderObject, nodeFrame ); + + } + dispose() { super.dispose(); @@ -63997,7 +66037,7 @@ const _drawingBufferSize = /*@__PURE__*/ new Vector2(); const _screen = /*@__PURE__*/ new Vector4(); const _frustum = /*@__PURE__*/ new Frustum(); const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); -const _vector3 = /*@__PURE__*/ new Vector3(); +const _vector4 = /*@__PURE__*/ new Vector4(); class Renderer { @@ -64010,6 +66050,8 @@ class Renderer { const { logarithmicDepthBuffer = false, alpha = true, + depth = true, + stencil = false, antialias = false, samples = 0, getFallback = null @@ -64038,15 +66080,17 @@ class Renderer { this.sortObjects = true; - this.depth = true; - this.stencil = false; + this.depth = depth; + this.stencil = stencil; this.clippingPlanes = []; this.info = new Info(); this.nodes = { - library: new NodeLibrary() + library: new NodeLibrary(), + modelViewMatrix: null, + modelNormalViewMatrix: null }; // internals @@ -64373,20 +66417,21 @@ class Renderer { _renderBundle( bundle, sceneRef, lightsNode ) { - const { object, camera, renderList } = bundle; + const { bundleGroup, camera, renderList } = bundle; const renderContext = this._currentRenderContext; // - const renderBundle = this._bundles.get( object, camera ); + const renderBundle = this._bundles.get( bundleGroup, camera ); const renderBundleData = this.backend.get( renderBundle ); if ( renderBundleData.renderContexts === undefined ) renderBundleData.renderContexts = new Set(); // - const renderBundleNeedsUpdate = renderBundleData.renderContexts.has( renderContext ) === false || object.needsUpdate === true; + const needsUpdate = bundleGroup.version !== renderBundleData.version; + const renderBundleNeedsUpdate = renderBundleData.renderContexts.has( renderContext ) === false || needsUpdate; renderBundleData.renderContexts.add( renderContext ); @@ -64394,7 +66439,7 @@ class Renderer { this.backend.beginBundle( renderContext ); - if ( renderBundleData.renderObjects === undefined || object.needsUpdate === true ) { + if ( renderBundleData.renderObjects === undefined || needsUpdate ) { renderBundleData.renderObjects = []; @@ -64412,27 +66457,26 @@ class Renderer { this.backend.finishBundle( renderContext, renderBundle ); - object.needsUpdate = false; + renderBundleData.version = bundleGroup.version; } else { - const renderObjects = renderBundleData.renderObjects; + const { renderObjects } = renderBundleData; for ( let i = 0, l = renderObjects.length; i < l; i ++ ) { const renderObject = renderObjects[ i ]; - this._nodes.updateBefore( renderObject ); + if ( this._nodes.needsRefresh( renderObject ) ) { - // + this._nodes.updateBefore( renderObject ); - renderObject.object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, renderObject.object.matrixWorld ); - renderObject.object.normalMatrix.getNormalMatrix( renderObject.object.modelViewMatrix ); + this._nodes.updateForRender( renderObject ); + this._bindings.updateForRender( renderObject ); - this._nodes.updateForRender( renderObject ); - this._bindings.updateForRender( renderObject ); + this._nodes.updateAfter( renderObject ); - this._nodes.updateAfter( renderObject ); + } } @@ -64678,10 +66722,12 @@ class Renderer { // process render lists - const opaqueObjects = renderList.opaque; - const transparentObjects = renderList.transparent; - const bundles = renderList.bundles; - const lightsNode = renderList.lightsNode; + const { + bundles, + lightsNode, + transparent: transparentObjects, + opaque: opaqueObjects + } = renderList; if ( bundles.length > 0 ) this._renderBundles( bundles, sceneRef, lightsNode ); if ( this.opaque === true && opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode ); @@ -65208,13 +67254,15 @@ class Renderer { } - copyFramebufferToTexture( framebufferTexture ) { + copyFramebufferToTexture( framebufferTexture, rectangle = null ) { const renderContext = this._currentRenderContext; this._textures.updateTexture( framebufferTexture ); - this.backend.copyFramebufferToTexture( framebufferTexture, renderContext ); + rectangle = rectangle === null ? _vector4.set( 0, 0, framebufferTexture.image.width, framebufferTexture.image.height ) : rectangle; + + this.backend.copyFramebufferToTexture( framebufferTexture, renderContext, rectangle ); } @@ -65228,9 +67276,9 @@ class Renderer { } - readRenderTargetPixelsAsync( renderTarget, x, y, width, height, index = 0 ) { + readRenderTargetPixelsAsync( renderTarget, x, y, width, height, index = 0, faceIndex = 0 ) { - return this.backend.copyTextureToBuffer( renderTarget.textures[ index ], x, y, width, height ); + return this.backend.copyTextureToBuffer( renderTarget.textures[ index ], x, y, width, height, faceIndex ); } @@ -65260,16 +67308,15 @@ class Renderer { if ( this.sortObjects === true ) { - _vector3.setFromMatrixPosition( object.matrixWorld ).applyMatrix4( _projScreenMatrix ); + _vector4.setFromMatrixPosition( object.matrixWorld ).applyMatrix4( _projScreenMatrix ); } - const geometry = object.geometry; - const material = object.material; + const { geometry, material } = object; if ( material.visible ) { - renderList.push( object, geometry, material, groupOrder, _vector3.z, null ); + renderList.push( object, geometry, material, groupOrder, _vector4.z, null ); } @@ -65283,14 +67330,13 @@ class Renderer { if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - const geometry = object.geometry; - const material = object.material; + const { geometry, material } = object; if ( this.sortObjects === true ) { if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - _vector3 + _vector4 .copy( geometry.boundingSphere.center ) .applyMatrix4( object.matrixWorld ) .applyMatrix4( _projScreenMatrix ); @@ -65308,7 +67354,7 @@ class Renderer { if ( groupMaterial && groupMaterial.visible ) { - renderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); + renderList.push( object, geometry, groupMaterial, groupOrder, _vector4.z, group ); } @@ -65316,7 +67362,7 @@ class Renderer { } else if ( material.visible ) { - renderList.push( object, geometry, material, groupOrder, _vector3.z, null ); + renderList.push( object, geometry, material, groupOrder, _vector4.z, null ); } @@ -65326,7 +67372,7 @@ class Renderer { } - if ( object.static === true && this.backend.beginBundle !== undefined ) { + if ( object.isBundleGroup === true && this.backend.beginBundle !== undefined ) { const baseRenderList = renderList; @@ -65336,7 +67382,7 @@ class Renderer { renderList.begin(); baseRenderList.pushBundle( { - object, + bundleGroup: object, camera, renderList, } ); @@ -65536,22 +67582,24 @@ class Renderer { _renderObjectDirect( object, material, scene, camera, lightsNode, group, passId ) { const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, passId ); - renderObject.drawRange = group || object.geometry.drawRange; + renderObject.drawRange = object.geometry.drawRange; + renderObject.group = group; // - this._nodes.updateBefore( renderObject ); + const needsRefresh = this._nodes.needsRefresh( renderObject ); - // + if ( needsRefresh ) { - object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); + this._nodes.updateBefore( renderObject ); - // + this._geometries.updateForRender( renderObject ); + + this._nodes.updateForRender( renderObject ); + this._bindings.updateForRender( renderObject ); + + } - this._nodes.updateForRender( renderObject ); - this._geometries.updateForRender( renderObject ); - this._bindings.updateForRender( renderObject ); this._pipelines.updateForRender( renderObject ); // @@ -65562,11 +67610,13 @@ class Renderer { renderBundleData.renderObjects.push( renderObject ); + renderObject.bundle = this._currentRenderBundle.scene; + } this.backend.draw( renderObject, this.info ); - this._nodes.updateAfter( renderObject ); + if ( needsRefresh ) this._nodes.updateAfter( renderObject ); } @@ -65578,10 +67628,9 @@ class Renderer { this._nodes.updateBefore( renderObject ); - // + this._geometries.updateForRender( renderObject ); this._nodes.updateForRender( renderObject ); - this._geometries.updateForRender( renderObject ); this._bindings.updateForRender( renderObject ); this._pipelines.getForRender( renderObject, this._compilationPromises ); @@ -65604,85 +67653,6 @@ class Renderer { } -class IESSpotLight extends SpotLight { - - constructor( color, intensity, distance, angle, penumbra, decay ) { - - super( color, intensity, distance, angle, penumbra, decay ); - - this.iesMap = null; - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.iesMap = source.iesMap; - - return this; - - } - -} - -class StandardNodeLibrary extends NodeLibrary { - - constructor() { - - super(); - - this.addMaterial( MeshPhongNodeMaterial, MeshPhongMaterial ); - this.addMaterial( MeshStandardNodeMaterial, MeshStandardMaterial ); - this.addMaterial( MeshPhysicalNodeMaterial, MeshPhysicalMaterial ); - this.addMaterial( MeshToonNodeMaterial, MeshToonMaterial ); - this.addMaterial( MeshBasicNodeMaterial, MeshBasicMaterial ); - this.addMaterial( MeshLambertNodeMaterial, MeshLambertMaterial ); - this.addMaterial( MeshNormalNodeMaterial, MeshNormalMaterial ); - this.addMaterial( MeshMatcapNodeMaterial, MeshMatcapMaterial ); - this.addMaterial( LineBasicNodeMaterial, LineBasicMaterial ); - this.addMaterial( LineDashedNodeMaterial, LineDashedMaterial ); - this.addMaterial( PointsNodeMaterial, PointsMaterial ); - this.addMaterial( SpriteNodeMaterial, SpriteMaterial ); - this.addMaterial( ShadowNodeMaterial, ShadowMaterial ); - - this.addLight( PointLightNode, PointLight ); - this.addLight( DirectionalLightNode, DirectionalLight ); - this.addLight( RectAreaLightNode, RectAreaLight ); - this.addLight( SpotLightNode, SpotLight ); - this.addLight( AmbientLightNode, AmbientLight ); - this.addLight( HemisphereLightNode, HemisphereLight ); - this.addLight( LightProbeNode, LightProbe ); - this.addLight( IESSpotLightNode, IESSpotLight ); - - this.addToneMapping( LinearToneMapping, LinearToneMapping$1 ); - this.addToneMapping( ReinhardToneMapping, ReinhardToneMapping$1 ); - this.addToneMapping( CineonToneMapping, CineonToneMapping$1 ); - this.addToneMapping( ACESFilmicToneMapping, ACESFilmicToneMapping$1 ); - this.addToneMapping( AgXToneMapping, AgXToneMapping$1 ); - this.addToneMapping( NeutralToneMapping, NeutralToneMapping$1 ); - - this.addColorSpace( LinearTosRGB, getColorSpaceMethod( LinearSRGBColorSpace, SRGBColorSpace ) ); - this.addColorSpace( sRGBToLinear, getColorSpaceMethod( SRGBColorSpace, LinearSRGBColorSpace ) ); - - } - -} - -class StandardRenderer extends Renderer { - - constructor( backend, parameters = {} ) { - - super( backend, parameters ); - - this.isStandardRenderer = true; - - this.nodes.library = new StandardNodeLibrary(); - - } - -} - class Binding { constructor( name = '' ) { @@ -66314,8 +68284,6 @@ class GLSLNodeBuilder extends NodeBuilder { this.transforms = []; this.extensions = {}; - this.instanceBindGroups = false; - this.useComparisonMethod = true; } @@ -66492,7 +68460,7 @@ ${ flowData.code } this.getVarFromNode( node, propertySizeName, 'uint' ); - this.addLineFlowCode( `${ propertySizeName } = uint( textureSize( ${ textureName }, 0 ).x )` ); + this.addLineFlowCode( `${ propertySizeName } = uint( textureSize( ${ textureName }, 0 ).x )`, storageArrayElementNode ); bufferNodeData.propertySizeName = propertySizeName; @@ -66522,7 +68490,7 @@ ${ flowData.code } } - this.addLineFlowCode( `${ propertyName } = ${prefix}(${ snippet })${channel}` ); + this.addLineFlowCode( `${ propertyName } = ${prefix}(${ snippet })${channel}`, storageArrayElementNode ); elementNodeData.propertyName = propertyName; @@ -67112,6 +69080,8 @@ void main() { const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; + this.sortBindingGroups(); + for ( const shaderStage in shadersData ) { let flow = '// code\n\n'; @@ -67684,10 +69654,16 @@ class WebGLAttributeUtils { const dstBuffer = new attribute.array.constructor( array.length ); + // Ensure the buffer is bound before reading + gl.bindBuffer( gl.COPY_WRITE_BUFFER, writeBuffer ); + gl.getBufferSubData( gl.COPY_WRITE_BUFFER, 0, dstBuffer ); gl.deleteBuffer( writeBuffer ); + gl.bindBuffer( gl.COPY_READ_BUFFER, null ); + gl.bindBuffer( gl.COPY_WRITE_BUFFER, null ); + return dstBuffer.buffer; } @@ -68211,7 +70187,7 @@ class WebGLState { this.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - material.alphaToCoverage === true + material.alphaToCoverage === true && this.backend.renderer.samples > 1 ? this.enable( gl.SAMPLE_ALPHA_TO_COVERAGE ) : this.disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); @@ -68348,7 +70324,6 @@ class WebGLState { } - } @@ -68410,10 +70385,8 @@ class WebGLState { boundTexture.type = webglType; boundTexture.texture = webglTexture; - } - } bindBufferBase( target, index, buffer ) { @@ -69412,20 +71385,22 @@ class WebGLTextureUtils { } - copyFramebufferToTexture( texture, renderContext ) { + copyFramebufferToTexture( texture, renderContext, rectangle ) { const { gl } = this; const { state } = this.backend; const { textureGPU } = this.backend.get( texture ); - const width = texture.image.width; - const height = texture.image.height; + const { x, y, z: width, w: height } = rectangle; const requireDrawFrameBuffer = texture.isDepthTexture === true || ( renderContext.renderTarget && renderContext.renderTarget.samples > 0 ); + const srcHeight = renderContext.renderTarget ? renderContext.renderTarget.height : this.backend.gerDrawingBufferSize().y; + if ( requireDrawFrameBuffer ) { + const partial = ( x !== 0 || y !== 0 ); let mask; let attachment; @@ -69447,19 +71422,45 @@ class WebGLTextureUtils { } - const fb = gl.createFramebuffer(); - state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb ); + if ( partial ) { + + const renderTargetContextData = this.backend.get( renderContext.renderTarget ); + + const fb = renderTargetContextData.framebuffers[ renderContext.getCacheKey() ]; + const msaaFrameBuffer = renderTargetContextData.msaaFrameBuffer; + + state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb ); + state.bindFramebuffer( gl.READ_FRAMEBUFFER, msaaFrameBuffer ); + + const flippedY = srcHeight - y - height; - gl.framebufferTexture2D( gl.DRAW_FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureGPU, 0 ); + gl.blitFramebuffer( x, flippedY, x + width, flippedY + height, x, flippedY, x + width, flippedY + height, mask, gl.NEAREST ); - gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, gl.NEAREST ); + state.bindFramebuffer( gl.READ_FRAMEBUFFER, fb ); - gl.deleteFramebuffer( fb ); + state.bindTexture( gl.TEXTURE_2D, textureGPU ); + + gl.copyTexSubImage2D( gl.TEXTURE_2D, 0, 0, 0, x, flippedY, width, height ); + + state.unbindTexture(); + + } else { + + const fb = gl.createFramebuffer(); + + state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb ); + + gl.framebufferTexture2D( gl.DRAW_FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureGPU, 0 ); + gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, gl.NEAREST ); + + gl.deleteFramebuffer( fb ); + + } } else { state.bindTexture( gl.TEXTURE_2D, textureGPU ); - gl.copyTexSubImage2D( gl.TEXTURE_2D, 0, 0, 0, 0, 0, width, height ); + gl.copyTexSubImage2D( gl.TEXTURE_2D, 0, 0, 0, x, srcHeight - height - y, width, height ); state.unbindTexture(); @@ -69526,7 +71527,7 @@ class WebGLTextureUtils { } - async copyTextureToBuffer( texture, x, y, width, height ) { + async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { const { backend, gl } = this; @@ -69535,10 +71536,13 @@ class WebGLTextureUtils { const fb = gl.createFramebuffer(); gl.bindFramebuffer( gl.READ_FRAMEBUFFER, fb ); - gl.framebufferTexture2D( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textureGPU, 0 ); + + const target = texture.isCubeTexture ? gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex : gl.TEXTURE_2D; + + gl.framebufferTexture2D( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, target, textureGPU, 0 ); const typedArrayType = this._getTypedArrayType( glType ); - const bytesPerTexel = this._getBytesPerTexel( glFormat ); + const bytesPerTexel = this._getBytesPerTexel( glType, glFormat ); const elementCount = width * height; const byteLength = elementCount * bytesPerTexel; @@ -69576,19 +71580,33 @@ class WebGLTextureUtils { if ( glType === gl.UNSIGNED_SHORT ) return Uint16Array; if ( glType === gl.UNSIGNED_INT ) return Uint32Array; + if ( glType === gl.HALF_FLOAT ) return Uint16Array; if ( glType === gl.FLOAT ) return Float32Array; throw new Error( `Unsupported WebGL type: ${glType}` ); } - _getBytesPerTexel( glFormat ) { + _getBytesPerTexel( glType, glFormat ) { const { gl } = this; - if ( glFormat === gl.RGBA ) return 4; - if ( glFormat === gl.RGB ) return 3; - if ( glFormat === gl.ALPHA ) return 1; + let bytesPerComponent = 0; + + if ( glType === gl.UNSIGNED_BYTE ) bytesPerComponent = 1; + + if ( glType === gl.UNSIGNED_SHORT_4_4_4_4 || + glType === gl.UNSIGNED_SHORT_5_5_5_1 || + glType === gl.UNSIGNED_SHORT_5_6_5 || + glType === gl.UNSIGNED_SHORT || + glType === gl.HALF_FLOAT ) bytesPerComponent = 2; + + if ( glType === gl.UNSIGNED_INT || + glType === gl.FLOAT ) bytesPerComponent = 4; + + if ( glFormat === gl.RGBA ) return bytesPerComponent * 4; + if ( glFormat === gl.RGB ) return bytesPerComponent * 3; + if ( glFormat === gl.ALPHA ) return bytesPerComponent; } @@ -69871,6 +71889,7 @@ class WebGLBackend extends Backend { this.disjoint = this.extensions.get( 'EXT_disjoint_timer_query_webgl2' ); this.parallel = this.extensions.get( 'KHR_parallel_shader_compile' ); + this._currentContext = null; } @@ -70406,6 +72425,10 @@ class WebGLBackend extends Backend { const contextData = this.get( context ); + const drawParms = renderObject.getDrawParameters(); + + if ( drawParms === null ) return; + // this._bindUniforms( renderObject.getBindings() ); @@ -70444,10 +72467,6 @@ class WebGLBackend extends Backend { const index = renderObject.getIndex(); - const geometry = renderObject.geometry; - const drawRange = renderObject.drawRange; - const firstVertex = drawRange.start; - // const lastObject = contextData.lastOcclusionObject; @@ -70478,7 +72497,6 @@ class WebGLBackend extends Backend { } // - const renderer = this.bufferRenderer; if ( object.isPoints ) renderer.mode = gl.POINTS; @@ -70502,33 +72520,26 @@ class WebGLBackend extends Backend { // - - let count; + const { vertexCount, instanceCount } = drawParms; + let { firstVertex } = drawParms; renderer.object = object; if ( index !== null ) { + firstVertex *= index.array.BYTES_PER_ELEMENT; + const indexData = this.get( index ); - const indexCount = ( drawRange.count !== Infinity ) ? drawRange.count : index.count; renderer.index = index.count; renderer.type = indexData.type; - count = indexCount; - } else { renderer.index = 0; - const vertexCount = ( drawRange.count !== Infinity ) ? drawRange.count : geometry.attributes.position.count; - - count = vertexCount; - } - const instanceCount = this.getInstanceCount( renderObject ); - if ( object.isBatchedMesh ) { if ( object._multiDrawInstances !== null ) { @@ -70547,11 +72558,11 @@ class WebGLBackend extends Backend { } else if ( instanceCount > 1 ) { - renderer.renderInstances( firstVertex, count, instanceCount ); + renderer.renderInstances( firstVertex, vertexCount, instanceCount ); } else { - renderer.render( firstVertex, count ); + renderer.render( firstVertex, vertexCount ); } // @@ -70605,9 +72616,9 @@ class WebGLBackend extends Backend { } - copyTextureToBuffer( texture, x, y, width, height ) { + copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { - return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height ); + return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height, faceIndex ); } @@ -70923,40 +72934,52 @@ class WebGLBackend extends Backend { updateBindings( bindGroup, bindings ) { - const { state, gl } = this; + if ( ! bindGroup ) return; - let groupIndex = 0; - let textureIndex = 0; + const { gl } = this; - for ( const bindGroup of bindings ) { + const bindingsData = this.get( bindings ); + const bindGroupData = this.get( bindGroup ); - for ( const binding of bindGroup.bindings ) { + if ( bindingsData.textureIndex === undefined ) bindingsData.textureIndex = 0; - if ( binding.isUniformsGroup || binding.isUniformBuffer ) { + if ( bindGroupData.textureIndex === undefined ) { - const bufferGPU = gl.createBuffer(); - const data = binding.buffer; + bindGroupData.textureIndex = bindingsData.textureIndex; - gl.bindBuffer( gl.UNIFORM_BUFFER, bufferGPU ); - gl.bufferData( gl.UNIFORM_BUFFER, data, gl.DYNAMIC_DRAW ); - state.bindBufferBase( gl.UNIFORM_BUFFER, groupIndex, bufferGPU ); + } else { - this.set( binding, { - index: groupIndex ++, - bufferGPU - } ); + // reset textureIndex to match previous mappimgs when rebuilt + bindingsData.textureIndex = bindGroupData.textureIndex; - } else if ( binding.isSampledTexture ) { + } - const { textureGPU, glTextureType } = this.get( binding.texture ); + let i = 0; - this.set( binding, { - index: textureIndex ++, - textureGPU, - glTextureType - } ); + for ( const binding of bindGroup.bindings ) { - } + if ( binding.isUniformsGroup || binding.isUniformBuffer ) { + + const data = binding.buffer; + const bufferGPU = gl.createBuffer(); + + gl.bindBuffer( gl.UNIFORM_BUFFER, bufferGPU ); + gl.bufferData( gl.UNIFORM_BUFFER, data, gl.DYNAMIC_DRAW ); + + this.set( binding, { + index: bindGroup.index * 2 + i ++, + bufferGPU + } ); + + } else if ( binding.isSampledTexture ) { + + const { textureGPU, glTextureType } = this.get( binding.texture ); + + this.set( binding, { + index: bindingsData.textureIndex ++, + textureGPU, + glTextureType + } ); } @@ -71057,9 +73080,9 @@ class WebGLBackend extends Backend { } - copyFramebufferToTexture( texture, renderContext ) { + copyFramebufferToTexture( texture, renderContext, rectangle ) { - this.textureUtils.copyFramebufferToTexture( texture, renderContext ); + this.textureUtils.copyFramebufferToTexture( texture, renderContext, rectangle ); } @@ -71932,6 +73955,8 @@ class WebGPUTextureUtils { const dimension = this._getDimension( texture ); const format = texture.internalFormat || options.format || getFormat( texture, backend.device ); + textureData.format = format; + let sampleCount = options.sampleCount !== undefined ? options.sampleCount : 1; sampleCount = backend.utils.getSampleCount( sampleCount ); @@ -72179,7 +74204,7 @@ class WebGPUTextureUtils { } - async copyTextureToBuffer( texture, x, y, width, height ) { + async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { const device = this.backend.device; @@ -72203,7 +74228,7 @@ class WebGPUTextureUtils { encoder.copyTextureToBuffer( { texture: textureGPU, - origin: { x, y }, + origin: { x, y, z: faceIndex }, }, { buffer: readBuffer, @@ -72602,9 +74627,9 @@ class WebGPUTextureUtils { if ( format === GPUTextureFormat.RG16Sint ) return Int16Array; if ( format === GPUTextureFormat.RGBA16Uint ) return Uint16Array; if ( format === GPUTextureFormat.RGBA16Sint ) return Int16Array; - if ( format === GPUTextureFormat.R16Float ) return Float32Array; - if ( format === GPUTextureFormat.RG16Float ) return Float32Array; - if ( format === GPUTextureFormat.RGBA16Float ) return Float32Array; + if ( format === GPUTextureFormat.R16Float ) return Uint16Array; + if ( format === GPUTextureFormat.RG16Float ) return Uint16Array; + if ( format === GPUTextureFormat.RGBA16Float ) return Uint16Array; if ( format === GPUTextureFormat.R32Uint ) return Uint32Array; @@ -73256,7 +75281,8 @@ fn tsl_repeatWrapping( uv : vec2, dimension : vec2 ) -> vec2 { biquadraticTexture: new CodeNode( ` fn tsl_biquadraticTexture( map : texture_2d, coord : vec2f, level : i32 ) -> vec4f { - let res = vec2f( textureDimensions( map, level ) ); + let iRes = vec2i( textureDimensions( map, level ) ); + let res = vec2f( iRes ); let uvScaled = coord * res; let uvWrapping = ( ( uvScaled % res ) + res ) % res; @@ -73267,10 +75293,10 @@ fn tsl_biquadraticTexture( map : texture_2d, coord : vec2f, level : i32 ) - let iuv = floor( uv ); let f = fract( uv ); - let rg1 = textureLoad( map, vec2i( iuv + vec2( 0.5, 0.5 ) ), level ); - let rg2 = textureLoad( map, vec2i( iuv + vec2( 1.5, 0.5 ) ), level ); - let rg3 = textureLoad( map, vec2i( iuv + vec2( 0.5, 1.5 ) ), level ); - let rg4 = textureLoad( map, vec2i( iuv + vec2( 1.5, 1.5 ) ), level ); + let rg1 = textureLoad( map, vec2i( iuv + vec2( 0.5, 0.5 ) ) % iRes, level ); + let rg2 = textureLoad( map, vec2i( iuv + vec2( 1.5, 0.5 ) ) % iRes, level ); + let rg3 = textureLoad( map, vec2i( iuv + vec2( 0.5, 1.5 ) ) % iRes, level ); + let rg4 = textureLoad( map, vec2i( iuv + vec2( 1.5, 1.5 ) ) % iRes, level ); return mix( mix( rg1, rg2, f.x ), mix( rg3, rg4, f.x ), f.y ); @@ -73311,6 +75337,16 @@ if ( /Windows/g.test( navigator.userAgent ) ) { // +let diagnostics = ''; + +if ( /Firefox/g.test( navigator.userAgent ) !== true ) { + + diagnostics += 'diagnostic( off, derivative_uniformity );\n'; + +} + +// + class WGSLNodeBuilder extends NodeBuilder { constructor( object, renderer ) { @@ -73323,6 +75359,8 @@ class WGSLNodeBuilder extends NodeBuilder { this.directives = {}; + this.scopedArrays = new Map(); + } needsToWorkingColorSpace( texture ) { @@ -73733,6 +75771,12 @@ class WGSLNodeBuilder extends NodeBuilder { } + hasBuiltin( name, shaderStage = this.shaderStage ) { + + return ( this.builtins[ shaderStage ] !== undefined && this.builtins[ shaderStage ].has( name ) ); + + } + getVertexIndex() { if ( this.shaderStage === 'vertex' ) { @@ -73805,11 +75849,19 @@ ${ flowData.code } } + getInvocationSubgroupIndex() { + + this.enableSubGroups(); + + return this.getBuiltin( 'subgroup_invocation_id', 'invocationSubgroupIndex', 'u32', 'attribute' ); + + } + getSubgroupIndex() { this.enableSubGroups(); - return this.getBuiltin( 'subgroup_invocation_id', 'subgroupIndex', 'u32', 'attribute' ); + return this.getBuiltin( 'subgroup_id', 'subgroupIndex', 'u32', 'attribute' ); } @@ -73918,6 +75970,45 @@ ${ flowData.code } } + getScopedArray( name, scope, bufferType, bufferCount ) { + + if ( this.scopedArrays.has( name ) === false ) { + + this.scopedArrays.set( name, { + name, + scope, + bufferType, + bufferCount + } ); + + } + + return name; + + } + + getScopedArrays( shaderStage ) { + + if ( shaderStage !== 'compute' ) { + + return; + + } + + const snippets = []; + + for ( const { name, scope, bufferType, bufferCount } of this.scopedArrays.values() ) { + + const type = this.getType( bufferType ); + + snippets.push( `var<${scope}> ${name}: array< ${type}, ${bufferCount} >;` ); + + } + + return snippets.join( '\n' ); + + } + getAttributes( shaderStage ) { const snippets = []; @@ -73929,6 +76020,13 @@ ${ flowData.code } this.getBuiltin( 'local_invocation_id', 'localId', 'vec3', 'attribute' ); this.getBuiltin( 'num_workgroups', 'numWorkgroups', 'vec3', 'attribute' ); + if ( this.renderer.hasFeature( 'subgroups' ) ) { + + this.enableDirective( 'subgroups', shaderStage ); + this.getBuiltin( 'subgroup_size', 'subgroupSize', 'u32', 'attribute' ); + + } + } if ( shaderStage === 'vertex' || shaderStage === 'compute' ) { @@ -74088,8 +76186,8 @@ ${ flowData.code } for ( const uniform of uniforms ) { - const groundName = uniform.groupNode.name; - const uniformIndexes = this.bindingsIndexes[ groundName ]; + const groupName = uniform.groupNode.name; + const uniformIndexes = this.bindingsIndexes[ groupName ]; if ( uniform.type === 'texture' || uniform.type === 'cubeTexture' || uniform.type === 'storageTexture' || uniform.type === 'texture3D' ) { @@ -74163,7 +76261,8 @@ ${ flowData.code } const bufferCount = bufferNode.bufferCount; const bufferCountSnippet = bufferCount > 0 ? ', ' + bufferCount : ''; - const bufferSnippet = `\t${ uniform.name } : array< ${ bufferType }${ bufferCountSnippet } >\n`; + const bufferTypeSnippet = bufferNode.isAtomic ? `atomic<${bufferType}>` : `${bufferType}`; + const bufferSnippet = `\t${ uniform.name } : array< ${ bufferTypeSnippet }${ bufferCountSnippet } >\n`; const bufferAccessMode = bufferNode.isStorageBufferNode ? `storage, ${ this.getStorageAccess( bufferNode ) }` : 'uniform'; bufferSnippets.push( this._getWGSLStructBinding( 'NodeBuffer_' + bufferNode.id, bufferSnippet, bufferAccessMode, uniformIndexes.binding ++, uniformIndexes.group ) ); @@ -74205,6 +76304,8 @@ ${ flowData.code } const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; + this.sortBindingGroups(); + for ( const shaderStage in shadersData ) { const stageData = shadersData[ shaderStage ]; @@ -74215,6 +76316,7 @@ ${ flowData.code } stageData.vars = this.getVars( shaderStage ); stageData.codes = this.getCodes( shaderStage ); stageData.directives = this.getDirectives( shaderStage ); + stageData.scopedArrays = this.getScopedArrays( shaderStage ); // @@ -74406,8 +76508,8 @@ fn main( ${shaderData.attributes} ) -> VaryingsStruct { _getWGSLFragmentCode( shaderData ) { return `${ this.getSignature() } - -diagnostic( off, derivative_uniformity ); +// global +${ diagnostics } // uniforms ${shaderData.uniforms} @@ -74441,6 +76543,9 @@ ${shaderData.directives} // system var instanceIndex : u32; +// locals +${shaderData.scopedArrays} + // uniforms ${shaderData.uniforms} @@ -74518,7 +76623,7 @@ class WebGPUUtils { getTextureFormatGPU( texture ) { - return this.backend.get( texture ).texture.format; + return this.backend.get( texture ).format; } @@ -74836,22 +76941,12 @@ class WebGPUAttributeUtils { const bufferGPU = data.buffer; const size = bufferGPU.size; - let readBufferGPU = data.readBuffer; - let needsUnmap = true; - - if ( readBufferGPU === undefined ) { - - readBufferGPU = device.createBuffer( { - label: attribute.name, - size, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ - } ); - - needsUnmap = false; - - data.readBuffer = readBufferGPU; + const readBufferGPU = device.createBuffer( { + label: attribute.name, + size, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ + } ); - } const cmdEncoder = device.createCommandEncoder( {} ); @@ -74863,7 +76958,7 @@ class WebGPUAttributeUtils { size ); - if ( needsUnmap ) readBufferGPU.unmap(); + readBufferGPU.unmap(); const gpuCommands = cmdEncoder.finish(); device.queue.submit( [ gpuCommands ] ); @@ -75345,7 +77440,7 @@ class WebGPUPipelineUtils { }, multisample: { count: sampleCount, - alphaToCoverageEnabled: material.alphaToCoverage + alphaToCoverageEnabled: material.alphaToCoverage && sampleCount > 1 }, layout: device.createPipelineLayout( { bindGroupLayouts @@ -76251,7 +78346,7 @@ class WebGPUBackend extends Backend { renderContextData.descriptor = descriptor; renderContextData.encoder = encoder; renderContextData.currentPass = currentPass; - renderContextData.currentSets = { attributes: {}, pipeline: null, index: null }; + renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; renderContextData.renderBundles = []; // @@ -76655,13 +78750,17 @@ class WebGPUBackend extends Backend { draw( renderObject, info ) { - const { object, geometry, context, pipeline } = renderObject; + const { object, context, pipeline } = renderObject; const bindings = renderObject.getBindings(); const renderContextData = this.get( context ); const pipelineGPU = this.get( pipeline ).pipeline; const currentSets = renderContextData.currentSets; const passEncoderGPU = renderContextData.currentPass; + const drawParms = renderObject.getDrawParameters(); + + if ( drawParms === null ) return; + // pipeline if ( currentSets.pipeline !== pipelineGPU ) { @@ -76674,12 +78773,19 @@ class WebGPUBackend extends Backend { // bind groups + const currentBindingGroups = currentSets.bindingGroups; + for ( let i = 0, l = bindings.length; i < l; i ++ ) { const bindGroup = bindings[ i ]; const bindingsData = this.get( bindGroup ); - passEncoderGPU.setBindGroup( bindGroup.index, bindingsData.group ); + if ( currentBindingGroups[ bindGroup.index ] !== bindGroup.id ) { + + passEncoderGPU.setBindGroup( bindGroup.index, bindingsData.group ); + currentBindingGroups[ bindGroup.index ] = bindGroup.id; + + } } @@ -76755,12 +78861,6 @@ class WebGPUBackend extends Backend { // draw - const drawRange = renderObject.drawRange; - const firstVertex = drawRange.start; - - const instanceCount = this.getInstanceCount( renderObject ); - if ( instanceCount === 0 ) return; - if ( object.isBatchedMesh === true ) { const starts = object._multiDrawStarts; @@ -76781,16 +78881,15 @@ class WebGPUBackend extends Backend { } else if ( hasIndex === true ) { - const indexCount = ( drawRange.count !== Infinity ) ? drawRange.count : index.count; + const { vertexCount: indexCount, instanceCount, firstVertex: firstIndex } = drawParms; - passEncoderGPU.drawIndexed( indexCount, instanceCount, firstVertex, 0, 0 ); + passEncoderGPU.drawIndexed( indexCount, instanceCount, firstIndex, 0, 0 ); info.update( object, indexCount, instanceCount ); } else { - const positionAttribute = geometry.attributes.position; - const vertexCount = ( drawRange.count !== Infinity ) ? drawRange.count : positionAttribute.count; + const { vertexCount, instanceCount, firstVertex } = drawParms; passEncoderGPU.draw( vertexCount, instanceCount, firstVertex, 0 ); @@ -76883,7 +78982,6 @@ class WebGPUBackend extends Backend { } - // textures createSampler( texture ) { @@ -76928,9 +79026,9 @@ class WebGPUBackend extends Backend { } - copyTextureToBuffer( texture, x, y, width, height ) { + copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { - return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height ); + return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height, faceIndex ); } @@ -77079,7 +79177,7 @@ class WebGPUBackend extends Backend { renderContextData._currentPass = renderContextData.currentPass; renderContextData._currentSets = renderContextData.currentSets; - renderContextData.currentSets = { attributes: {}, pipeline: null, index: null }; + renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; renderContextData.currentPass = this.pipelineUtils.createBundleEncoder( renderContext ); } @@ -77187,9 +79285,11 @@ class WebGPUBackend extends Backend { let dstX = 0; let dstY = 0; + let dstLayer = 0; let srcX = 0; let srcY = 0; + let srcLayer = 0; let srcWidth = srcTexture.image.width; let srcHeight = srcTexture.image.height; @@ -77198,6 +79298,7 @@ class WebGPUBackend extends Backend { srcX = srcRegion.x; srcY = srcRegion.y; + srcLayer = srcRegion.z || 0; srcWidth = srcRegion.width; srcHeight = srcRegion.height; @@ -77207,6 +79308,7 @@ class WebGPUBackend extends Backend { dstX = dstPosition.x; dstY = dstPosition.y; + dstLayer = dstPosition.z || 0; } @@ -77219,16 +79321,17 @@ class WebGPUBackend extends Backend { { texture: sourceGPU, mipLevel: level, - origin: { x: srcX, y: srcY, z: 0 } + origin: { x: srcX, y: srcY, z: srcLayer } }, { texture: destinationGPU, mipLevel: level, - origin: { x: dstX, y: dstY, z: 0 } + origin: { x: dstX, y: dstY, z: dstLayer } }, [ srcWidth, - srcHeight + srcHeight, + 1 ] ); @@ -77236,7 +79339,7 @@ class WebGPUBackend extends Backend { } - copyFramebufferToTexture( texture, renderContext ) { + copyFramebufferToTexture( texture, renderContext, rectangle ) { const renderContextData = this.get( renderContext ); @@ -77285,14 +79388,14 @@ class WebGPUBackend extends Backend { encoder.copyTextureToTexture( { texture: sourceGPU, - origin: { x: 0, y: 0, z: 0 } + origin: { x: rectangle.x, y: rectangle.y, z: 0 } }, { texture: destinationGPU }, [ - texture.image.width, - texture.image.height + rectangle.z, + rectangle.w ] ); @@ -77308,7 +79411,72 @@ class WebGPUBackend extends Backend { if ( renderContext.stencil ) descriptor.depthStencilAttachment.stencilLoadOp = GPULoadOp.Load; renderContextData.currentPass = encoder.beginRenderPass( descriptor ); - renderContextData.currentSets = { attributes: {}, pipeline: null, index: null }; + renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; + + } + +} + +class IESSpotLight extends SpotLight { + + constructor( color, intensity, distance, angle, penumbra, decay ) { + + super( color, intensity, distance, angle, penumbra, decay ); + + this.iesMap = null; + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.iesMap = source.iesMap; + + return this; + + } + +} + +class StandardNodeLibrary extends NodeLibrary { + + constructor() { + + super(); + + this.addMaterial( MeshPhongNodeMaterial, MeshPhongMaterial ); + this.addMaterial( MeshStandardNodeMaterial, MeshStandardMaterial ); + this.addMaterial( MeshPhysicalNodeMaterial, MeshPhysicalMaterial ); + this.addMaterial( MeshToonNodeMaterial, MeshToonMaterial ); + this.addMaterial( MeshBasicNodeMaterial, MeshBasicMaterial ); + this.addMaterial( MeshLambertNodeMaterial, MeshLambertMaterial ); + this.addMaterial( MeshNormalNodeMaterial, MeshNormalMaterial ); + this.addMaterial( MeshMatcapNodeMaterial, MeshMatcapMaterial ); + this.addMaterial( LineBasicNodeMaterial, LineBasicMaterial ); + this.addMaterial( LineDashedNodeMaterial, LineDashedMaterial ); + this.addMaterial( PointsNodeMaterial, PointsMaterial ); + this.addMaterial( SpriteNodeMaterial, SpriteMaterial ); + this.addMaterial( ShadowNodeMaterial, ShadowMaterial ); + + this.addLight( PointLightNode, PointLight ); + this.addLight( DirectionalLightNode, DirectionalLight ); + this.addLight( RectAreaLightNode, RectAreaLight ); + this.addLight( SpotLightNode, SpotLight ); + this.addLight( AmbientLightNode, AmbientLight ); + this.addLight( HemisphereLightNode, HemisphereLight ); + this.addLight( LightProbeNode, LightProbe ); + this.addLight( IESSpotLightNode, IESSpotLight ); + + this.addToneMapping( linearToneMapping, LinearToneMapping ); + this.addToneMapping( reinhardToneMapping, ReinhardToneMapping ); + this.addToneMapping( cineonToneMapping, CineonToneMapping ); + this.addToneMapping( acesFilmicToneMapping, ACESFilmicToneMapping ); + this.addToneMapping( agxToneMapping, AgXToneMapping ); + this.addToneMapping( neutralToneMapping, NeutralToneMapping ); + + this.addColorSpace( linearSRGBTosRGB, getColorSpaceMethod( LinearSRGBColorSpace, SRGBColorSpace ) ); + this.addColorSpace( sRGBToLinearSRGB, getColorSpaceMethod( SRGBColorSpace, LinearSRGBColorSpace ) ); } @@ -77328,7 +79496,7 @@ const debugHandler = { }; */ -class WebGPURenderer extends StandardRenderer { +class WebGPURenderer extends Renderer { constructor( parameters = {} ) { @@ -77357,12 +79525,37 @@ class WebGPURenderer extends StandardRenderer { //super( new Proxy( backend, debugHandler ) ); super( backend, parameters ); + this.nodes.library = new StandardNodeLibrary(); + this.isWebGPURenderer = true; } } +class BundleGroup extends Group { + + constructor() { + + super(); + + this.isBundleGroup = true; + + this.type = 'BundleGroup'; + + this.static = true; + this.version = 0; + + } + + set needsUpdate( value ) { + + if ( value === true ) this.version ++; + + } + +} + const _material = /*@__PURE__*/ new NodeMaterial(); const _quadMesh = /*@__PURE__*/ new QuadMesh( _material ); @@ -77499,6 +79692,7 @@ class NodeLoader extends Loader { super( manager ); this.textures = {}; + this.nodes = {}; } @@ -77544,7 +79738,7 @@ class NodeLoader extends Loader { const { uuid, type } = nodeJSON; - nodes[ uuid ] = nodeObject( createNodeFromType( type ) ); + nodes[ uuid ] = this.createNodeFromType( type ); nodes[ uuid ].uuid = uuid; } @@ -77570,7 +79764,7 @@ class NodeLoader extends Loader { parse( json ) { - const node = nodeObject( createNodeFromType( json.type ) ); + const node = this.createNodeFromType( json.type ); node.uuid = json.uuid; const nodes = this.parseNodes( json.nodes ); @@ -77593,23 +79787,27 @@ class NodeLoader extends Loader { } -} + setNodes( value ) { -const superFromTypeFunction = MaterialLoader.createMaterialFromType; + this.nodes = value; + return this; -MaterialLoader.createMaterialFromType = function ( type ) { + } - const material = createNodeMaterialFromType( type ); + createNodeFromType( type ) { - if ( material !== undefined ) { + if ( this.nodes[ type ] === undefined ) { - return material; + console.error( 'THREE.NodeLoader: Node type not found:', type ); + return float(); - } + } - return superFromTypeFunction.call( this, type ); + return nodeObject( new this.nodes[ type ]() ); -}; + } + +} class NodeMaterialLoader extends MaterialLoader { @@ -77618,6 +79816,7 @@ class NodeMaterialLoader extends MaterialLoader { super( manager ); this.nodes = {}; + this.nodeMaterials = {}; } @@ -77643,11 +79842,31 @@ class NodeMaterialLoader extends MaterialLoader { setNodes( value ) { this.nodes = value; + return this; + + } + setNodeMaterials( value ) { + + this.nodeMaterials = value; return this; } + createMaterialFromType( type ) { + + const materialClass = this.nodeMaterials[ type ]; + + if ( materialClass !== undefined ) { + + return new materialClass(); + + } + + return super.createMaterialFromType( type ); + + } + } class NodeObjectLoader extends ObjectLoader { @@ -77656,10 +79875,27 @@ class NodeObjectLoader extends ObjectLoader { super( manager ); + this.nodes = {}; + this.nodeMaterials = {}; + this._nodesJSON = null; } + setNodes( value ) { + + this.nodes = value; + return this; + + } + + setNodeMaterials( value ) { + + this.nodeMaterials = value; + return this; + + } + parse( json, onLoad ) { this._nodesJSON = json.nodes; @@ -77677,6 +79913,7 @@ class NodeObjectLoader extends ObjectLoader { if ( json !== undefined ) { const loader = new NodeLoader(); + loader.setNodes( this.nodes ); loader.setTextures( textures ); return loader.parseNodes( json ); @@ -77698,6 +79935,7 @@ class NodeObjectLoader extends ObjectLoader { const loader = new NodeMaterialLoader(); loader.setTextures( textures ); loader.setNodes( nodes ); + loader.setNodeMaterials( this.nodeMaterials ); for ( let i = 0, l = json.length; i < l; i ++ ) { @@ -77737,4 +79975,4 @@ if ( typeof window !== 'undefined' ) { } -export { ACESFilmicToneMapping$1 as ACESFilmicToneMapping, AONode, AddEquation, AddOperation, AdditiveAnimationBlendMode, AdditiveBlending, AfterImageNode, AgXToneMapping$1 as AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AmbientLightNode, AnaglyphPassNode, AnalyticLightNode, AnamorphicNode, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrayCamera, ArrayElementNode, ArrowHelper, AssignNode, AttachedBindMode, AttributeNode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BRDF_GGX, BRDF_Lambert, BackSide, BasicDepthPacking, BasicEnvironmentNode, BasicShadowMap$1 as BasicShadowMap, BatchNode, BatchedMesh, BloomNode, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxGeometry, BoxHelper, Break, BufferAttribute, BufferAttributeNode, BufferGeometry, BufferGeometryLoader, BufferNode, BumpMapNode, BypassNode, ByteType, Cache, CacheNode, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CineonToneMapping$1 as CineonToneMapping, CircleGeometry, ClampToEdgeWrapping, Clock, CodeNode, Color, ColorKeyframeTrack, ColorManagement, ColorSpaceFunctions, ColorSpaceNode, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ComputeNode, ConeGeometry, ConstNode, ConstantAlphaFactor, ConstantColorFactor, ContextNode, Continue, Controls, ConvertNode, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureLoader, CubeTextureNode, CubeUVReflectionMapping, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceBack, CullFaceFront, CullFaceFrontBack, CullFaceNone, Curve, CurvePath, CustomBlending, CustomToneMapping, CylinderGeometry, Cylindrical, DFGApprox, D_GGX, Data3DTexture, DataArrayTexture, DataTexture, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DenoiseNode, DepthFormat, DepthOfFieldNode, DepthStencilFormat, DepthTexture, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DirectionalLightNode, Discard, DiscreteInterpolant, DisplayP3ColorSpace, DodecahedronGeometry, DotScreenNode, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EPSILON, EdgesGeometry, EllipseCurve, EnvironmentNode, EqualCompare, EqualDepth, EqualStencilFunc, EquirectUVNode, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExpressionNode, ExtrudeGeometry, FXAANode, F_Schlick, FileLoader, FilmNode, Float16BufferAttribute, Float32BufferAttribute, FloatType, Fn, Fog, FogExp2, FogExp2Node, FogNode, FogRangeNode, FramebufferTexture, FrontFacingNode, FrontSide, Frustum, FunctionCallNode, FunctionNode, FunctionOverloadingNode, GLBufferAttribute, GLSL1, GLSL3, GLSLNodeParser, GTAONode, GaussianBlurNode, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HalfFloatType, HemisphereLight, HemisphereLightHelper, HemisphereLightNode, IESSpotLight, IESSpotLightNode, INFINITY, IcosahedronGeometry, If, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, IndexNode, InstanceNode, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, InstancedPointsNodeMaterial, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, IntType, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InvertStencilOp, IrradianceNode, JoinNode, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, Layers, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, Light, LightNode, LightProbe, LightProbeNode, LightingContextNode, LightingModel, LightingNode, LightsNode, Line, Line2NodeMaterial, Line3, LineBasicMaterial, LineBasicNodeMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineDashedNodeMaterial, LineLoop, LineSegments, LinearDisplayP3ColorSpace, LinearFilter, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping$1 as LinearToneMapping, LinearTransfer, Loader, LoaderUtils, LoadingManager, Loop, LoopNode, LoopOnce, LoopPingPong, LoopRepeat, LuminanceAlphaFormat, LuminanceFormat, Lut3DNode, MOUSE, MRTNode, MatcapUVNode, Material, MaterialLoader, MaterialNode, MaterialReferenceNode, MathUtils, Matrix2, Matrix3, Matrix4, MaxEquation, MaxMipLevelNode, Mesh, MeshBasicMaterial, MeshBasicNodeMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshLambertMaterial, MeshLambertNodeMaterial, MeshMatcapMaterial, MeshMatcapNodeMaterial, MeshNormalMaterial, MeshNormalNodeMaterial, MeshPhongMaterial, MeshPhongNodeMaterial, MeshPhysicalMaterial, MeshPhysicalNodeMaterial, MeshSSSNodeMaterial, MeshStandardMaterial, MeshStandardNodeMaterial, MeshToonMaterial, MeshToonNodeMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, ModelNode, ModelViewProjectionNode, MorphNode, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping$1 as NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoToneMapping, Node, NodeAttribute, NodeBuilder, NodeCache, NodeCode, NodeFrame, NodeFunctionInput, NodeLoader, NodeMaterial, NodeMaterialLoader, NodeObjectLoader, NodeShaderStage, NodeType, NodeUniform, NodeUpdateType, NodeUtils, NodeVar, NodeVarying, NormalAnimationBlendMode, NormalBlending, NormalMapNode, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, Object3DNode, ObjectLoader, ObjectSpaceNormalMap, OctahedronGeometry, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, OscNode, OutputStructNode, P3Primaries, PCFShadowMap$1 as PCFShadowMap, PCFSoftShadowMap$1 as PCFSoftShadowMap, PI, PI2, PMREMGenerator, PMREMNode, ParallaxBarrierPassNode, ParameterNode, PassNode, Path, PerspectiveCamera, PhongLightingModel, PhysicalLightingModel, PixelationPassNode, Plane, PlaneGeometry, PlaneHelper, PointLight, PointLightHelper, PointLightNode, PointUVNode, Points, PointsMaterial, PointsNodeMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PostProcessing, PosterizeNode, PropertyBinding, PropertyMixer, PropertyNode, QuadMesh, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RGBADepthPacking, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBDepthPacking, RGBFormat, RGBIntegerFormat, RGBShiftNode, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGDepthPacking, RGFormat, RGIntegerFormat, RTTNode, RangeNode, RawShaderMaterial, Ray, Raycaster, Rec709Primaries, RectAreaLight, RectAreaLightNode, RedFormat, RedIntegerFormat, ReferenceNode, ReflectorNode, ReinhardToneMapping$1 as ReinhardToneMapping, RemapNode, RenderOutputNode, RenderTarget, RendererReferenceNode, RepeatWrapping, ReplaceStencilOp, Return, ReverseSubtractEquation, RingGeometry, RotateNode, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, SRGBTransfer, SSAAPassNode, Scene, SceneNode, Schlick_to_F0, ScriptableNode, ScriptableValueNode, SetNode, ShaderMaterial, ShaderNode, ShadowMaterial, ShadowNodeMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, SkinningNode, SobelOperatorNode, Source, Sphere, SphereGeometry, Spherical, SphericalHarmonics3, SplineCurve, SplitNode, SpotLight, SpotLightHelper, SpotLightNode, Sprite, SpriteMaterial, SpriteNodeMaterial, SpriteSheetUVNode, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StackNode, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StereoPassNode, StorageArrayElementNode, StorageBufferAttribute, StorageBufferNode, StorageInstancedBufferAttribute, StorageTexture, StorageTextureNode, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SubtractEquation, SubtractiveBlending, TBNViewMatrix, TOUCH, TangentSpaceNormalMap, TempNode, TetrahedronGeometry, Texture, Texture3DNode, TextureLoader, TextureNode, TextureSizeNode, TimerNode, ToneMappingFunctions, ToneMappingNode, TorusGeometry, TorusKnotGeometry, TransitionNode, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TriplanarTexturesNode, TubeGeometry, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform$1 as Uniform, UniformArrayNode, UniformGroupNode, UniformNode, UniformsGroup$1 as UniformsGroup, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, UserDataNode, VSMShadowMap, V_GGX_SmithCorrelated, VarNode, VaryingNode, Vector2, Vector3, Vector4, VectorKeyframeTrack, VertexColorNode, VideoTexture, ViewportDepthNode, ViewportDepthTextureNode, ViewportNode, ViewportSharedTextureNode, ViewportTextureNode, VolumeNodeMaterial, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGLMultipleRenderTargets, WebGLRenderTarget, WebGPUCoordinateSystem, WebGPURenderer, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, abs, acos, add, addMethodChaining, addNodeElement, afterImage, all, alphaT, anaglyphPass, anamorphic, and, anisotropy, anisotropyB, anisotropyT, any, ao, append, arrayBuffer, asin, assign, atan, atan2, attenuationColor, attenuationDistance, attribute, backgroundBlurriness, backgroundIntensity, batch, billboarding, bitAnd, bitNot, bitOr, bitXor, bitangentGeometry, bitangentLocal, bitangentView, bitangentWorld, bitcast, bleach, bloom, blur, bool, buffer, bufferAttribute, bumpMap, burn, bvec2, bvec3, bvec4, bypass, cache, call, cameraFar, cameraLogDepth, cameraNear, cameraNormalMatrix, cameraPosition, cameraProjectionMatrix, cameraProjectionMatrixInverse, cameraViewMatrix, cameraWorldMatrix, cbrt, ceil, checker, clamp, clearcoat, clearcoatRoughness, code, color, colorToDirection, compute, cond, context, convert, convertToTexture, cos, createCanvasElement, cross, cubeTexture, dFdx, dFdy, dashSize, defaultBuildStages, defaultShaderStages, defined, degrees, denoise, densityFog, depth, depthPass, difference, diffuseColor, directionToColor, dispersion, distance, div, dodge, dof, dot, dotScreen, drawIndex, dynamicBufferAttribute, element, emissive, equal, equals, equirectUV, exp, exp2, expression, faceDirection, faceForward, film, float, floor, fog, fract, frameGroup, frameId, frontFacing, fwidth, fxaa, gain, gapSize, gaussianBlur, getColorSpaceMethod, getConstNodeType, getCurrentStack, getDirection, getDistanceAttenuation, getGeometryRoughness, getRoughness, getTextureIndex, global, glsl, glslFn, grayscale, greaterThan, greaterThanEqual, hash, hue, instance, instanceIndex, instancedBufferAttribute, instancedDynamicBufferAttribute, int, inverseSqrt, invocationLocalIndex, ior, iridescence, iridescenceIOR, iridescenceThickness, ivec2, ivec3, ivec4, js, label, length, lengthSq, lessThan, lessThanEqual, lightTargetDirection, lightingContext, lights, linearDepth, log, log2, luminance, lut3D, mat2, mat3, mat4, matcapUV, materialAOMap, materialAlphaTest, materialAnisotropy, materialAnisotropyVector, materialClearcoat, materialClearcoatNormal, materialClearcoatRoughness, materialColor, materialDispersion, materialEmissive, materialIridescence, materialIridescenceIOR, materialIridescenceThickness, materialLightMap, materialLineDashOffset, materialLineDashSize, materialLineGapSize, materialLineScale, materialLineWidth, materialMetalness, materialNormal, materialOpacity, materialPointWidth, materialReference, materialReflectivity, materialRefractionRatio, materialRotation, materialRoughness, materialSheen, materialSheenRoughness, materialShininess, materialSpecular, materialSpecularStrength, max$1 as max, maxMipLevel, metalness, min$1 as min, mix, mixElement, mod, modInt, modelDirection, modelNormalMatrix, modelPosition, modelScale, modelViewMatrix, modelViewPosition, modelViewProjection, modelWorldMatrix, modelWorldMatrixInverse, morphReference, motionBlur, mrt, mul, mx_aastep, mx_cell_noise_float, mx_contrast, mx_fractal_noise_float, mx_fractal_noise_vec2, mx_fractal_noise_vec3, mx_fractal_noise_vec4, mx_hsvtorgb, mx_noise_float, mx_noise_vec3, mx_noise_vec4, mx_ramplr, mx_ramptb, mx_rgbtohsv, mx_safepower, mx_splitlr, mx_splittb, mx_srgb_texture_to_lin_rec709, mx_transform_uv, mx_worley_noise_float, mx_worley_noise_vec2, mx_worley_noise_vec3, negate, nodeArray, nodeImmutable, nodeObject, nodeObjects, nodeProxy, normalFlat, normalGeometry, normalLocal, normalMap, normalView, normalWorld, normalize, not, notEqual, objectDirection, objectGroup, objectNormalMatrix, objectPosition, objectScale, objectViewMatrix, objectViewPosition, objectWorldMatrix, oneMinus, or, orthographicDepthToViewZ, oscSawtooth, oscSine, oscSquare, oscTriangle, output, outputStruct, overlay, overloadingFn, parabola, parallaxBarrierPass, parallaxDirection, parallaxUV, parameter, pass, passTexture, pcurve, perspectiveDepthToViewZ, pixelationPass, pmremTexture, pointUV, pointWidth, positionGeometry, positionLocal, positionPrevious, positionView, positionViewDirection, positionWorld, positionWorldDirection, posterize, pow, pow2, pow3, pow4, property, radians, rand, range, rangeFog, reciprocal, reference, referenceBuffer, reflect, reflectVector, reflectView, reflector, refract, refractVector, refractView, registerNode, remainder, remap, remapClamp, renderGroup, renderOutput, rendererReference, rgbShift, rotate, rotateUV, roughness, round, rtt, sampler, saturate, saturation, screen, scriptable, scriptableValue, select, sepia, setCurrentStack, shaderStages, sharedUniformGroup, sheen, sheenRoughness, shiftLeft, shiftRight, shininess, sign, sin, sinc, skinning, skinningReference, smoothstep, smoothstepElement, sobel, specularColor, specularF90, spherizeUV, split, spritesheetUV, sqrt, ssaaPass, stack, step, stereoPass, storage, storageObject, storageTexture, string, sub, tan, tangentGeometry, tangentLocal, tangentView, tangentWorld, temp, texture, texture3D, textureBicubic, textureCubeUV, textureLoad, textureSize, textureStore, thickness, threshold, timerDelta, timerGlobal, timerLocal, toOutputColorSpace, toWorkingColorSpace, toneMapping, toneMappingExposure, transformDirection, transformedBentNormalView, transformedBitangentView, transformedBitangentWorld, transformedClearcoatNormalView, transformedNormalView, transformedNormalWorld, transformedTangentView, transformedTangentWorld, transition, transmission, transpose, tri, tri3, triNoise3D, triplanarTexture, triplanarTextures, trunc, tslFn, uint, uniform, uniformArray, uniformGroup, userData, uv, uvec2, uvec3, uvec4, varying, varyingProperty, vec2, vec3, vec4, vectorComponents, velocity, vertexColor, vertexIndex, vibrance, viewZToOrthographicDepth, viewZToPerspectiveDepth, viewport, viewportBottomLeft, viewportCoordinate, viewportDepthTexture, viewportLinearDepth, viewportMipTexture, viewportResolution, viewportSafeUV, viewportSharedTexture, viewportTexture, viewportTopLeft, viewportUV, wgsl, wgslFn, xor }; +export { ACESFilmicToneMapping, AONode, AddEquation, AddOperation, AdditiveAnimationBlendMode, AdditiveBlending, AfterImageNode, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AmbientLightNode, AnaglyphPassNode, AnalyticLightNode, AnamorphicNode, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrayCamera, ArrayElementNode, ArrowHelper, AssignNode, AttachedBindMode, AttributeNode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BRDF_GGX, BRDF_Lambert, BackSide, BasicDepthPacking, BasicEnvironmentNode, BasicShadowMap$1 as BasicShadowMap, BatchNode, BatchedMesh, BloomNode, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxGeometry, BoxHelper, Break, BufferAttribute, BufferAttributeNode, BufferGeometry, BufferGeometryLoader, BufferNode, BumpMapNode, BundleGroup, BypassNode, ByteType, Cache, CacheNode, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CineonToneMapping, CircleGeometry, ClampToEdgeWrapping, Clock, CodeNode, Color, ColorKeyframeTrack, ColorManagement, ColorSpaceNode, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ComputeNode, ConeGeometry, ConstNode, ConstantAlphaFactor, ConstantColorFactor, ContextNode, Continue, Controls, ConvertNode, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureLoader, CubeTextureNode, CubeUVReflectionMapping, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceBack, CullFaceFront, CullFaceFrontBack, CullFaceNone, Curve, CurvePath, CustomBlending, CustomToneMapping, CylinderGeometry, Cylindrical, DFGApprox, D_GGX, Data3DTexture, DataArrayTexture, DataTexture, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DenoiseNode, DepthFormat, DepthOfFieldNode, DepthStencilFormat, DepthTexture, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DirectionalLightNode, Discard, DiscreteInterpolant, DisplayP3ColorSpace, DodecahedronGeometry, DotScreenNode, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EPSILON, EdgesGeometry, EllipseCurve, EnvironmentNode, EqualCompare, EqualDepth, EqualStencilFunc, EquirectUVNode, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExpressionNode, ExtrudeGeometry, FXAANode, F_Schlick, FileLoader, FilmNode, Float16BufferAttribute, Float32BufferAttribute, FloatType, Fn, Fog, FogExp2, FogExp2Node, FogNode, FogRangeNode, FramebufferTexture, FrontFacingNode, FrontSide, Frustum, FunctionCallNode, FunctionNode, FunctionOverloadingNode, GLBufferAttribute, GLSL1, GLSL3, GLSLNodeParser, GTAONode, GaussianBlurNode, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HalfFloatType, HemisphereLight, HemisphereLightHelper, HemisphereLightNode, IESSpotLight, IESSpotLightNode, INFINITY, IcosahedronGeometry, If, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, IndexNode, InstanceNode, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, InstancedPointsNodeMaterial, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, IntType, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InvertStencilOp, IrradianceNode, JoinNode, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, Layers, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, LightProbeNode, LightingContextNode, LightingModel, LightingNode, LightsNode, Line, Line2NodeMaterial, Line3, LineBasicMaterial, LineBasicNodeMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineDashedNodeMaterial, LineLoop, LineSegments, LinearDisplayP3ColorSpace, LinearFilter, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Loader, LoaderUtils, LoadingManager, Loop, LoopNode, LoopOnce, LoopPingPong, LoopRepeat, LuminanceAlphaFormat, LuminanceFormat, Lut3DNode, MOUSE, MRTNode, MatcapUVNode, Material, MaterialLoader, MaterialNode, MaterialReferenceNode, MathUtils, Matrix2, Matrix3, Matrix4, MaxEquation, MaxMipLevelNode, Mesh, MeshBasicMaterial, MeshBasicNodeMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshLambertMaterial, MeshLambertNodeMaterial, MeshMatcapMaterial, MeshMatcapNodeMaterial, MeshNormalMaterial, MeshNormalNodeMaterial, MeshPhongMaterial, MeshPhongNodeMaterial, MeshPhysicalMaterial, MeshPhysicalNodeMaterial, MeshSSSNodeMaterial, MeshStandardMaterial, MeshStandardNodeMaterial, MeshToonMaterial, MeshToonNodeMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, ModelNode, ModelViewProjectionNode, MorphNode, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoToneMapping, Node, NodeAttribute, NodeBuilder, NodeCache, NodeCode, NodeFrame, NodeFunctionInput, NodeLoader, NodeMaterial, NodeMaterialLoader, NodeMaterialObserver, NodeObjectLoader, NodeShaderStage, NodeType, NodeUniform, NodeUpdateType, NodeUtils, NodeVar, NodeVarying, NormalAnimationBlendMode, NormalBlending, NormalMapNode, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, Object3DNode, ObjectLoader, ObjectSpaceNormalMap, OctahedronGeometry, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, OscNode, OutputStructNode, P3Primaries, PCFShadowMap$1 as PCFShadowMap, PCFSoftShadowMap$1 as PCFSoftShadowMap, PI, PI2, PMREMGenerator, PMREMNode, ParallaxBarrierPassNode, ParameterNode, PassNode, Path, PerspectiveCamera, PhongLightingModel, PhysicalLightingModel, PixelationPassNode, Plane, PlaneGeometry, PlaneHelper, PointLight, PointLightHelper, PointLightNode, PointUVNode, Points, PointsMaterial, PointsNodeMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PostProcessing, PosterizeNode, PropertyBinding, PropertyMixer, PropertyNode, QuadMesh, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RGBADepthPacking, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBDepthPacking, RGBFormat, RGBIntegerFormat, RGBShiftNode, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGDepthPacking, RGFormat, RGIntegerFormat, RTTNode, RangeNode, RawShaderMaterial, Ray, Raycaster, Rec709Primaries, RectAreaLight, RectAreaLightNode, RedFormat, RedIntegerFormat, ReferenceNode, ReflectorNode, ReinhardToneMapping, RemapNode, RenderOutputNode, RenderTarget, RendererReferenceNode, RepeatWrapping, ReplaceStencilOp, Return, ReverseSubtractEquation, RingGeometry, RotateNode, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, SRGBTransfer, SSAAPassNode, Scene, SceneNode, Schlick_to_F0, ScreenNode, ScriptableNode, ScriptableValueNode, SetNode, ShaderMaterial, ShaderNode, ShadowMaterial, ShadowNodeMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, SkinningNode, SobelOperatorNode, Source, Sphere, SphereGeometry, Spherical, SphericalHarmonics3, SplineCurve, SplitNode, SpotLight, SpotLightHelper, SpotLightNode, Sprite, SpriteMaterial, SpriteNodeMaterial, SpriteSheetUVNode, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StackNode, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StereoPassNode, StorageArrayElementNode, StorageBufferAttribute, StorageBufferNode, StorageInstancedBufferAttribute, StorageTexture, StorageTextureNode, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SubtractEquation, SubtractiveBlending, TBNViewMatrix, TOUCH, TangentSpaceNormalMap, TempNode, TetrahedronGeometry, Texture, Texture3DNode, TextureLoader, TextureNode, TextureSizeNode, TimerNode, ToneMappingNode, ToonOutlinePassNode, TorusGeometry, TorusKnotGeometry, TransitionNode, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TriplanarTexturesNode, TubeGeometry, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform$1 as Uniform, UniformArrayNode, UniformGroupNode, UniformNode, UniformsGroup$1 as UniformsGroup, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, UserDataNode, VSMShadowMap, V_GGX_SmithCorrelated, VarNode, VaryingNode, Vector2, Vector3, Vector4, VectorKeyframeTrack, VertexColorNode, VideoTexture, ViewportDepthNode, ViewportDepthTextureNode, ViewportSharedTextureNode, ViewportTextureNode, VolumeNodeMaterial, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGLMultipleRenderTargets, WebGLRenderTarget, WebGPUCoordinateSystem, WebGPURenderer, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, abs, acesFilmicToneMapping, acos, add, addMethodChaining, addNodeElement, afterImage, agxToneMapping, all, alphaT, anaglyphPass, anamorphic, and, anisotropy, anisotropyB, anisotropyT, any, ao, append, arrayBuffer, asin, assign, atan, atan2, atomicAdd, atomicAnd, atomicFunc, atomicMax, atomicMin, atomicOr, atomicStore, atomicSub, atomicXor, attenuationColor, attenuationDistance, attribute, backgroundBlurriness, backgroundIntensity, batch, billboarding, bitAnd, bitNot, bitOr, bitXor, bitangentGeometry, bitangentLocal, bitangentView, bitangentWorld, bitcast, bleach, bloom, blur, bool, buffer, bufferAttribute, bumpMap, burn, bvec2, bvec3, bvec4, bypass, cache, call, cameraFar, cameraLogDepth, cameraNear, cameraNormalMatrix, cameraPosition, cameraProjectionMatrix, cameraProjectionMatrixInverse, cameraViewMatrix, cameraWorldMatrix, cbrt, ceil, checker, cineonToneMapping, clamp, clearcoat, clearcoatRoughness, code, color, colorSpaceToWorking, colorToDirection, compute, cond, context, convert, convertToTexture, cos, createCanvasElement, cross, cubeTexture, dFdx, dFdy, dashSize, defaultBuildStages, defaultShaderStages, defined, degrees, denoise, densityFog, depth, depthPass, difference, diffuseColor, directionToColor, dispersion, distance, div, dodge, dof, dot, dotScreen, drawIndex, dynamicBufferAttribute, element, emissive, equal, equals, equirectUV, exp, exp2, expression, faceDirection, faceForward, film, float, floor, fog, fract, frameGroup, frameId, frontFacing, fwidth, fxaa, gain, gapSize, gaussianBlur, getColorSpaceMethod, getConstNodeType, getCurrentStack, getDirection, getDistanceAttenuation, getGeometryRoughness, getRoughness, getShIrradianceAt, getTextureIndex, global, glsl, glslFn, grayscale, greaterThan, greaterThanEqual, hash, highPrecisionModelNormalViewMatrix, highPrecisionModelViewMatrix, hue, instance, instanceIndex, instancedBufferAttribute, instancedDynamicBufferAttribute, int, inverseSqrt, invocationLocalIndex, invocationSubgroupIndex, ior, iridescence, iridescenceIOR, iridescenceThickness, ivec2, ivec3, ivec4, js, label, length, lengthSq, lessThan, lessThanEqual, lightPosition, lightTargetDirection, lightTargetPosition, lightViewPosition, lightingContext, lights, linearDepth, linearSRGBTosRGB, linearToneMapping, localId, log, log2, loop, luminance, lut3D, mat2, mat3, mat4, matcapUV, materialAOMap, materialAlphaTest, materialAnisotropy, materialAnisotropyVector, materialAttenuationColor, materialAttenuationDistance, materialClearcoat, materialClearcoatNormal, materialClearcoatRoughness, materialColor, materialDispersion, materialEmissive, materialIOR, materialIridescence, materialIridescenceIOR, materialIridescenceThickness, materialLightMap, materialLineDashOffset, materialLineDashSize, materialLineGapSize, materialLineScale, materialLineWidth, materialMetalness, materialNormal, materialOpacity, materialPointWidth, materialReference, materialReflectivity, materialRefractionRatio, materialRotation, materialRoughness, materialSheen, materialSheenRoughness, materialShininess, materialSpecular, materialSpecularColor, materialSpecularIntensity, materialSpecularStrength, materialThickness, materialTransmission, max$1 as max, maxMipLevel, metalness, min$1 as min, mix, mixElement, mod, modInt, modelDirection, modelNormalMatrix, modelPosition, modelScale, modelViewMatrix, modelViewPosition, modelViewProjection, modelWorldMatrix, modelWorldMatrixInverse, morphReference, motionBlur, mrt, mul, mx_aastep, mx_cell_noise_float, mx_contrast, mx_fractal_noise_float, mx_fractal_noise_vec2, mx_fractal_noise_vec3, mx_fractal_noise_vec4, mx_hsvtorgb, mx_noise_float, mx_noise_vec3, mx_noise_vec4, mx_ramplr, mx_ramptb, mx_rgbtohsv, mx_safepower, mx_splitlr, mx_splittb, mx_srgb_texture_to_lin_rec709, mx_transform_uv, mx_worley_noise_float, mx_worley_noise_vec2, mx_worley_noise_vec3, negate, neutralToneMapping, nodeArray, nodeImmutable, nodeObject, nodeObjects, nodeProxy, normalFlat, normalGeometry, normalLocal, normalMap, normalView, normalWorld, normalize, not, notEqual, numWorkgroups, objectDirection, objectGroup, objectPosition, objectScale, objectViewPosition, objectWorldMatrix, oneMinus, or, orthographicDepthToViewZ, oscSawtooth, oscSine, oscSquare, oscTriangle, output, outputStruct, overlay, overloadingFn, parabola, parallaxBarrierPass, parallaxDirection, parallaxUV, parameter, pass, passTexture, pcurve, perspectiveDepthToViewZ, pixelationPass, pmremTexture, pointUV, pointWidth, positionGeometry, positionLocal, positionPrevious, positionView, positionViewDirection, positionWorld, positionWorldDirection, posterize, pow, pow2, pow3, pow4, property, radians, rand, range, rangeFog, reciprocal, reference, referenceBuffer, reflect, reflectVector, reflectView, reflector, refract, refractVector, refractView, reinhardToneMapping, remainder, remap, remapClamp, renderGroup, renderOutput, rendererReference, rgbShift, rotate, rotateUV, roughness, round, rtt, sRGBToLinearSRGB, sampler, saturate, saturation, screen, screenCoordinate, screenSize, screenUV, scriptable, scriptableValue, select, sepia, setCurrentStack, shaderStages, sharedUniformGroup, sheen, sheenRoughness, shiftLeft, shiftRight, shininess, sign, sin, sinc, skinning, skinningReference, smoothstep, smoothstepElement, sobel, specularColor, specularF90, spherizeUV, split, spritesheetUV, sqrt, ssaaPass, stack, step, stereoPass, storage, storageBarrier, storageObject, storageTexture, string, sub, subgroupIndex, subgroupSize, tan, tangentGeometry, tangentLocal, tangentView, tangentWorld, temp, texture, texture3D, textureBarrier, textureBicubic, textureCubeUV, textureLoad, textureSize, textureStore, thickness, threshold, timerDelta, timerGlobal, timerLocal, toOutputColorSpace, toWorkingColorSpace, toneMapping, toneMappingExposure, toonOutlinePass, transformDirection, transformNormal, transformNormalToView, transformedBentNormalView, transformedBitangentView, transformedBitangentWorld, transformedClearcoatNormalView, transformedNormalView, transformedNormalWorld, transformedTangentView, transformedTangentWorld, transition, transmission, transpose, tri, tri3, triNoise3D, triplanarTexture, triplanarTextures, trunc, tslFn, uint, uniform, uniformArray, uniformGroup, uniforms, userData, uv, uvec2, uvec3, uvec4, varying, varyingProperty, vec2, vec3, vec4, vectorComponents, velocity, vertexColor, vertexIndex, vibrance, viewZToOrthographicDepth, viewZToPerspectiveDepth, viewport, viewportBottomLeft, viewportCoordinate, viewportDepthTexture, viewportLinearDepth, viewportMipTexture, viewportResolution, viewportSafeUV, viewportSharedTexture, viewportSize, viewportTexture, viewportTopLeft, viewportUV, wgsl, wgslFn, workgroupArray, workgroupBarrier, workgroupId, workingToColorSpace, xor }; diff --git a/build/three.webgpu.min.js b/build/three.webgpu.min.js index ae202e426cbca2..36502a3dfb4932 100644 --- a/build/three.webgpu.min.js +++ b/build/three.webgpu.min.js @@ -3,4 +3,4 @@ * Copyright 2010-2024 Three.js Authors * SPDX-License-Identifier: MIT */ -const e="168",t={LEFT:0,MIDDLE:1,RIGHT:2,ROTATE:0,DOLLY:1,PAN:2},s={ROTATE:0,PAN:1,DOLLY_PAN:2,DOLLY_ROTATE:3},i=0,r=1,n=2,o=3,a=0,h=1,l=2,u=3,c=0,d=1,p=2,m=0,g=1,f=2,y=3,x=4,b=5,v=100,T=101,_=102,w=103,S=104,M=200,A=201,N=202,R=203,C=204,E=205,B=206,I=207,P=208,F=209,z=210,U=211,L=212,O=213,V=214,D=0,k=1,G=2,W=3,H=4,j=5,q=6,$=7,X=0,Y=1,J=2,Z=0,K=1,Q=2,ee=3,te=4,se=5,ie=6,re=7,ne="attached",oe="detached",ae=300,he=301,le=302,ue=303,ce=304,de=306,pe=1e3,me=1001,ge=1002,fe=1003,ye=1004,xe=1004,be=1005,ve=1005,Te=1006,_e=1007,we=1007,Se=1008,Me=1008,Ae=1009,Ne=1010,Re=1011,Ce=1012,Ee=1013,Be=1014,Ie=1015,Pe=1016,Fe=1017,ze=1018,Ue=1020,Le=35902,Oe=1021,Ve=1022,De=1023,ke=1024,Ge=1025,We=1026,He=1027,je=1028,qe=1029,$e=1030,Xe=1031,Ye=1032,Je=1033,Ze=33776,Ke=33777,Qe=33778,et=33779,tt=35840,st=35841,it=35842,rt=35843,nt=36196,ot=37492,at=37496,ht=37808,lt=37809,ut=37810,ct=37811,dt=37812,pt=37813,mt=37814,gt=37815,ft=37816,yt=37817,xt=37818,bt=37819,vt=37820,Tt=37821,_t=36492,wt=36494,St=36495,Mt=36283,At=36284,Nt=36285,Rt=36286,Ct=2200,Et=2201,Bt=2202,It=2300,Pt=2301,Ft=2302,zt=2400,Ut=2401,Lt=2402,Ot=2500,Vt=2501,Dt=0,kt=1,Gt=2,Wt=3200,Ht=3201,jt=3202,qt=3203,$t=0,Xt=1,Yt="",Jt="srgb",Zt="srgb-linear",Kt="display-p3",Qt="display-p3-linear",es="linear",ts="srgb",ss="rec709",is="p3",rs=0,ns=7680,os=7681,as=7682,hs=7683,ls=34055,us=34056,cs=5386,ds=512,ps=513,ms=514,gs=515,fs=516,ys=517,xs=518,bs=519,vs=512,Ts=513,_s=514,ws=515,Ss=516,Ms=517,As=518,Ns=519,Rs=35044,Cs=35048,Es=35040,Bs=35045,Is=35049,Ps=35041,Fs=35046,zs=35050,Us=35042,Ls="100",Os="300 es",Vs=2e3,Ds=2001;class ks{addEventListener(e,t){void 0===this._listeners&&(this._listeners={});const s=this._listeners;void 0===s[e]&&(s[e]=[]),-1===s[e].indexOf(t)&&s[e].push(t)}hasEventListener(e,t){if(void 0===this._listeners)return!1;const s=this._listeners;return void 0!==s[e]&&-1!==s[e].indexOf(t)}removeEventListener(e,t){if(void 0===this._listeners)return;const s=this._listeners[e];if(void 0!==s){const e=s.indexOf(t);-1!==e&&s.splice(e,1)}}dispatchEvent(e){if(void 0===this._listeners)return;const t=this._listeners[e.type];if(void 0!==t){e.target=this;const s=t.slice(0);for(let t=0,i=s.length;t>8&255]+Gs[e>>16&255]+Gs[e>>24&255]+"-"+Gs[255&t]+Gs[t>>8&255]+"-"+Gs[t>>16&15|64]+Gs[t>>24&255]+"-"+Gs[63&s|128]+Gs[s>>8&255]+"-"+Gs[s>>16&255]+Gs[s>>24&255]+Gs[255&i]+Gs[i>>8&255]+Gs[i>>16&255]+Gs[i>>24&255]).toLowerCase()}function $s(e,t,s){return Math.max(t,Math.min(s,e))}function Xs(e,t){return(e%t+t)%t}function Ys(e,t,s){return(1-s)*e+s*t}function Js(e,t){switch(t.constructor){case Float32Array:return e;case Uint32Array:return e/4294967295;case Uint16Array:return e/65535;case Uint8Array:return e/255;case Int32Array:return Math.max(e/2147483647,-1);case Int16Array:return Math.max(e/32767,-1);case Int8Array:return Math.max(e/127,-1);default:throw new Error("Invalid component type.")}}function Zs(e,t){switch(t.constructor){case Float32Array:return e;case Uint32Array:return Math.round(4294967295*e);case Uint16Array:return Math.round(65535*e);case Uint8Array:return Math.round(255*e);case Int32Array:return Math.round(2147483647*e);case Int16Array:return Math.round(32767*e);case Int8Array:return Math.round(127*e);default:throw new Error("Invalid component type.")}}const Ks={DEG2RAD:Hs,RAD2DEG:js,generateUUID:qs,clamp:$s,euclideanModulo:Xs,mapLinear:function(e,t,s,i,r){return i+(e-t)*(r-i)/(s-t)},inverseLerp:function(e,t,s){return e!==t?(s-e)/(t-e):0},lerp:Ys,damp:function(e,t,s,i){return Ys(e,t,1-Math.exp(-s*i))},pingpong:function(e,t=1){return t-Math.abs(Xs(e,2*t)-t)},smoothstep:function(e,t,s){return e<=t?0:e>=s?1:(e=(e-t)/(s-t))*e*(3-2*e)},smootherstep:function(e,t,s){return e<=t?0:e>=s?1:(e=(e-t)/(s-t))*e*e*(e*(6*e-15)+10)},randInt:function(e,t){return e+Math.floor(Math.random()*(t-e+1))},randFloat:function(e,t){return e+Math.random()*(t-e)},randFloatSpread:function(e){return e*(.5-Math.random())},seededRandom:function(e){void 0!==e&&(Ws=e);let t=Ws+=1831565813;return t=Math.imul(t^t>>>15,1|t),t^=t+Math.imul(t^t>>>7,61|t),((t^t>>>14)>>>0)/4294967296},degToRad:function(e){return e*Hs},radToDeg:function(e){return e*js},isPowerOfTwo:function(e){return 0==(e&e-1)&&0!==e},ceilPowerOfTwo:function(e){return Math.pow(2,Math.ceil(Math.log(e)/Math.LN2))},floorPowerOfTwo:function(e){return Math.pow(2,Math.floor(Math.log(e)/Math.LN2))},setQuaternionFromProperEuler:function(e,t,s,i,r){const n=Math.cos,o=Math.sin,a=n(s/2),h=o(s/2),l=n((t+i)/2),u=o((t+i)/2),c=n((t-i)/2),d=o((t-i)/2),p=n((i-t)/2),m=o((i-t)/2);switch(r){case"XYX":e.set(a*u,h*c,h*d,a*l);break;case"YZY":e.set(h*d,a*u,h*c,a*l);break;case"ZXZ":e.set(h*c,h*d,a*u,a*l);break;case"XZX":e.set(a*u,h*m,h*p,a*l);break;case"YXY":e.set(h*p,a*u,h*m,a*l);break;case"ZYZ":e.set(h*m,h*p,a*u,a*l);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+r)}},normalize:Zs,denormalize:Js};class Qs{constructor(e=0,t=0){Qs.prototype.isVector2=!0,this.x=e,this.y=t}get width(){return this.x}set width(e){this.x=e}get height(){return this.y}set height(e){this.y=e}set(e,t){return this.x=e,this.y=t,this}setScalar(e){return this.x=e,this.y=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}addScalar(e){return this.x+=e,this.y+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this}subScalar(e){return this.x-=e,this.y-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this}multiply(e){return this.x*=e.x,this.y*=e.y,this}multiplyScalar(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e.x,this.y/=e.y,this}divideScalar(e){return this.multiplyScalar(1/e)}applyMatrix3(e){const t=this.x,s=this.y,i=e.elements;return this.x=i[0]*t+i[3]*s+i[6],this.y=i[1]*t+i[4]*s+i[7],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this}clampLength(e,t){const s=this.length();return this.divideScalar(s||1).multiplyScalar(Math.max(e,Math.min(t,s)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(e){return this.x*e.x+this.y*e.y}cross(e){return this.x*e.y-this.y*e.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(0===t)return Math.PI/2;const s=this.dot(e)/t;return Math.acos($s(s,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,s=this.y-e.y;return t*t+s*s}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this}lerpVectors(e,t,s){return this.x=e.x+(t.x-e.x)*s,this.y=e.y+(t.y-e.y)*s,this}equals(e){return e.x===this.x&&e.y===this.y}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this}rotateAround(e,t){const s=Math.cos(t),i=Math.sin(t),r=this.x-e.x,n=this.y-e.y;return this.x=r*s-n*i+e.x,this.y=r*i+n*s+e.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class ei{constructor(e,t,s,i,r,n,o,a,h){ei.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],void 0!==e&&this.set(e,t,s,i,r,n,o,a,h)}set(e,t,s,i,r,n,o,a,h){const l=this.elements;return l[0]=e,l[1]=i,l[2]=o,l[3]=t,l[4]=r,l[5]=a,l[6]=s,l[7]=n,l[8]=h,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(e){const t=this.elements,s=e.elements;return t[0]=s[0],t[1]=s[1],t[2]=s[2],t[3]=s[3],t[4]=s[4],t[5]=s[5],t[6]=s[6],t[7]=s[7],t[8]=s[8],this}extractBasis(e,t,s){return e.setFromMatrix3Column(this,0),t.setFromMatrix3Column(this,1),s.setFromMatrix3Column(this,2),this}setFromMatrix4(e){const t=e.elements;return this.set(t[0],t[4],t[8],t[1],t[5],t[9],t[2],t[6],t[10]),this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const s=e.elements,i=t.elements,r=this.elements,n=s[0],o=s[3],a=s[6],h=s[1],l=s[4],u=s[7],c=s[2],d=s[5],p=s[8],m=i[0],g=i[3],f=i[6],y=i[1],x=i[4],b=i[7],v=i[2],T=i[5],_=i[8];return r[0]=n*m+o*y+a*v,r[3]=n*g+o*x+a*T,r[6]=n*f+o*b+a*_,r[1]=h*m+l*y+u*v,r[4]=h*g+l*x+u*T,r[7]=h*f+l*b+u*_,r[2]=c*m+d*y+p*v,r[5]=c*g+d*x+p*T,r[8]=c*f+d*b+p*_,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[3]*=e,t[6]*=e,t[1]*=e,t[4]*=e,t[7]*=e,t[2]*=e,t[5]*=e,t[8]*=e,this}determinant(){const e=this.elements,t=e[0],s=e[1],i=e[2],r=e[3],n=e[4],o=e[5],a=e[6],h=e[7],l=e[8];return t*n*l-t*o*h-s*r*l+s*o*a+i*r*h-i*n*a}invert(){const e=this.elements,t=e[0],s=e[1],i=e[2],r=e[3],n=e[4],o=e[5],a=e[6],h=e[7],l=e[8],u=l*n-o*h,c=o*a-l*r,d=h*r-n*a,p=t*u+s*c+i*d;if(0===p)return this.set(0,0,0,0,0,0,0,0,0);const m=1/p;return e[0]=u*m,e[1]=(i*h-l*s)*m,e[2]=(o*s-i*n)*m,e[3]=c*m,e[4]=(l*t-i*a)*m,e[5]=(i*r-o*t)*m,e[6]=d*m,e[7]=(s*a-h*t)*m,e[8]=(n*t-s*r)*m,this}transpose(){let e;const t=this.elements;return e=t[1],t[1]=t[3],t[3]=e,e=t[2],t[2]=t[6],t[6]=e,e=t[5],t[5]=t[7],t[7]=e,this}getNormalMatrix(e){return this.setFromMatrix4(e).invert().transpose()}transposeIntoArray(e){const t=this.elements;return e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8],this}setUvTransform(e,t,s,i,r,n,o){const a=Math.cos(r),h=Math.sin(r);return this.set(s*a,s*h,-s*(a*n+h*o)+n+e,-i*h,i*a,-i*(-h*n+a*o)+o+t,0,0,1),this}scale(e,t){return this.premultiply(ti.makeScale(e,t)),this}rotate(e){return this.premultiply(ti.makeRotation(-e)),this}translate(e,t){return this.premultiply(ti.makeTranslation(e,t)),this}makeTranslation(e,t){return e.isVector2?this.set(1,0,e.x,0,1,e.y,0,0,1):this.set(1,0,e,0,1,t,0,0,1),this}makeRotation(e){const t=Math.cos(e),s=Math.sin(e);return this.set(t,-s,0,s,t,0,0,0,1),this}makeScale(e,t){return this.set(e,0,0,0,t,0,0,0,1),this}equals(e){const t=this.elements,s=e.elements;for(let e=0;e<9;e++)if(t[e]!==s[e])return!1;return!0}fromArray(e,t=0){for(let s=0;s<9;s++)this.elements[s]=e[s+t];return this}toArray(e=[],t=0){const s=this.elements;return e[t]=s[0],e[t+1]=s[1],e[t+2]=s[2],e[t+3]=s[3],e[t+4]=s[4],e[t+5]=s[5],e[t+6]=s[6],e[t+7]=s[7],e[t+8]=s[8],e}clone(){return(new this.constructor).fromArray(this.elements)}}const ti=new ei;const si={Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:Uint8ClampedArray,Int16Array:Int16Array,Uint16Array:Uint16Array,Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array};function ii(e,t){return new si[e](t)}function ri(e){return document.createElementNS("http://www.w3.org/1999/xhtml",e)}function ni(){const e=ri("canvas");return e.style.display="block",e}const oi={};function ai(e){e in oi||(oi[e]=!0,console.warn(e))}const hi=(new ei).set(.8224621,.177538,0,.0331941,.9668058,0,.0170827,.0723974,.9105199),li=(new ei).set(1.2249401,-.2249404,0,-.0420569,1.0420571,0,-.0196376,-.0786361,1.0982735),ui={[Zt]:{transfer:es,primaries:ss,luminanceCoefficients:[.2126,.7152,.0722],toReference:e=>e,fromReference:e=>e},[Jt]:{transfer:ts,primaries:ss,luminanceCoefficients:[.2126,.7152,.0722],toReference:e=>e.convertSRGBToLinear(),fromReference:e=>e.convertLinearToSRGB()},[Qt]:{transfer:es,primaries:is,luminanceCoefficients:[.2289,.6917,.0793],toReference:e=>e.applyMatrix3(li),fromReference:e=>e.applyMatrix3(hi)},[Kt]:{transfer:ts,primaries:is,luminanceCoefficients:[.2289,.6917,.0793],toReference:e=>e.convertSRGBToLinear().applyMatrix3(li),fromReference:e=>e.applyMatrix3(hi).convertLinearToSRGB()}},ci=new Set([Zt,Qt]),di={enabled:!0,_workingColorSpace:Zt,get workingColorSpace(){return this._workingColorSpace},set workingColorSpace(e){if(!ci.has(e))throw new Error(`Unsupported working color space, "${e}".`);this._workingColorSpace=e},convert:function(e,t,s){if(!1===this.enabled||t===s||!t||!s)return e;const i=ui[t].toReference;return(0,ui[s].fromReference)(i(e))},fromWorkingColorSpace:function(e,t){return this.convert(e,this._workingColorSpace,t)},toWorkingColorSpace:function(e,t){return this.convert(e,t,this._workingColorSpace)},getPrimaries:function(e){return ui[e].primaries},getTransfer:function(e){return e===Yt?es:ui[e].transfer},getLuminanceCoefficients:function(e,t=this._workingColorSpace){return e.fromArray(ui[t].luminanceCoefficients)}};function pi(e){return e<.04045?.0773993808*e:Math.pow(.9478672986*e+.0521327014,2.4)}function mi(e){return e<.0031308?12.92*e:1.055*Math.pow(e,.41666)-.055}let gi;class fi{static getDataURL(e){if(/^data:/i.test(e.src))return e.src;if("undefined"==typeof HTMLCanvasElement)return e.src;let t;if(e instanceof HTMLCanvasElement)t=e;else{void 0===gi&&(gi=ri("canvas")),gi.width=e.width,gi.height=e.height;const s=gi.getContext("2d");e instanceof ImageData?s.putImageData(e,0,0):s.drawImage(e,0,0,e.width,e.height),t=gi}return t.width>2048||t.height>2048?(console.warn("THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons",e),t.toDataURL("image/jpeg",.6)):t.toDataURL("image/png")}static sRGBToLinear(e){if("undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap){const t=ri("canvas");t.width=e.width,t.height=e.height;const s=t.getContext("2d");s.drawImage(e,0,0,e.width,e.height);const i=s.getImageData(0,0,e.width,e.height),r=i.data;for(let e=0;e0&&(s.userData=this.userData),t||(e.textures[this.uuid]=s),s}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(e){if(this.mapping!==ae)return e;if(e.applyMatrix3(this.matrix),e.x<0||e.x>1)switch(this.wrapS){case pe:e.x=e.x-Math.floor(e.x);break;case me:e.x=e.x<0?0:1;break;case ge:1===Math.abs(Math.floor(e.x)%2)?e.x=Math.ceil(e.x)-e.x:e.x=e.x-Math.floor(e.x)}if(e.y<0||e.y>1)switch(this.wrapT){case pe:e.y=e.y-Math.floor(e.y);break;case me:e.y=e.y<0?0:1;break;case ge:1===Math.abs(Math.floor(e.y)%2)?e.y=Math.ceil(e.y)-e.y:e.y=e.y-Math.floor(e.y)}return this.flipY&&(e.y=1-e.y),e}set needsUpdate(e){!0===e&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(e){!0===e&&this.pmremVersion++}}Ti.DEFAULT_IMAGE=null,Ti.DEFAULT_MAPPING=ae,Ti.DEFAULT_ANISOTROPY=1;class _i{constructor(e=0,t=0,s=0,i=1){_i.prototype.isVector4=!0,this.x=e,this.y=t,this.z=s,this.w=i}get width(){return this.z}set width(e){this.z=e}get height(){return this.w}set height(e){this.w=e}set(e,t,s,i){return this.x=e,this.y=t,this.z=s,this.w=i,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this.w=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setW(e){return this.w=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;case 3:this.w=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=void 0!==e.w?e.w:1,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this.w+=e.w,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this.w+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this.w=e.w+t.w,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this.w+=e.w*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this.w-=e.w,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this.w-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this.w=e.w-t.w,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this.w*=e.w,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this.w*=e,this}applyMatrix4(e){const t=this.x,s=this.y,i=this.z,r=this.w,n=e.elements;return this.x=n[0]*t+n[4]*s+n[8]*i+n[12]*r,this.y=n[1]*t+n[5]*s+n[9]*i+n[13]*r,this.z=n[2]*t+n[6]*s+n[10]*i+n[14]*r,this.w=n[3]*t+n[7]*s+n[11]*i+n[15]*r,this}divideScalar(e){return this.multiplyScalar(1/e)}setAxisAngleFromQuaternion(e){this.w=2*Math.acos(e.w);const t=Math.sqrt(1-e.w*e.w);return t<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=e.x/t,this.y=e.y/t,this.z=e.z/t),this}setAxisAngleFromRotationMatrix(e){let t,s,i,r;const n=.01,o=.1,a=e.elements,h=a[0],l=a[4],u=a[8],c=a[1],d=a[5],p=a[9],m=a[2],g=a[6],f=a[10];if(Math.abs(l-c)a&&e>y?ey?a=0?1:-1,i=1-t*t;if(i>Number.EPSILON){const r=Math.sqrt(i),n=Math.atan2(r,t*s);e=Math.sin(e*n)/r,o=Math.sin(o*n)/r}const r=o*s;if(a=a*e+c*r,h=h*e+d*r,l=l*e+p*r,u=u*e+m*r,e===1-o){const e=1/Math.sqrt(a*a+h*h+l*l+u*u);a*=e,h*=e,l*=e,u*=e}}e[t]=a,e[t+1]=h,e[t+2]=l,e[t+3]=u}static multiplyQuaternionsFlat(e,t,s,i,r,n){const o=s[i],a=s[i+1],h=s[i+2],l=s[i+3],u=r[n],c=r[n+1],d=r[n+2],p=r[n+3];return e[t]=o*p+l*u+a*d-h*c,e[t+1]=a*p+l*c+h*u-o*d,e[t+2]=h*p+l*d+o*c-a*u,e[t+3]=l*p-o*u-a*c-h*d,e}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get w(){return this._w}set w(e){this._w=e,this._onChangeCallback()}set(e,t,s,i){return this._x=e,this._y=t,this._z=s,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(e){return this._x=e.x,this._y=e.y,this._z=e.z,this._w=e.w,this._onChangeCallback(),this}setFromEuler(e,t=!0){const s=e._x,i=e._y,r=e._z,n=e._order,o=Math.cos,a=Math.sin,h=o(s/2),l=o(i/2),u=o(r/2),c=a(s/2),d=a(i/2),p=a(r/2);switch(n){case"XYZ":this._x=c*l*u+h*d*p,this._y=h*d*u-c*l*p,this._z=h*l*p+c*d*u,this._w=h*l*u-c*d*p;break;case"YXZ":this._x=c*l*u+h*d*p,this._y=h*d*u-c*l*p,this._z=h*l*p-c*d*u,this._w=h*l*u+c*d*p;break;case"ZXY":this._x=c*l*u-h*d*p,this._y=h*d*u+c*l*p,this._z=h*l*p+c*d*u,this._w=h*l*u-c*d*p;break;case"ZYX":this._x=c*l*u-h*d*p,this._y=h*d*u+c*l*p,this._z=h*l*p-c*d*u,this._w=h*l*u+c*d*p;break;case"YZX":this._x=c*l*u+h*d*p,this._y=h*d*u+c*l*p,this._z=h*l*p-c*d*u,this._w=h*l*u-c*d*p;break;case"XZY":this._x=c*l*u-h*d*p,this._y=h*d*u-c*l*p,this._z=h*l*p+c*d*u,this._w=h*l*u+c*d*p;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+n)}return!0===t&&this._onChangeCallback(),this}setFromAxisAngle(e,t){const s=t/2,i=Math.sin(s);return this._x=e.x*i,this._y=e.y*i,this._z=e.z*i,this._w=Math.cos(s),this._onChangeCallback(),this}setFromRotationMatrix(e){const t=e.elements,s=t[0],i=t[4],r=t[8],n=t[1],o=t[5],a=t[9],h=t[2],l=t[6],u=t[10],c=s+o+u;if(c>0){const e=.5/Math.sqrt(c+1);this._w=.25/e,this._x=(l-a)*e,this._y=(r-h)*e,this._z=(n-i)*e}else if(s>o&&s>u){const e=2*Math.sqrt(1+s-o-u);this._w=(l-a)/e,this._x=.25*e,this._y=(i+n)/e,this._z=(r+h)/e}else if(o>u){const e=2*Math.sqrt(1+o-s-u);this._w=(r-h)/e,this._x=(i+n)/e,this._y=.25*e,this._z=(a+l)/e}else{const e=2*Math.sqrt(1+u-s-o);this._w=(n-i)/e,this._x=(r+h)/e,this._y=(a+l)/e,this._z=.25*e}return this._onChangeCallback(),this}setFromUnitVectors(e,t){let s=e.dot(t)+1;return sMath.abs(e.z)?(this._x=-e.y,this._y=e.x,this._z=0,this._w=s):(this._x=0,this._y=-e.z,this._z=e.y,this._w=s)):(this._x=e.y*t.z-e.z*t.y,this._y=e.z*t.x-e.x*t.z,this._z=e.x*t.y-e.y*t.x,this._w=s),this.normalize()}angleTo(e){return 2*Math.acos(Math.abs($s(this.dot(e),-1,1)))}rotateTowards(e,t){const s=this.angleTo(e);if(0===s)return this;const i=Math.min(1,t/s);return this.slerp(e,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(e){return this._x*e._x+this._y*e._y+this._z*e._z+this._w*e._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let e=this.length();return 0===e?(this._x=0,this._y=0,this._z=0,this._w=1):(e=1/e,this._x=this._x*e,this._y=this._y*e,this._z=this._z*e,this._w=this._w*e),this._onChangeCallback(),this}multiply(e){return this.multiplyQuaternions(this,e)}premultiply(e){return this.multiplyQuaternions(e,this)}multiplyQuaternions(e,t){const s=e._x,i=e._y,r=e._z,n=e._w,o=t._x,a=t._y,h=t._z,l=t._w;return this._x=s*l+n*o+i*h-r*a,this._y=i*l+n*a+r*o-s*h,this._z=r*l+n*h+s*a-i*o,this._w=n*l-s*o-i*a-r*h,this._onChangeCallback(),this}slerp(e,t){if(0===t)return this;if(1===t)return this.copy(e);const s=this._x,i=this._y,r=this._z,n=this._w;let o=n*e._w+s*e._x+i*e._y+r*e._z;if(o<0?(this._w=-e._w,this._x=-e._x,this._y=-e._y,this._z=-e._z,o=-o):this.copy(e),o>=1)return this._w=n,this._x=s,this._y=i,this._z=r,this;const a=1-o*o;if(a<=Number.EPSILON){const e=1-t;return this._w=e*n+t*this._w,this._x=e*s+t*this._x,this._y=e*i+t*this._y,this._z=e*r+t*this._z,this.normalize(),this}const h=Math.sqrt(a),l=Math.atan2(h,o),u=Math.sin((1-t)*l)/h,c=Math.sin(t*l)/h;return this._w=n*u+this._w*c,this._x=s*u+this._x*c,this._y=i*u+this._y*c,this._z=r*u+this._z*c,this._onChangeCallback(),this}slerpQuaternions(e,t,s){return this.copy(e).slerp(t,s)}random(){const e=2*Math.PI*Math.random(),t=2*Math.PI*Math.random(),s=Math.random(),i=Math.sqrt(1-s),r=Math.sqrt(s);return this.set(i*Math.sin(e),i*Math.cos(e),r*Math.sin(t),r*Math.cos(t))}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._w===this._w}fromArray(e,t=0){return this._x=e[t],this._y=e[t+1],this._z=e[t+2],this._w=e[t+3],this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._w,e}fromBufferAttribute(e,t){return this._x=e.getX(t),this._y=e.getY(t),this._z=e.getZ(t),this._w=e.getW(t),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}class Ei{constructor(e=0,t=0,s=0){Ei.prototype.isVector3=!0,this.x=e,this.y=t,this.z=s}set(e,t,s){return void 0===s&&(s=this.z),this.x=e,this.y=t,this.z=s,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this}multiplyVectors(e,t){return this.x=e.x*t.x,this.y=e.y*t.y,this.z=e.z*t.z,this}applyEuler(e){return this.applyQuaternion(Ii.setFromEuler(e))}applyAxisAngle(e,t){return this.applyQuaternion(Ii.setFromAxisAngle(e,t))}applyMatrix3(e){const t=this.x,s=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[3]*s+r[6]*i,this.y=r[1]*t+r[4]*s+r[7]*i,this.z=r[2]*t+r[5]*s+r[8]*i,this}applyNormalMatrix(e){return this.applyMatrix3(e).normalize()}applyMatrix4(e){const t=this.x,s=this.y,i=this.z,r=e.elements,n=1/(r[3]*t+r[7]*s+r[11]*i+r[15]);return this.x=(r[0]*t+r[4]*s+r[8]*i+r[12])*n,this.y=(r[1]*t+r[5]*s+r[9]*i+r[13])*n,this.z=(r[2]*t+r[6]*s+r[10]*i+r[14])*n,this}applyQuaternion(e){const t=this.x,s=this.y,i=this.z,r=e.x,n=e.y,o=e.z,a=e.w,h=2*(n*i-o*s),l=2*(o*t-r*i),u=2*(r*s-n*t);return this.x=t+a*h+n*u-o*l,this.y=s+a*l+o*h-r*u,this.z=i+a*u+r*l-n*h,this}project(e){return this.applyMatrix4(e.matrixWorldInverse).applyMatrix4(e.projectionMatrix)}unproject(e){return this.applyMatrix4(e.projectionMatrixInverse).applyMatrix4(e.matrixWorld)}transformDirection(e){const t=this.x,s=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[4]*s+r[8]*i,this.y=r[1]*t+r[5]*s+r[9]*i,this.z=r[2]*t+r[6]*s+r[10]*i,this.normalize()}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this}divideScalar(e){return this.multiplyScalar(1/e)}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this.z=Math.max(e,Math.min(t,this.z)),this}clampLength(e,t){const s=this.length();return this.divideScalar(s||1).multiplyScalar(Math.max(e,Math.min(t,s)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this}lerpVectors(e,t,s){return this.x=e.x+(t.x-e.x)*s,this.y=e.y+(t.y-e.y)*s,this.z=e.z+(t.z-e.z)*s,this}cross(e){return this.crossVectors(this,e)}crossVectors(e,t){const s=e.x,i=e.y,r=e.z,n=t.x,o=t.y,a=t.z;return this.x=i*a-r*o,this.y=r*n-s*a,this.z=s*o-i*n,this}projectOnVector(e){const t=e.lengthSq();if(0===t)return this.set(0,0,0);const s=e.dot(this)/t;return this.copy(e).multiplyScalar(s)}projectOnPlane(e){return Bi.copy(this).projectOnVector(e),this.sub(Bi)}reflect(e){return this.sub(Bi.copy(e).multiplyScalar(2*this.dot(e)))}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(0===t)return Math.PI/2;const s=this.dot(e)/t;return Math.acos($s(s,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,s=this.y-e.y,i=this.z-e.z;return t*t+s*s+i*i}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)+Math.abs(this.z-e.z)}setFromSpherical(e){return this.setFromSphericalCoords(e.radius,e.phi,e.theta)}setFromSphericalCoords(e,t,s){const i=Math.sin(t)*e;return this.x=i*Math.sin(s),this.y=Math.cos(t)*e,this.z=i*Math.cos(s),this}setFromCylindrical(e){return this.setFromCylindricalCoords(e.radius,e.theta,e.y)}setFromCylindricalCoords(e,t,s){return this.x=e*Math.sin(t),this.y=s,this.z=e*Math.cos(t),this}setFromMatrixPosition(e){const t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this}setFromMatrixScale(e){const t=this.setFromMatrixColumn(e,0).length(),s=this.setFromMatrixColumn(e,1).length(),i=this.setFromMatrixColumn(e,2).length();return this.x=t,this.y=s,this.z=i,this}setFromMatrixColumn(e,t){return this.fromArray(e.elements,4*t)}setFromMatrix3Column(e,t){return this.fromArray(e.elements,3*t)}setFromEuler(e){return this.x=e._x,this.y=e._y,this.z=e._z,this}setFromColor(e){return this.x=e.r,this.y=e.g,this.z=e.b,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const e=Math.random()*Math.PI*2,t=2*Math.random()-1,s=Math.sqrt(1-t*t);return this.x=s*Math.cos(e),this.y=t,this.z=s*Math.sin(e),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const Bi=new Ei,Ii=new Ci;class Pi{constructor(e=new Ei(1/0,1/0,1/0),t=new Ei(-1/0,-1/0,-1/0)){this.isBox3=!0,this.min=e,this.max=t}set(e,t){return this.min.copy(e),this.max.copy(t),this}setFromArray(e){this.makeEmpty();for(let t=0,s=e.length;t=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y&&e.z>=this.min.z&&e.z<=this.max.z}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y),(e.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y&&e.max.z>=this.min.z&&e.min.z<=this.max.z}intersectsSphere(e){return this.clampPoint(e.center,zi),zi.distanceToSquared(e.center)<=e.radius*e.radius}intersectsPlane(e){let t,s;return e.normal.x>0?(t=e.normal.x*this.min.x,s=e.normal.x*this.max.x):(t=e.normal.x*this.max.x,s=e.normal.x*this.min.x),e.normal.y>0?(t+=e.normal.y*this.min.y,s+=e.normal.y*this.max.y):(t+=e.normal.y*this.max.y,s+=e.normal.y*this.min.y),e.normal.z>0?(t+=e.normal.z*this.min.z,s+=e.normal.z*this.max.z):(t+=e.normal.z*this.max.z,s+=e.normal.z*this.min.z),t<=-e.constant&&s>=-e.constant}intersectsTriangle(e){if(this.isEmpty())return!1;this.getCenter(Wi),Hi.subVectors(this.max,Wi),Li.subVectors(e.a,Wi),Oi.subVectors(e.b,Wi),Vi.subVectors(e.c,Wi),Di.subVectors(Oi,Li),ki.subVectors(Vi,Oi),Gi.subVectors(Li,Vi);let t=[0,-Di.z,Di.y,0,-ki.z,ki.y,0,-Gi.z,Gi.y,Di.z,0,-Di.x,ki.z,0,-ki.x,Gi.z,0,-Gi.x,-Di.y,Di.x,0,-ki.y,ki.x,0,-Gi.y,Gi.x,0];return!!$i(t,Li,Oi,Vi,Hi)&&(t=[1,0,0,0,1,0,0,0,1],!!$i(t,Li,Oi,Vi,Hi)&&(ji.crossVectors(Di,ki),t=[ji.x,ji.y,ji.z],$i(t,Li,Oi,Vi,Hi)))}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,zi).distanceTo(e)}getBoundingSphere(e){return this.isEmpty()?e.makeEmpty():(this.getCenter(e.center),e.radius=.5*this.getSize(zi).length()),e}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}applyMatrix4(e){return this.isEmpty()||(Fi[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(e),Fi[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(e),Fi[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(e),Fi[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(e),Fi[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(e),Fi[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(e),Fi[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(e),Fi[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(e),this.setFromPoints(Fi)),this}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}const Fi=[new Ei,new Ei,new Ei,new Ei,new Ei,new Ei,new Ei,new Ei],zi=new Ei,Ui=new Pi,Li=new Ei,Oi=new Ei,Vi=new Ei,Di=new Ei,ki=new Ei,Gi=new Ei,Wi=new Ei,Hi=new Ei,ji=new Ei,qi=new Ei;function $i(e,t,s,i,r){for(let n=0,o=e.length-3;n<=o;n+=3){qi.fromArray(e,n);const o=r.x*Math.abs(qi.x)+r.y*Math.abs(qi.y)+r.z*Math.abs(qi.z),a=t.dot(qi),h=s.dot(qi),l=i.dot(qi);if(Math.max(-Math.max(a,h,l),Math.min(a,h,l))>o)return!1}return!0}const Xi=new Pi,Yi=new Ei,Ji=new Ei;class Zi{constructor(e=new Ei,t=-1){this.isSphere=!0,this.center=e,this.radius=t}set(e,t){return this.center.copy(e),this.radius=t,this}setFromPoints(e,t){const s=this.center;void 0!==t?s.copy(t):Xi.setFromPoints(e).getCenter(s);let i=0;for(let t=0,r=e.length;tthis.radius*this.radius&&(t.sub(this.center).normalize(),t.multiplyScalar(this.radius).add(this.center)),t}getBoundingBox(e){return this.isEmpty()?(e.makeEmpty(),e):(e.set(this.center,this.center),e.expandByScalar(this.radius),e)}applyMatrix4(e){return this.center.applyMatrix4(e),this.radius=this.radius*e.getMaxScaleOnAxis(),this}translate(e){return this.center.add(e),this}expandByPoint(e){if(this.isEmpty())return this.center.copy(e),this.radius=0,this;Yi.subVectors(e,this.center);const t=Yi.lengthSq();if(t>this.radius*this.radius){const e=Math.sqrt(t),s=.5*(e-this.radius);this.center.addScaledVector(Yi,s/e),this.radius+=s}return this}union(e){return e.isEmpty()?this:this.isEmpty()?(this.copy(e),this):(!0===this.center.equals(e.center)?this.radius=Math.max(this.radius,e.radius):(Ji.subVectors(e.center,this.center).setLength(e.radius),this.expandByPoint(Yi.copy(e.center).add(Ji)),this.expandByPoint(Yi.copy(e.center).sub(Ji))),this)}equals(e){return e.center.equals(this.center)&&e.radius===this.radius}clone(){return(new this.constructor).copy(this)}}const Ki=new Ei,Qi=new Ei,er=new Ei,tr=new Ei,sr=new Ei,ir=new Ei,rr=new Ei;class nr{constructor(e=new Ei,t=new Ei(0,0,-1)){this.origin=e,this.direction=t}set(e,t){return this.origin.copy(e),this.direction.copy(t),this}copy(e){return this.origin.copy(e.origin),this.direction.copy(e.direction),this}at(e,t){return t.copy(this.origin).addScaledVector(this.direction,e)}lookAt(e){return this.direction.copy(e).sub(this.origin).normalize(),this}recast(e){return this.origin.copy(this.at(e,Ki)),this}closestPointToPoint(e,t){t.subVectors(e,this.origin);const s=t.dot(this.direction);return s<0?t.copy(this.origin):t.copy(this.origin).addScaledVector(this.direction,s)}distanceToPoint(e){return Math.sqrt(this.distanceSqToPoint(e))}distanceSqToPoint(e){const t=Ki.subVectors(e,this.origin).dot(this.direction);return t<0?this.origin.distanceToSquared(e):(Ki.copy(this.origin).addScaledVector(this.direction,t),Ki.distanceToSquared(e))}distanceSqToSegment(e,t,s,i){Qi.copy(e).add(t).multiplyScalar(.5),er.copy(t).sub(e).normalize(),tr.copy(this.origin).sub(Qi);const r=.5*e.distanceTo(t),n=-this.direction.dot(er),o=tr.dot(this.direction),a=-tr.dot(er),h=tr.lengthSq(),l=Math.abs(1-n*n);let u,c,d,p;if(l>0)if(u=n*a-o,c=n*o-a,p=r*l,u>=0)if(c>=-p)if(c<=p){const e=1/l;u*=e,c*=e,d=u*(u+n*c+2*o)+c*(n*u+c+2*a)+h}else c=r,u=Math.max(0,-(n*c+o)),d=-u*u+c*(c+2*a)+h;else c=-r,u=Math.max(0,-(n*c+o)),d=-u*u+c*(c+2*a)+h;else c<=-p?(u=Math.max(0,-(-n*r+o)),c=u>0?-r:Math.min(Math.max(-r,-a),r),d=-u*u+c*(c+2*a)+h):c<=p?(u=0,c=Math.min(Math.max(-r,-a),r),d=c*(c+2*a)+h):(u=Math.max(0,-(n*r+o)),c=u>0?r:Math.min(Math.max(-r,-a),r),d=-u*u+c*(c+2*a)+h);else c=n>0?-r:r,u=Math.max(0,-(n*c+o)),d=-u*u+c*(c+2*a)+h;return s&&s.copy(this.origin).addScaledVector(this.direction,u),i&&i.copy(Qi).addScaledVector(er,c),d}intersectSphere(e,t){Ki.subVectors(e.center,this.origin);const s=Ki.dot(this.direction),i=Ki.dot(Ki)-s*s,r=e.radius*e.radius;if(i>r)return null;const n=Math.sqrt(r-i),o=s-n,a=s+n;return a<0?null:o<0?this.at(a,t):this.at(o,t)}intersectsSphere(e){return this.distanceSqToPoint(e.center)<=e.radius*e.radius}distanceToPlane(e){const t=e.normal.dot(this.direction);if(0===t)return 0===e.distanceToPoint(this.origin)?0:null;const s=-(this.origin.dot(e.normal)+e.constant)/t;return s>=0?s:null}intersectPlane(e,t){const s=this.distanceToPlane(e);return null===s?null:this.at(s,t)}intersectsPlane(e){const t=e.distanceToPoint(this.origin);if(0===t)return!0;return e.normal.dot(this.direction)*t<0}intersectBox(e,t){let s,i,r,n,o,a;const h=1/this.direction.x,l=1/this.direction.y,u=1/this.direction.z,c=this.origin;return h>=0?(s=(e.min.x-c.x)*h,i=(e.max.x-c.x)*h):(s=(e.max.x-c.x)*h,i=(e.min.x-c.x)*h),l>=0?(r=(e.min.y-c.y)*l,n=(e.max.y-c.y)*l):(r=(e.max.y-c.y)*l,n=(e.min.y-c.y)*l),s>n||r>i?null:((r>s||isNaN(s))&&(s=r),(n=0?(o=(e.min.z-c.z)*u,a=(e.max.z-c.z)*u):(o=(e.max.z-c.z)*u,a=(e.min.z-c.z)*u),s>a||o>i?null:((o>s||s!=s)&&(s=o),(a=0?s:i,t)))}intersectsBox(e){return null!==this.intersectBox(e,Ki)}intersectTriangle(e,t,s,i,r){sr.subVectors(t,e),ir.subVectors(s,e),rr.crossVectors(sr,ir);let n,o=this.direction.dot(rr);if(o>0){if(i)return null;n=1}else{if(!(o<0))return null;n=-1,o=-o}tr.subVectors(this.origin,e);const a=n*this.direction.dot(ir.crossVectors(tr,ir));if(a<0)return null;const h=n*this.direction.dot(sr.cross(tr));if(h<0)return null;if(a+h>o)return null;const l=-n*tr.dot(rr);return l<0?null:this.at(l/o,r)}applyMatrix4(e){return this.origin.applyMatrix4(e),this.direction.transformDirection(e),this}equals(e){return e.origin.equals(this.origin)&&e.direction.equals(this.direction)}clone(){return(new this.constructor).copy(this)}}class or{constructor(e,t,s,i,r,n,o,a,h,l,u,c,d,p,m,g){or.prototype.isMatrix4=!0,this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],void 0!==e&&this.set(e,t,s,i,r,n,o,a,h,l,u,c,d,p,m,g)}set(e,t,s,i,r,n,o,a,h,l,u,c,d,p,m,g){const f=this.elements;return f[0]=e,f[4]=t,f[8]=s,f[12]=i,f[1]=r,f[5]=n,f[9]=o,f[13]=a,f[2]=h,f[6]=l,f[10]=u,f[14]=c,f[3]=d,f[7]=p,f[11]=m,f[15]=g,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return(new or).fromArray(this.elements)}copy(e){const t=this.elements,s=e.elements;return t[0]=s[0],t[1]=s[1],t[2]=s[2],t[3]=s[3],t[4]=s[4],t[5]=s[5],t[6]=s[6],t[7]=s[7],t[8]=s[8],t[9]=s[9],t[10]=s[10],t[11]=s[11],t[12]=s[12],t[13]=s[13],t[14]=s[14],t[15]=s[15],this}copyPosition(e){const t=this.elements,s=e.elements;return t[12]=s[12],t[13]=s[13],t[14]=s[14],this}setFromMatrix3(e){const t=e.elements;return this.set(t[0],t[3],t[6],0,t[1],t[4],t[7],0,t[2],t[5],t[8],0,0,0,0,1),this}extractBasis(e,t,s){return e.setFromMatrixColumn(this,0),t.setFromMatrixColumn(this,1),s.setFromMatrixColumn(this,2),this}makeBasis(e,t,s){return this.set(e.x,t.x,s.x,0,e.y,t.y,s.y,0,e.z,t.z,s.z,0,0,0,0,1),this}extractRotation(e){const t=this.elements,s=e.elements,i=1/ar.setFromMatrixColumn(e,0).length(),r=1/ar.setFromMatrixColumn(e,1).length(),n=1/ar.setFromMatrixColumn(e,2).length();return t[0]=s[0]*i,t[1]=s[1]*i,t[2]=s[2]*i,t[3]=0,t[4]=s[4]*r,t[5]=s[5]*r,t[6]=s[6]*r,t[7]=0,t[8]=s[8]*n,t[9]=s[9]*n,t[10]=s[10]*n,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromEuler(e){const t=this.elements,s=e.x,i=e.y,r=e.z,n=Math.cos(s),o=Math.sin(s),a=Math.cos(i),h=Math.sin(i),l=Math.cos(r),u=Math.sin(r);if("XYZ"===e.order){const e=n*l,s=n*u,i=o*l,r=o*u;t[0]=a*l,t[4]=-a*u,t[8]=h,t[1]=s+i*h,t[5]=e-r*h,t[9]=-o*a,t[2]=r-e*h,t[6]=i+s*h,t[10]=n*a}else if("YXZ"===e.order){const e=a*l,s=a*u,i=h*l,r=h*u;t[0]=e+r*o,t[4]=i*o-s,t[8]=n*h,t[1]=n*u,t[5]=n*l,t[9]=-o,t[2]=s*o-i,t[6]=r+e*o,t[10]=n*a}else if("ZXY"===e.order){const e=a*l,s=a*u,i=h*l,r=h*u;t[0]=e-r*o,t[4]=-n*u,t[8]=i+s*o,t[1]=s+i*o,t[5]=n*l,t[9]=r-e*o,t[2]=-n*h,t[6]=o,t[10]=n*a}else if("ZYX"===e.order){const e=n*l,s=n*u,i=o*l,r=o*u;t[0]=a*l,t[4]=i*h-s,t[8]=e*h+r,t[1]=a*u,t[5]=r*h+e,t[9]=s*h-i,t[2]=-h,t[6]=o*a,t[10]=n*a}else if("YZX"===e.order){const e=n*a,s=n*h,i=o*a,r=o*h;t[0]=a*l,t[4]=r-e*u,t[8]=i*u+s,t[1]=u,t[5]=n*l,t[9]=-o*l,t[2]=-h*l,t[6]=s*u+i,t[10]=e-r*u}else if("XZY"===e.order){const e=n*a,s=n*h,i=o*a,r=o*h;t[0]=a*l,t[4]=-u,t[8]=h*l,t[1]=e*u+r,t[5]=n*l,t[9]=s*u-i,t[2]=i*u-s,t[6]=o*l,t[10]=r*u+e}return t[3]=0,t[7]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromQuaternion(e){return this.compose(lr,e,ur)}lookAt(e,t,s){const i=this.elements;return pr.subVectors(e,t),0===pr.lengthSq()&&(pr.z=1),pr.normalize(),cr.crossVectors(s,pr),0===cr.lengthSq()&&(1===Math.abs(s.z)?pr.x+=1e-4:pr.z+=1e-4,pr.normalize(),cr.crossVectors(s,pr)),cr.normalize(),dr.crossVectors(pr,cr),i[0]=cr.x,i[4]=dr.x,i[8]=pr.x,i[1]=cr.y,i[5]=dr.y,i[9]=pr.y,i[2]=cr.z,i[6]=dr.z,i[10]=pr.z,this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const s=e.elements,i=t.elements,r=this.elements,n=s[0],o=s[4],a=s[8],h=s[12],l=s[1],u=s[5],c=s[9],d=s[13],p=s[2],m=s[6],g=s[10],f=s[14],y=s[3],x=s[7],b=s[11],v=s[15],T=i[0],_=i[4],w=i[8],S=i[12],M=i[1],A=i[5],N=i[9],R=i[13],C=i[2],E=i[6],B=i[10],I=i[14],P=i[3],F=i[7],z=i[11],U=i[15];return r[0]=n*T+o*M+a*C+h*P,r[4]=n*_+o*A+a*E+h*F,r[8]=n*w+o*N+a*B+h*z,r[12]=n*S+o*R+a*I+h*U,r[1]=l*T+u*M+c*C+d*P,r[5]=l*_+u*A+c*E+d*F,r[9]=l*w+u*N+c*B+d*z,r[13]=l*S+u*R+c*I+d*U,r[2]=p*T+m*M+g*C+f*P,r[6]=p*_+m*A+g*E+f*F,r[10]=p*w+m*N+g*B+f*z,r[14]=p*S+m*R+g*I+f*U,r[3]=y*T+x*M+b*C+v*P,r[7]=y*_+x*A+b*E+v*F,r[11]=y*w+x*N+b*B+v*z,r[15]=y*S+x*R+b*I+v*U,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[4]*=e,t[8]*=e,t[12]*=e,t[1]*=e,t[5]*=e,t[9]*=e,t[13]*=e,t[2]*=e,t[6]*=e,t[10]*=e,t[14]*=e,t[3]*=e,t[7]*=e,t[11]*=e,t[15]*=e,this}determinant(){const e=this.elements,t=e[0],s=e[4],i=e[8],r=e[12],n=e[1],o=e[5],a=e[9],h=e[13],l=e[2],u=e[6],c=e[10],d=e[14];return e[3]*(+r*a*u-i*h*u-r*o*c+s*h*c+i*o*d-s*a*d)+e[7]*(+t*a*d-t*h*c+r*n*c-i*n*d+i*h*l-r*a*l)+e[11]*(+t*h*u-t*o*d-r*n*u+s*n*d+r*o*l-s*h*l)+e[15]*(-i*o*l-t*a*u+t*o*c+i*n*u-s*n*c+s*a*l)}transpose(){const e=this.elements;let t;return t=e[1],e[1]=e[4],e[4]=t,t=e[2],e[2]=e[8],e[8]=t,t=e[6],e[6]=e[9],e[9]=t,t=e[3],e[3]=e[12],e[12]=t,t=e[7],e[7]=e[13],e[13]=t,t=e[11],e[11]=e[14],e[14]=t,this}setPosition(e,t,s){const i=this.elements;return e.isVector3?(i[12]=e.x,i[13]=e.y,i[14]=e.z):(i[12]=e,i[13]=t,i[14]=s),this}invert(){const e=this.elements,t=e[0],s=e[1],i=e[2],r=e[3],n=e[4],o=e[5],a=e[6],h=e[7],l=e[8],u=e[9],c=e[10],d=e[11],p=e[12],m=e[13],g=e[14],f=e[15],y=u*g*h-m*c*h+m*a*d-o*g*d-u*a*f+o*c*f,x=p*c*h-l*g*h-p*a*d+n*g*d+l*a*f-n*c*f,b=l*m*h-p*u*h+p*o*d-n*m*d-l*o*f+n*u*f,v=p*u*a-l*m*a-p*o*c+n*m*c+l*o*g-n*u*g,T=t*y+s*x+i*b+r*v;if(0===T)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const _=1/T;return e[0]=y*_,e[1]=(m*c*r-u*g*r-m*i*d+s*g*d+u*i*f-s*c*f)*_,e[2]=(o*g*r-m*a*r+m*i*h-s*g*h-o*i*f+s*a*f)*_,e[3]=(u*a*r-o*c*r-u*i*h+s*c*h+o*i*d-s*a*d)*_,e[4]=x*_,e[5]=(l*g*r-p*c*r+p*i*d-t*g*d-l*i*f+t*c*f)*_,e[6]=(p*a*r-n*g*r-p*i*h+t*g*h+n*i*f-t*a*f)*_,e[7]=(n*c*r-l*a*r+l*i*h-t*c*h-n*i*d+t*a*d)*_,e[8]=b*_,e[9]=(p*u*r-l*m*r-p*s*d+t*m*d+l*s*f-t*u*f)*_,e[10]=(n*m*r-p*o*r+p*s*h-t*m*h-n*s*f+t*o*f)*_,e[11]=(l*o*r-n*u*r-l*s*h+t*u*h+n*s*d-t*o*d)*_,e[12]=v*_,e[13]=(l*m*i-p*u*i+p*s*c-t*m*c-l*s*g+t*u*g)*_,e[14]=(p*o*i-n*m*i-p*s*a+t*m*a+n*s*g-t*o*g)*_,e[15]=(n*u*i-l*o*i+l*s*a-t*u*a-n*s*c+t*o*c)*_,this}scale(e){const t=this.elements,s=e.x,i=e.y,r=e.z;return t[0]*=s,t[4]*=i,t[8]*=r,t[1]*=s,t[5]*=i,t[9]*=r,t[2]*=s,t[6]*=i,t[10]*=r,t[3]*=s,t[7]*=i,t[11]*=r,this}getMaxScaleOnAxis(){const e=this.elements,t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2],s=e[4]*e[4]+e[5]*e[5]+e[6]*e[6],i=e[8]*e[8]+e[9]*e[9]+e[10]*e[10];return Math.sqrt(Math.max(t,s,i))}makeTranslation(e,t,s){return e.isVector3?this.set(1,0,0,e.x,0,1,0,e.y,0,0,1,e.z,0,0,0,1):this.set(1,0,0,e,0,1,0,t,0,0,1,s,0,0,0,1),this}makeRotationX(e){const t=Math.cos(e),s=Math.sin(e);return this.set(1,0,0,0,0,t,-s,0,0,s,t,0,0,0,0,1),this}makeRotationY(e){const t=Math.cos(e),s=Math.sin(e);return this.set(t,0,s,0,0,1,0,0,-s,0,t,0,0,0,0,1),this}makeRotationZ(e){const t=Math.cos(e),s=Math.sin(e);return this.set(t,-s,0,0,s,t,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(e,t){const s=Math.cos(t),i=Math.sin(t),r=1-s,n=e.x,o=e.y,a=e.z,h=r*n,l=r*o;return this.set(h*n+s,h*o-i*a,h*a+i*o,0,h*o+i*a,l*o+s,l*a-i*n,0,h*a-i*o,l*a+i*n,r*a*a+s,0,0,0,0,1),this}makeScale(e,t,s){return this.set(e,0,0,0,0,t,0,0,0,0,s,0,0,0,0,1),this}makeShear(e,t,s,i,r,n){return this.set(1,s,r,0,e,1,n,0,t,i,1,0,0,0,0,1),this}compose(e,t,s){const i=this.elements,r=t._x,n=t._y,o=t._z,a=t._w,h=r+r,l=n+n,u=o+o,c=r*h,d=r*l,p=r*u,m=n*l,g=n*u,f=o*u,y=a*h,x=a*l,b=a*u,v=s.x,T=s.y,_=s.z;return i[0]=(1-(m+f))*v,i[1]=(d+b)*v,i[2]=(p-x)*v,i[3]=0,i[4]=(d-b)*T,i[5]=(1-(c+f))*T,i[6]=(g+y)*T,i[7]=0,i[8]=(p+x)*_,i[9]=(g-y)*_,i[10]=(1-(c+m))*_,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,this}decompose(e,t,s){const i=this.elements;let r=ar.set(i[0],i[1],i[2]).length();const n=ar.set(i[4],i[5],i[6]).length(),o=ar.set(i[8],i[9],i[10]).length();this.determinant()<0&&(r=-r),e.x=i[12],e.y=i[13],e.z=i[14],hr.copy(this);const a=1/r,h=1/n,l=1/o;return hr.elements[0]*=a,hr.elements[1]*=a,hr.elements[2]*=a,hr.elements[4]*=h,hr.elements[5]*=h,hr.elements[6]*=h,hr.elements[8]*=l,hr.elements[9]*=l,hr.elements[10]*=l,t.setFromRotationMatrix(hr),s.x=r,s.y=n,s.z=o,this}makePerspective(e,t,s,i,r,n,o=2e3){const a=this.elements,h=2*r/(t-e),l=2*r/(s-i),u=(t+e)/(t-e),c=(s+i)/(s-i);let d,p;if(o===Vs)d=-(n+r)/(n-r),p=-2*n*r/(n-r);else{if(o!==Ds)throw new Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: "+o);d=-n/(n-r),p=-n*r/(n-r)}return a[0]=h,a[4]=0,a[8]=u,a[12]=0,a[1]=0,a[5]=l,a[9]=c,a[13]=0,a[2]=0,a[6]=0,a[10]=d,a[14]=p,a[3]=0,a[7]=0,a[11]=-1,a[15]=0,this}makeOrthographic(e,t,s,i,r,n,o=2e3){const a=this.elements,h=1/(t-e),l=1/(s-i),u=1/(n-r),c=(t+e)*h,d=(s+i)*l;let p,m;if(o===Vs)p=(n+r)*u,m=-2*u;else{if(o!==Ds)throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+o);p=r*u,m=-1*u}return a[0]=2*h,a[4]=0,a[8]=0,a[12]=-c,a[1]=0,a[5]=2*l,a[9]=0,a[13]=-d,a[2]=0,a[6]=0,a[10]=m,a[14]=-p,a[3]=0,a[7]=0,a[11]=0,a[15]=1,this}equals(e){const t=this.elements,s=e.elements;for(let e=0;e<16;e++)if(t[e]!==s[e])return!1;return!0}fromArray(e,t=0){for(let s=0;s<16;s++)this.elements[s]=e[s+t];return this}toArray(e=[],t=0){const s=this.elements;return e[t]=s[0],e[t+1]=s[1],e[t+2]=s[2],e[t+3]=s[3],e[t+4]=s[4],e[t+5]=s[5],e[t+6]=s[6],e[t+7]=s[7],e[t+8]=s[8],e[t+9]=s[9],e[t+10]=s[10],e[t+11]=s[11],e[t+12]=s[12],e[t+13]=s[13],e[t+14]=s[14],e[t+15]=s[15],e}}const ar=new Ei,hr=new or,lr=new Ei(0,0,0),ur=new Ei(1,1,1),cr=new Ei,dr=new Ei,pr=new Ei,mr=new or,gr=new Ci;class fr{constructor(e=0,t=0,s=0,i=fr.DEFAULT_ORDER){this.isEuler=!0,this._x=e,this._y=t,this._z=s,this._order=i}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get order(){return this._order}set order(e){this._order=e,this._onChangeCallback()}set(e,t,s,i=this._order){return this._x=e,this._y=t,this._z=s,this._order=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(e){return this._x=e._x,this._y=e._y,this._z=e._z,this._order=e._order,this._onChangeCallback(),this}setFromRotationMatrix(e,t=this._order,s=!0){const i=e.elements,r=i[0],n=i[4],o=i[8],a=i[1],h=i[5],l=i[9],u=i[2],c=i[6],d=i[10];switch(t){case"XYZ":this._y=Math.asin($s(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-l,d),this._z=Math.atan2(-n,r)):(this._x=Math.atan2(c,h),this._z=0);break;case"YXZ":this._x=Math.asin(-$s(l,-1,1)),Math.abs(l)<.9999999?(this._y=Math.atan2(o,d),this._z=Math.atan2(a,h)):(this._y=Math.atan2(-u,r),this._z=0);break;case"ZXY":this._x=Math.asin($s(c,-1,1)),Math.abs(c)<.9999999?(this._y=Math.atan2(-u,d),this._z=Math.atan2(-n,h)):(this._y=0,this._z=Math.atan2(a,r));break;case"ZYX":this._y=Math.asin(-$s(u,-1,1)),Math.abs(u)<.9999999?(this._x=Math.atan2(c,d),this._z=Math.atan2(a,r)):(this._x=0,this._z=Math.atan2(-n,h));break;case"YZX":this._z=Math.asin($s(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(-l,h),this._y=Math.atan2(-u,r)):(this._x=0,this._y=Math.atan2(o,d));break;case"XZY":this._z=Math.asin(-$s(n,-1,1)),Math.abs(n)<.9999999?(this._x=Math.atan2(c,h),this._y=Math.atan2(o,r)):(this._x=Math.atan2(-l,d),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+t)}return this._order=t,!0===s&&this._onChangeCallback(),this}setFromQuaternion(e,t,s){return mr.makeRotationFromQuaternion(e),this.setFromRotationMatrix(mr,t,s)}setFromVector3(e,t=this._order){return this.set(e.x,e.y,e.z,t)}reorder(e){return gr.setFromEuler(this),this.setFromQuaternion(gr,e)}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._order===this._order}fromArray(e){return this._x=e[0],this._y=e[1],this._z=e[2],void 0!==e[3]&&(this._order=e[3]),this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._order,e}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._order}}fr.DEFAULT_ORDER="XYZ";class yr{constructor(){this.mask=1}set(e){this.mask=(1<>>0}enable(e){this.mask|=1<1){for(let e=0;e1){for(let e=0;e0&&(i.userData=this.userData),i.layers=this.layers.mask,i.matrix=this.matrix.toArray(),i.up=this.up.toArray(),!1===this.matrixAutoUpdate&&(i.matrixAutoUpdate=!1),this.isInstancedMesh&&(i.type="InstancedMesh",i.count=this.count,i.instanceMatrix=this.instanceMatrix.toJSON(),null!==this.instanceColor&&(i.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(i.type="BatchedMesh",i.perObjectFrustumCulled=this.perObjectFrustumCulled,i.sortObjects=this.sortObjects,i.drawRanges=this._drawRanges,i.reservedRanges=this._reservedRanges,i.visibility=this._visibility,i.active=this._active,i.bounds=this._bounds.map((e=>({boxInitialized:e.boxInitialized,boxMin:e.box.min.toArray(),boxMax:e.box.max.toArray(),sphereInitialized:e.sphereInitialized,sphereRadius:e.sphere.radius,sphereCenter:e.sphere.center.toArray()}))),i.maxInstanceCount=this._maxInstanceCount,i.maxVertexCount=this._maxVertexCount,i.maxIndexCount=this._maxIndexCount,i.geometryInitialized=this._geometryInitialized,i.geometryCount=this._geometryCount,i.matricesTexture=this._matricesTexture.toJSON(e),null!==this._colorsTexture&&(i.colorsTexture=this._colorsTexture.toJSON(e)),null!==this.boundingSphere&&(i.boundingSphere={center:i.boundingSphere.center.toArray(),radius:i.boundingSphere.radius}),null!==this.boundingBox&&(i.boundingBox={min:i.boundingBox.min.toArray(),max:i.boundingBox.max.toArray()})),this.isScene)this.background&&(this.background.isColor?i.background=this.background.toJSON():this.background.isTexture&&(i.background=this.background.toJSON(e).uuid)),this.environment&&this.environment.isTexture&&!0!==this.environment.isRenderTargetTexture&&(i.environment=this.environment.toJSON(e).uuid);else if(this.isMesh||this.isLine||this.isPoints){i.geometry=r(e.geometries,this.geometry);const t=this.geometry.parameters;if(void 0!==t&&void 0!==t.shapes){const s=t.shapes;if(Array.isArray(s))for(let t=0,i=s.length;t0){i.children=[];for(let t=0;t0){i.animations=[];for(let t=0;t0&&(s.geometries=t),i.length>0&&(s.materials=i),r.length>0&&(s.textures=r),o.length>0&&(s.images=o),a.length>0&&(s.shapes=a),h.length>0&&(s.skeletons=h),l.length>0&&(s.animations=l),u.length>0&&(s.nodes=u)}return s.object=i,s;function n(e){const t=[];for(const s in e){const i=e[s];delete i.metadata,t.push(i)}return t}}clone(e){return(new this.constructor).copy(this,e)}copy(e,t=!0){if(this.name=e.name,this.up.copy(e.up),this.position.copy(e.position),this.rotation.order=e.rotation.order,this.quaternion.copy(e.quaternion),this.scale.copy(e.scale),this.matrix.copy(e.matrix),this.matrixWorld.copy(e.matrixWorld),this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrixWorldAutoUpdate=e.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=e.matrixWorldNeedsUpdate,this.layers.mask=e.layers.mask,this.visible=e.visible,this.castShadow=e.castShadow,this.receiveShadow=e.receiveShadow,this.frustumCulled=e.frustumCulled,this.renderOrder=e.renderOrder,this.animations=e.animations.slice(),this.userData=JSON.parse(JSON.stringify(e.userData)),!0===t)for(let t=0;t0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(e,t,s,i,r){Fr.subVectors(i,t),zr.subVectors(s,t),Ur.subVectors(e,t);const n=Fr.dot(Fr),o=Fr.dot(zr),a=Fr.dot(Ur),h=zr.dot(zr),l=zr.dot(Ur),u=n*h-o*o;if(0===u)return r.set(0,0,0),null;const c=1/u,d=(h*a-o*l)*c,p=(n*l-o*a)*c;return r.set(1-d-p,p,d)}static containsPoint(e,t,s,i){return null!==this.getBarycoord(e,t,s,i,Lr)&&(Lr.x>=0&&Lr.y>=0&&Lr.x+Lr.y<=1)}static getInterpolation(e,t,s,i,r,n,o,a){return null===this.getBarycoord(e,t,s,i,Lr)?(a.x=0,a.y=0,"z"in a&&(a.z=0),"w"in a&&(a.w=0),null):(a.setScalar(0),a.addScaledVector(r,Lr.x),a.addScaledVector(n,Lr.y),a.addScaledVector(o,Lr.z),a)}static isFrontFacing(e,t,s,i){return Fr.subVectors(s,t),zr.subVectors(e,t),Fr.cross(zr).dot(i)<0}set(e,t,s){return this.a.copy(e),this.b.copy(t),this.c.copy(s),this}setFromPointsAndIndices(e,t,s,i){return this.a.copy(e[t]),this.b.copy(e[s]),this.c.copy(e[i]),this}setFromAttributeAndIndices(e,t,s,i){return this.a.fromBufferAttribute(e,t),this.b.fromBufferAttribute(e,s),this.c.fromBufferAttribute(e,i),this}clone(){return(new this.constructor).copy(this)}copy(e){return this.a.copy(e.a),this.b.copy(e.b),this.c.copy(e.c),this}getArea(){return Fr.subVectors(this.c,this.b),zr.subVectors(this.a,this.b),.5*Fr.cross(zr).length()}getMidpoint(e){return e.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(e){return Hr.getNormal(this.a,this.b,this.c,e)}getPlane(e){return e.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(e,t){return Hr.getBarycoord(e,this.a,this.b,this.c,t)}getInterpolation(e,t,s,i,r){return Hr.getInterpolation(e,this.a,this.b,this.c,t,s,i,r)}containsPoint(e){return Hr.containsPoint(e,this.a,this.b,this.c)}isFrontFacing(e){return Hr.isFrontFacing(this.a,this.b,this.c,e)}intersectsBox(e){return e.intersectsTriangle(this)}closestPointToPoint(e,t){const s=this.a,i=this.b,r=this.c;let n,o;Or.subVectors(i,s),Vr.subVectors(r,s),kr.subVectors(e,s);const a=Or.dot(kr),h=Vr.dot(kr);if(a<=0&&h<=0)return t.copy(s);Gr.subVectors(e,i);const l=Or.dot(Gr),u=Vr.dot(Gr);if(l>=0&&u<=l)return t.copy(i);const c=a*u-l*h;if(c<=0&&a>=0&&l<=0)return n=a/(a-l),t.copy(s).addScaledVector(Or,n);Wr.subVectors(e,r);const d=Or.dot(Wr),p=Vr.dot(Wr);if(p>=0&&d<=p)return t.copy(r);const m=d*h-a*p;if(m<=0&&h>=0&&p<=0)return o=h/(h-p),t.copy(s).addScaledVector(Vr,o);const g=l*p-d*u;if(g<=0&&u-l>=0&&d-p>=0)return Dr.subVectors(r,i),o=(u-l)/(u-l+(d-p)),t.copy(i).addScaledVector(Dr,o);const f=1/(g+m+c);return n=m*f,o=c*f,t.copy(s).addScaledVector(Or,n).addScaledVector(Vr,o)}equals(e){return e.a.equals(this.a)&&e.b.equals(this.b)&&e.c.equals(this.c)}}const jr={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},qr={h:0,s:0,l:0},$r={h:0,s:0,l:0};function Xr(e,t,s){return s<0&&(s+=1),s>1&&(s-=1),s<1/6?e+6*(t-e)*s:s<.5?t:s<2/3?e+6*(t-e)*(2/3-s):e}class Yr{constructor(e,t,s){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(e,t,s)}set(e,t,s){if(void 0===t&&void 0===s){const t=e;t&&t.isColor?this.copy(t):"number"==typeof t?this.setHex(t):"string"==typeof t&&this.setStyle(t)}else this.setRGB(e,t,s);return this}setScalar(e){return this.r=e,this.g=e,this.b=e,this}setHex(e,t=Jt){return e=Math.floor(e),this.r=(e>>16&255)/255,this.g=(e>>8&255)/255,this.b=(255&e)/255,di.toWorkingColorSpace(this,t),this}setRGB(e,t,s,i=di.workingColorSpace){return this.r=e,this.g=t,this.b=s,di.toWorkingColorSpace(this,i),this}setHSL(e,t,s,i=di.workingColorSpace){if(e=Xs(e,1),t=$s(t,0,1),s=$s(s,0,1),0===t)this.r=this.g=this.b=s;else{const i=s<=.5?s*(1+t):s+t-s*t,r=2*s-i;this.r=Xr(r,i,e+1/3),this.g=Xr(r,i,e),this.b=Xr(r,i,e-1/3)}return di.toWorkingColorSpace(this,i),this}setStyle(e,t=Jt){function s(t){void 0!==t&&parseFloat(t)<1&&console.warn("THREE.Color: Alpha component of "+e+" will be ignored.")}let i;if(i=/^(\w+)\(([^\)]*)\)/.exec(e)){let r;const n=i[1],o=i[2];switch(n){case"rgb":case"rgba":if(r=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return s(r[4]),this.setRGB(Math.min(255,parseInt(r[1],10))/255,Math.min(255,parseInt(r[2],10))/255,Math.min(255,parseInt(r[3],10))/255,t);if(r=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return s(r[4]),this.setRGB(Math.min(100,parseInt(r[1],10))/100,Math.min(100,parseInt(r[2],10))/100,Math.min(100,parseInt(r[3],10))/100,t);break;case"hsl":case"hsla":if(r=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return s(r[4]),this.setHSL(parseFloat(r[1])/360,parseFloat(r[2])/100,parseFloat(r[3])/100,t);break;default:console.warn("THREE.Color: Unknown color model "+e)}}else if(i=/^\#([A-Fa-f\d]+)$/.exec(e)){const s=i[1],r=s.length;if(3===r)return this.setRGB(parseInt(s.charAt(0),16)/15,parseInt(s.charAt(1),16)/15,parseInt(s.charAt(2),16)/15,t);if(6===r)return this.setHex(parseInt(s,16),t);console.warn("THREE.Color: Invalid hex color "+e)}else if(e&&e.length>0)return this.setColorName(e,t);return this}setColorName(e,t=Jt){const s=jr[e.toLowerCase()];return void 0!==s?this.setHex(s,t):console.warn("THREE.Color: Unknown color "+e),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(e){return this.r=e.r,this.g=e.g,this.b=e.b,this}copySRGBToLinear(e){return this.r=pi(e.r),this.g=pi(e.g),this.b=pi(e.b),this}copyLinearToSRGB(e){return this.r=mi(e.r),this.g=mi(e.g),this.b=mi(e.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(e=Jt){return di.fromWorkingColorSpace(Jr.copy(this),e),65536*Math.round($s(255*Jr.r,0,255))+256*Math.round($s(255*Jr.g,0,255))+Math.round($s(255*Jr.b,0,255))}getHexString(e=Jt){return("000000"+this.getHex(e).toString(16)).slice(-6)}getHSL(e,t=di.workingColorSpace){di.fromWorkingColorSpace(Jr.copy(this),t);const s=Jr.r,i=Jr.g,r=Jr.b,n=Math.max(s,i,r),o=Math.min(s,i,r);let a,h;const l=(o+n)/2;if(o===n)a=0,h=0;else{const e=n-o;switch(h=l<=.5?e/(n+o):e/(2-n-o),n){case s:a=(i-r)/e+(i0!=e>0&&this.version++,this._alphaTest=e}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(e){if(void 0!==e)for(const t in e){const s=e[t];if(void 0===s){console.warn(`THREE.Material: parameter '${t}' has value of undefined.`);continue}const i=this[t];void 0!==i?i&&i.isColor?i.set(s):i&&i.isVector3&&s&&s.isVector3?i.copy(s):this[t]=s:console.warn(`THREE.Material: '${t}' is not a property of THREE.${this.type}.`)}}toJSON(e){const t=void 0===e||"string"==typeof e;t&&(e={textures:{},images:{}});const s={metadata:{version:4.6,type:"Material",generator:"Material.toJSON"}};function i(e){const t=[];for(const s in e){const i=e[s];delete i.metadata,t.push(i)}return t}if(s.uuid=this.uuid,s.type=this.type,""!==this.name&&(s.name=this.name),this.color&&this.color.isColor&&(s.color=this.color.getHex()),void 0!==this.roughness&&(s.roughness=this.roughness),void 0!==this.metalness&&(s.metalness=this.metalness),void 0!==this.sheen&&(s.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(s.sheenColor=this.sheenColor.getHex()),void 0!==this.sheenRoughness&&(s.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(s.emissive=this.emissive.getHex()),void 0!==this.emissiveIntensity&&1!==this.emissiveIntensity&&(s.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(s.specular=this.specular.getHex()),void 0!==this.specularIntensity&&(s.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(s.specularColor=this.specularColor.getHex()),void 0!==this.shininess&&(s.shininess=this.shininess),void 0!==this.clearcoat&&(s.clearcoat=this.clearcoat),void 0!==this.clearcoatRoughness&&(s.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(s.clearcoatMap=this.clearcoatMap.toJSON(e).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(s.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(e).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(s.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(e).uuid,s.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),void 0!==this.dispersion&&(s.dispersion=this.dispersion),void 0!==this.iridescence&&(s.iridescence=this.iridescence),void 0!==this.iridescenceIOR&&(s.iridescenceIOR=this.iridescenceIOR),void 0!==this.iridescenceThicknessRange&&(s.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(s.iridescenceMap=this.iridescenceMap.toJSON(e).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(s.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(e).uuid),void 0!==this.anisotropy&&(s.anisotropy=this.anisotropy),void 0!==this.anisotropyRotation&&(s.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(s.anisotropyMap=this.anisotropyMap.toJSON(e).uuid),this.map&&this.map.isTexture&&(s.map=this.map.toJSON(e).uuid),this.matcap&&this.matcap.isTexture&&(s.matcap=this.matcap.toJSON(e).uuid),this.alphaMap&&this.alphaMap.isTexture&&(s.alphaMap=this.alphaMap.toJSON(e).uuid),this.lightMap&&this.lightMap.isTexture&&(s.lightMap=this.lightMap.toJSON(e).uuid,s.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(s.aoMap=this.aoMap.toJSON(e).uuid,s.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(s.bumpMap=this.bumpMap.toJSON(e).uuid,s.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(s.normalMap=this.normalMap.toJSON(e).uuid,s.normalMapType=this.normalMapType,s.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(s.displacementMap=this.displacementMap.toJSON(e).uuid,s.displacementScale=this.displacementScale,s.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(s.roughnessMap=this.roughnessMap.toJSON(e).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(s.metalnessMap=this.metalnessMap.toJSON(e).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(s.emissiveMap=this.emissiveMap.toJSON(e).uuid),this.specularMap&&this.specularMap.isTexture&&(s.specularMap=this.specularMap.toJSON(e).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(s.specularIntensityMap=this.specularIntensityMap.toJSON(e).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(s.specularColorMap=this.specularColorMap.toJSON(e).uuid),this.envMap&&this.envMap.isTexture&&(s.envMap=this.envMap.toJSON(e).uuid,void 0!==this.combine&&(s.combine=this.combine)),void 0!==this.envMapRotation&&(s.envMapRotation=this.envMapRotation.toArray()),void 0!==this.envMapIntensity&&(s.envMapIntensity=this.envMapIntensity),void 0!==this.reflectivity&&(s.reflectivity=this.reflectivity),void 0!==this.refractionRatio&&(s.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(s.gradientMap=this.gradientMap.toJSON(e).uuid),void 0!==this.transmission&&(s.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(s.transmissionMap=this.transmissionMap.toJSON(e).uuid),void 0!==this.thickness&&(s.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(s.thicknessMap=this.thicknessMap.toJSON(e).uuid),void 0!==this.attenuationDistance&&this.attenuationDistance!==1/0&&(s.attenuationDistance=this.attenuationDistance),void 0!==this.attenuationColor&&(s.attenuationColor=this.attenuationColor.getHex()),void 0!==this.size&&(s.size=this.size),null!==this.shadowSide&&(s.shadowSide=this.shadowSide),void 0!==this.sizeAttenuation&&(s.sizeAttenuation=this.sizeAttenuation),1!==this.blending&&(s.blending=this.blending),this.side!==c&&(s.side=this.side),!0===this.vertexColors&&(s.vertexColors=!0),this.opacity<1&&(s.opacity=this.opacity),!0===this.transparent&&(s.transparent=!0),this.blendSrc!==C&&(s.blendSrc=this.blendSrc),this.blendDst!==E&&(s.blendDst=this.blendDst),this.blendEquation!==v&&(s.blendEquation=this.blendEquation),null!==this.blendSrcAlpha&&(s.blendSrcAlpha=this.blendSrcAlpha),null!==this.blendDstAlpha&&(s.blendDstAlpha=this.blendDstAlpha),null!==this.blendEquationAlpha&&(s.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(s.blendColor=this.blendColor.getHex()),0!==this.blendAlpha&&(s.blendAlpha=this.blendAlpha),3!==this.depthFunc&&(s.depthFunc=this.depthFunc),!1===this.depthTest&&(s.depthTest=this.depthTest),!1===this.depthWrite&&(s.depthWrite=this.depthWrite),!1===this.colorWrite&&(s.colorWrite=this.colorWrite),255!==this.stencilWriteMask&&(s.stencilWriteMask=this.stencilWriteMask),this.stencilFunc!==bs&&(s.stencilFunc=this.stencilFunc),0!==this.stencilRef&&(s.stencilRef=this.stencilRef),255!==this.stencilFuncMask&&(s.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==ns&&(s.stencilFail=this.stencilFail),this.stencilZFail!==ns&&(s.stencilZFail=this.stencilZFail),this.stencilZPass!==ns&&(s.stencilZPass=this.stencilZPass),!0===this.stencilWrite&&(s.stencilWrite=this.stencilWrite),void 0!==this.rotation&&0!==this.rotation&&(s.rotation=this.rotation),!0===this.polygonOffset&&(s.polygonOffset=!0),0!==this.polygonOffsetFactor&&(s.polygonOffsetFactor=this.polygonOffsetFactor),0!==this.polygonOffsetUnits&&(s.polygonOffsetUnits=this.polygonOffsetUnits),void 0!==this.linewidth&&1!==this.linewidth&&(s.linewidth=this.linewidth),void 0!==this.dashSize&&(s.dashSize=this.dashSize),void 0!==this.gapSize&&(s.gapSize=this.gapSize),void 0!==this.scale&&(s.scale=this.scale),!0===this.dithering&&(s.dithering=!0),this.alphaTest>0&&(s.alphaTest=this.alphaTest),!0===this.alphaHash&&(s.alphaHash=!0),!0===this.alphaToCoverage&&(s.alphaToCoverage=!0),!0===this.premultipliedAlpha&&(s.premultipliedAlpha=!0),!0===this.forceSinglePass&&(s.forceSinglePass=!0),!0===this.wireframe&&(s.wireframe=!0),this.wireframeLinewidth>1&&(s.wireframeLinewidth=this.wireframeLinewidth),"round"!==this.wireframeLinecap&&(s.wireframeLinecap=this.wireframeLinecap),"round"!==this.wireframeLinejoin&&(s.wireframeLinejoin=this.wireframeLinejoin),!0===this.flatShading&&(s.flatShading=!0),!1===this.visible&&(s.visible=!1),!1===this.toneMapped&&(s.toneMapped=!1),!1===this.fog&&(s.fog=!1),Object.keys(this.userData).length>0&&(s.userData=this.userData),t){const t=i(e.textures),r=i(e.images);t.length>0&&(s.textures=t),r.length>0&&(s.images=r)}return s}clone(){return(new this.constructor).copy(this)}copy(e){this.name=e.name,this.blending=e.blending,this.side=e.side,this.vertexColors=e.vertexColors,this.opacity=e.opacity,this.transparent=e.transparent,this.blendSrc=e.blendSrc,this.blendDst=e.blendDst,this.blendEquation=e.blendEquation,this.blendSrcAlpha=e.blendSrcAlpha,this.blendDstAlpha=e.blendDstAlpha,this.blendEquationAlpha=e.blendEquationAlpha,this.blendColor.copy(e.blendColor),this.blendAlpha=e.blendAlpha,this.depthFunc=e.depthFunc,this.depthTest=e.depthTest,this.depthWrite=e.depthWrite,this.stencilWriteMask=e.stencilWriteMask,this.stencilFunc=e.stencilFunc,this.stencilRef=e.stencilRef,this.stencilFuncMask=e.stencilFuncMask,this.stencilFail=e.stencilFail,this.stencilZFail=e.stencilZFail,this.stencilZPass=e.stencilZPass,this.stencilWrite=e.stencilWrite;const t=e.clippingPlanes;let s=null;if(null!==t){const e=t.length;s=new Array(e);for(let i=0;i!==e;++i)s[i]=t[i].clone()}return this.clippingPlanes=s,this.clipIntersection=e.clipIntersection,this.clipShadows=e.clipShadows,this.shadowSide=e.shadowSide,this.colorWrite=e.colorWrite,this.precision=e.precision,this.polygonOffset=e.polygonOffset,this.polygonOffsetFactor=e.polygonOffsetFactor,this.polygonOffsetUnits=e.polygonOffsetUnits,this.dithering=e.dithering,this.alphaTest=e.alphaTest,this.alphaHash=e.alphaHash,this.alphaToCoverage=e.alphaToCoverage,this.premultipliedAlpha=e.premultipliedAlpha,this.forceSinglePass=e.forceSinglePass,this.visible=e.visible,this.toneMapped=e.toneMapped,this.userData=JSON.parse(JSON.stringify(e.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){!0===e&&this.version++}onBuild(){console.warn("Material: onBuild() has been removed.")}}class Qr extends Kr{constructor(e){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new Yr(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new fr,this.combine=0,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}}const en=tn();function tn(){const e=new ArrayBuffer(4),t=new Float32Array(e),s=new Uint32Array(e),i=new Uint32Array(512),r=new Uint32Array(512);for(let e=0;e<256;++e){const t=e-127;t<-27?(i[e]=0,i[256|e]=32768,r[e]=24,r[256|e]=24):t<-14?(i[e]=1024>>-t-14,i[256|e]=1024>>-t-14|32768,r[e]=-t-1,r[256|e]=-t-1):t<=15?(i[e]=t+15<<10,i[256|e]=t+15<<10|32768,r[e]=13,r[256|e]=13):t<128?(i[e]=31744,i[256|e]=64512,r[e]=24,r[256|e]=24):(i[e]=31744,i[256|e]=64512,r[e]=13,r[256|e]=13)}const n=new Uint32Array(2048),o=new Uint32Array(64),a=new Uint32Array(64);for(let e=1;e<1024;++e){let t=e<<13,s=0;for(;0==(8388608&t);)t<<=1,s-=8388608;t&=-8388609,s+=947912704,n[e]=t|s}for(let e=1024;e<2048;++e)n[e]=939524096+(e-1024<<13);for(let e=1;e<31;++e)o[e]=e<<23;o[31]=1199570944,o[32]=2147483648;for(let e=33;e<63;++e)o[e]=2147483648+(e-32<<23);o[63]=3347054592;for(let e=1;e<64;++e)32!==e&&(a[e]=1024);return{floatView:t,uint32View:s,baseTable:i,shiftTable:r,mantissaTable:n,exponentTable:o,offsetTable:a}}function sn(e){Math.abs(e)>65504&&console.warn("THREE.DataUtils.toHalfFloat(): Value out of range."),e=$s(e,-65504,65504),en.floatView[0]=e;const t=en.uint32View[0],s=t>>23&511;return en.baseTable[s]+((8388607&t)>>en.shiftTable[s])}function rn(e){const t=e>>10;return en.uint32View[0]=en.mantissaTable[en.offsetTable[t]+(1023&e)]+en.exponentTable[t],en.floatView[0]}const nn={toHalfFloat:sn,fromHalfFloat:rn},on=new Ei,an=new Qs;class hn{constructor(e,t,s=!1){if(Array.isArray(e))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,this.name="",this.array=e,this.itemSize=t,this.count=void 0!==e?e.length/t:0,this.normalized=s,this.usage=Rs,this._updateRange={offset:0,count:-1},this.updateRanges=[],this.gpuType=Ie,this.version=0}onUploadCallback(){}set needsUpdate(e){!0===e&&this.version++}get updateRange(){return ai("THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead."),this._updateRange}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.name=e.name,this.array=new e.array.constructor(e.array),this.itemSize=e.itemSize,this.count=e.count,this.normalized=e.normalized,this.usage=e.usage,this.gpuType=e.gpuType,this}copyAt(e,t,s){e*=this.itemSize,s*=t.itemSize;for(let i=0,r=this.itemSize;i=0;--t)if(e[t]>=65535)return!0;return!1}(e)?gn:pn)(e,1):this.index=e,this}getAttribute(e){return this.attributes[e]}setAttribute(e,t){return this.attributes[e]=t,this}deleteAttribute(e){return delete this.attributes[e],this}hasAttribute(e){return void 0!==this.attributes[e]}addGroup(e,t,s=0){this.groups.push({start:e,count:t,materialIndex:s})}clearGroups(){this.groups=[]}setDrawRange(e,t){this.drawRange.start=e,this.drawRange.count=t}applyMatrix4(e){const t=this.attributes.position;void 0!==t&&(t.applyMatrix4(e),t.needsUpdate=!0);const s=this.attributes.normal;if(void 0!==s){const t=(new ei).getNormalMatrix(e);s.applyNormalMatrix(t),s.needsUpdate=!0}const i=this.attributes.tangent;return void 0!==i&&(i.transformDirection(e),i.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this}applyQuaternion(e){return bn.makeRotationFromQuaternion(e),this.applyMatrix4(bn),this}rotateX(e){return bn.makeRotationX(e),this.applyMatrix4(bn),this}rotateY(e){return bn.makeRotationY(e),this.applyMatrix4(bn),this}rotateZ(e){return bn.makeRotationZ(e),this.applyMatrix4(bn),this}translate(e,t,s){return bn.makeTranslation(e,t,s),this.applyMatrix4(bn),this}scale(e,t,s){return bn.makeScale(e,t,s),this.applyMatrix4(bn),this}lookAt(e){return vn.lookAt(e),vn.updateMatrix(),this.applyMatrix4(vn.matrix),this}center(){return this.computeBoundingBox(),this.boundingBox.getCenter(Tn).negate(),this.translate(Tn.x,Tn.y,Tn.z),this}setFromPoints(e){const t=[];for(let s=0,i=e.length;s0&&(e.userData=this.userData),void 0!==this.parameters){const t=this.parameters;for(const s in t)void 0!==t[s]&&(e[s]=t[s]);return e}e.data={attributes:{}};const t=this.index;null!==t&&(e.data.index={type:t.array.constructor.name,array:Array.prototype.slice.call(t.array)});const s=this.attributes;for(const t in s){const i=s[t];e.data.attributes[t]=i.toJSON(e.data)}const i={};let r=!1;for(const t in this.morphAttributes){const s=this.morphAttributes[t],n=[];for(let t=0,i=s.length;t0&&(i[t]=n,r=!0)}r&&(e.data.morphAttributes=i,e.data.morphTargetsRelative=this.morphTargetsRelative);const n=this.groups;n.length>0&&(e.data.groups=JSON.parse(JSON.stringify(n)));const o=this.boundingSphere;return null!==o&&(e.data.boundingSphere={center:o.center.toArray(),radius:o.radius}),e}clone(){return(new this.constructor).copy(this)}copy(e){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const t={};this.name=e.name;const s=e.index;null!==s&&this.setIndex(s.clone(t));const i=e.attributes;for(const e in i){const s=i[e];this.setAttribute(e,s.clone(t))}const r=e.morphAttributes;for(const e in r){const s=[],i=r[e];for(let e=0,r=i.length;e0){const s=e[t[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,t=s.length;e(e.far-e.near)**2)return}An.copy(r).invert(),Nn.copy(e.ray).applyMatrix4(An),null!==s.boundingBox&&!1===Nn.intersectsBox(s.boundingBox)||this._computeIntersections(e,t,Nn)}}_computeIntersections(e,t,s){let i;const r=this.geometry,n=this.material,o=r.index,a=r.attributes.position,h=r.attributes.uv,l=r.attributes.uv1,u=r.attributes.normal,c=r.groups,d=r.drawRange;if(null!==o)if(Array.isArray(n))for(let r=0,a=c.length;rs.far?null:{distance:l,point:Gn.clone(),object:e}}(e,t,s,i,En,Bn,In,kn);if(u){r&&(zn.fromBufferAttribute(r,a),Un.fromBufferAttribute(r,h),Ln.fromBufferAttribute(r,l),u.uv=Hr.getInterpolation(kn,En,Bn,In,zn,Un,Ln,new Qs)),n&&(zn.fromBufferAttribute(n,a),Un.fromBufferAttribute(n,h),Ln.fromBufferAttribute(n,l),u.uv1=Hr.getInterpolation(kn,En,Bn,In,zn,Un,Ln,new Qs)),o&&(On.fromBufferAttribute(o,a),Vn.fromBufferAttribute(o,h),Dn.fromBufferAttribute(o,l),u.normal=Hr.getInterpolation(kn,En,Bn,In,On,Vn,Dn,new Ei),u.normal.dot(i.direction)>0&&u.normal.multiplyScalar(-1));const e={a:a,b:h,c:l,normal:new Ei,materialIndex:0};Hr.getNormal(En,Bn,In,e.normal),u.face=e}return u}class jn extends Mn{constructor(e=1,t=1,s=1,i=1,r=1,n=1){super(),this.type="BoxGeometry",this.parameters={width:e,height:t,depth:s,widthSegments:i,heightSegments:r,depthSegments:n};const o=this;i=Math.floor(i),r=Math.floor(r),n=Math.floor(n);const a=[],h=[],l=[],u=[];let c=0,d=0;function p(e,t,s,i,r,n,p,m,g,f,y){const x=n/g,b=p/f,v=n/2,T=p/2,_=m/2,w=g+1,S=f+1;let M=0,A=0;const N=new Ei;for(let n=0;n0?1:-1,l.push(N.x,N.y,N.z),u.push(a/g),u.push(1-n/f),M+=1}}for(let e=0;e0&&(t.defines=this.defines),t.vertexShader=this.vertexShader,t.fragmentShader=this.fragmentShader,t.lights=this.lights,t.clipping=this.clipping;const s={};for(const e in this.extensions)!0===this.extensions[e]&&(s[e]=!0);return Object.keys(s).length>0&&(t.extensions=s),t}}class Xn extends Pr{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new or,this.projectionMatrix=new or,this.projectionMatrixInverse=new or,this.coordinateSystem=Vs}copy(e,t){return super.copy(e,t),this.matrixWorldInverse.copy(e.matrixWorldInverse),this.projectionMatrix.copy(e.projectionMatrix),this.projectionMatrixInverse.copy(e.projectionMatrixInverse),this.coordinateSystem=e.coordinateSystem,this}getWorldDirection(e){return super.getWorldDirection(e).negate()}updateMatrixWorld(e){super.updateMatrixWorld(e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(e,t){super.updateWorldMatrix(e,t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return(new this.constructor).copy(this)}}const Yn=new Ei,Jn=new Qs,Zn=new Qs;class Kn extends Xn{constructor(e=50,t=1,s=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=e,this.zoom=1,this.near=s,this.far=i,this.focus=10,this.aspect=t,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(e,t){return super.copy(e,t),this.fov=e.fov,this.zoom=e.zoom,this.near=e.near,this.far=e.far,this.focus=e.focus,this.aspect=e.aspect,this.view=null===e.view?null:Object.assign({},e.view),this.filmGauge=e.filmGauge,this.filmOffset=e.filmOffset,this}setFocalLength(e){const t=.5*this.getFilmHeight()/e;this.fov=2*js*Math.atan(t),this.updateProjectionMatrix()}getFocalLength(){const e=Math.tan(.5*Hs*this.fov);return.5*this.getFilmHeight()/e}getEffectiveFOV(){return 2*js*Math.atan(Math.tan(.5*Hs*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(e,t,s){Yn.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),t.set(Yn.x,Yn.y).multiplyScalar(-e/Yn.z),Yn.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),s.set(Yn.x,Yn.y).multiplyScalar(-e/Yn.z)}getViewSize(e,t){return this.getViewBounds(e,Jn,Zn),t.subVectors(Zn,Jn)}setViewOffset(e,t,s,i,r,n){this.aspect=e/t,null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=s,this.view.offsetY=i,this.view.width=r,this.view.height=n,this.updateProjectionMatrix()}clearViewOffset(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const e=this.near;let t=e*Math.tan(.5*Hs*this.fov)/this.zoom,s=2*t,i=this.aspect*s,r=-.5*i;const n=this.view;if(null!==this.view&&this.view.enabled){const e=n.fullWidth,o=n.fullHeight;r+=n.offsetX*i/e,t-=n.offsetY*s/o,i*=n.width/e,s*=n.height/o}const o=this.filmOffset;0!==o&&(r+=e*o/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,t,t-s,e,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(e){const t=super.toJSON(e);return t.object.fov=this.fov,t.object.zoom=this.zoom,t.object.near=this.near,t.object.far=this.far,t.object.focus=this.focus,t.object.aspect=this.aspect,null!==this.view&&(t.object.view=Object.assign({},this.view)),t.object.filmGauge=this.filmGauge,t.object.filmOffset=this.filmOffset,t}}const Qn=-90;class eo extends Pr{constructor(e,t,s){super(),this.type="CubeCamera",this.renderTarget=s,this.coordinateSystem=null,this.activeMipmapLevel=0;const i=new Kn(Qn,1,e,t);i.layers=this.layers,this.add(i);const r=new Kn(Qn,1,e,t);r.layers=this.layers,this.add(r);const n=new Kn(Qn,1,e,t);n.layers=this.layers,this.add(n);const o=new Kn(Qn,1,e,t);o.layers=this.layers,this.add(o);const a=new Kn(Qn,1,e,t);a.layers=this.layers,this.add(a);const h=new Kn(Qn,1,e,t);h.layers=this.layers,this.add(h)}updateCoordinateSystem(){const e=this.coordinateSystem,t=this.children.concat(),[s,i,r,n,o,a]=t;for(const e of t)this.remove(e);if(e===Vs)s.up.set(0,1,0),s.lookAt(1,0,0),i.up.set(0,1,0),i.lookAt(-1,0,0),r.up.set(0,0,-1),r.lookAt(0,1,0),n.up.set(0,0,1),n.lookAt(0,-1,0),o.up.set(0,1,0),o.lookAt(0,0,1),a.up.set(0,1,0),a.lookAt(0,0,-1);else{if(e!==Ds)throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+e);s.up.set(0,-1,0),s.lookAt(-1,0,0),i.up.set(0,-1,0),i.lookAt(1,0,0),r.up.set(0,0,1),r.lookAt(0,1,0),n.up.set(0,0,-1),n.lookAt(0,-1,0),o.up.set(0,-1,0),o.lookAt(0,0,1),a.up.set(0,-1,0),a.lookAt(0,0,-1)}for(const e of t)this.add(e),e.updateMatrixWorld()}update(e,t){null===this.parent&&this.updateMatrixWorld();const{renderTarget:s,activeMipmapLevel:i}=this;this.coordinateSystem!==e.coordinateSystem&&(this.coordinateSystem=e.coordinateSystem,this.updateCoordinateSystem());const[r,n,o,a,h,l]=this.children,u=e.getRenderTarget(),c=e.getActiveCubeFace(),d=e.getActiveMipmapLevel(),p=e.xr.enabled;e.xr.enabled=!1;const m=s.texture.generateMipmaps;s.texture.generateMipmaps=!1,e.setRenderTarget(s,0,i),e.render(t,r),e.setRenderTarget(s,1,i),e.render(t,n),e.setRenderTarget(s,2,i),e.render(t,o),e.setRenderTarget(s,3,i),e.render(t,a),e.setRenderTarget(s,4,i),e.render(t,h),s.texture.generateMipmaps=m,e.setRenderTarget(s,5,i),e.render(t,l),e.setRenderTarget(u,c,d),e.xr.enabled=p,s.texture.needsPMREMUpdate=!0}}class to extends Ti{constructor(e,t,s,i,r,n,o,a,h,l){super(e=void 0!==e?e:[],t=void 0!==t?t:he,s,i,r,n,o,a,h,l),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(e){this.image=e}}class so extends Si{constructor(e=1,t={}){super(e,e,t),this.isWebGLCubeRenderTarget=!0;const s={width:e,height:e,depth:1},i=[s,s,s,s,s,s];this.texture=new to(i,t.mapping,t.wrapS,t.wrapT,t.magFilter,t.minFilter,t.format,t.type,t.anisotropy,t.colorSpace),this.texture.isRenderTargetTexture=!0,this.texture.generateMipmaps=void 0!==t.generateMipmaps&&t.generateMipmaps,this.texture.minFilter=void 0!==t.minFilter?t.minFilter:Te}fromEquirectangularTexture(e,t){this.texture.type=t.type,this.texture.colorSpace=t.colorSpace,this.texture.generateMipmaps=t.generateMipmaps,this.texture.minFilter=t.minFilter,this.texture.magFilter=t.magFilter;const s={uniforms:{tEquirect:{value:null}},vertexShader:"\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\tvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\n\t\t\t\t\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvWorldDirection = transformDirection( position, modelMatrix );\n\n\t\t\t\t\t#include \n\t\t\t\t\t#include \n\n\t\t\t\t}\n\t\t\t",fragmentShader:"\n\n\t\t\t\tuniform sampler2D tEquirect;\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\t#include \n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvec3 direction = normalize( vWorldDirection );\n\n\t\t\t\t\tvec2 sampleUV = equirectUv( direction );\n\n\t\t\t\t\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\n\t\t\t\t}\n\t\t\t"},i=new jn(5,5,5),r=new $n({name:"CubemapFromEquirect",uniforms:qn(s.uniforms),vertexShader:s.vertexShader,fragmentShader:s.fragmentShader,side:d,blending:m});r.uniforms.tEquirect.value=t;const n=new Wn(i,r),o=t.minFilter;t.minFilter===Se&&(t.minFilter=Te);return new eo(1,10,this).update(e,n),t.minFilter=o,n.geometry.dispose(),n.material.dispose(),this}clear(e,t,s,i){const r=e.getRenderTarget();for(let r=0;r<6;r++)e.setRenderTarget(this,r),e.clear(t,s,i);e.setRenderTarget(r)}}class io{constructor(e,t=25e-5){this.isFogExp2=!0,this.name="",this.color=new Yr(e),this.density=t}clone(){return new io(this.color,this.density)}toJSON(){return{type:"FogExp2",name:this.name,color:this.color.getHex(),density:this.density}}}class ro{constructor(e,t=1,s=1e3){this.isFog=!0,this.name="",this.color=new Yr(e),this.near=t,this.far=s}clone(){return new ro(this.color,this.near,this.far)}toJSON(){return{type:"Fog",name:this.name,color:this.color.getHex(),near:this.near,far:this.far}}}class no extends Pr{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.backgroundRotation=new fr,this.environmentIntensity=1,this.environmentRotation=new fr,this.overrideMaterial=null,"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(e,t){return super.copy(e,t),null!==e.background&&(this.background=e.background.clone()),null!==e.environment&&(this.environment=e.environment.clone()),null!==e.fog&&(this.fog=e.fog.clone()),this.backgroundBlurriness=e.backgroundBlurriness,this.backgroundIntensity=e.backgroundIntensity,this.backgroundRotation.copy(e.backgroundRotation),this.environmentIntensity=e.environmentIntensity,this.environmentRotation.copy(e.environmentRotation),null!==e.overrideMaterial&&(this.overrideMaterial=e.overrideMaterial.clone()),this.matrixAutoUpdate=e.matrixAutoUpdate,this}toJSON(e){const t=super.toJSON(e);return null!==this.fog&&(t.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(t.object.backgroundBlurriness=this.backgroundBlurriness),1!==this.backgroundIntensity&&(t.object.backgroundIntensity=this.backgroundIntensity),t.object.backgroundRotation=this.backgroundRotation.toArray(),1!==this.environmentIntensity&&(t.object.environmentIntensity=this.environmentIntensity),t.object.environmentRotation=this.environmentRotation.toArray(),t}}class oo{constructor(e,t){this.isInterleavedBuffer=!0,this.array=e,this.stride=t,this.count=void 0!==e?e.length/t:0,this.usage=Rs,this._updateRange={offset:0,count:-1},this.updateRanges=[],this.version=0,this.uuid=qs()}onUploadCallback(){}set needsUpdate(e){!0===e&&this.version++}get updateRange(){return ai("THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead."),this._updateRange}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.array=new e.array.constructor(e.array),this.count=e.count,this.stride=e.stride,this.usage=e.usage,this}copyAt(e,t,s){e*=this.stride,s*=t.stride;for(let i=0,r=this.stride;ie.far||t.push({distance:a,point:co.clone(),uv:Hr.getInterpolation(co,xo,bo,vo,To,_o,wo,new Qs),face:null,object:this})}copy(e,t){return super.copy(e,t),void 0!==e.center&&this.center.copy(e.center),this.material=e.material,this}}function Mo(e,t,s,i,r,n){go.subVectors(e,s).addScalar(.5).multiply(i),void 0!==r?(fo.x=n*go.x-r*go.y,fo.y=r*go.x+n*go.y):fo.copy(go),e.copy(t),e.x+=fo.x,e.y+=fo.y,e.applyMatrix4(yo)}const Ao=new Ei,No=new Ei;class Ro extends Pr{constructor(){super(),this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]},isLOD:{value:!0}}),this.autoUpdate=!0}copy(e){super.copy(e,!1);const t=e.levels;for(let e=0,s=t.length;e0){let s,i;for(s=1,i=t.length;s0){Ao.setFromMatrixPosition(this.matrixWorld);const s=e.ray.origin.distanceTo(Ao);this.getObjectForDistance(s).raycast(e,t)}}update(e){const t=this.levels;if(t.length>1){Ao.setFromMatrixPosition(e.matrixWorld),No.setFromMatrixPosition(this.matrixWorld);const s=Ao.distanceTo(No)/e.zoom;let i,r;for(t[0].object.visible=!0,i=1,r=t.length;i=e))break;t[i-1].object.visible=!1,t[i].object.visible=!0}for(this._currentLevel=i-1;i1?null:t.copy(e.start).addScaledVector(s,r)}intersectsLine(e){const t=this.distanceToPoint(e.start),s=this.distanceToPoint(e.end);return t<0&&s>0||s<0&&t>0}intersectsBox(e){return e.intersectsPlane(this)}intersectsSphere(e){return e.intersectsPlane(this)}coplanarPoint(e){return e.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(e,t){const s=t||ta.getNormalMatrix(e),i=this.coplanarPoint(Qo).applyMatrix4(e),r=this.normal.applyMatrix3(s).normalize();return this.constant=-i.dot(r),this}translate(e){return this.constant-=e.dot(this.normal),this}equals(e){return e.normal.equals(this.normal)&&e.constant===this.constant}clone(){return(new this.constructor).copy(this)}}const ia=new Zi,ra=new Ei;class na{constructor(e=new sa,t=new sa,s=new sa,i=new sa,r=new sa,n=new sa){this.planes=[e,t,s,i,r,n]}set(e,t,s,i,r,n){const o=this.planes;return o[0].copy(e),o[1].copy(t),o[2].copy(s),o[3].copy(i),o[4].copy(r),o[5].copy(n),this}copy(e){const t=this.planes;for(let s=0;s<6;s++)t[s].copy(e.planes[s]);return this}setFromProjectionMatrix(e,t=2e3){const s=this.planes,i=e.elements,r=i[0],n=i[1],o=i[2],a=i[3],h=i[4],l=i[5],u=i[6],c=i[7],d=i[8],p=i[9],m=i[10],g=i[11],f=i[12],y=i[13],x=i[14],b=i[15];if(s[0].setComponents(a-r,c-h,g-d,b-f).normalize(),s[1].setComponents(a+r,c+h,g+d,b+f).normalize(),s[2].setComponents(a+n,c+l,g+p,b+y).normalize(),s[3].setComponents(a-n,c-l,g-p,b-y).normalize(),s[4].setComponents(a-o,c-u,g-m,b-x).normalize(),t===Vs)s[5].setComponents(a+o,c+u,g+m,b+x).normalize();else{if(t!==Ds)throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+t);s[5].setComponents(o,u,m,x).normalize()}return this}intersectsObject(e){if(void 0!==e.boundingSphere)null===e.boundingSphere&&e.computeBoundingSphere(),ia.copy(e.boundingSphere).applyMatrix4(e.matrixWorld);else{const t=e.geometry;null===t.boundingSphere&&t.computeBoundingSphere(),ia.copy(t.boundingSphere).applyMatrix4(e.matrixWorld)}return this.intersectsSphere(ia)}intersectsSprite(e){return ia.center.set(0,0,0),ia.radius=.7071067811865476,ia.applyMatrix4(e.matrixWorld),this.intersectsSphere(ia)}intersectsSphere(e){const t=this.planes,s=e.center,i=-e.radius;for(let e=0;e<6;e++){if(t[e].distanceToPoint(s)0?e.max.x:e.min.x,ra.y=i.normal.y>0?e.max.y:e.min.y,ra.z=i.normal.z>0?e.max.z:e.min.z,i.distanceToPoint(ra)<0)return!1}return!0}containsPoint(e){const t=this.planes;for(let s=0;s<6;s++)if(t[s].distanceToPoint(e)<0)return!1;return!0}clone(){return(new this.constructor).copy(this)}}function oa(e,t){return e.z-t.z}function aa(e,t){return t.z-e.z}class ha{constructor(){this.index=0,this.pool=[],this.list=[]}push(e,t,s){const i=this.pool,r=this.list;this.index>=i.length&&i.push({start:-1,count:-1,z:-1,index:-1});const n=i[this.index];r.push(n),this.index++,n.start=e.start,n.count=e.count,n.z=t,n.index=s}reset(){this.list.length=0,this.index=0}}const la=new or,ua=new or,ca=new or,da=new Yr(1,1,1),pa=new or,ma=new na,ga=new Pi,fa=new Zi,ya=new Ei,xa=new Ei,ba=new Ei,va=new ha,Ta=new Wn,_a=[];function wa(e,t,s=0){const i=t.itemSize;if(e.isInterleavedBufferAttribute||e.array.constructor!==t.array.constructor){const r=e.count;for(let n=0;n65535?new Uint32Array(i):new Uint16Array(i);t.setIndex(new hn(e,1))}this._geometryInitialized=!0}}_validateGeometry(e){const t=this.geometry;if(Boolean(e.getIndex())!==Boolean(t.getIndex()))throw new Error('BatchedMesh: All geometries must consistently have "index".');for(const s in t.attributes){if(!e.hasAttribute(s))throw new Error(`BatchedMesh: Added geometry missing "${s}". All geometries must have consistent attributes.`);const i=e.getAttribute(s),r=t.getAttribute(s);if(i.itemSize!==r.itemSize||i.normalized!==r.normalized)throw new Error("BatchedMesh: All attributes must have a consistent itemSize and normalized value.")}}setCustomSort(e){return this.customSort=e,this}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new Pi);const e=this.boundingBox,t=this._drawInfo;e.makeEmpty();for(let s=0,i=t.length;s=this._maxInstanceCount)throw new Error("BatchedMesh: Maximum item count reached.");this._drawInfo.push({visible:!0,active:!0,geometryIndex:e});const t=this._drawInfo.length-1,s=this._matricesTexture,i=s.image.data;ca.toArray(i,16*t),s.needsUpdate=!0;const r=this._colorsTexture;return r&&(da.toArray(r.image.data,4*t),r.needsUpdate=!0),t}addGeometry(e,t=-1,s=-1){if(this._initializeGeometry(e),this._validateGeometry(e),this._drawInfo.length>=this._maxInstanceCount)throw new Error("BatchedMesh: Maximum item count reached.");const i={vertexStart:-1,vertexCount:-1,indexStart:-1,indexCount:-1};let r=null;const n=this._reservedRanges,o=this._drawRanges,a=this._bounds;0!==this._geometryCount&&(r=n[n.length-1]),i.vertexCount=-1===t?e.getAttribute("position").count:t,i.vertexStart=null===r?0:r.vertexStart+r.vertexCount;const h=e.getIndex(),l=null!==h;if(l&&(i.indexCount=-1===s?h.count:s,i.indexStart=null===r?0:r.indexStart+r.indexCount),-1!==i.indexStart&&i.indexStart+i.indexCount>this._maxIndexCount||i.vertexStart+i.vertexCount>this._maxVertexCount)throw new Error("BatchedMesh: Reserved space request exceeds the maximum buffer size.");const u=this._geometryCount;return this._geometryCount++,n.push(i),o.push({start:l?i.indexStart:i.vertexStart,count:-1}),a.push({boxInitialized:!1,box:new Pi,sphereInitialized:!1,sphere:new Zi}),this.setGeometryAt(u,e),u}setGeometryAt(e,t){if(e>=this._geometryCount)throw new Error("BatchedMesh: Maximum geometry count reached.");this._validateGeometry(t);const s=this.geometry,i=null!==s.getIndex(),r=s.getIndex(),n=t.getIndex(),o=this._reservedRanges[e];if(i&&n.count>o.indexCount||t.attributes.position.count>o.vertexCount)throw new Error("BatchedMesh: Reserved space not large enough for provided geometry.");const a=o.vertexStart,h=o.vertexCount;for(const e in s.attributes){const i=t.getAttribute(e),r=s.getAttribute(e);wa(i,r,a);const n=i.itemSize;for(let e=i.count,t=h;e=this._geometryCount)return null;const s=this._bounds[e],i=s.box,r=this.geometry;if(!1===s.boxInitialized){i.makeEmpty();const t=r.index,n=r.attributes.position,o=this._drawRanges[e];for(let e=o.start,s=o.start+o.count;e=this._geometryCount)return null;const s=this._bounds[e],i=s.sphere,r=this.geometry;if(!1===s.sphereInitialized){i.makeEmpty(),this.getBoundingBoxAt(e,ga),ga.getCenter(i.center);const t=r.index,n=r.attributes.position,o=this._drawRanges[e];let a=0;for(let e=o.start,s=o.start+o.count;e=s.length||!1===s[e].active||(t.toArray(r,16*e),i.needsUpdate=!0),this}getMatrixAt(e,t){const s=this._drawInfo,i=this._matricesTexture.image.data;return e>=s.length||!1===s[e].active?null:t.fromArray(i,16*e)}setColorAt(e,t){null===this._colorsTexture&&this._initColorsTexture();const s=this._colorsTexture,i=this._colorsTexture.image.data,r=this._drawInfo;return e>=r.length||!1===r[e].active||(t.toArray(i,4*e),s.needsUpdate=!0),this}getColorAt(e,t){const s=this._colorsTexture.image.data,i=this._drawInfo;return e>=i.length||!1===i[e].active?null:t.fromArray(s,4*e)}setVisibleAt(e,t){const s=this._drawInfo;return e>=s.length||!1===s[e].active||s[e].visible===t||(s[e].visible=t,this._visibilityChanged=!0),this}getVisibleAt(e){const t=this._drawInfo;return!(e>=t.length||!1===t[e].active)&&t[e].visible}raycast(e,t){const s=this._drawInfo,i=this._drawRanges,r=this.matrixWorld,n=this.geometry;Ta.material=this.material,Ta.geometry.index=n.index,Ta.geometry.attributes=n.attributes,null===Ta.geometry.boundingBox&&(Ta.geometry.boundingBox=new Pi),null===Ta.geometry.boundingSphere&&(Ta.geometry.boundingSphere=new Zi);for(let n=0,o=s.length;n({...e}))),this._reservedRanges=e._reservedRanges.map((e=>({...e}))),this._drawInfo=e._drawInfo.map((e=>({...e}))),this._bounds=e._bounds.map((e=>({boxInitialized:e.boxInitialized,box:e.box.clone(),sphereInitialized:e.sphereInitialized,sphere:e.sphere.clone()}))),this._maxInstanceCount=e._maxInstanceCount,this._maxVertexCount=e._maxVertexCount,this._maxIndexCount=e._maxIndexCount,this._geometryInitialized=e._geometryInitialized,this._geometryCount=e._geometryCount,this._multiDrawCounts=e._multiDrawCounts.slice(),this._multiDrawStarts=e._multiDrawStarts.slice(),this._matricesTexture=e._matricesTexture.clone(),this._matricesTexture.image.data=this._matricesTexture.image.data.slice(),null!==this._colorsTexture&&(this._colorsTexture=e._colorsTexture.clone(),this._colorsTexture.image.data=this._colorsTexture.image.data.slice()),this}dispose(){return this.geometry.dispose(),this._matricesTexture.dispose(),this._matricesTexture=null,this._indirectTexture.dispose(),this._indirectTexture=null,null!==this._colorsTexture&&(this._colorsTexture.dispose(),this._colorsTexture=null),this}onBeforeRender(e,t,s,i,r){if(!this._visibilityChanged&&!this.perObjectFrustumCulled&&!this.sortObjects)return;const n=i.getIndex(),o=null===n?1:n.array.BYTES_PER_ELEMENT,a=this._drawInfo,h=this._multiDrawStarts,l=this._multiDrawCounts,u=this._drawRanges,c=this.perObjectFrustumCulled,d=this._indirectTexture,p=d.image.data;c&&(pa.multiplyMatrices(s.projectionMatrix,s.matrixWorldInverse).multiply(this.matrixWorld),ma.setFromProjectionMatrix(pa,e.coordinateSystem));let m=0;if(this.sortObjects){ua.copy(this.matrixWorld).invert(),ya.setFromMatrixPosition(s.matrixWorld).applyMatrix4(ua),xa.set(0,0,-1).transformDirection(s.matrixWorld).transformDirection(ua);for(let e=0,t=a.length;e0){const s=e[t[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,t=s.length;ei)return;Ba.applyMatrix4(e.matrixWorld);const a=t.ray.origin.distanceTo(Ba);return at.far?void 0:{distance:a,point:Ia.clone().applyMatrix4(e.matrixWorld),index:r,face:null,faceIndex:null,object:e}}const za=new Ei,Ua=new Ei;class La extends Pa{constructor(e,t){super(e,t),this.isLineSegments=!0,this.type="LineSegments"}computeLineDistances(){const e=this.geometry;if(null===e.index){const t=e.attributes.position,s=[];for(let e=0,i=t.count;e0){const s=e[t[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,t=s.length;er.far)return;n.push({distance:h,distanceToRay:Math.sqrt(a),point:s,index:t,face:null,object:o})}}class qa extends Pr{constructor(){super(),this.isGroup=!0,this.type="Group"}}class $a extends Ti{constructor(e,t,s,i,r,n,o,a,h){super(e,t,s,i,r,n,o,a,h),this.isVideoTexture=!0,this.minFilter=void 0!==n?n:Te,this.magFilter=void 0!==r?r:Te,this.generateMipmaps=!1;const l=this;"requestVideoFrameCallback"in e&&e.requestVideoFrameCallback((function t(){l.needsUpdate=!0,e.requestVideoFrameCallback(t)}))}clone(){return new this.constructor(this.image).copy(this)}update(){const e=this.image;!1==="requestVideoFrameCallback"in e&&e.readyState>=e.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}}class Xa extends Ti{constructor(e,t){super({width:e,height:t}),this.isFramebufferTexture=!0,this.magFilter=fe,this.minFilter=fe,this.generateMipmaps=!1,this.needsUpdate=!0}}class Ya extends Ti{constructor(e,t,s,i,r,n,o,a,h,l,u,c){super(null,n,o,a,h,l,i,r,u,c),this.isCompressedTexture=!0,this.image={width:t,height:s},this.mipmaps=e,this.flipY=!1,this.generateMipmaps=!1}}class Ja extends Ya{constructor(e,t,s,i,r,n){super(e,t,s,r,n),this.isCompressedArrayTexture=!0,this.image.depth=i,this.wrapR=me,this.layerUpdates=new Set}addLayerUpdate(e){this.layerUpdates.add(e)}clearLayerUpdates(){this.layerUpdates.clear()}}class Za extends Ya{constructor(e,t,s){super(void 0,e[0].width,e[0].height,t,s,he),this.isCompressedCubeTexture=!0,this.isCubeTexture=!0,this.image=e}}class Ka extends Ti{constructor(e,t,s,i,r,n,o,a,h){super(e,t,s,i,r,n,o,a,h),this.isCanvasTexture=!0,this.needsUpdate=!0}}class Qa extends Ti{constructor(e,t,s,i,r,n,o,a,h,l=1026){if(l!==We&&l!==He)throw new Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");void 0===s&&l===We&&(s=Be),void 0===s&&l===He&&(s=Ue),super(null,i,r,n,o,a,l,s,h),this.isDepthTexture=!0,this.image={width:e,height:t},this.magFilter=void 0!==o?o:fe,this.minFilter=void 0!==a?a:fe,this.flipY=!1,this.generateMipmaps=!1,this.compareFunction=null}copy(e){return super.copy(e),this.compareFunction=e.compareFunction,this}toJSON(e){const t=super.toJSON(e);return null!==this.compareFunction&&(t.compareFunction=this.compareFunction),t}}class eh{constructor(){this.type="Curve",this.arcLengthDivisions=200}getPoint(){return console.warn("THREE.Curve: .getPoint() not implemented."),null}getPointAt(e,t){const s=this.getUtoTmapping(e);return this.getPoint(s,t)}getPoints(e=5){const t=[];for(let s=0;s<=e;s++)t.push(this.getPoint(s/e));return t}getSpacedPoints(e=5){const t=[];for(let s=0;s<=e;s++)t.push(this.getPointAt(s/e));return t}getLength(){const e=this.getLengths();return e[e.length-1]}getLengths(e=this.arcLengthDivisions){if(this.cacheArcLengths&&this.cacheArcLengths.length===e+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;const t=[];let s,i=this.getPoint(0),r=0;t.push(0);for(let n=1;n<=e;n++)s=this.getPoint(n/e),r+=s.distanceTo(i),t.push(r),i=s;return this.cacheArcLengths=t,t}updateArcLengths(){this.needsUpdate=!0,this.getLengths()}getUtoTmapping(e,t){const s=this.getLengths();let i=0;const r=s.length;let n;n=t||e*s[r-1];let o,a=0,h=r-1;for(;a<=h;)if(i=Math.floor(a+(h-a)/2),o=s[i]-n,o<0)a=i+1;else{if(!(o>0)){h=i;break}h=i-1}if(i=h,s[i]===n)return i/(r-1);const l=s[i];return(i+(n-l)/(s[i+1]-l))/(r-1)}getTangent(e,t){const s=1e-4;let i=e-s,r=e+s;i<0&&(i=0),r>1&&(r=1);const n=this.getPoint(i),o=this.getPoint(r),a=t||(n.isVector2?new Qs:new Ei);return a.copy(o).sub(n).normalize(),a}getTangentAt(e,t){const s=this.getUtoTmapping(e);return this.getTangent(s,t)}computeFrenetFrames(e,t){const s=new Ei,i=[],r=[],n=[],o=new Ei,a=new or;for(let t=0;t<=e;t++){const s=t/e;i[t]=this.getTangentAt(s,new Ei)}r[0]=new Ei,n[0]=new Ei;let h=Number.MAX_VALUE;const l=Math.abs(i[0].x),u=Math.abs(i[0].y),c=Math.abs(i[0].z);l<=h&&(h=l,s.set(1,0,0)),u<=h&&(h=u,s.set(0,1,0)),c<=h&&s.set(0,0,1),o.crossVectors(i[0],s).normalize(),r[0].crossVectors(i[0],o),n[0].crossVectors(i[0],r[0]);for(let t=1;t<=e;t++){if(r[t]=r[t-1].clone(),n[t]=n[t-1].clone(),o.crossVectors(i[t-1],i[t]),o.length()>Number.EPSILON){o.normalize();const e=Math.acos($s(i[t-1].dot(i[t]),-1,1));r[t].applyMatrix4(a.makeRotationAxis(o,e))}n[t].crossVectors(i[t],r[t])}if(!0===t){let t=Math.acos($s(r[0].dot(r[e]),-1,1));t/=e,i[0].dot(o.crossVectors(r[0],r[e]))>0&&(t=-t);for(let s=1;s<=e;s++)r[s].applyMatrix4(a.makeRotationAxis(i[s],t*s)),n[s].crossVectors(i[s],r[s])}return{tangents:i,normals:r,binormals:n}}clone(){return(new this.constructor).copy(this)}copy(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}toJSON(){const e={metadata:{version:4.6,type:"Curve",generator:"Curve.toJSON"}};return e.arcLengthDivisions=this.arcLengthDivisions,e.type=this.type,e}fromJSON(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}}class th extends eh{constructor(e=0,t=0,s=1,i=1,r=0,n=2*Math.PI,o=!1,a=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=e,this.aY=t,this.xRadius=s,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=n,this.aClockwise=o,this.aRotation=a}getPoint(e,t=new Qs){const s=t,i=2*Math.PI;let r=this.aEndAngle-this.aStartAngle;const n=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(h)/r)+1)*r:0===l&&h===r-1&&(h=r-2,l=1),this.closed||h>0?o=i[(h-1)%r]:(rh.subVectors(i[0],i[1]).add(i[0]),o=rh);const u=i[h%r],c=i[(h+1)%r];if(this.closed||h+2i.length-2?i.length-1:n+1],u=i[n>i.length-3?i.length-1:n+2];return s.set(lh(o,a.x,h.x,l.x,u.x),lh(o,a.y,h.y,l.y,u.y)),s}copy(e){super.copy(e),this.points=[];for(let t=0,s=e.points.length;t=s){const e=i[r]-s,n=this.curves[r],o=n.getLength(),a=0===o?0:1-e/o;return n.getPointAt(a,t)}r++}return null}getLength(){const e=this.getCurveLengths();return e[e.length-1]}updateArcLengths(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()}getCurveLengths(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;const e=[];let t=0;for(let s=0,i=this.curves.length;s1&&!t[t.length-1].equals(t[0])&&t.push(t[0]),t}copy(e){super.copy(e),this.curves=[];for(let t=0,s=e.curves.length;t0){const e=h.getPoint(0);e.equals(this.currentPoint)||this.lineTo(e.x,e.y)}this.curves.push(h);const l=h.getPoint(1);return this.currentPoint.copy(l),this}copy(e){return super.copy(e),this.currentPoint.copy(e.currentPoint),this}toJSON(){const e=super.toJSON();return e.currentPoint=this.currentPoint.toArray(),e}fromJSON(e){return super.fromJSON(e),this.currentPoint.fromArray(e.currentPoint),this}}class _h extends Mn{constructor(e=[new Qs(0,-.5),new Qs(.5,0),new Qs(0,.5)],t=12,s=0,i=2*Math.PI){super(),this.type="LatheGeometry",this.parameters={points:e,segments:t,phiStart:s,phiLength:i},t=Math.floor(t),i=$s(i,0,2*Math.PI);const r=[],n=[],o=[],a=[],h=[],l=1/t,u=new Ei,c=new Qs,d=new Ei,p=new Ei,m=new Ei;let g=0,f=0;for(let t=0;t<=e.length-1;t++)switch(t){case 0:g=e[t+1].x-e[t].x,f=e[t+1].y-e[t].y,d.x=1*f,d.y=-g,d.z=0*f,m.copy(d),d.normalize(),a.push(d.x,d.y,d.z);break;case e.length-1:a.push(m.x,m.y,m.z);break;default:g=e[t+1].x-e[t].x,f=e[t+1].y-e[t].y,d.x=1*f,d.y=-g,d.z=0*f,p.copy(d),d.x+=m.x,d.y+=m.y,d.z+=m.z,d.normalize(),a.push(d.x,d.y,d.z),m.copy(p)}for(let r=0;r<=t;r++){const d=s+r*l*i,p=Math.sin(d),m=Math.cos(d);for(let s=0;s<=e.length-1;s++){u.x=e[s].x*p,u.y=e[s].y,u.z=e[s].x*m,n.push(u.x,u.y,u.z),c.x=r/t,c.y=s/(e.length-1),o.push(c.x,c.y);const i=a[3*s+0]*p,l=a[3*s+1],d=a[3*s+0]*m;h.push(i,l,d)}}for(let s=0;s0&&y(!0),t>0&&y(!1)),this.setIndex(l),this.setAttribute("position",new yn(u,3)),this.setAttribute("normal",new yn(c,3)),this.setAttribute("uv",new yn(d,2))}copy(e){return super.copy(e),this.parameters=Object.assign({},e.parameters),this}static fromJSON(e){return new Mh(e.radiusTop,e.radiusBottom,e.height,e.radialSegments,e.heightSegments,e.openEnded,e.thetaStart,e.thetaLength)}}class Ah extends Mh{constructor(e=1,t=1,s=32,i=1,r=!1,n=0,o=2*Math.PI){super(0,e,t,s,i,r,n,o),this.type="ConeGeometry",this.parameters={radius:e,height:t,radialSegments:s,heightSegments:i,openEnded:r,thetaStart:n,thetaLength:o}}static fromJSON(e){return new Ah(e.radius,e.height,e.radialSegments,e.heightSegments,e.openEnded,e.thetaStart,e.thetaLength)}}class Nh extends Mn{constructor(e=[],t=[],s=1,i=0){super(),this.type="PolyhedronGeometry",this.parameters={vertices:e,indices:t,radius:s,detail:i};const r=[],n=[];function o(e,t,s,i){const r=i+1,n=[];for(let i=0;i<=r;i++){n[i]=[];const o=e.clone().lerp(s,i/r),a=t.clone().lerp(s,i/r),h=r-i;for(let e=0;e<=h;e++)n[i][e]=0===e&&i===r?o:o.clone().lerp(a,e/h)}for(let e=0;e.9&&o<.1&&(t<.2&&(n[e+0]+=1),s<.2&&(n[e+2]+=1),i<.2&&(n[e+4]+=1))}}()}(),this.setAttribute("position",new yn(r,3)),this.setAttribute("normal",new yn(r.slice(),3)),this.setAttribute("uv",new yn(n,2)),0===i?this.computeVertexNormals():this.normalizeNormals()}copy(e){return super.copy(e),this.parameters=Object.assign({},e.parameters),this}static fromJSON(e){return new Nh(e.vertices,e.indices,e.radius,e.details)}}class Rh extends Nh{constructor(e=1,t=0){const s=(1+Math.sqrt(5))/2,i=1/s;super([-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-i,-s,0,-i,s,0,i,-s,0,i,s,-i,-s,0,-i,s,0,i,-s,0,i,s,0,-s,0,-i,s,0,-i,-s,0,i,s,0,i],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],e,t),this.type="DodecahedronGeometry",this.parameters={radius:e,detail:t}}static fromJSON(e){return new Rh(e.radius,e.detail)}}const Ch=new Ei,Eh=new Ei,Bh=new Ei,Ih=new Hr;class Ph extends Mn{constructor(e=null,t=1){if(super(),this.type="EdgesGeometry",this.parameters={geometry:e,thresholdAngle:t},null!==e){const s=4,i=Math.pow(10,s),r=Math.cos(Hs*t),n=e.getIndex(),o=e.getAttribute("position"),a=n?n.count:o.count,h=[0,0,0],l=["a","b","c"],u=new Array(3),c={},d=[];for(let e=0;e80*s){a=l=e[0],h=u=e[1];for(let t=s;tl&&(l=c),d>u&&(u=d);p=Math.max(l-a,u-h),p=0!==p?32767/p:0}return Oh(n,o,s,a,h,p,0),o};function Uh(e,t,s,i,r){let n,o;if(r===function(e,t,s,i){let r=0;for(let n=t,o=s-i;n0)for(n=t;n=t;n-=i)o=il(n,e[n],e[n+1],o);return o&&Zh(o,o.next)&&(rl(o),o=o.next),o}function Lh(e,t){if(!e)return e;t||(t=e);let s,i=e;do{if(s=!1,i.steiner||!Zh(i,i.next)&&0!==Jh(i.prev,i,i.next))i=i.next;else{if(rl(i),i=t=i.prev,i===i.next)break;s=!0}}while(s||i!==t);return t}function Oh(e,t,s,i,r,n,o){if(!e)return;!o&&n&&function(e,t,s,i){let r=e;do{0===r.z&&(r.z=qh(r.x,r.y,t,s,i)),r.prevZ=r.prev,r.nextZ=r.next,r=r.next}while(r!==e);r.prevZ.nextZ=null,r.prevZ=null,function(e){let t,s,i,r,n,o,a,h,l=1;do{for(s=e,e=null,n=null,o=0;s;){for(o++,i=s,a=0,t=0;t0||h>0&&i;)0!==a&&(0===h||!i||s.z<=i.z)?(r=s,s=s.nextZ,a--):(r=i,i=i.nextZ,h--),n?n.nextZ=r:e=r,r.prevZ=n,n=r;s=i}n.nextZ=null,l*=2}while(o>1)}(r)}(e,i,r,n);let a,h,l=e;for(;e.prev!==e.next;)if(a=e.prev,h=e.next,n?Dh(e,i,r,n):Vh(e))t.push(a.i/s|0),t.push(e.i/s|0),t.push(h.i/s|0),rl(e),e=h.next,l=h.next;else if((e=h)===l){o?1===o?Oh(e=kh(Lh(e),t,s),t,s,i,r,n,2):2===o&&Gh(e,t,s,i,r,n):Oh(Lh(e),t,s,i,r,n,1);break}}function Vh(e){const t=e.prev,s=e,i=e.next;if(Jh(t,s,i)>=0)return!1;const r=t.x,n=s.x,o=i.x,a=t.y,h=s.y,l=i.y,u=rn?r>o?r:o:n>o?n:o,p=a>h?a>l?a:l:h>l?h:l;let m=i.next;for(;m!==t;){if(m.x>=u&&m.x<=d&&m.y>=c&&m.y<=p&&Xh(r,a,n,h,o,l,m.x,m.y)&&Jh(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function Dh(e,t,s,i){const r=e.prev,n=e,o=e.next;if(Jh(r,n,o)>=0)return!1;const a=r.x,h=n.x,l=o.x,u=r.y,c=n.y,d=o.y,p=ah?a>l?a:l:h>l?h:l,f=u>c?u>d?u:d:c>d?c:d,y=qh(p,m,t,s,i),x=qh(g,f,t,s,i);let b=e.prevZ,v=e.nextZ;for(;b&&b.z>=y&&v&&v.z<=x;){if(b.x>=p&&b.x<=g&&b.y>=m&&b.y<=f&&b!==r&&b!==o&&Xh(a,u,h,c,l,d,b.x,b.y)&&Jh(b.prev,b,b.next)>=0)return!1;if(b=b.prevZ,v.x>=p&&v.x<=g&&v.y>=m&&v.y<=f&&v!==r&&v!==o&&Xh(a,u,h,c,l,d,v.x,v.y)&&Jh(v.prev,v,v.next)>=0)return!1;v=v.nextZ}for(;b&&b.z>=y;){if(b.x>=p&&b.x<=g&&b.y>=m&&b.y<=f&&b!==r&&b!==o&&Xh(a,u,h,c,l,d,b.x,b.y)&&Jh(b.prev,b,b.next)>=0)return!1;b=b.prevZ}for(;v&&v.z<=x;){if(v.x>=p&&v.x<=g&&v.y>=m&&v.y<=f&&v!==r&&v!==o&&Xh(a,u,h,c,l,d,v.x,v.y)&&Jh(v.prev,v,v.next)>=0)return!1;v=v.nextZ}return!0}function kh(e,t,s){let i=e;do{const r=i.prev,n=i.next.next;!Zh(r,n)&&Kh(r,i,i.next,n)&&tl(r,n)&&tl(n,r)&&(t.push(r.i/s|0),t.push(i.i/s|0),t.push(n.i/s|0),rl(i),rl(i.next),i=e=n),i=i.next}while(i!==e);return Lh(i)}function Gh(e,t,s,i,r,n){let o=e;do{let e=o.next.next;for(;e!==o.prev;){if(o.i!==e.i&&Yh(o,e)){let a=sl(o,e);return o=Lh(o,o.next),a=Lh(a,a.next),Oh(o,t,s,i,r,n,0),void Oh(a,t,s,i,r,n,0)}e=e.next}o=o.next}while(o!==e)}function Wh(e,t){return e.x-t.x}function Hh(e,t){const s=function(e,t){let s,i=t,r=-1/0;const n=e.x,o=e.y;do{if(o<=i.y&&o>=i.next.y&&i.next.y!==i.y){const e=i.x+(o-i.y)*(i.next.x-i.x)/(i.next.y-i.y);if(e<=n&&e>r&&(r=e,s=i.x=i.x&&i.x>=h&&n!==i.x&&Xh(os.x||i.x===s.x&&jh(s,i)))&&(s=i,c=u)),i=i.next}while(i!==a);return s}(e,t);if(!s)return t;const i=sl(s,e);return Lh(i,i.next),Lh(s,s.next)}function jh(e,t){return Jh(e.prev,e,t.prev)<0&&Jh(t.next,e,e.next)<0}function qh(e,t,s,i,r){return(e=1431655765&((e=858993459&((e=252645135&((e=16711935&((e=(e-s)*r|0)|e<<8))|e<<4))|e<<2))|e<<1))|(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=(t-i)*r|0)|t<<8))|t<<4))|t<<2))|t<<1))<<1}function $h(e){let t=e,s=e;do{(t.x=(e-o)*(n-a)&&(e-o)*(i-a)>=(s-o)*(t-a)&&(s-o)*(n-a)>=(r-o)*(i-a)}function Yh(e,t){return e.next.i!==t.i&&e.prev.i!==t.i&&!function(e,t){let s=e;do{if(s.i!==e.i&&s.next.i!==e.i&&s.i!==t.i&&s.next.i!==t.i&&Kh(s,s.next,e,t))return!0;s=s.next}while(s!==e);return!1}(e,t)&&(tl(e,t)&&tl(t,e)&&function(e,t){let s=e,i=!1;const r=(e.x+t.x)/2,n=(e.y+t.y)/2;do{s.y>n!=s.next.y>n&&s.next.y!==s.y&&r<(s.next.x-s.x)*(n-s.y)/(s.next.y-s.y)+s.x&&(i=!i),s=s.next}while(s!==e);return i}(e,t)&&(Jh(e.prev,e,t.prev)||Jh(e,t.prev,t))||Zh(e,t)&&Jh(e.prev,e,e.next)>0&&Jh(t.prev,t,t.next)>0)}function Jh(e,t,s){return(t.y-e.y)*(s.x-t.x)-(t.x-e.x)*(s.y-t.y)}function Zh(e,t){return e.x===t.x&&e.y===t.y}function Kh(e,t,s,i){const r=el(Jh(e,t,s)),n=el(Jh(e,t,i)),o=el(Jh(s,i,e)),a=el(Jh(s,i,t));return r!==n&&o!==a||(!(0!==r||!Qh(e,s,t))||(!(0!==n||!Qh(e,i,t))||(!(0!==o||!Qh(s,e,i))||!(0!==a||!Qh(s,t,i)))))}function Qh(e,t,s){return t.x<=Math.max(e.x,s.x)&&t.x>=Math.min(e.x,s.x)&&t.y<=Math.max(e.y,s.y)&&t.y>=Math.min(e.y,s.y)}function el(e){return e>0?1:e<0?-1:0}function tl(e,t){return Jh(e.prev,e,e.next)<0?Jh(e,t,e.next)>=0&&Jh(e,e.prev,t)>=0:Jh(e,t,e.prev)<0||Jh(e,e.next,t)<0}function sl(e,t){const s=new nl(e.i,e.x,e.y),i=new nl(t.i,t.x,t.y),r=e.next,n=t.prev;return e.next=t,t.prev=e,s.next=r,r.prev=s,i.next=s,s.prev=i,n.next=i,i.prev=n,i}function il(e,t,s,i){const r=new nl(e,t,s);return i?(r.next=i.next,r.prev=i,i.next.prev=r,i.next=r):(r.prev=r,r.next=r),r}function rl(e){e.next.prev=e.prev,e.prev.next=e.next,e.prevZ&&(e.prevZ.nextZ=e.nextZ),e.nextZ&&(e.nextZ.prevZ=e.prevZ)}function nl(e,t,s){this.i=e,this.x=t,this.y=s,this.prev=null,this.next=null,this.z=0,this.prevZ=null,this.nextZ=null,this.steiner=!1}class ol{static area(e){const t=e.length;let s=0;for(let i=t-1,r=0;r2&&e[t-1].equals(e[0])&&e.pop()}function hl(e,t){for(let s=0;sNumber.EPSILON){const c=Math.sqrt(u),d=Math.sqrt(h*h+l*l),p=t.x-a/c,m=t.y+o/c,g=((s.x-l/d-p)*l-(s.y+h/d-m)*h)/(o*l-a*h);i=p+o*g-e.x,r=m+a*g-e.y;const f=i*i+r*r;if(f<=2)return new Qs(i,r);n=Math.sqrt(f/2)}else{let e=!1;o>Number.EPSILON?h>Number.EPSILON&&(e=!0):o<-Number.EPSILON?h<-Number.EPSILON&&(e=!0):Math.sign(a)===Math.sign(l)&&(e=!0),e?(i=-a,r=o,n=Math.sqrt(u)):(i=o,r=a,n=Math.sqrt(u/2))}return new Qs(i/n,r/n)}const B=[];for(let e=0,t=A.length,s=t-1,i=e+1;e=0;e--){const t=e/p,s=u*Math.cos(t*Math.PI/2),i=c*Math.sin(t*Math.PI/2)+d;for(let e=0,t=A.length;e=0;){const i=s;let r=s-1;r<0&&(r=e.length-1);for(let e=0,s=a+2*p;e0)&&d.push(t,r,h),(e!==s-1||a0!=e>0&&this.version++,this._anisotropy=e}get clearcoat(){return this._clearcoat}set clearcoat(e){this._clearcoat>0!=e>0&&this.version++,this._clearcoat=e}get iridescence(){return this._iridescence}set iridescence(e){this._iridescence>0!=e>0&&this.version++,this._iridescence=e}get dispersion(){return this._dispersion}set dispersion(e){this._dispersion>0!=e>0&&this.version++,this._dispersion=e}get sheen(){return this._sheen}set sheen(e){this._sheen>0!=e>0&&this.version++,this._sheen=e}get transmission(){return this._transmission}set transmission(e){this._transmission>0!=e>0&&this.version++,this._transmission=e}copy(e){return super.copy(e),this.defines={STANDARD:"",PHYSICAL:""},this.anisotropy=e.anisotropy,this.anisotropyRotation=e.anisotropyRotation,this.anisotropyMap=e.anisotropyMap,this.clearcoat=e.clearcoat,this.clearcoatMap=e.clearcoatMap,this.clearcoatRoughness=e.clearcoatRoughness,this.clearcoatRoughnessMap=e.clearcoatRoughnessMap,this.clearcoatNormalMap=e.clearcoatNormalMap,this.clearcoatNormalScale.copy(e.clearcoatNormalScale),this.dispersion=e.dispersion,this.ior=e.ior,this.iridescence=e.iridescence,this.iridescenceMap=e.iridescenceMap,this.iridescenceIOR=e.iridescenceIOR,this.iridescenceThicknessRange=[...e.iridescenceThicknessRange],this.iridescenceThicknessMap=e.iridescenceThicknessMap,this.sheen=e.sheen,this.sheenColor.copy(e.sheenColor),this.sheenColorMap=e.sheenColorMap,this.sheenRoughness=e.sheenRoughness,this.sheenRoughnessMap=e.sheenRoughnessMap,this.transmission=e.transmission,this.transmissionMap=e.transmissionMap,this.thickness=e.thickness,this.thicknessMap=e.thicknessMap,this.attenuationDistance=e.attenuationDistance,this.attenuationColor.copy(e.attenuationColor),this.specularIntensity=e.specularIntensity,this.specularIntensityMap=e.specularIntensityMap,this.specularColor.copy(e.specularColor),this.specularColorMap=e.specularColorMap,this}}class Rl extends Kr{constructor(e){super(),this.isMeshPhongMaterial=!0,this.type="MeshPhongMaterial",this.color=new Yr(16777215),this.specular=new Yr(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Yr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new fr,this.combine=0,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.specular.copy(e.specular),this.shininess=e.shininess,this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.flatShading=e.flatShading,this.fog=e.fog,this}}class Cl extends Kr{constructor(e){super(),this.isMeshToonMaterial=!0,this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new Yr(16777215),this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Yr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.gradientMap=e.gradientMap,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}}class El extends Kr{constructor(e){super(),this.isMeshNormalMaterial=!0,this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.flatShading=!1,this.setValues(e)}copy(e){return super.copy(e),this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.flatShading=e.flatShading,this}}class Bl extends Kr{constructor(e){super(),this.isMeshLambertMaterial=!0,this.type="MeshLambertMaterial",this.color=new Yr(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Yr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new fr,this.combine=0,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.flatShading=e.flatShading,this.fog=e.fog,this}}class Il extends Kr{constructor(e){super(),this.isMeshDepthMaterial=!0,this.type="MeshDepthMaterial",this.depthPacking=3200,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.setValues(e)}copy(e){return super.copy(e),this.depthPacking=e.depthPacking,this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this}}class Pl extends Kr{constructor(e){super(),this.isMeshDistanceMaterial=!0,this.type="MeshDistanceMaterial",this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.setValues(e)}copy(e){return super.copy(e),this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this}}class Fl extends Kr{constructor(e){super(),this.isMeshMatcapMaterial=!0,this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new Yr(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.defines={MATCAP:""},this.color.copy(e.color),this.matcap=e.matcap,this.map=e.map,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.flatShading=e.flatShading,this.fog=e.fog,this}}class zl extends Ma{constructor(e){super(),this.isLineDashedMaterial=!0,this.type="LineDashedMaterial",this.scale=1,this.dashSize=3,this.gapSize=1,this.setValues(e)}copy(e){return super.copy(e),this.scale=e.scale,this.dashSize=e.dashSize,this.gapSize=e.gapSize,this}}function Ul(e,t=!1){let s="{";!0===e.isNode&&(s+=e.id,e=e.getSelf());for(const{property:i,childNode:r}of Ll(e))s+=","+i.slice(0,-4)+":"+r.getCacheKey(t);return s+="}",s}function*Ll(e,t=!1){for(const s in e){if(!0===s.startsWith("_"))continue;const i=e[s];if(!0===Array.isArray(i))for(let e=0;ee.charCodeAt(0))).buffer}var Gl=Object.freeze({__proto__:null,arrayBufferToBase64:Dl,base64ToArrayBuffer:kl,getCacheKey:Ul,getNodeChildren:Ll,getValueFromType:Vl,getValueType:Ol});const Wl={VERTEX:"vertex",FRAGMENT:"fragment"},Hl={NONE:"none",FRAME:"frame",RENDER:"render",OBJECT:"object"},jl={BOOLEAN:"bool",INTEGER:"int",FLOAT:"float",VECTOR2:"vec2",VECTOR3:"vec3",VECTOR4:"vec4",MATRIX2:"mat2",MATRIX3:"mat3",MATRIX4:"mat4"},ql=["fragment","vertex"],$l=["setup","analyze","generate"],Xl=[...ql,"compute"],Yl=["x","y","z","w"],Jl=new Map;let Zl=0;class Kl extends ks{constructor(e=null){super(),this.nodeType=e,this.updateType=Hl.NONE,this.updateBeforeType=Hl.NONE,this.updateAfterType=Hl.NONE,this.uuid=Ks.generateUUID(),this.version=0,this._cacheKey=null,this._cacheKeyVersion=0,this.global=!1,this.isNode=!0,Object.defineProperty(this,"id",{value:Zl++})}set needsUpdate(e){!0===e&&this.version++}get type(){return this.constructor.type}onUpdate(e,t){return this.updateType=t,this.update=e.bind(this.getSelf()),this}onFrameUpdate(e){return this.onUpdate(e,Hl.FRAME)}onRenderUpdate(e){return this.onUpdate(e,Hl.RENDER)}onObjectUpdate(e){return this.onUpdate(e,Hl.OBJECT)}onReference(e){return this.updateReference=e.bind(this.getSelf()),this}getSelf(){return this.self||this}updateReference(){return this}isGlobal(){return this.global}*getChildren(){for(const{childNode:e}of Ll(this))yield e}dispose(){this.dispatchEvent({type:"dispose"})}traverse(e){e(this);for(const t of this.getChildren())t.traverse(e)}getCacheKey(e=!1){return!0!==(e=e||this.version!==this._cacheKeyVersion)&&null!==this._cacheKey||(this._cacheKey=Ul(this,e),this._cacheKeyVersion=this.version),this._cacheKey}getScope(){return this}getHash(){return this.uuid}getUpdateType(){return this.updateType}getUpdateBeforeType(){return this.updateBeforeType}getUpdateAfterType(){return this.updateAfterType}getElementType(e){const t=this.getNodeType(e);return e.getElementType(t)}getNodeType(e){const t=e.getNodeProperties(this);return t.outputNode?t.outputNode.getNodeType(e):this.nodeType}getShared(e){const t=this.getHash(e);return e.getNodeFromHash(t)||this}setup(e){const t=e.getNodeProperties(this);let s=0;for(const e of this.getChildren())t["node"+s++]=e;return null}analyze(e){if(1===e.increaseUsage(this)){const t=e.getNodeProperties(this);for(const s of Object.values(t))s&&!0===s.isNode&&s.build(e)}}generate(e,t){const{outputNode:s}=e.getNodeProperties(this);if(s&&!0===s.isNode)return s.build(e,t)}updateBefore(){console.warn("Abstract function.")}updateAfter(){console.warn("Abstract function.")}update(){console.warn("Abstract function.")}build(e,t=null){const s=this.getShared(e);if(this!==s)return s.build(e,t);e.addNode(this),e.addChain(this);let i=null;const r=e.getBuildStage();if("setup"===r){this.updateReference(e);const t=e.getNodeProperties(this);if(!0!==t.initialized){e.stack.nodes.length;t.initialized=!0,t.outputNode=this.setup(e),null!==t.outputNode&&e.stack.nodes.length;for(const s of Object.values(t))s&&!0===s.isNode&&s.build(e)}}else if("analyze"===r)this.analyze(e);else if("generate"===r){if(1===this.generate.length){const s=this.getNodeType(e),r=e.getDataFromNode(this);i=r.snippet,void 0===i&&(i=this.generate(e)||"",r.snippet=i),i=e.format(i,s,t)}else i=this.generate(e,t)||""}return e.removeChain(this),i}getSerializeChildren(){return Ll(this)}serialize(e){const t=this.getSerializeChildren(),s={};for(const{property:i,index:r,childNode:n}of t)void 0!==r?(void 0===s[i]&&(s[i]=Number.isInteger(r)?[]:{}),s[i][r]=n.toJSON(e.meta).uuid):s[i]=n.toJSON(e.meta).uuid;Object.keys(s).length>0&&(e.inputNodes=s)}deserialize(e){if(void 0!==e.inputNodes){const t=e.meta.nodes;for(const s in e.inputNodes)if(Array.isArray(e.inputNodes[s])){const i=[];for(const r of e.inputNodes[s])i.push(t[r]);this[s]=i}else if("object"==typeof e.inputNodes[s]){const i={};for(const r in e.inputNodes[s]){const n=e.inputNodes[s][r];i[r]=t[n]}this[s]=i}else{const i=e.inputNodes[s];this[s]=t[i]}}}toJSON(e){const{uuid:t,type:s}=this,i=void 0===e||"string"==typeof e;i&&(e={textures:{},images:{},nodes:{}});let r=e.nodes[t];function n(e){const t=[];for(const s in e){const i=e[s];delete i.metadata,t.push(i)}return t}if(void 0===r&&(r={uuid:t,type:s,meta:e,metadata:{version:4.6,type:"Node",generator:"Node.toJSON"}},!0!==i&&(e.nodes[r.uuid]=r),this.serialize(r),delete r.meta),i){const t=n(e.textures),s=n(e.images),i=n(e.nodes);t.length>0&&(r.textures=t),s.length>0&&(r.images=s),i.length>0&&(r.nodes=i)}return r}}function Ql(e,t){const s="Node",i=e+s;if("function"!=typeof t)throw new Error(`TSL.Node: Node class ${e} is not a class`);if(Jl.has(i))console.warn(`TSL.Node: Redefinition of node class ${i}`);else{if(e.slice(-4)!==s)return Jl.set(i,t),t.type=i,i;console.warn(`TSL.Node: Node class ${i} should not have '${s}' suffix.`)}}function eu(e){const t=Jl.get(e);if(void 0!==t)return new t}Kl.type=Ql("",Kl);class tu extends Kl{constructor(e,t){super(),this.node=e,this.indexNode=t,this.isArrayElementNode=!0}getNodeType(e){return this.node.getElementType(e)}generate(e){return`${this.node.build(e)}[ ${this.indexNode.build(e,"uint")} ]`}}tu.type=Ql("ArrayElement",tu);class su extends Kl{constructor(e,t){super(),this.node=e,this.convertTo=t}getNodeType(e){const t=this.node.getNodeType(e);let s=null;for(const i of this.convertTo.split("|"))null!==s&&e.getTypeLength(t)!==e.getTypeLength(i)||(s=i);return s}serialize(e){super.serialize(e),e.convertTo=this.convertTo}deserialize(e){super.deserialize(e),this.convertTo=e.convertTo}generate(e,t){const s=this.node,i=this.getNodeType(e),r=s.build(e,i);return e.format(r,i,t)}}su.type=Ql("Convert",su);class iu extends Kl{constructor(e){super(e),this.isTempNode=!0}hasDependencies(e){return e.getDataFromNode(this).usageCount>1}build(e,t){if("generate"===e.getBuildStage()){const s=e.getVectorType(this.getNodeType(e,t)),i=e.getDataFromNode(this);if(void 0!==i.propertyName)return e.format(i.propertyName,s,t);if("void"!==s&&"void"!==t&&this.hasDependencies(e)){const r=super.build(e,s),n=e.getVarFromNode(this,null,s),o=e.getPropertyName(n);return e.addLineFlowCode(`${o} = ${r}`),i.snippet=r,i.propertyName=o,e.format(i.propertyName,s,t)}}return super.build(e,t)}}iu.type=Ql("Temp",iu);class ru extends iu{constructor(e=[],t=null){super(t),this.nodes=e}getNodeType(e){return null!==this.nodeType?e.getVectorType(this.nodeType):e.getTypeFromLength(this.nodes.reduce(((t,s)=>t+e.getTypeLength(s.getNodeType(e))),0))}generate(e,t){const s=this.getNodeType(e),i=this.nodes,r=e.getComponentType(s),n=[];for(const t of i){let s=t.build(e);const i=e.getComponentType(t.getNodeType(e));i!==r&&(s=e.format(s,i,r)),n.push(s)}const o=`${e.getType(s)}( ${n.join(", ")} )`;return e.format(o,s,t)}}ru.type=Ql("Join",ru);const nu=Yl.join("");class ou extends Kl{constructor(e,t="x"){super(),this.node=e,this.components=t,this.isSplitNode=!0}getVectorLength(){let e=this.components.length;for(const t of this.components)e=Math.max(Yl.indexOf(t)+1,e);return e}getComponentType(e){return e.getComponentType(this.node.getNodeType(e))}getNodeType(e){return e.getTypeFromLength(this.components.length,this.getComponentType(e))}generate(e,t){const s=this.node,i=e.getTypeLength(s.getNodeType(e));let r=null;if(i>1){let n=null;this.getVectorLength()>=i&&(n=e.getTypeFromLength(this.getVectorLength(),this.getComponentType(e)));const o=s.build(e,n);r=this.components.length===i&&this.components===nu.slice(0,this.components.length)?e.format(o,n,t):e.format(`${o}.${this.components}`,this.getNodeType(e),t)}else r=s.build(e,t);return r}serialize(e){super.serialize(e),e.components=this.components}deserialize(e){super.deserialize(e),this.components=e.components}}ou.type=Ql("Split",ou);class au extends iu{constructor(e,t,s){super(),this.sourceNode=e,this.components=t,this.targetNode=s}getNodeType(e){return this.sourceNode.getNodeType(e)}generate(e){const{sourceNode:t,components:s,targetNode:i}=this,r=this.getNodeType(e),n=e.getTypeFromLength(s.length),o=i.build(e,n),a=t.build(e,r),h=e.getTypeLength(r),l=[];for(let e=0;ee.replace(/r|s/g,"x").replace(/g|t/g,"y").replace(/b|p/g,"z").replace(/a|q/g,"w"),gu=e=>mu(e).split("").sort().join(""),fu={setup(e,t){const s=t.shift();return e(ku(s),...t)},get(e,t,s){if("string"==typeof t&&void 0===e[t]){if(!0!==e.isStackNode&&"assign"===t)return(...e)=>(cu.assign(s,...e),s);if(du.has(t)){const i=du.get(t);return e.isStackNode?(...e)=>s.add(i(...e)):(...e)=>i(s,...e)}if("self"===t)return e;if(t.endsWith("Assign")&&du.has(t.slice(0,t.length-6))){const i=du.get(t.slice(0,t.length-6));return e.isStackNode?(...e)=>s.assign(e[0],i(...e)):(...e)=>s.assign(i(s,...e))}if(!0===/^[xyzwrgbastpq]{1,4}$/.test(t))return t=mu(t),Du(new ou(s,t));if(!0===/^set[XYZWRGBASTPQ]{1,4}$/.test(t))return t=gu(t.slice(3).toLowerCase()),s=>Du(new au(e,t,s));if(!0===/^flip[XYZWRGBASTPQ]{1,4}$/.test(t))return t=gu(t.slice(4).toLowerCase()),()=>Du(new hu(Du(e),t));if("width"===t||"height"===t||"depth"===t)return"width"===t?t="x":"height"===t?t="y":"depth"===t&&(t="z"),Du(new ou(e,t));if(!0===/^\d+$/.test(t))return Du(new tu(s,new uu(Number(t),"uint")))}return Reflect.get(e,t,s)},set:(e,t,s,i)=>"string"!=typeof t||void 0!==e[t]||!0!==/^[xyzwrgbastpq]{1,4}$/.test(t)&&"width"!==t&&"height"!==t&&"depth"!==t&&!0!==/^\d+$/.test(t)?Reflect.set(e,t,s,i):(i[t].assign(s),!0)},yu=new WeakMap,xu=new WeakMap,bu=function(e,t=null){for(const s in e)e[s]=Du(e[s],t);return e},vu=function(e,t=null){const s=e.length;for(let i=0;iDu(null!==i?Object.assign(e,i):e);return null===t?(...t)=>r(new e(...Gu(t))):null!==s?(s=Du(s),(...i)=>r(new e(t,...Gu(i),s))):(...s)=>r(new e(t,...Gu(s)))},_u=function(e,...t){return Du(new e(...Gu(t)))};class wu extends Kl{constructor(e,t){super(),this.shaderNode=e,this.inputNodes=t}getNodeType(e){return this.shaderNode.nodeType||this.getOutputNode(e).getNodeType(e)}call(e){const{shaderNode:t,inputNodes:s}=this,i=e.getNodeProperties(t);if(i.onceOutput)return i.onceOutput;let r=null;if(t.layout){let i=xu.get(e.constructor);void 0===i&&(i=new WeakMap,xu.set(e.constructor,i));let n=i.get(t);void 0===n&&(n=Du(e.buildFunctionNode(t)),i.set(t,n)),null!==e.currentFunctionNode&&e.currentFunctionNode.includes.push(n),r=Du(n.call(s))}else{const i=t.jsFunc,n=null!==s?i(s,e):i(e);r=Du(n)}return t.once&&(i.onceOutput=r),r}getOutputNode(e){const t=e.getNodeProperties(this);return null===t.outputNode&&(t.outputNode=this.setupOutput(e)),t.outputNode}setup(e){return this.getOutputNode(e)}setupOutput(e){return e.addStack(),e.stack.outputNode=this.call(e),e.removeStack()}generate(e,t){return this.getOutputNode(e).build(e,t)}}class Su extends Kl{constructor(e,t){super(t),this.jsFunc=e,this.layout=null,this.global=!0,this.once=!1}setLayout(e){return this.layout=e,this}call(e=null){return ku(e),Du(new wu(this,e))}setup(){return this.call()}}const Mu=[!1,!0],Au=[0,1,2,3],Nu=[-1,-2],Ru=[.5,1.5,1/3,1e-6,1e6,Math.PI,2*Math.PI,1/Math.PI,2/Math.PI,1/(2*Math.PI),Math.PI/2],Cu=new Map;for(const e of Mu)Cu.set(e,new uu(e));const Eu=new Map;for(const e of Au)Eu.set(e,new uu(e,"uint"));const Bu=new Map([...Eu].map((e=>new uu(e.value,"int"))));for(const e of Nu)Bu.set(e,new uu(e,"int"));const Iu=new Map([...Bu].map((e=>new uu(e.value))));for(const e of Ru)Iu.set(e,new uu(e));for(const e of Ru)Iu.set(-e,new uu(-e));const Pu={bool:Cu,uint:Eu,ints:Bu,float:Iu},Fu=new Map([...Cu,...Iu]),zu=(e,t)=>Fu.has(e)?Fu.get(e):!0===e.isNode?e:new uu(e,t),Uu=function(e,t=null){return(...s)=>{if((0===s.length||!["bool","float","int","uint"].includes(e)&&s.every((e=>"object"!=typeof e)))&&(s=[Vl(e,...s)]),1===s.length&&null!==t&&t.has(s[0]))return Du(t.get(s[0]));if(1===s.length){const t=zu(s[0],e);return(e=>{try{return e.getNodeType()}catch(e){return}})(t)===e?Du(t):Du(new su(t,e))}const i=s.map((e=>zu(e)));return Du(new ru(i,e))}},Lu=e=>"object"==typeof e&&null!==e?e.value:e,Ou=e=>null!=e?e.nodeType||e.convertTo||("string"==typeof e?e:null):null;function Vu(e,t){return new Proxy(new Su(e,t),fu)}const Du=(e,t=null)=>function(e,t=null){const s=Ol(e);if("node"===s){let t=yu.get(e);return void 0===t&&(t=new Proxy(e,fu),yu.set(e,t),yu.set(t,t)),t}return null===t&&("float"===s||"boolean"===s)||s&&"shader"!==s&&"string"!==s?Du(zu(e,t)):"shader"===s?ju(e):e}(e,t),ku=(e,t=null)=>new bu(e,t),Gu=(e,t=null)=>new vu(e,t),Wu=(...e)=>new Tu(...e),Hu=(...e)=>new _u(...e),ju=(e,t)=>{const s=new Vu(e,t),i=(...e)=>{let t;return ku(e),t=e[0]&&e[0].isNode?[...e]:e[0],s.call(t)};return i.shaderNode=s,i.setLayout=e=>(s.setLayout(e),i),i.once=()=>(s.once=!0,i),i},qu=(...e)=>(console.warn("TSL.ShaderNode: tslFn() has been renamed to Fn()."),ju(...e));pu("toGlobal",(e=>(e.global=!0,e)));const $u=e=>{cu=e},Xu=()=>cu,Yu=(...e)=>cu.If(...e);function Ju(e){return cu&&cu.add(e),e}pu("append",Ju);const Zu=new Uu("color"),Ku=new Uu("float",Pu.float),Qu=new Uu("int",Pu.ints),ec=new Uu("uint",Pu.uint),tc=new Uu("bool",Pu.bool),sc=new Uu("vec2"),ic=new Uu("ivec2"),rc=new Uu("uvec2"),nc=new Uu("bvec2"),oc=new Uu("vec3"),ac=new Uu("ivec3"),hc=new Uu("uvec3"),lc=new Uu("bvec3"),uc=new Uu("vec4"),cc=new Uu("ivec4"),dc=new Uu("uvec4"),pc=new Uu("bvec4"),mc=new Uu("mat2"),gc=new Uu("mat3"),fc=new Uu("mat4"),yc=(e="")=>Du(new uu(e,"string")),xc=e=>Du(new uu(e,"ArrayBuffer"));pu("toColor",Zu),pu("toFloat",Ku),pu("toInt",Qu),pu("toUint",ec),pu("toBool",tc),pu("toVec2",sc),pu("toIVec2",ic),pu("toUVec2",rc),pu("toBVec2",nc),pu("toVec3",oc),pu("toIVec3",ac),pu("toUVec3",hc),pu("toBVec3",lc),pu("toVec4",uc),pu("toIVec4",cc),pu("toUVec4",dc),pu("toBVec4",pc),pu("toMat2",mc),pu("toMat3",gc),pu("toMat4",fc);const bc=Wu(tu),vc=(e,t)=>Du(new su(Du(e),t)),Tc=(e,t)=>Du(new ou(Du(e),t));pu("element",bc),pu("convert",vc);class _c extends Kl{constructor(e,t=!1){super("string"),this.name=e,this.version=0,this.shared=t,this.isUniformGroup=!0}set needsUpdate(e){!0===e&&this.version++}serialize(e){super.serialize(e),e.name=this.name,e.version=this.version,e.shared=this.shared}deserialize(e){super.deserialize(e),this.name=e.name,this.version=e.version,this.shared=e.shared}}_c.type=Ql("UniformGroup",_c);const wc=e=>new _c(e),Sc=e=>new _c(e,!0),Mc=Sc("frame"),Ac=Sc("render"),Nc=wc("object");class Rc extends lu{constructor(e,t=null){super(e,t),this.isUniformNode=!0,this.name="",this.groupNode=Nc}label(e){return this.name=e,this}setGroup(e){return this.groupNode=e,this}getGroup(){return this.groupNode}getUniformHash(e){return this.getHash(e)}onUpdate(e,t){const s=this.getSelf();return e=e.bind(s),super.onUpdate((t=>{const i=e(t,s);void 0!==i&&(this.value=i)}),t)}generate(e,t){const s=this.getNodeType(e),i=this.getUniformHash(e);let r=e.getNodeFromHash(i);void 0===r&&(e.setHashNode(this,i),r=this);const n=r.getInputType(e),o=e.getUniformFromNode(r,n,e.shaderStage,this.name||e.context.label),a=e.getPropertyName(o);return void 0!==e.context.label&&delete e.context.label,e.format(a,s,t)}}Rc.type=Ql("Uniform",Rc);const Cc=(e,t)=>{const s=Ou(t||e),i=e&&!0===e.isNode?e.node&&e.node.value||e.value:e;return Du(new Rc(i,s))};class Ec extends Kl{constructor(e,t=null,s=!1){super(e),this.name=t,this.varying=s,this.isPropertyNode=!0}getHash(e){return this.name||super.getHash(e)}isGlobal(){return!0}generate(e){let t;return!0===this.varying?(t=e.getVaryingFromNode(this,this.name),t.needsInterpolation=!0):t=e.getVarFromNode(this,this.name),e.getPropertyName(t)}}Ec.type=Ql("Property",Ec);const Bc=(e,t)=>Du(new Ec(e,t)),Ic=(e,t)=>Du(new Ec(e,t,!0)),Pc=Hu(Ec,"vec4","DiffuseColor"),Fc=Hu(Ec,"vec3","EmissiveColor"),zc=Hu(Ec,"float","Roughness"),Uc=Hu(Ec,"float","Metalness"),Lc=Hu(Ec,"float","Clearcoat"),Oc=Hu(Ec,"float","ClearcoatRoughness"),Vc=Hu(Ec,"vec3","Sheen"),Dc=Hu(Ec,"float","SheenRoughness"),kc=Hu(Ec,"float","Iridescence"),Gc=Hu(Ec,"float","IridescenceIOR"),Wc=Hu(Ec,"float","IridescenceThickness"),Hc=Hu(Ec,"float","AlphaT"),jc=Hu(Ec,"float","Anisotropy"),qc=Hu(Ec,"vec3","AnisotropyT"),$c=Hu(Ec,"vec3","AnisotropyB"),Xc=Hu(Ec,"color","SpecularColor"),Yc=Hu(Ec,"float","SpecularF90"),Jc=Hu(Ec,"float","Shininess"),Zc=Hu(Ec,"vec4","Output"),Kc=Hu(Ec,"float","dashSize"),Qc=Hu(Ec,"float","gapSize"),ed=Hu(Ec,"float","pointWidth"),td=Hu(Ec,"float","IOR"),sd=Hu(Ec,"float","Transmission"),id=Hu(Ec,"float","Thickness"),rd=Hu(Ec,"float","AttenuationDistance"),nd=Hu(Ec,"color","AttenuationColor"),od=Hu(Ec,"float","Dispersion");class ad extends iu{constructor(e,t){super(),this.targetNode=e,this.sourceNode=t}hasDependencies(){return!1}getNodeType(e,t){return"void"!==t?this.targetNode.getNodeType(e):"void"}needsSplitAssign(e){const{targetNode:t}=this;if(!1===e.isAvailable("swizzleAssign")&&t.isSplitNode&&t.components.length>1){const s=e.getTypeLength(t.node.getNodeType(e));return Yl.join("").slice(0,s)!==t.components}return!1}generate(e,t){const{targetNode:s,sourceNode:i}=this,r=this.needsSplitAssign(e),n=s.getNodeType(e),o=s.context({assign:!0}).build(e),a=i.build(e,n),h=i.getNodeType(e),l=e.getDataFromNode(this);let u;if(!0===l.initialized)"void"!==t&&(u=o);else if(r){const i=e.getVarFromNode(this,null,n),r=e.getPropertyName(i);e.addLineFlowCode(`${r} = ${a}`);const h=s.node.context({assign:!0}).build(e);for(let t=0;t(t=t.length>1||t[0]&&!0===t[0].isNode?Gu(t):ku(t[0]),Du(new ld(Du(e),t)));pu("call",ud);class cd extends iu{constructor(e,t,s,...i){if(super(),i.length>0){let r=new cd(e,t,s);for(let t=0;t>"===s||"<<"===s)return e.getIntegerType(n);if("!"===s||"=="===s||"&&"===s||"||"===s||"^^"===s)return"bool";if("<"===s||">"===s||"<="===s||">="===s){const s=t?e.getTypeLength(t):Math.max(e.getTypeLength(n),e.getTypeLength(o));return s>1?`bvec${s}`:"bool"}return"float"===n&&e.isMatrix(o)?o:e.isMatrix(n)&&e.isVector(o)?e.getVectorFromMatrix(n):e.isVector(n)&&e.isMatrix(o)?e.getVectorFromMatrix(o):e.getTypeLength(o)>e.getTypeLength(n)?o:n}generate(e,t){const s=this.op,i=this.aNode,r=this.bNode,n=this.getNodeType(e,t);let o=null,a=null;"void"!==n?(o=i.getNodeType(e),a=void 0!==r?r.getNodeType(e):null,"<"===s||">"===s||"<="===s||">="===s||"=="===s?e.isVector(o)?a=o:o!==a&&(o=a="float"):">>"===s||"<<"===s?(o=n,a=e.changeComponentType(a,"uint")):e.isMatrix(o)&&e.isVector(a)?a=e.getVectorFromMatrix(o):o=e.isVector(o)&&e.isMatrix(a)?e.getVectorFromMatrix(a):a=n):o=a=n;const h=i.build(e,o),l=void 0!==r?r.build(e,a):null,u=e.getTypeLength(t),c=e.getFunctionOperator(s);return"void"!==t?"<"===s&&u>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThan",t)}( ${h}, ${l} )`,n,t):e.format(`( ${h} < ${l} )`,n,t):"<="===s&&u>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThanEqual",t)}( ${h}, ${l} )`,n,t):e.format(`( ${h} <= ${l} )`,n,t):">"===s&&u>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThan",t)}( ${h}, ${l} )`,n,t):e.format(`( ${h} > ${l} )`,n,t):">="===s&&u>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThanEqual",t)}( ${h}, ${l} )`,n,t):e.format(`( ${h} >= ${l} )`,n,t):"!"===s||"~"===s?e.format(`(${s}${h})`,o,t):c?e.format(`${c}( ${h}, ${l} )`,n,t):e.format(`( ${h} ${s} ${l} )`,n,t):"void"!==o?c?e.format(`${c}( ${h}, ${l} )`,n,t):e.format(`${h} ${s} ${l}`,n,t):void 0}serialize(e){super.serialize(e),e.op=this.op}deserialize(e){super.deserialize(e),this.op=e.op}}cd.type=Ql("Operator",cd);const dd=Wu(cd,"+"),pd=Wu(cd,"-"),md=Wu(cd,"*"),gd=Wu(cd,"/"),fd=Wu(cd,"%"),yd=Wu(cd,"=="),xd=Wu(cd,"!="),bd=Wu(cd,"<"),vd=Wu(cd,">"),Td=Wu(cd,"<="),_d=Wu(cd,">="),wd=Wu(cd,"&&"),Sd=Wu(cd,"||"),Md=Wu(cd,"!"),Ad=Wu(cd,"^^"),Nd=Wu(cd,"&"),Rd=Wu(cd,"~"),Cd=Wu(cd,"|"),Ed=Wu(cd,"^"),Bd=Wu(cd,"<<"),Id=Wu(cd,">>");pu("add",dd),pu("sub",pd),pu("mul",md),pu("div",gd),pu("modInt",fd),pu("equal",yd),pu("notEqual",xd),pu("lessThan",bd),pu("greaterThan",vd),pu("lessThanEqual",Td),pu("greaterThanEqual",_d),pu("and",wd),pu("or",Sd),pu("not",Md),pu("xor",Ad),pu("bitAnd",Nd),pu("bitNot",Rd),pu("bitOr",Cd),pu("bitXor",Ed),pu("shiftLeft",Bd),pu("shiftRight",Id);const Pd=(...e)=>(console.warn("TSL.OperatorNode: .remainder() has been renamed to .modInt()."),fd(...e));pu("remainder",Pd);class Fd extends iu{constructor(e,t,s=null,i=null){super(),this.method=e,this.aNode=t,this.bNode=s,this.cNode=i}getInputType(e){const t=this.aNode.getNodeType(e),s=this.bNode?this.bNode.getNodeType(e):null,i=this.cNode?this.cNode.getNodeType(e):null,r=e.isMatrix(t)?0:e.getTypeLength(t),n=e.isMatrix(s)?0:e.getTypeLength(s),o=e.isMatrix(i)?0:e.getTypeLength(i);return r>n&&r>o?t:n>o?s:o>r?i:t}getNodeType(e){const t=this.method;return t===Fd.LENGTH||t===Fd.DISTANCE||t===Fd.DOT?"float":t===Fd.CROSS?"vec3":t===Fd.ALL?"bool":t===Fd.EQUALS?e.changeComponentType(this.aNode.getNodeType(e),"bool"):t===Fd.MOD?this.aNode.getNodeType(e):this.getInputType(e)}generate(e,t){const s=this.method,i=this.getNodeType(e),r=this.getInputType(e),n=this.aNode,o=this.bNode,a=this.cNode,h=!0===e.renderer.isWebGLRenderer;if(s===Fd.TRANSFORM_DIRECTION){let s=n,i=o;e.isMatrix(s.getNodeType(e))?i=uc(oc(i),0):s=uc(oc(s),0);const r=md(s,i).xyz;return Kd(r).build(e,t)}if(s===Fd.NEGATE)return e.format("( - "+n.build(e,r)+" )",i,t);if(s===Fd.ONE_MINUS)return pd(1,n).build(e,t);if(s===Fd.RECIPROCAL)return gd(1,n).build(e,t);if(s===Fd.DIFFERENCE)return op(pd(n,o)).build(e,t);{const l=[];return s===Fd.CROSS||s===Fd.MOD?l.push(n.build(e,i),o.build(e,i)):h&&s===Fd.STEP?l.push(n.build(e,1===e.getTypeLength(n.getNodeType(e))?"float":r),o.build(e,r)):h&&(s===Fd.MIN||s===Fd.MAX)||s===Fd.MOD?l.push(n.build(e,r),o.build(e,1===e.getTypeLength(o.getNodeType(e))?"float":r)):s===Fd.REFRACT?l.push(n.build(e,r),o.build(e,r),a.build(e,"float")):s===Fd.MIX?l.push(n.build(e,r),o.build(e,r),a.build(e,1===e.getTypeLength(a.getNodeType(e))?"float":r)):(l.push(n.build(e,r)),null!==o&&l.push(o.build(e,r)),null!==a&&l.push(a.build(e,r))),e.format(`${e.getMethod(s,i)}( ${l.join(", ")} )`,i,t)}}serialize(e){super.serialize(e),e.method=this.method}deserialize(e){super.deserialize(e),this.method=e.method}}Fd.ALL="all",Fd.ANY="any",Fd.EQUALS="equals",Fd.RADIANS="radians",Fd.DEGREES="degrees",Fd.EXP="exp",Fd.EXP2="exp2",Fd.LOG="log",Fd.LOG2="log2",Fd.SQRT="sqrt",Fd.INVERSE_SQRT="inversesqrt",Fd.FLOOR="floor",Fd.CEIL="ceil",Fd.NORMALIZE="normalize",Fd.FRACT="fract",Fd.SIN="sin",Fd.COS="cos",Fd.TAN="tan",Fd.ASIN="asin",Fd.ACOS="acos",Fd.ATAN="atan",Fd.ABS="abs",Fd.SIGN="sign",Fd.LENGTH="length",Fd.NEGATE="negate",Fd.ONE_MINUS="oneMinus",Fd.DFDX="dFdx",Fd.DFDY="dFdy",Fd.ROUND="round",Fd.RECIPROCAL="reciprocal",Fd.TRUNC="trunc",Fd.FWIDTH="fwidth",Fd.BITCAST="bitcast",Fd.TRANSPOSE="transpose",Fd.ATAN2="atan2",Fd.MIN="min",Fd.MAX="max",Fd.MOD="mod",Fd.STEP="step",Fd.REFLECT="reflect",Fd.DISTANCE="distance",Fd.DIFFERENCE="difference",Fd.DOT="dot",Fd.CROSS="cross",Fd.POW="pow",Fd.TRANSFORM_DIRECTION="transformDirection",Fd.MIX="mix",Fd.CLAMP="clamp",Fd.REFRACT="refract",Fd.SMOOTHSTEP="smoothstep",Fd.FACEFORWARD="faceforward",Fd.type=Ql("Math",Fd);const zd=Ku(1e-6),Ud=Ku(1e6),Ld=Ku(Math.PI),Od=Ku(2*Math.PI),Vd=Wu(Fd,Fd.ALL),Dd=Wu(Fd,Fd.ANY),kd=Wu(Fd,Fd.EQUALS),Gd=Wu(Fd,Fd.RADIANS),Wd=Wu(Fd,Fd.DEGREES),Hd=Wu(Fd,Fd.EXP),jd=Wu(Fd,Fd.EXP2),qd=Wu(Fd,Fd.LOG),$d=Wu(Fd,Fd.LOG2),Xd=Wu(Fd,Fd.SQRT),Yd=Wu(Fd,Fd.INVERSE_SQRT),Jd=Wu(Fd,Fd.FLOOR),Zd=Wu(Fd,Fd.CEIL),Kd=Wu(Fd,Fd.NORMALIZE),Qd=Wu(Fd,Fd.FRACT),ep=Wu(Fd,Fd.SIN),tp=Wu(Fd,Fd.COS),sp=Wu(Fd,Fd.TAN),ip=Wu(Fd,Fd.ASIN),rp=Wu(Fd,Fd.ACOS),np=Wu(Fd,Fd.ATAN),op=Wu(Fd,Fd.ABS),ap=Wu(Fd,Fd.SIGN),hp=Wu(Fd,Fd.LENGTH),lp=Wu(Fd,Fd.NEGATE),up=Wu(Fd,Fd.ONE_MINUS),cp=Wu(Fd,Fd.DFDX),dp=Wu(Fd,Fd.DFDY),pp=Wu(Fd,Fd.ROUND),mp=Wu(Fd,Fd.RECIPROCAL),gp=Wu(Fd,Fd.TRUNC),fp=Wu(Fd,Fd.FWIDTH),yp=Wu(Fd,Fd.BITCAST),xp=Wu(Fd,Fd.TRANSPOSE),bp=Wu(Fd,Fd.ATAN2),vp=Wu(Fd,Fd.MIN),Tp=Wu(Fd,Fd.MAX),_p=Wu(Fd,Fd.MOD),wp=Wu(Fd,Fd.STEP),Sp=Wu(Fd,Fd.REFLECT),Mp=Wu(Fd,Fd.DISTANCE),Ap=Wu(Fd,Fd.DIFFERENCE),Np=Wu(Fd,Fd.DOT),Rp=Wu(Fd,Fd.CROSS),Cp=Wu(Fd,Fd.POW),Ep=Wu(Fd,Fd.POW,2),Bp=Wu(Fd,Fd.POW,3),Ip=Wu(Fd,Fd.POW,4),Pp=Wu(Fd,Fd.TRANSFORM_DIRECTION),Fp=e=>md(ap(e),Cp(op(e),1/3)),zp=e=>Np(e,e),Up=Wu(Fd,Fd.MIX),Lp=(e,t=0,s=1)=>Du(new Fd(Fd.CLAMP,Du(e),Du(t),Du(s))),Op=e=>Lp(e),Vp=Wu(Fd,Fd.REFRACT),Dp=Wu(Fd,Fd.SMOOTHSTEP),kp=Wu(Fd,Fd.FACEFORWARD),Gp=ju((([e])=>{const t=Np(e.xy,sc(12.9898,78.233)),s=_p(t,Ld);return Qd(ep(s).mul(43758.5453))})),Wp=(e,t,s)=>Up(t,s,e),Hp=(e,t,s)=>Dp(t,s,e);pu("all",Vd),pu("any",Dd),pu("equals",kd),pu("radians",Gd),pu("degrees",Wd),pu("exp",Hd),pu("exp2",jd),pu("log",qd),pu("log2",$d),pu("sqrt",Xd),pu("inverseSqrt",Yd),pu("floor",Jd),pu("ceil",Zd),pu("normalize",Kd),pu("fract",Qd),pu("sin",ep),pu("cos",tp),pu("tan",sp),pu("asin",ip),pu("acos",rp),pu("atan",np),pu("abs",op),pu("sign",ap),pu("length",hp),pu("lengthSq",zp),pu("negate",lp),pu("oneMinus",up),pu("dFdx",cp),pu("dFdy",dp),pu("round",pp),pu("reciprocal",mp),pu("trunc",gp),pu("fwidth",fp),pu("atan2",bp),pu("min",vp),pu("max",Tp),pu("mod",_p),pu("step",wp),pu("reflect",Sp),pu("distance",Mp),pu("dot",Np),pu("cross",Rp),pu("pow",Cp),pu("pow2",Ep),pu("pow3",Bp),pu("pow4",Ip),pu("transformDirection",Pp),pu("mix",Wp),pu("clamp",Lp),pu("refract",Vp),pu("smoothstep",Hp),pu("faceForward",kp),pu("difference",Ap),pu("saturate",Op),pu("cbrt",Fp),pu("transpose",xp),pu("rand",Gp);class jp extends Kl{constructor(e,t,s=null){super(),this.condNode=e,this.ifNode=t,this.elseNode=s}getNodeType(e){const t=this.ifNode.getNodeType(e);if(null!==this.elseNode){const s=this.elseNode.getNodeType(e);if(e.getTypeLength(s)>e.getTypeLength(t))return s}return t}setup(e){const t=e.getNodeProperties(this);t.condNode=this.condNode.cache(),t.ifNode=this.ifNode.cache(),t.elseNode=this.elseNode?this.elseNode.cache():null}generate(e,t){const s=this.getNodeType(e),i=e.getDataFromNode(this);if(void 0!==i.nodeProperty)return i.nodeProperty;const{condNode:r,ifNode:n,elseNode:o}=e.getNodeProperties(this),a="void"!==t,h=a?Bc(s).build(e):"";i.nodeProperty=h;const l=r.build(e,"bool");e.addFlowCode(`\n${e.tab}if ( ${l} ) {\n\n`).addFlowTab();let u=n.build(e,s);if(u&&(u=a?h+" = "+u+";":"return "+u+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+u+"\n\n"+e.tab+"}"),null!==o){e.addFlowCode(" else {\n\n").addFlowTab();let t=o.build(e,s);t&&(t=a?h+" = "+t+";":"return "+t+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+t+"\n\n"+e.tab+"}\n\n")}else e.addFlowCode("\n\n");return e.format(h,s,t)}}jp.type=Ql("Conditional",jp);const qp=Wu(jp);pu("select",qp);const $p=(...e)=>(console.warn("TSL.ConditionalNode: cond() has been renamed to select()."),qp(...e));pu("cond",$p);class Xp extends Kl{constructor(e,t={}){super(),this.isContextNode=!0,this.node=e,this.value=t}getScope(){return this.node.getScope()}getNodeType(e){return this.node.getNodeType(e)}analyze(e){this.node.build(e)}setup(e){const t=e.getContext();e.setContext({...e.context,...this.value});const s=this.node.build(e);return e.setContext(t),s}generate(e,t){const s=e.getContext();e.setContext({...e.context,...this.value});const i=this.node.build(e,t);return e.setContext(s),i}}Xp.type=Ql("Context",Xp);const Yp=Wu(Xp),Jp=(e,t)=>Yp(e,{label:t});pu("context",Yp),pu("label",Jp);class Zp extends Kl{constructor(e,t=null){super(),this.node=e,this.name=t,this.global=!0,this.isVarNode=!0}getHash(e){return this.name||super.getHash(e)}getNodeType(e){return this.node.getNodeType(e)}generate(e){const{node:t,name:s}=this,i=e.getVarFromNode(this,s,e.getVectorType(this.getNodeType(e))),r=e.getPropertyName(i),n=t.build(e,i.type);return e.addLineFlowCode(`${r} = ${n}`),r}}Zp.type=Ql("Var",Zp);const Kp=Wu(Zp);pu("temp",Kp),pu("toVar",((...e)=>Kp(...e).append()));class Qp extends Kl{constructor(e,t=null){super(),this.node=e,this.name=t,this.isVaryingNode=!0}isGlobal(){return!0}getHash(e){return this.name||super.getHash(e)}getNodeType(e){return this.node.getNodeType(e)}setupVarying(e){const t=e.getNodeProperties(this);let s=t.varying;if(void 0===s){const i=this.name,r=this.getNodeType(e);t.varying=s=e.getVaryingFromNode(this,i,r),t.node=this.node}return s.needsInterpolation||(s.needsInterpolation="fragment"===e.shaderStage),s}setup(e){this.setupVarying(e)}analyze(e){return this.setupVarying(e),this.node.analyze(e)}generate(e){const t=e.getNodeProperties(this),s=this.setupVarying(e);if(void 0===t.propertyName){const i=this.getNodeType(e),r=e.getPropertyName(s,Wl.VERTEX);e.flowNodeFromShaderStage(Wl.VERTEX,this.node,i,r),t.propertyName=r}return e.getPropertyName(s)}}Qp.type=Ql("Varying",Qp);const em=Wu(Qp);pu("varying",em);const tm=e=>{let t=null;return e===Zt?t="Linear":e===Jt&&(t="sRGB"),t},sm=(e,t)=>tm(e)+"To"+tm(t);class im extends iu{constructor(e,t=null,s=null){super("vec4"),this.colorNode=e,this.target=t,this.source=s}setup(e){const{renderer:t,context:s}=e,i=this.source||s.outputColorSpace||t.outputColorSpace,r=this.target||s.outputColorSpace||t.outputColorSpace,n=this.colorNode;if(i===r)return n;const o=sm(i,r);let a=null;const h=t.nodes.library.getColorSpaceFunction(o);return null!==h?a=uc(h(n.rgb),n.a):(console.error("ColorSpaceNode: Unsupported Color Space configuration.",o),a=n),a}}im.type=Ql("ColorSpace",im);const rm=(e,t=null)=>Du(new im(Du(e),t,Zt)),nm=(e,t=null)=>Du(new im(Du(e),Zt,t));pu("toOutputColorSpace",rm),pu("toWorkingColorSpace",nm);let om=class extends tu{constructor(e,t){super(e,t),this.referenceNode=e,this.isReferenceElementNode=!0}getNodeType(){return this.referenceNode.uniformType}generate(e){const t=super.generate(e),s=this.referenceNode.getNodeType(),i=this.getNodeType();return e.format(t,s,i)}};class am extends Kl{constructor(e,t,s=null,i=null){super(),this.property=e,this.uniformType=t,this.object=s,this.count=i,this.properties=e.split("."),this.reference=s,this.node=null,this.updateType=Hl.OBJECT}element(e){return Du(new om(this,Du(e)))}setNodeType(e){this.node=Cc(null,e).getSelf()}getNodeType(e){return null===this.node&&this.updateValue(),this.node.getNodeType(e)}getValueFromReference(e=this.reference){const{properties:t}=this;let s=e[t[0]];for(let e=1;eDu(new hm(e,t,s));class um extends iu{constructor(e,t=dm,s=null){super("vec3"),this.toneMapping=e,this.exposureNode=t,this.colorNode=s}getCacheKey(){let e=super.getCacheKey();return e="{toneMapping:"+this.toneMapping+",nodes:"+e+"}",e}setup(e){const t=this.colorNode||e.context.color,s=this.toneMapping;if(0===s)return t;let i=null;const r=e.renderer.nodes.library.getToneMappingFunction(s);return null!==r?i=uc(r(t.rgb,this.exposureNode),t.a):(console.error("ToneMappingNode: Unsupported Tone Mapping configuration.",s),i=t),i}}um.type=Ql("ToneMapping",um);const cm=(e,t,s)=>Du(new um(e,Du(t),Du(s))),dm=lm("toneMappingExposure","float");pu("toneMapping",((e,t,s)=>cm(t,s,e)));class pm extends lu{constructor(e,t=null,s=0,i=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferStride=s,this.bufferOffset=i,this.usage=Rs,this.instanced=!1,this.attribute=null,this.global=!0,e&&!0===e.isBufferAttribute&&(this.attribute=e,this.usage=e.usage,this.instanced=e.isInstancedBufferAttribute)}getHash(e){if(0===this.bufferStride&&0===this.bufferOffset){let t=e.globalCache.getData(this.value);return void 0===t&&(t={node:this},e.globalCache.setData(this.value,t)),t.node.uuid}return this.uuid}getNodeType(e){return null===this.bufferType&&(this.bufferType=e.getTypeFromAttribute(this.attribute)),this.bufferType}setup(e){if(null!==this.attribute)return;const t=this.getNodeType(e),s=this.value,i=e.getTypeLength(t),r=this.bufferStride||i,n=this.bufferOffset,o=!0===s.isInterleavedBuffer?s:new oo(s,r),a=new ho(o,i,n);o.setUsage(this.usage),this.attribute=a,this.attribute.isInstancedBufferAttribute=this.instanced}generate(e){const t=this.getNodeType(e),s=e.getBufferAttributeFromNode(this,t),i=e.getPropertyName(s);let r=null;if("vertex"===e.shaderStage||"compute"===e.shaderStage)this.name=i,r=i;else{r=em(this).build(e,t)}return r}getInputType(){return"bufferAttribute"}setUsage(e){return this.usage=e,this.attribute&&!0===this.attribute.isBufferAttribute&&(this.attribute.usage=e),this}setInstanced(e){return this.instanced=e,this}}pm.type=Ql("BufferAttribute",pm);const mm=(e,t,s,i)=>Du(new pm(e,t,s,i)),gm=(e,t,s,i)=>mm(e,t,s,i).setUsage(Cs),fm=(e,t,s,i)=>mm(e,t,s,i).setInstanced(!0),ym=(e,t,s,i)=>gm(e,t,s,i).setInstanced(!0);pu("toAttribute",(e=>mm(e.value)));class xm extends Kl{constructor(e,t,s=[64]){super("void"),this.isComputeNode=!0,this.computeNode=e,this.count=t,this.workgroupSize=s,this.dispatchCount=0,this.version=1,this.updateBeforeType=Hl.OBJECT,this.updateDispatchCount()}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){!0===e&&this.version++}updateDispatchCount(){const{count:e,workgroupSize:t}=this;let s=t[0];for(let e=1;eDu(new xm(Du(e),t,s));pu("compute",bm);class vm extends Kl{constructor(e,t=!0){super(),this.node=e,this.parent=t,this.isCacheNode=!0}getNodeType(e){return this.node.getNodeType(e)}build(e,...t){const s=e.getCache(),i=e.getCacheFromNode(this,parent);e.setCache(i);const r=this.node.build(e,...t);return e.setCache(s),r}}vm.type=Ql("Cache",vm);const Tm=(e,...t)=>Du(new vm(Du(e),...t));pu("cache",Tm);class _m extends Kl{constructor(e,t){super(),this.isBypassNode=!0,this.outputNode=e,this.callNode=t}getNodeType(e){return this.outputNode.getNodeType(e)}generate(e){const t=this.callNode.build(e,"void");return""!==t&&e.addLineFlowCode(t),this.outputNode.build(e)}}_m.type=Ql("Bypass",_m);const wm=Wu(_m);pu("bypass",wm);class Sm extends Kl{constructor(e,t,s,i=Ku(0),r=Ku(1)){super(),this.node=e,this.inLowNode=t,this.inHighNode=s,this.outLowNode=i,this.outHighNode=r,this.doClamp=!0}setup(){const{node:e,inLowNode:t,inHighNode:s,outLowNode:i,outHighNode:r,doClamp:n}=this;let o=e.sub(t).div(s.sub(t));return!0===n&&(o=o.clamp()),o.mul(r.sub(i)).add(i)}}Sm.type=Ql("Remap",Sm);const Mm=Wu(Sm,null,null,{doClamp:!1}),Am=Wu(Sm);pu("remap",Mm),pu("remapClamp",Am);class Nm extends Kl{constructor(e="",t="void"){super(t),this.snippet=e}generate(e,t){const s=this.getNodeType(e),i=this.snippet;if("void"!==s)return e.format(`( ${i} )`,s,t);e.addLineFlowCode(i)}}Nm.type=Ql("Expression",Nm);const Rm=Wu(Nm),Cm=e=>(e?qp(e,Rm("discard")):Rm("discard")).append(),Em=()=>Rm("return").append();pu("discard",Cm);class Bm extends iu{constructor(e,t,s){super("vec4"),this.colorNode=e,this.toneMapping=t,this.outputColorSpace=s,this.isRenderOutput=!0}setup({context:e}){let t=this.colorNode||e.color;const s=(null!==this.toneMapping?this.toneMapping:e.toneMapping)||0,i=(null!==this.outputColorSpace?this.outputColorSpace:e.outputColorSpace)||Zt;return 0!==s&&(t=t.toneMapping(s)),i===Jt&&(t=t.toOutputColorSpace(i)),t}}Bm.type=Ql("RenderOutput",Bm);const Im=(e,t=null,s=null)=>Du(new Bm(Du(e),t,s));function Pm(e){console.warn("THREE.TSLBase: AddNodeElement has been removed in favor of tree-shaking. Trying add",e)}pu("renderOutput",Im);class Fm extends Kl{constructor(e,t=null){super(t),this.global=!0,this._attributeName=e}getHash(e){return this.getAttributeName(e)}getNodeType(e){let t=this.nodeType;if(null===t){const s=this.getAttributeName(e);if(e.hasGeometryAttribute(s)){const i=e.geometry.getAttribute(s);t=e.getTypeFromAttribute(i)}else t="float"}return t}setAttributeName(e){return this._attributeName=e,this}getAttributeName(){return this._attributeName}generate(e){const t=this.getAttributeName(e),s=this.getNodeType(e);if(!0===e.hasGeometryAttribute(t)){const i=e.geometry.getAttribute(t),r=e.getTypeFromAttribute(i),n=e.getAttribute(t,r);if("vertex"===e.shaderStage)return e.format(n.name,r,s);return em(this).build(e,s)}return console.warn(`AttributeNode: Vertex attribute "${t}" not found on geometry.`),e.generateConst(s)}serialize(e){super.serialize(e),e.global=this.global,e._attributeName=this._attributeName}deserialize(e){super.deserialize(e),this.global=e.global,this._attributeName=e._attributeName}}Fm.type=Ql("Attribute",Fm);const zm=(e,t)=>Du(new Fm(e,t)),Um=e=>zm("uv"+(e>0?e:""),"vec2");class Lm extends Kl{constructor(e,t=null){super("uvec2"),this.isTextureSizeNode=!0,this.textureNode=e,this.levelNode=t}generate(e,t){const s=this.textureNode.build(e,"property"),i=this.levelNode.build(e,"int");return e.format(`${e.getMethod("textureDimensions")}( ${s}, ${i} )`,this.getNodeType(e),t)}}Lm.type=Ql("TextureSize",Lm);const Om=Wu(Lm);class Vm extends Rc{constructor(e){super(0),this._textureNode=e,this.updateType=Hl.FRAME}get textureNode(){return this._textureNode}get texture(){return this._textureNode.value}update(){const e=this.texture,t=e.images,s=t&&t.length>0?t[0]&&t[0].image||t[0]:e.image;if(s&&void 0!==s.width){const{width:e,height:t}=s;this.value=Math.log2(Math.max(e,t))}}}Vm.type=Ql("MaxMipLevel",Vm);const Dm=Wu(Vm);class km extends Rc{constructor(e,t=null,s=null,i=null){super(e),this.isTextureNode=!0,this.uvNode=t,this.levelNode=s,this.biasNode=i,this.compareNode=null,this.depthNode=null,this.gradNode=null,this.sampler=!0,this.updateMatrix=!1,this.updateType=Hl.NONE,this.referenceNode=null,this._value=e,this._matrixUniform=null,this.setUpdateMatrix(null===t)}set value(e){this.referenceNode?this.referenceNode.value=e:this._value=e}get value(){return this.referenceNode?this.referenceNode.value:this._value}getUniformHash(){return this.value.uuid}getNodeType(){return!0===this.value.isDepthTexture?"float":this.value.type===Be?"uvec4":this.value.type===Ee?"ivec4":"vec4"}getInputType(){return"texture"}getDefaultUV(){return Um(this.value.channel)}updateReference(){return this.value}getTransformedUV(e){return null===this._matrixUniform&&(this._matrixUniform=Cc(this.value.matrix)),this._matrixUniform.mul(oc(e,1)).xy}setUpdateMatrix(e){return this.updateMatrix=e,this.updateType=e?Hl.FRAME:Hl.NONE,this}setupUV(e,t){const s=this.value;return!e.isFlipY()||!0!==s.isRenderTargetTexture&&!0!==s.isFramebufferTexture&&!0!==s.isDepthTexture||(t=t.setY(t.y.oneMinus())),t}setup(e){const t=e.getNodeProperties(this);t.referenceNode=this.referenceNode;let s=this.uvNode;null!==s&&!0!==e.context.forceUVContext||!e.context.getUV||(s=e.context.getUV(this)),s||(s=this.getDefaultUV()),!0===this.updateMatrix&&(s=this.getTransformedUV(s)),s=this.setupUV(e,s);let i=this.levelNode;null===i&&e.context.getTextureLevel&&(i=e.context.getTextureLevel(this)),t.uvNode=s,t.levelNode=i,t.biasNode=this.biasNode,t.compareNode=this.compareNode,t.gradNode=this.gradNode,t.depthNode=this.depthNode}generateUV(e,t){return t.build(e,!0===this.sampler?"vec2":"ivec2")}generateSnippet(e,t,s,i,r,n,o,a){const h=this.value;let l;return l=i?e.generateTextureLevel(h,t,s,i,n):r?e.generateTextureBias(h,t,s,r,n):a?e.generateTextureGrad(h,t,s,a,n):o?e.generateTextureCompare(h,t,s,o,n):!1===this.sampler?e.generateTextureLoad(h,t,s,n):e.generateTexture(h,t,s,n),l}generate(e,t){const s=e.getNodeProperties(this),i=this.value;if(!i||!0!==i.isTexture)throw new Error("TextureNode: Need a three.js texture.");const r=super.generate(e,"property");if("sampler"===t)return r+"_sampler";if(e.isReference(t))return r;{const n=e.getDataFromNode(this);let o=n.propertyName;if(void 0===o){const{uvNode:t,levelNode:i,biasNode:a,compareNode:h,depthNode:l,gradNode:u}=s,c=this.generateUV(e,t),d=i?i.build(e,"float"):null,p=a?a.build(e,"float"):null,m=l?l.build(e,"int"):null,g=h?h.build(e,"float"):null,f=u?[u[0].build(e,"vec2"),u[1].build(e,"vec2")]:null,y=e.getVarFromNode(this);o=e.getPropertyName(y);const x=this.generateSnippet(e,r,c,d,p,m,g,f);e.addLineFlowCode(`${o} = ${x}`),n.snippet=x,n.propertyName=o}let a=o;const h=this.getNodeType(e);return e.needsToWorkingColorSpace(i)&&(a=nm(Rm(a,h),i.colorSpace).setup(e).build(e,h)),e.format(a,h,t)}}setSampler(e){return this.sampler=e,this}getSampler(){return this.sampler}uv(e){const t=this.clone();return t.uvNode=Du(e),t.referenceNode=this.getSelf(),Du(t)}blur(e){const t=this.clone();return t.biasNode=Du(e).mul(Dm(t)),t.referenceNode=this.getSelf(),Du(t)}level(e){const t=this.clone();return t.levelNode=Du(e),t.referenceNode=this.getSelf(),Du(t)}size(e){return Om(this,e)}bias(e){const t=this.clone();return t.biasNode=Du(e),t.referenceNode=this.getSelf(),Du(t)}compare(e){const t=this.clone();return t.compareNode=Du(e),t.referenceNode=this.getSelf(),Du(t)}grad(e,t){const s=this.clone();return s.gradNode=[Du(e),Du(t)],s.referenceNode=this.getSelf(),Du(s)}depth(e){const t=this.clone();return t.depthNode=Du(e),t.referenceNode=this.getSelf(),Du(t)}serialize(e){super.serialize(e),e.value=this.value.toJSON(e.meta).uuid,e.sampler=this.sampler,e.updateMatrix=this.updateMatrix,e.updateType=this.updateType}deserialize(e){super.deserialize(e),this.value=e.meta.textures[e.value],this.sampler=e.sampler,this.updateMatrix=e.updateMatrix,this.updateType=e.updateType}update(){const e=this.value,t=this._matrixUniform;null!==t&&(t.value=e.matrix),!0===e.matrixAutoUpdate&&e.updateMatrix()}clone(){const e=new this.constructor(this.value,this.uvNode,this.levelNode,this.biasNode);return e.sampler=this.sampler,e}}km.type=Ql("Texture",km);const Gm=Wu(km),Wm=(...e)=>Gm(...e).setSampler(!1),Hm=e=>(!0===e.isNode?e:Gm(e)).convert("sampler"),jm=Sc("camera").onRenderUpdate((()=>{jm.needsUpdate=!0})),qm=Cc("float").label("cameraNear").setGroup(jm).onRenderUpdate((({camera:e})=>e.near)),$m=Cc("float").label("cameraFar").setGroup(jm).onRenderUpdate((({camera:e})=>e.far)),Xm=Cc("float").label("cameraLogDepth").setGroup(jm).onRenderUpdate((({camera:e})=>2/(Math.log(e.far+1)/Math.LN2))),Ym=Cc("mat4").label("cameraProjectionMatrix").setGroup(jm).onRenderUpdate((({camera:e})=>e.projectionMatrix)),Jm=Cc("mat4").label("cameraProjectionMatrixInverse").setGroup(jm).onRenderUpdate((({camera:e})=>e.projectionMatrixInverse)),Zm=Cc("mat4").label("cameraViewMatrix").setGroup(jm).onRenderUpdate((({camera:e})=>e.matrixWorldInverse)),Km=Cc("mat4").label("cameraWorldMatrix").setGroup(jm).onRenderUpdate((({camera:e})=>e.matrixWorld)),Qm=Cc("mat3").label("cameraNormalMatrix").setGroup(jm).onRenderUpdate((({camera:e})=>e.normalMatrix)),eg=Cc(new Ei).label("cameraPosition").setGroup(jm).onRenderUpdate((({camera:e},t)=>t.value.setFromMatrixPosition(e.matrixWorld)));class tg extends Kl{constructor(e=tg.VIEW_MATRIX,t=null){super(),this.scope=e,this.object3d=t,this.updateType=Hl.OBJECT,this._uniformNode=new Rc(null)}getNodeType(){const e=this.scope;return e===tg.WORLD_MATRIX||e===tg.VIEW_MATRIX?"mat4":e===tg.NORMAL_MATRIX?"mat3":e===tg.POSITION||e===tg.VIEW_POSITION||e===tg.DIRECTION||e===tg.SCALE?"vec3":void 0}update(e){const t=this.object3d,s=this._uniformNode,i=this.scope;if(i===tg.VIEW_MATRIX)s.value=t.modelViewMatrix;else if(i===tg.NORMAL_MATRIX)s.value=t.normalMatrix;else if(i===tg.WORLD_MATRIX)s.value=t.matrixWorld;else if(i===tg.POSITION)s.value=s.value||new Ei,s.value.setFromMatrixPosition(t.matrixWorld);else if(i===tg.SCALE)s.value=s.value||new Ei,s.value.setFromMatrixScale(t.matrixWorld);else if(i===tg.DIRECTION)s.value=s.value||new Ei,t.getWorldDirection(s.value);else if(i===tg.VIEW_POSITION){const i=e.camera;s.value=s.value||new Ei,s.value.setFromMatrixPosition(t.matrixWorld),s.value.applyMatrix4(i.matrixWorldInverse)}}generate(e){const t=this.scope;return t===tg.WORLD_MATRIX||t===tg.VIEW_MATRIX?this._uniformNode.nodeType="mat4":t===tg.NORMAL_MATRIX?this._uniformNode.nodeType="mat3":t!==tg.POSITION&&t!==tg.VIEW_POSITION&&t!==tg.DIRECTION&&t!==tg.SCALE||(this._uniformNode.nodeType="vec3"),this._uniformNode.build(e)}serialize(e){super.serialize(e),e.scope=this.scope}deserialize(e){super.deserialize(e),this.scope=e.scope}}tg.VIEW_MATRIX="viewMatrix",tg.NORMAL_MATRIX="normalMatrix",tg.WORLD_MATRIX="worldMatrix",tg.POSITION="position",tg.SCALE="scale",tg.VIEW_POSITION="viewPosition",tg.DIRECTION="direction",tg.type=Ql("Object3D",tg);const sg=Wu(tg,tg.DIRECTION),ig=Wu(tg,tg.VIEW_MATRIX),rg=Wu(tg,tg.NORMAL_MATRIX),ng=Wu(tg,tg.WORLD_MATRIX),og=Wu(tg,tg.POSITION),ag=Wu(tg,tg.SCALE),hg=Wu(tg,tg.VIEW_POSITION);class lg extends tg{constructor(e=lg.VIEW_MATRIX){super(e)}update(e){this.object3d=e.object,super.update(e)}}lg.type=Ql("Model",lg);const ug=Hu(lg,lg.DIRECTION),cg=Hu(lg,lg.VIEW_MATRIX).label("modelViewMatrix").toVar("ModelViewMatrix"),dg=Hu(lg,lg.NORMAL_MATRIX),pg=Hu(lg,lg.WORLD_MATRIX),mg=Hu(lg,lg.POSITION),gg=Hu(lg,lg.SCALE),fg=Hu(lg,lg.VIEW_POSITION),yg=Cc(new or).onObjectUpdate((({object:e},t)=>t.value.copy(e.matrixWorld).invert())),xg=zm("position","vec3"),bg=xg.varying("positionLocal"),vg=xg.varying("positionPrevious"),Tg=pg.mul(bg).xyz.varying("v_positionWorld"),_g=bg.transformDirection(pg).varying("v_positionWorldDirection").normalize().toVar("positionWorldDirection"),wg=cg.mul(bg).xyz.varying("v_positionView"),Sg=wg.negate().varying("v_positionViewDirection").normalize().toVar("positionViewDirection");class Mg extends Kl{constructor(){super("bool"),this.isFrontFacingNode=!0}generate(e){const{renderer:t,material:s}=e;return t.coordinateSystem===Vs&&s.side===d?"false":e.getFrontFacing()}}Mg.type=Ql("FrontFacing",Mg);const Ag=Hu(Mg),Ng=Ku(Ag).mul(2).sub(1),Rg=zm("normal","vec3"),Cg=ju((e=>!1===e.geometry.hasAttribute("normal")?(console.warn('TSL.NormalNode: Vertex attribute "normal" not found on geometry.'),oc(0,1,0)):Rg),"vec3").once()().toVar("normalLocal"),Eg=wg.dFdx().cross(wg.dFdy()).normalize().toVar("normalFlat");let Bg=null;const Ig=ju((e=>{let t;return t=!0===e.material.flatShading?Eg:Bg||(Bg=em(dg.mul(Cg),"v_normalView").normalize()),t}),"vec3").once()().toVar("normalView"),Pg=em(Ig.transformDirection(Zm),"v_normalWorld").normalize().toVar("normalWorld"),Fg=ju((e=>e.context.setupNormal()),"vec3").once()().mul(Ng).toVar("transformedNormalView"),zg=Fg.transformDirection(Zm).normalize().toVar("transformedNormalWorld"),Ug=ju((e=>e.context.setupClearcoatNormal()),"vec3").once()().mul(Ng).toVar("transformedClearcoatNormalView"),Lg=Cc(0).onReference((({material:e})=>e)).onRenderUpdate((({material:e})=>e.refractionRatio)),Og=Sg.negate().reflect(Fg),Vg=Sg.negate().refract(Fg,Lg),Dg=Og.transformDirection(Zm).toVar("reflectVector"),kg=Vg.transformDirection(Zm).toVar("reflectVector");class Gg extends km{constructor(e,t=null,s=null,i=null){super(e,t,s,i),this.isCubeTextureNode=!0}getInputType(){return"cubeTexture"}getDefaultUV(){const e=this.value;return e.mapping===he?Dg:e.mapping===le?kg:(console.error('THREE.CubeTextureNode: Mapping "%s" not supported.',e.mapping),oc(0,0,0))}setUpdateMatrix(){}setupUV(e,t){const s=this.value;return e.renderer.coordinateSystem!==Ds&&s.isRenderTargetTexture?t:oc(t.x.negate(),t.yz)}generateUV(e,t){return t.build(e,"vec3")}}Gg.type=Ql("CubeTexture",Gg);const Wg=Wu(Gg);class Hg extends Rc{constructor(e,t,s=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferCount=s}getElementType(e){return this.getNodeType(e)}getInputType(){return"buffer"}}Hg.type=Ql("Buffer",Hg);const jg=(e,t,s)=>Du(new Hg(e,t,s));class qg extends tu{constructor(e,t){super(e,t),this.isArrayBufferElementNode=!0}getNodeType(e){return this.node.getElementType(e)}generate(e){const t=super.generate(e),s=this.getNodeType();return e.format(t,"vec4",s)}}class $g extends Hg{constructor(e,t=null){super(null,"vec4"),this.array=e,this.elementType=t,this._elementType=null,this._elementLength=0,this.updateType=Hl.RENDER,this.isArrayBufferNode=!0}getElementType(){return this.elementType||this._elementType}getElementLength(){return this._elementLength}update(){const{array:e,value:t}=this,s=this.getElementLength(),i=this.getElementType();if(1===s)for(let s=0;sDu(new $g(e,t));class Yg extends tu{constructor(e,t){super(e,t),this.referenceNode=e,this.isReferenceElementNode=!0}getNodeType(){return this.referenceNode.uniformType}generate(e){const t=super.generate(e),s=this.referenceNode.getNodeType(),i=this.getNodeType();return e.format(t,s,i)}}class Jg extends Kl{constructor(e,t,s=null,i=null){super(),this.property=e,this.uniformType=t,this.object=s,this.count=i,this.properties=e.split("."),this.reference=s,this.node=null,this.updateType=Hl.OBJECT}element(e){return Du(new Yg(this,Du(e)))}setNodeType(e){let t=null;t=null!==this.count?jg(null,e,this.count):Array.isArray(this.getValueFromReference())?Xg(null,e):"texture"===e?Gm(null):"cubeTexture"===e?Wg(null):Cc(null,e),this.node=t.getSelf()}getNodeType(e){return null===this.node&&this.updateValue(),this.node.getNodeType(e)}getValueFromReference(e=this.reference){const{properties:t}=this;let s=e[t[0]];for(let e=1;eDu(new Jg(e,t,s)),Kg=(e,t,s,i)=>Du(new Jg(e,t,i,s));class Qg extends Jg{constructor(e,t,s=null){super(e,t,s),this.material=s,this.isMaterialReferenceNode=!0}updateReference(e){return this.reference=null!==this.material?this.material:e.material,this.reference}}Qg.type=Ql("MaterialReference",Qg);const ef=(e,t,s)=>Du(new Qg(e,t,s)),tf=ju((e=>(!1===e.geometry.hasAttribute("tangent")&&e.geometry.computeTangents(),zm("tangent","vec4"))))(),sf=tf.xyz.toVar("tangentLocal"),rf=cg.mul(uc(sf,0)).xyz.varying("v_tangentView").normalize().toVar("tangentView"),nf=rf.transformDirection(Zm).varying("v_tangentWorld").normalize().toVar("tangentWorld"),of=rf.toVar("transformedTangentView"),af=of.transformDirection(Zm).normalize().toVar("transformedTangentWorld"),hf=e=>e.mul(tf.w).xyz,lf=em(hf(Rg.cross(tf)),"v_bitangentGeometry").normalize().toVar("bitangentGeometry"),uf=em(hf(Cg.cross(sf)),"v_bitangentLocal").normalize().toVar("bitangentLocal"),cf=em(hf(Ig.cross(rf)),"v_bitangentView").normalize().toVar("bitangentView"),df=em(hf(Pg.cross(nf)),"v_bitangentWorld").normalize().toVar("bitangentWorld"),pf=hf(Fg.cross(of)).normalize().toVar("transformedBitangentView"),mf=pf.transformDirection(Zm).normalize().toVar("transformedBitangentWorld"),gf=gc(rf,cf,Ig),ff=Sg.mul(gf),yf=(e,t)=>e.sub(ff.mul(t)),xf=(()=>{let e=$c.cross(Sg);return e=e.cross($c).normalize(),e=Up(e,Fg,jc.mul(zc.oneMinus()).oneMinus().pow2().pow2()).normalize(),e})(),bf=ju((e=>{const{eye_pos:t,surf_norm:s,mapN:i,uv:r}=e,n=t.dFdx(),o=t.dFdy(),a=r.dFdx(),h=r.dFdy(),l=s,u=o.cross(l),c=l.cross(n),d=u.mul(a.x).add(c.mul(h.x)),p=u.mul(a.y).add(c.mul(h.y)),m=d.dot(d).max(p.dot(p)),g=Ng.mul(m.inverseSqrt());return dd(d.mul(i.x,g),p.mul(i.y,g),l.mul(i.z)).normalize()}));class vf extends iu{constructor(e,t=null){super("vec3"),this.node=e,this.scaleNode=t,this.normalMapType=0}setup(e){const{normalMapType:t,scaleNode:s}=this;let i=this.node.mul(2).sub(1);null!==s&&(i=oc(i.xy.mul(s),i.z));let r=null;if(1===t)r=dg.mul(i).normalize();else if(0===t){r=!0===e.hasGeometryAttribute("tangent")?gf.mul(i).normalize():bf({eye_pos:wg,surf_norm:Ig,mapN:i,uv:Um()})}return r}}vf.type=Ql("NormalMap",vf);const Tf=Wu(vf),_f=ju((({textureNode:e,bumpScale:t})=>{const s=t=>e.cache().context({getUV:e=>t(e.uvNode||Um()),forceUVContext:!0}),i=Ku(s((e=>e)));return sc(Ku(s((e=>e.add(e.dFdx())))).sub(i),Ku(s((e=>e.add(e.dFdy())))).sub(i)).mul(t)})),wf=ju((e=>{const{surf_pos:t,surf_norm:s,dHdxy:i}=e,r=t.dFdx().normalize(),n=s,o=t.dFdy().normalize().cross(n),a=n.cross(r),h=r.dot(o).mul(Ng),l=h.sign().mul(i.x.mul(o).add(i.y.mul(a)));return h.abs().mul(s).sub(l).normalize()}));class Sf extends iu{constructor(e,t=null){super("vec3"),this.textureNode=e,this.scaleNode=t}setup(){const e=null!==this.scaleNode?this.scaleNode:1,t=_f({textureNode:this.textureNode,bumpScale:e});return wf({surf_pos:wg,surf_norm:Ig,dHdxy:t})}}const Mf=Wu(Sf),Af=new Map;class Nf extends Kl{constructor(e){super(),this.scope=e}getCache(e,t){let s=Af.get(e);return void 0===s&&(s=ef(e,t),Af.set(e,s)),s}getFloat(e){return this.getCache(e,"float")}getColor(e){return this.getCache(e,"color")}getTexture(e){return this.getCache("map"===e?"map":e+"Map","texture")}setup(e){const t=e.context.material,s=this.scope;let i=null;if(s===Nf.COLOR){const e=void 0!==t.color?this.getColor(s):oc();i=t.map&&!0===t.map.isTexture?e.mul(this.getTexture("map")):e}else if(s===Nf.OPACITY){const e=this.getFloat(s);i=t.alphaMap&&!0===t.alphaMap.isTexture?e.mul(this.getTexture("alpha")):e}else if(s===Nf.SPECULAR_STRENGTH)i=t.specularMap&&!0===t.specularMap.isTexture?this.getTexture("specular").r:Ku(1);else if(s===Nf.SPECULAR_INTENSITY){const e=this.getFloat(s);i=t.specularMap?e.mul(this.getTexture(s).a):e}else if(s===Nf.SPECULAR_COLOR){const e=this.getColor(s);i=t.specularColorMap&&!0===t.specularColorMap.isTexture?e.mul(this.getTexture(s).rgb):e}else if(s===Nf.ROUGHNESS){const e=this.getFloat(s);i=t.roughnessMap&&!0===t.roughnessMap.isTexture?e.mul(this.getTexture(s).g):e}else if(s===Nf.METALNESS){const e=this.getFloat(s);i=t.metalnessMap&&!0===t.metalnessMap.isTexture?e.mul(this.getTexture(s).b):e}else if(s===Nf.EMISSIVE){const e=this.getFloat("emissiveIntensity"),r=this.getColor(s).mul(e);i=t.emissiveMap&&!0===t.emissiveMap.isTexture?r.mul(this.getTexture(s)):r}else if(s===Nf.NORMAL)i=t.normalMap?Tf(this.getTexture("normal"),this.getCache("normalScale","vec2")):t.bumpMap?Mf(this.getTexture("bump").r,this.getFloat("bumpScale")):Ig;else if(s===Nf.CLEARCOAT){const e=this.getFloat(s);i=t.clearcoatMap&&!0===t.clearcoatMap.isTexture?e.mul(this.getTexture(s).r):e}else if(s===Nf.CLEARCOAT_ROUGHNESS){const e=this.getFloat(s);i=t.clearcoatRoughnessMap&&!0===t.clearcoatRoughnessMap.isTexture?e.mul(this.getTexture(s).r):e}else if(s===Nf.CLEARCOAT_NORMAL)i=t.clearcoatNormalMap?Tf(this.getTexture(s),this.getCache(s+"Scale","vec2")):Ig;else if(s===Nf.SHEEN){const e=this.getColor("sheenColor").mul(this.getFloat("sheen"));i=t.sheenColorMap&&!0===t.sheenColorMap.isTexture?e.mul(this.getTexture("sheenColor").rgb):e}else if(s===Nf.SHEEN_ROUGHNESS){const e=this.getFloat(s);i=t.sheenRoughnessMap&&!0===t.sheenRoughnessMap.isTexture?e.mul(this.getTexture(s).a):e,i=i.clamp(.07,1)}else if(s===Nf.ANISOTROPY)if(t.anisotropyMap&&!0===t.anisotropyMap.isTexture){const e=this.getTexture(s);i=mc(cy.x,cy.y,cy.y.negate(),cy.x).mul(e.rg.mul(2).sub(sc(1)).normalize().mul(e.b))}else i=cy;else if(s===Nf.IRIDESCENCE_THICKNESS){const e=Zg("1","float",t.iridescenceThicknessRange);if(t.iridescenceThicknessMap){const r=Zg("0","float",t.iridescenceThicknessRange);i=e.sub(r).mul(this.getTexture(s).g).add(r)}else i=e}else if(s===Nf.TRANSMISSION){const e=this.getFloat(s);i=t.transmissionMap?e.mul(this.getTexture(s).r):e}else if(s===Nf.THICKNESS){const e=this.getFloat(s);i=t.thicknessMap?e.mul(this.getTexture(s).g):e}else if(s===Nf.IOR)i=this.getFloat(s);else if(s===Nf.LIGHT_MAP)i=this.getTexture(s).rgb.mul(this.getFloat("lightMapIntensity"));else if(s===Nf.AO_MAP)i=this.getTexture(s).r.sub(1).mul(this.getFloat("aoMapIntensity")).add(1);else{const t=this.getNodeType(e);i=this.getCache(s,t)}return i}}Nf.ALPHA_TEST="alphaTest",Nf.COLOR="color",Nf.OPACITY="opacity",Nf.SHININESS="shininess",Nf.SPECULAR="specular",Nf.SPECULAR_STRENGTH="specularStrength",Nf.SPECULAR_INTENSITY="specularIntensity",Nf.SPECULAR_COLOR="specularColor",Nf.REFLECTIVITY="reflectivity",Nf.ROUGHNESS="roughness",Nf.METALNESS="metalness",Nf.NORMAL="normal",Nf.CLEARCOAT="clearcoat",Nf.CLEARCOAT_ROUGHNESS="clearcoatRoughness",Nf.CLEARCOAT_NORMAL="clearcoatNormal",Nf.EMISSIVE="emissive",Nf.ROTATION="rotation",Nf.SHEEN="sheen",Nf.SHEEN_ROUGHNESS="sheenRoughness",Nf.ANISOTROPY="anisotropy",Nf.IRIDESCENCE="iridescence",Nf.IRIDESCENCE_IOR="iridescenceIOR",Nf.IRIDESCENCE_THICKNESS="iridescenceThickness",Nf.IOR="ior",Nf.TRANSMISSION="transmission",Nf.THICKNESS="thickness",Nf.ATTENUATION_DISTANCE="attenuationDistance",Nf.ATTENUATION_COLOR="attenuationColor",Nf.LINE_SCALE="scale",Nf.LINE_DASH_SIZE="dashSize",Nf.LINE_GAP_SIZE="gapSize",Nf.LINE_WIDTH="linewidth",Nf.LINE_DASH_OFFSET="dashOffset",Nf.POINT_WIDTH="pointWidth",Nf.DISPERSION="dispersion",Nf.LIGHT_MAP="light",Nf.AO_MAP="ao",Nf.type=Ql("Material",Nf);const Rf=Hu(Nf,Nf.ALPHA_TEST),Cf=Hu(Nf,Nf.COLOR),Ef=Hu(Nf,Nf.SHININESS),Bf=Hu(Nf,Nf.EMISSIVE),If=Hu(Nf,Nf.OPACITY),Pf=Hu(Nf,Nf.SPECULAR),Ff=Hu(Nf,Nf.SPECULAR_INTENSITY),zf=Hu(Nf,Nf.SPECULAR_COLOR),Uf=Hu(Nf,Nf.SPECULAR_STRENGTH),Lf=Hu(Nf,Nf.REFLECTIVITY),Of=Hu(Nf,Nf.ROUGHNESS),Vf=Hu(Nf,Nf.METALNESS),Df=Hu(Nf,Nf.NORMAL).context({getUV:null}),kf=Hu(Nf,Nf.CLEARCOAT),Gf=Hu(Nf,Nf.CLEARCOAT_ROUGHNESS),Wf=Hu(Nf,Nf.CLEARCOAT_NORMAL).context({getUV:null}),Hf=Hu(Nf,Nf.ROTATION),jf=Hu(Nf,Nf.SHEEN),qf=Hu(Nf,Nf.SHEEN_ROUGHNESS),$f=Hu(Nf,Nf.ANISOTROPY),Xf=Hu(Nf,Nf.IRIDESCENCE),Yf=Hu(Nf,Nf.IRIDESCENCE_IOR),Jf=Hu(Nf,Nf.IRIDESCENCE_THICKNESS),Zf=Hu(Nf,Nf.TRANSMISSION),Kf=Hu(Nf,Nf.THICKNESS),Qf=Hu(Nf,Nf.IOR),ey=Hu(Nf,Nf.ATTENUATION_DISTANCE),ty=Hu(Nf,Nf.ATTENUATION_COLOR),sy=Hu(Nf,Nf.LINE_SCALE),iy=Hu(Nf,Nf.LINE_DASH_SIZE),ry=Hu(Nf,Nf.LINE_GAP_SIZE),ny=Hu(Nf,Nf.LINE_WIDTH),oy=Hu(Nf,Nf.LINE_DASH_OFFSET),ay=Hu(Nf,Nf.POINT_WIDTH),hy=Hu(Nf,Nf.DISPERSION),ly=Hu(Nf,Nf.LIGHT_MAP),uy=Hu(Nf,Nf.AO_MAP);Nf.REFRACTION_RATIO;const cy=Cc(new Qs).onReference((function(e){return e.material})).onRenderUpdate((function({material:e}){this.value.set(e.anisotropy*Math.cos(e.anisotropyRotation),e.anisotropy*Math.sin(e.anisotropyRotation))}));class dy extends iu{constructor(e=null){super("vec4"),this.positionNode=e}setup(e){if("fragment"===e.shaderStage)return em(e.context.mvp);const t=this.positionNode||bg;return Ym.mul(cg).mul(t)}}dy.type=Ql("ModelViewProjection",dy);const py=Wu(dy);class my extends Kl{constructor(e){super("uint"),this.scope=e,this.isInstanceIndexNode=!0}generate(e){const t=this.getNodeType(e),s=this.scope;let i,r;if(s===my.VERTEX)i=e.getVertexIndex();else if(s===my.INSTANCE)i=e.getInstanceIndex();else if(s===my.DRAW)i=e.getDrawIndex();else{if(s!==my.INVOCATION_LOCAL)throw new Error("THREE.IndexNode: Unknown scope: "+s);i=e.getInvocationLocalIndex()}if("vertex"===e.shaderStage||"compute"===e.shaderStage)r=i;else{r=em(this).build(e,t)}return r}}my.VERTEX="vertex",my.INSTANCE="instance",my.INVOCATION_LOCAL="invocationLocal",my.DRAW="draw",my.type=Ql("Index",my);const gy=Hu(my,my.VERTEX),fy=Hu(my,my.INSTANCE),yy=Hu(my,my.INVOCATION_LOCAL),xy=Hu(my,my.DRAW);class by extends oo{constructor(e,t,s=1){super(e,t),this.isInstancedInterleavedBuffer=!0,this.meshPerAttribute=s}copy(e){return super.copy(e),this.meshPerAttribute=e.meshPerAttribute,this}clone(e){const t=super.clone(e);return t.meshPerAttribute=this.meshPerAttribute,t}toJSON(e){const t=super.toJSON(e);return t.isInstancedInterleavedBuffer=!0,t.meshPerAttribute=this.meshPerAttribute,t}}class vy extends Kl{constructor(e){super("void"),this.instanceMesh=e,this.instanceMatrixNode=null,this.instanceColorNode=null,this.updateType=Hl.FRAME,this.buffer=null,this.bufferColor=null}setup(e){let t=this.instanceMatrixNode,s=this.instanceColorNode;const i=this.instanceMesh;if(null===t){const e=i.instanceMatrix;if(i.count<=1e3)t=jg(e.array,"mat4",i.count).element(fy);else{const s=new by(e.array,16,1);this.buffer=s;const i=e.usage===Cs?ym:fm,r=[i(s,"vec4",16,0),i(s,"vec4",16,4),i(s,"vec4",16,8),i(s,"vec4",16,12)];t=fc(...r)}this.instanceMatrixNode=t}const r=i.instanceColor;if(r&&null===s){const e=new Ho(r.array,3),t=r.usage===Cs?ym:fm;this.bufferColor=e,s=oc(t(e,"vec3",3,0)),this.instanceColorNode=s}const n=t.mul(bg).xyz;if(bg.assign(n),e.hasGeometryAttribute("normal")){const e=gc(t),s=Cg.div(oc(e[0].dot(e[0]),e[1].dot(e[1]),e[2].dot(e[2]))),i=e.mul(s).xyz;Cg.assign(i)}null!==this.instanceColorNode&&Ic("vec3","vInstanceColor").assign(this.instanceColorNode)}update(){this.instanceMesh.instanceMatrix.usage!==Cs&&null!=this.buffer&&this.instanceMesh.instanceMatrix.version!==this.buffer.version&&(this.buffer.version=this.instanceMesh.instanceMatrix.version),this.instanceMesh.instanceColor&&this.instanceMesh.instanceColor.usage!==Cs&&null!=this.bufferColor&&this.instanceMesh.instanceColor.version!==this.bufferColor.version&&(this.bufferColor.version=this.instanceMesh.instanceColor.version)}}vy.type=Ql("Instance",vy);const Ty=Wu(vy);class _y extends Kl{constructor(e){super("void"),this.batchMesh=e,this.batchingIdNode=null}setup(e){null===this.batchingIdNode&&(null===e.getDrawIndex()?this.batchingIdNode=fy:this.batchingIdNode=xy);const t=ju((([e])=>{const t=Om(Wm(this.batchMesh._indirectTexture),0),s=Qu(e).modInt(Qu(t)),i=Qu(e).div(Qu(t));return Wm(this.batchMesh._indirectTexture,ic(s,i)).x})).setLayout({name:"getIndirectIndex",type:"uint",inputs:[{name:"id",type:"int"}]}),s=t(Qu(this.batchingIdNode)),i=this.batchMesh._matricesTexture,r=Om(Wm(i),0),n=Ku(s).mul(4).toInt().toVar(),o=n.modInt(r),a=n.div(Qu(r)),h=fc(Wm(i,ic(o,a)),Wm(i,ic(o.add(1),a)),Wm(i,ic(o.add(2),a)),Wm(i,ic(o.add(3),a))),l=this.batchMesh._colorsTexture;if(null!==l){const e=ju((([e])=>{const t=Om(Wm(l),0).x,s=e,i=s.modInt(t),r=s.div(t);return Wm(l,ic(i,r)).rgb})).setLayout({name:"getBatchingColor",type:"vec3",inputs:[{name:"id",type:"int"}]}),t=e(s);Ic("vec3","vBatchColor").assign(t)}const u=gc(h);bg.assign(h.mul(bg));const c=Cg.div(oc(u[0].dot(u[0]),u[1].dot(u[1]),u[2].dot(u[2]))),d=u.mul(c).xyz;Cg.assign(d),e.hasGeometryAttribute("tangent")&&sf.mulAssign(u)}}_y.type=Ql("Batch",_y);const wy=Wu(_y),Sy=new WeakMap;class My extends Kl{constructor(e,t=!1){let s,i,r;super("void"),this.skinnedMesh=e,this.useReference=t,this.updateType=Hl.OBJECT,this.skinIndexNode=zm("skinIndex","uvec4"),this.skinWeightNode=zm("skinWeight","vec4"),t?(s=Zg("bindMatrix","mat4"),i=Zg("bindMatrixInverse","mat4"),r=Kg("skeleton.boneMatrices","mat4",e.skeleton.bones.length)):(s=Cc(e.bindMatrix,"mat4"),i=Cc(e.bindMatrixInverse,"mat4"),r=jg(e.skeleton.boneMatrices,"mat4",e.skeleton.bones.length)),this.bindMatrixNode=s,this.bindMatrixInverseNode=i,this.boneMatricesNode=r,this.previousBoneMatricesNode=null}getSkinnedPosition(e=this.boneMatricesNode,t=bg){const{skinIndexNode:s,skinWeightNode:i,bindMatrixNode:r,bindMatrixInverseNode:n}=this,o=e.element(s.x),a=e.element(s.y),h=e.element(s.z),l=e.element(s.w),u=r.mul(t),c=dd(o.mul(i.x).mul(u),a.mul(i.y).mul(u),h.mul(i.z).mul(u),l.mul(i.w).mul(u));return n.mul(c).xyz}getSkinnedNormal(e=this.boneMatricesNode,t=Cg){const{skinIndexNode:s,skinWeightNode:i,bindMatrixNode:r,bindMatrixInverseNode:n}=this,o=e.element(s.x),a=e.element(s.y),h=e.element(s.z),l=e.element(s.w);let u=dd(i.x.mul(o),i.y.mul(a),i.z.mul(h),i.w.mul(l));return u=n.mul(u).mul(r),u.transformDirection(t).xyz}getPreviousSkinnedPosition(e){const t=e.object;return null===this.previousBoneMatricesNode&&(t.skeleton.previousBoneMatrices=new Float32Array(t.skeleton.boneMatrices),this.previousBoneMatricesNode=Kg("skeleton.previousBoneMatrices","mat4",t.skeleton.bones.length)),this.getSkinnedPosition(this.previousBoneMatricesNode,vg)}needsPreviousBoneMatrices(e){const t=e.renderer.getMRT();return t&&t.has("velocity")}setup(e){this.needsPreviousBoneMatrices(e)&&vg.assign(this.getPreviousSkinnedPosition(e));const t=this.getSkinnedPosition();if(bg.assign(t),e.hasGeometryAttribute("normal")){const t=this.getSkinnedNormal();Cg.assign(t),e.hasGeometryAttribute("tangent")&&sf.assign(t)}}generate(e,t){if("void"!==t)return bg.build(e,t)}update(e){const t=(this.useReference?e.object:this.skinnedMesh).skeleton;Sy.get(t)!==e.frameId&&(Sy.set(t,e.frameId),null!==this.previousBoneMatricesNode&&t.previousBoneMatrices.set(t.boneMatrices),t.update())}}My.type=Ql("Skinning",My);const Ay=e=>Du(new My(e)),Ny=e=>Du(new My(e,!0));class Ry extends Kl{constructor(e=[]){super(),this.params=e}getVarName(e){return String.fromCharCode("i".charCodeAt()+e)}getProperties(e){const t=e.getNodeProperties(this);if(void 0!==t.stackNode)return t;const s={};for(let e=0,t=this.params.length-1;eNumber(n)?">=":"<"));const u={start:r,end:n,condition:h},c=u.start,d=u.end;let p="",m="",g="";l||(l="int"===a||"uint"===a?h.includes("<")?"++":"--":h.includes("<")?"+= 1.":"-= 1."),p+=e.getVar(a,o)+" = "+c,m+=o+" "+h+" "+d,g+=o+" "+l;const f=`for ( ${p}; ${m}; ${g} )`;e.addFlowCode((0===t?"\n":"")+e.tab+f+" {\n\n").addFlowTab()}const r=i.build(e,"void"),n=t.returnsNode?t.returnsNode.build(e):"";e.removeFlowTab().addFlowCode("\n"+e.tab+r);for(let t=0,s=this.params.length-1;tDu(new Ry(Gu(e,"int"))).append(),Ey=()=>Rm("continue").append(),By=()=>Rm("break").append(),Iy=new WeakMap,Py=new _i,Fy=ju((({bufferMap:e,influence:t,stride:s,width:i,depth:r,offset:n})=>{const o=Qu(gy).mul(s).add(n),a=o.div(i),h=o.sub(a.mul(i));return Wm(e,ic(h,a)).depth(r).mul(t)}));class zy extends Kl{constructor(e){super("void"),this.mesh=e,this.morphBaseInfluence=Cc(1),this.updateType=Hl.OBJECT}setup(e){const{geometry:t}=e,s=void 0!==t.morphAttributes.position,i=t.hasAttribute("normal")&&void 0!==t.morphAttributes.normal,r=t.morphAttributes.position||t.morphAttributes.normal||t.morphAttributes.color,n=void 0!==r?r.length:0,{texture:o,stride:a,size:h}=function(e){const t=void 0!==e.morphAttributes.position,s=void 0!==e.morphAttributes.normal,i=void 0!==e.morphAttributes.color,r=e.morphAttributes.position||e.morphAttributes.normal||e.morphAttributes.color,n=void 0!==r?r.length:0;let o=Iy.get(e);if(void 0===o||o.count!==n){void 0!==o&&o.texture.dispose();const a=e.morphAttributes.position||[],h=e.morphAttributes.normal||[],l=e.morphAttributes.color||[];let u=0;!0===t&&(u=1),!0===s&&(u=2),!0===i&&(u=3);let c=e.attributes.position.count*u,d=1;const p=4096;c>p&&(d=Math.ceil(c/p),c=p);const m=new Float32Array(c*d*4*n),g=new Mi(m,c,d,n);g.type=Ie,g.needsUpdate=!0;const f=4*u;for(let x=0;x{const t=Ku(0).toVar();this.mesh.count>1&&null!==this.mesh.morphTexture&&void 0!==this.mesh.morphTexture?t.assign(Wm(this.mesh.morphTexture,ic(Qu(e).add(1),Qu(fy))).r):t.assign(Zg("morphTargetInfluences","float").element(e).toVar()),!0===s&&bg.addAssign(Fy({bufferMap:o,influence:t,stride:a,width:l,depth:e,offset:Qu(0)})),!0===i&&Cg.addAssign(Fy({bufferMap:o,influence:t,stride:a,width:l,depth:e,offset:Qu(1)}))}))}update(){const e=this.morphBaseInfluence;this.mesh.geometry.morphTargetsRelative?e.value=1:e.value=1-this.mesh.morphTargetInfluences.reduce(((e,t)=>e+t),0)}}zy.type=Ql("Morph",zy);const Uy=Wu(zy),Ly=(e,t)=>{for(const s of t)if(s.isAnalyticLightNode&&s.light.id===e)return s;return null};class Oy extends Kl{constructor(e=[]){super("vec3"),this.totalDiffuseNode=oc().toVar("totalDiffuse"),this.totalSpecularNode=oc().toVar("totalSpecular"),this.outgoingLightNode=oc().toVar("outgoingLight"),this._lights=e,this._lightNodes=null,this._lightNodesHash=null,this.global=!0}getHash(e){if(null===this._lightNodesHash){null===this._lightNodes&&this.setupLightsNode(e);const t=[];for(const e of this._lightNodes)t.push(e.getHash());this._lightNodesHash="lights-"+t.join(",")}return this._lightNodesHash}analyze(e){const t=e.getDataFromNode(this);for(const s of t.nodes)s.build(e)}setupLightsNode(e){const t=[],s=this._lightNodes,i=(e=>e.sort(((e,t)=>e.id-t.id)))(this._lights),r=e.renderer.nodes.library;for(const e of i)if(e.isNode)t.push(Du(e));else{let i=null;if(null!==s&&(i=Ly(e.id,s)),null===i){const s=r.getLightNodeClass(e.constructor);if(void 0===s){console.warn(`LightsNode.setupNodeLights: Light node not found for ${e.constructor.name}`);continue}t.push(Du(new s(e)))}}this._lightNodes=t}setup(e){null===this._lightNodes&&this.setupLightsNode(e);const t=e.context,s=t.lightingModel;let i=this.outgoingLightNode;if(s){const{_lightNodes:r,totalDiffuseNode:n,totalSpecularNode:o}=this;t.outgoingLight=i;const a=e.addStack();e.getDataFromNode(this).nodes=a.nodes,s.start(t,a,e);for(const t of r)t.build(e);s.indirect(t,a,e);const{backdrop:h,backdropAlpha:l}=t,{directDiffuse:u,directSpecular:c,indirectDiffuse:d,indirectSpecular:p}=t.reflectedLight;let m=u.add(d);null!==h&&(m=oc(null!==l?l.mix(m,h):h),t.material.transparent=!0),n.assign(m),o.assign(c.add(p)),i.assign(n.add(o)),s.finish(t,a,e),i=i.bypass(e.removeStack())}return i}setLights(e){return this._lights=e,this._lightNodes=null,this._lightNodesHash=null,this}getLights(){return this._lights}}Oy.type=Ql("Lights",Oy);const Vy=Wu(Oy);class Dy extends Kl{constructor(){super("vec3"),this.isLightingNode=!0}generate(){console.warn("Abstract function.")}}Dy.type=Ql("Lighting",Dy);class ky extends Dy{constructor(e=null){super(),this.aoNode=e}setup(e){e.context.ambientOcclusion.mulAssign(this.aoNode)}}ky.type=Ql("AO",ky);class Gy extends Xp{constructor(e,t=null,s=null,i=null){super(e),this.lightingModel=t,this.backdropNode=s,this.backdropAlphaNode=i,this._value=null}getContext(){const{backdropNode:e,backdropAlphaNode:t}=this,s={directDiffuse:oc().toVar("directDiffuse"),directSpecular:oc().toVar("directSpecular"),indirectDiffuse:oc().toVar("indirectDiffuse"),indirectSpecular:oc().toVar("indirectSpecular")};return{radiance:oc().toVar("radiance"),irradiance:oc().toVar("irradiance"),iblIrradiance:oc().toVar("iblIrradiance"),ambientOcclusion:Ku(1).toVar("ambientOcclusion"),reflectedLight:s,backdrop:e,backdropAlpha:t}}setup(e){return this.value=this._value||(this._value=this.getContext()),this.value.lightingModel=this.lightingModel||e.context.lightingModel,super.setup(e)}}Gy.type=Ql("LightingContext",Gy);const Wy=Wu(Gy);class Hy extends Dy{constructor(e){super(),this.node=e}setup(e){e.context.irradiance.addAssign(this.node)}}let jy,qy;Hy.type=Ql("Irradiance",Hy);class $y extends Kl{constructor(e){super(),this.scope=e,this.isViewportNode=!0}getNodeType(){return this.scope===$y.VIEWPORT?"vec4":"vec2"}getUpdateType(){let e=Hl.NONE;return this.scope!==$y.RESOLUTION&&this.scope!==$y.VIEWPORT||(e=Hl.RENDER),this.updateType=e,e}update({renderer:e}){this.scope===$y.VIEWPORT?e.getViewport(qy):e.getDrawingBufferSize(jy)}setup(){const e=this.scope;let t=null;return t=e===$y.RESOLUTION?Cc(jy||(jy=new Qs)):e===$y.VIEWPORT?Cc(qy||(qy=new _i)):sc(Xy.div(Yy)),t}generate(e){if(this.scope===$y.COORDINATE){let t=e.getFragCoord();if(e.isFlipY()){const s=e.getNodeProperties(Yy).outputNode.build(e);t=`${e.getType("vec2")}( ${t}.x, ${s}.y - ${t}.y )`}return t}return super.generate(e)}}$y.COORDINATE="coordinate",$y.RESOLUTION="resolution",$y.VIEWPORT="viewport",$y.UV="uv",$y.type=Ql("Viewport",$y);const Xy=Hu($y,$y.COORDINATE),Yy=Hu($y,$y.RESOLUTION),Jy=Hu($y,$y.VIEWPORT),Zy=Hu($y,$y.UV),Ky=ju((()=>(console.warn('TSL.ViewportNode: "viewportTopLeft" is deprecated. Use "viewportUV" instead.'),Zy)),"vec2").once()(),Qy=ju((()=>(console.warn('TSL.ViewportNode: "viewportBottomLeft" is deprecated. Use "viewportUV.flipY()" instead.'),Zy.flipY())),"vec2").once()(),ex=new Qs;class tx extends km{constructor(e=Zy,t=null,s=null){null===s&&((s=new Xa).minFilter=Se),super(s,e,t),this.generateMipmaps=!1,this.isOutputTextureNode=!0,this.updateBeforeType=Hl.FRAME}updateBefore(e){const t=e.renderer;t.getDrawingBufferSize(ex);const s=this.value;s.image.width===ex.width&&s.image.height===ex.height||(s.image.width=ex.width,s.image.height=ex.height,s.needsUpdate=!0);const i=s.generateMipmaps;s.generateMipmaps=this.generateMipmaps,t.copyFramebufferToTexture(s),s.generateMipmaps=i}clone(){const e=new this.constructor(this.uvNode,this.levelNode,this.value);return e.generateMipmaps=this.generateMipmaps,e}}tx.type=Ql("ViewportTexture",tx);const sx=Wu(tx),ix=Wu(tx,null,null,{generateMipmaps:!0});let rx=null;class nx extends tx{constructor(e=Zy,t=null){null===rx&&(rx=new Qa),super(e,t,rx)}}nx.type=Ql("ViewportDepthTexture",nx);const ox=Wu(nx);class ax extends Kl{constructor(e,t=null){super("float"),this.scope=e,this.valueNode=t,this.isViewportDepthNode=!0}generate(e){const{scope:t}=this;return t===ax.DEPTH_BASE?e.getFragDepth():super.generate(e)}setup({camera:e}){const{scope:t}=this,s=this.valueNode;let i=null;if(t===ax.DEPTH_BASE)null!==s&&(i=dx().assign(s));else if(t===ax.DEPTH)i=e.isPerspectiveCamera?ux(wg.z,qm,$m):hx(wg.z,qm,$m);else if(t===ax.LINEAR_DEPTH)if(null!==s)if(e.isPerspectiveCamera){const e=cx(s,qm,$m);i=hx(e,qm,$m)}else i=s;else i=hx(wg.z,qm,$m);return i}}ax.DEPTH_BASE="depthBase",ax.DEPTH="depth",ax.LINEAR_DEPTH="linearDepth",ax.type=Ql("ViewportDepth",ax);const hx=(e,t,s)=>e.add(t).div(t.sub(s)),lx=(e,t,s)=>t.sub(s).mul(e).sub(t),ux=(e,t,s)=>t.add(e).mul(s).div(s.sub(t).mul(e)),cx=(e,t,s)=>t.mul(s).div(s.sub(t).mul(e).sub(s)),dx=Wu(ax,ax.DEPTH_BASE),px=Hu(ax,ax.DEPTH),mx=Wu(ax,ax.LINEAR_DEPTH),gx=mx(ox());px.assign=e=>dx(e);class fx extends Kl{constructor(e=fx.DEFAULT){super(),this.scope=e}setup(e){super.setup(e);const t=e.clippingContext,{localClipIntersection:s,localClippingCount:i,globalClippingCount:r}=t,n=r+i,o=s?n-i:n;return this.scope===fx.ALPHA_TO_COVERAGE?this.setupAlphaToCoverage(t.planes,n,o):this.setupDefault(t.planes,n,o)}setupAlphaToCoverage(e,t,s){return ju((()=>{const i=Xg(e),r=Bc("float","distanceToPlane"),n=Bc("float","distanceToGradient"),o=Bc("float","clipOpacity");let a;if(o.assign(1),Cy(s,(({i:e})=>{a=i.element(e),r.assign(wg.dot(a.xyz).negate().add(a.w)),n.assign(r.fwidth().div(2)),o.mulAssign(Dp(n.negate(),n,r)),o.equal(0).discard()})),s{a=i.element(t),r.assign(wg.dot(a.xyz).negate().add(a.w)),n.assign(r.fwidth().div(2)),e.mulAssign(Dp(n.negate(),n,r).oneMinus())})),o.mulAssign(e.oneMinus())}Pc.a.mulAssign(o),Pc.a.equal(0).discard()}))()}setupDefault(e,t,s){return ju((()=>{const i=Xg(e);let r;if(Cy(s,(({i:e})=>{r=i.element(e),wg.dot(r.xyz).greaterThan(r.w).discard()})),s{r=i.element(t),e.assign(wg.dot(r.xyz).greaterThan(r.w).and(e))})),e.discard()}}))()}}fx.ALPHA_TO_COVERAGE="alphaToCoverage",fx.DEFAULT="default",fx.type=Ql("Clipping",fx);const yx=new Map;class xx extends Kr{constructor(){super(),this.isNodeMaterial=!0,this.type=this.constructor.type,this.forceSinglePass=!1,this.fog=!0,this.lights=!1,this.lightsNode=null,this.envNode=null,this.aoNode=null,this.colorNode=null,this.normalNode=null,this.opacityNode=null,this.backdropNode=null,this.backdropAlphaNode=null,this.alphaTestNode=null,this.positionNode=null,this.depthNode=null,this.shadowNode=null,this.shadowPositionNode=null,this.outputNode=null,this.mrtNode=null,this.fragmentNode=null,this.vertexNode=null}customProgramCacheKey(){return this.type+Ul(this)}build(e){this.setup(e)}setup(e){let t;e.context.setupNormal=()=>this.setupNormal(e),e.addStack(),e.stack.outputNode=this.vertexNode||this.setupPosition(e),e.addFlow("vertex",e.removeStack()),e.addStack();const s=this.setupClipping(e);if(!0===this.depthWrite&&this.setupDepth(e),null===this.fragmentNode){this.setupDiffuseColor(e),this.setupVariants(e);const i=this.setupLighting(e);null!==s&&e.stack.add(s);const r=uc(i,Pc.a).max(0);t=this.setupOutput(e,r),Zc.assign(t),null!==this.outputNode&&(t=this.outputNode);if(null!==e.renderer.getRenderTarget()){const s=e.renderer.getMRT(),i=this.mrtNode;null!==s?(t=s,null!==i&&(t=s.merge(i))):null!==i&&(t=i)}}else{let s=this.fragmentNode;!0!==s.isOutputStructNode&&(s=uc(s)),t=this.setupOutput(e,s)}e.stack.outputNode=t,e.addFlow("fragment",e.removeStack())}setupClipping(e){if(null===e.clippingContext)return null;const{globalClippingCount:t,localClippingCount:s}=e.clippingContext;let i=null;return(t||s)&&(this.alphaToCoverage?i=Du(new fx(fx.ALPHA_TO_COVERAGE)):e.stack.add(Du(new fx))),i}setupDepth(e){const{renderer:t}=e;let s=this.depthNode;if(null===s){const e=t.getMRT();if(e&&e.has("depth"))s=e.get("depth");else if(!0===t.logarithmicDepthBuffer){s=py().w.add(1).log2().mul(Xm).mul(.5)}}null!==s&&px.assign(s).append()}setupPosition(e){const{object:t}=e,s=t.geometry;if(e.addStack(),(s.morphAttributes.position||s.morphAttributes.normal||s.morphAttributes.color)&&Uy(t).append(),!0===t.isSkinnedMesh&&Ny(t).append(),this.displacementMap){const e=ef("displacementMap","texture"),t=ef("displacementScale","float"),s=ef("displacementBias","float");bg.addAssign(Cg.normalize().mul(e.x.mul(t).add(s)))}t.isBatchedMesh&&wy(t).append(),t.instanceMatrix&&!0===t.instanceMatrix.isInstancedBufferAttribute&&Ty(t).append(),null!==this.positionNode&&bg.assign(this.positionNode);const i=py();return e.context.vertex=e.removeStack(),e.context.mvp=i,i}setupDiffuseColor({object:e,geometry:t}){let s=this.colorNode?uc(this.colorNode):Cf;if(!0===this.vertexColors&&t.hasAttribute("color")&&(s=uc(s.xyz.mul(zm("color","vec3")),s.a)),e.instanceColor){s=Ic("vec3","vInstanceColor").mul(s)}if(e.isBatchedMesh&&e._colorsTexture){s=Ic("vec3","vBatchColor").mul(s)}Pc.assign(s);const i=this.opacityNode?Ku(this.opacityNode):If;if(Pc.a.assign(Pc.a.mul(i)),null!==this.alphaTestNode||this.alphaTest>0){const e=null!==this.alphaTestNode?Ku(this.alphaTestNode):Rf;Pc.a.lessThanEqual(e).discard()}!1===this.transparent&&1===this.blending&&!1===this.alphaToCoverage&&Pc.a.assign(1)}setupVariants(){}setupOutgoingLight(){return!0===this.lights?oc(0):Pc.rgb}setupNormal(){return this.normalNode?oc(this.normalNode):Df}setupEnvironment(){let e=null;return this.envNode?e=this.envNode:this.envMap&&(e=this.envMap.isCubeTexture?ef("envMap","cubeTexture"):ef("envMap","texture")),e}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new Hy(ly)),t}setupLights(e){const t=[],s=this.setupEnvironment(e);s&&s.isLightingNode&&t.push(s);const i=this.setupLightMap(e);if(i&&i.isLightingNode&&t.push(i),null!==this.aoNode||e.material.aoMap){const e=null!==this.aoNode?this.aoNode:uy;t.push(new ky(e))}let r=this.lightsNode||e.lightsNode;return t.length>0&&(r=Vy([...r.getLights(),...t])),r}setupLightingModel(){}setupLighting(e){const{material:t}=e,{backdropNode:s,backdropAlphaNode:i,emissiveNode:r}=this,n=!0===this.lights||null!==this.lightsNode?this.setupLights(e):null;let o=this.setupOutgoingLight(e);if(n&&n.getScope().getLights().length>0){const t=this.setupLightingModel(e);o=Wy(n,t,s,i)}else null!==s&&(o=oc(null!==i?Up(o,s,i):s));return(r&&!0===r.isNode||t.emissive&&!0===t.emissive.isColor)&&(Fc.assign(oc(r||Bf)),o=o.add(Fc)),o}setupOutput(e,t){if(!0===this.fog){const s=e.fogNode;s&&(t=uc(s.mix(t.rgb,s.colorNode),t.a))}return t}setDefaultValues(e){for(const t in e){const s=e[t];void 0===this[t]&&(this[t]=s,s&&s.clone&&(this[t]=s.clone()))}const t=Object.getOwnPropertyDescriptors(e.constructor.prototype);for(const e in t)void 0===Object.getOwnPropertyDescriptor(this.constructor.prototype,e)&&void 0!==t[e].get&&Object.defineProperty(this.constructor.prototype,e,t[e])}toJSON(e){const t=void 0===e||"string"==typeof e;t&&(e={textures:{},images:{},nodes:{}});const s=Kr.prototype.toJSON.call(this,e),i=Ll(this);s.inputNodes={};for(const{property:t,childNode:r}of i)s.inputNodes[t]=r.toJSON(e).uuid;function r(e){const t=[];for(const s in e){const i=e[s];delete i.metadata,t.push(i)}return t}if(t){const t=r(e.textures),i=r(e.images),n=r(e.nodes);t.length>0&&(s.textures=t),i.length>0&&(s.images=i),n.length>0&&(s.nodes=n)}return s}copy(e){return this.lightsNode=e.lightsNode,this.envNode=e.envNode,this.colorNode=e.colorNode,this.normalNode=e.normalNode,this.opacityNode=e.opacityNode,this.backdropNode=e.backdropNode,this.backdropAlphaNode=e.backdropAlphaNode,this.alphaTestNode=e.alphaTestNode,this.positionNode=e.positionNode,this.depthNode=e.depthNode,this.shadowNode=e.shadowNode,this.shadowPositionNode=e.shadowPositionNode,this.outputNode=e.outputNode,this.mrtNode=e.mrtNode,this.fragmentNode=e.fragmentNode,this.vertexNode=e.vertexNode,super.copy(e)}}function bx(e,t){const s="NodeMaterial",i=e+s;if("function"!=typeof t)throw new Error(`THREE.Node: NodeMaterial class "${e}" is not a class.`);if(yx.has(i))console.warn(`THREE.Node: Redefinition of NodeMaterial class "${i}".`);else{if(e.slice(-12)!==s)return yx.set(i,t),t.type=i,i;console.warn(`THREE.NodeMaterial: NodeMaterial class ${i} should not have '${s}' suffix.`)}}xx.type=bx("",xx);const vx=new Va;class Tx extends xx{constructor(e={}){super(),this.lights=!1,this.useAlphaToCoverage=!0,this.useColor=e.vertexColors,this.pointWidth=1,this.pointColorNode=null,this.pointWidthNode=null,this.setDefaultValues(vx),this.setupShaders(),this.setValues(e)}setup(e){this.setupShaders(),super.setup(e)}setupShaders(){const e=this.alphaToCoverage,t=this.useColor;this.vertexNode=ju((()=>{em(sc(),"vUv").assign(Um());const e=zm("instancePosition").xyz,t=Bc("vec4","mvPos");t.assign(cg.mul(uc(e,1)));const s=Jy.z.div(Jy.w),i=Ym.mul(t),r=Bc("vec2","offset");return r.assign(xg.xy),r.mulAssign(this.pointWidthNode?this.pointWidthNode:ay),r.assign(r.div(Jy.z)),r.y.assign(r.y.mul(s)),r.assign(r.mul(i.w)),i.assign(i.add(uc(r,0,0))),i}))(),this.fragmentNode=ju((()=>{const s=em(sc(),"vUv"),i=Bc("float","alpha");i.assign(1);const r=s.x,n=s.y,o=r.mul(r).add(n.mul(n));if(e){const e=Bc("float","dlen");e.assign(o.fwidth()),i.assign(Dp(e.oneMinus(),e.add(1),o).oneMinus())}else o.greaterThan(1).discard();let a;if(this.pointColorNode)a=this.pointColorNode;else if(t){a=zm("instanceColor").mul(Cf)}else a=Cf;return i.mulAssign(If),uc(a,i)}))()}get alphaToCoverage(){return this.useAlphaToCoverage}set alphaToCoverage(e){this.useAlphaToCoverage!==e&&(this.useAlphaToCoverage=e,this.needsUpdate=!0)}}Tx.type=bx("InstancedPoints",Tx);const _x=new Ma;class wx extends xx{constructor(e){super(),this.isLineBasicNodeMaterial=!0,this.lights=!1,this.setDefaultValues(_x),this.setValues(e)}}wx.type=bx("LineBasic",wx);const Sx=new zl;class Mx extends xx{constructor(e){super(),this.isLineDashedNodeMaterial=!0,this.lights=!1,this.setDefaultValues(Sx),this.offsetNode=null,this.dashScaleNode=null,this.dashSizeNode=null,this.gapSizeNode=null,this.setValues(e)}setupVariants(){const e=this.offsetNode,t=this.dashScaleNode?Ku(this.dashScaleNode):sy,s=this.dashSizeNode?Ku(this.dashSizeNode):iy,i=this.dashSizeNode?Ku(this.dashGapNode):ry;Kc.assign(s),Qc.assign(i);const r=em(zm("lineDistance").mul(t));(e?r.add(e):r).mod(Kc.add(Qc)).greaterThan(Kc).discard()}}Mx.type=bx("LineDashed",Mx);const Ax=new zl;class Nx extends xx{constructor(e={}){super(),this.lights=!1,this.setDefaultValues(Ax),this.useAlphaToCoverage=!0,this.useColor=e.vertexColors,this.useDash=e.dashed,this.useWorldUnits=!1,this.dashOffset=0,this.lineWidth=1,this.lineColorNode=null,this.offsetNode=null,this.dashScaleNode=null,this.dashSizeNode=null,this.gapSizeNode=null,this.setValues(e)}setup(e){this.setupShaders(),super.setup(e)}setupShaders(){const e=this.alphaToCoverage,t=this.useColor,s=this.dashed,i=this.worldUnits,r=ju((({start:e,end:t})=>{const s=Ym.element(2).element(2),i=Ym.element(3).element(2).mul(-.5).div(s).sub(e.z).div(t.z.sub(e.z));return uc(Up(e.xyz,t.xyz,i),t.w)}));this.vertexNode=ju((()=>{Ic("vec2","vUv").assign(Um());const e=zm("instanceStart"),t=zm("instanceEnd"),n=Bc("vec4","start"),o=Bc("vec4","end");n.assign(cg.mul(uc(e,1))),o.assign(cg.mul(uc(t,1))),i&&(Ic("vec3","worldStart").assign(n.xyz),Ic("vec3","worldEnd").assign(o.xyz));const a=Jy.z.div(Jy.w),h=Ym.element(2).element(3).equal(-1);Yu(h,(()=>{Yu(n.z.lessThan(0).and(o.z.greaterThan(0)),(()=>{o.assign(r({start:n,end:o}))})).ElseIf(o.z.lessThan(0).and(n.z.greaterThanEqual(0)),(()=>{n.assign(r({start:o,end:n}))}))}));const l=Ym.mul(n),u=Ym.mul(o),c=l.xyz.div(l.w),d=u.xyz.div(u.w),p=d.xy.sub(c.xy).toVar();p.x.assign(p.x.mul(a)),p.assign(p.normalize());const m=uc().toVar();if(i){const e=o.xyz.sub(n.xyz).normalize(),t=Up(n.xyz,o.xyz,.5).normalize(),i=e.cross(t).normalize(),r=e.cross(i),a=Ic("vec4","worldPos");a.assign(xg.y.lessThan(.5).select(n,o));const h=ny.mul(.5);a.addAssign(uc(xg.x.lessThan(0).select(i.mul(h),i.mul(h).negate()),0)),s||(a.addAssign(uc(xg.y.lessThan(.5).select(e.mul(h).negate(),e.mul(h)),0)),a.addAssign(uc(r.mul(h),0)),Yu(xg.y.greaterThan(1).or(xg.y.lessThan(0)),(()=>{a.subAssign(uc(r.mul(2).mul(h),0))}))),m.assign(Ym.mul(a));const l=oc().toVar();l.assign(xg.y.lessThan(.5).select(c,d)),m.z.assign(l.z.mul(m.w))}else{const e=Bc("vec2","offset");e.assign(sc(p.y,p.x.negate())),p.x.assign(p.x.div(a)),e.x.assign(e.x.div(a)),e.assign(xg.x.lessThan(0).select(e.negate(),e)),Yu(xg.y.lessThan(0),(()=>{e.assign(e.sub(p))})).ElseIf(xg.y.greaterThan(1),(()=>{e.assign(e.add(p))})),e.assign(e.mul(ny)),e.assign(e.div(Jy.w)),m.assign(xg.y.lessThan(.5).select(l,u)),e.assign(e.mul(m.w)),m.assign(m.add(uc(e,0,0)))}return m}))();const n=ju((({p1:e,p2:t,p3:s,p4:i})=>{const r=e.sub(s),n=i.sub(s),o=t.sub(e),a=r.dot(n),h=n.dot(o),l=r.dot(o),u=n.dot(n),c=o.dot(o).mul(u).sub(h.mul(h)),d=a.mul(h).sub(l.mul(u)).div(c).clamp(),p=a.add(h.mul(d)).div(u).clamp();return sc(d,p)}));this.fragmentNode=ju((()=>{const r=Ic("vec2","vUv");if(s){const e=this.offsetNode?Ku(this.offsetNodeNode):oy,t=this.dashScaleNode?Ku(this.dashScaleNode):sy,s=this.dashSizeNode?Ku(this.dashSizeNode):iy,i=this.dashSizeNode?Ku(this.dashGapNode):ry;Kc.assign(s),Qc.assign(i);const n=zm("instanceDistanceStart"),o=zm("instanceDistanceEnd"),a=xg.y.lessThan(.5).select(t.mul(n),sy.mul(o)),h=em(a.add(oy)),l=e?h.add(e):h;r.y.lessThan(-1).or(r.y.greaterThan(1)).discard(),l.mod(Kc.add(Qc)).greaterThan(Kc).discard()}const o=Bc("float","alpha");if(o.assign(1),i){const t=Ic("vec3","worldStart"),i=Ic("vec3","worldEnd"),r=Ic("vec4","worldPos").xyz.normalize().mul(1e5),a=i.sub(t),h=n({p1:t,p2:i,p3:oc(0,0,0),p4:r}),l=t.add(a.mul(h.x)),u=r.mul(h.y),c=l.sub(u).length().div(ny);if(!s)if(e){const e=c.fwidth();o.assign(Dp(e.negate().add(.5),e.add(.5),c).oneMinus())}else c.greaterThan(.5).discard()}else if(e){const e=r.x,t=r.y.greaterThan(0).select(r.y.sub(1),r.y.add(1)),s=e.mul(e).add(t.mul(t)),i=Bc("float","dlen");i.assign(s.fwidth()),Yu(r.y.abs().greaterThan(1),(()=>{o.assign(Dp(i.oneMinus(),i.add(1),s).oneMinus())}))}else Yu(r.y.abs().greaterThan(1),(()=>{const e=r.x,t=r.y.greaterThan(0).select(r.y.sub(1),r.y.add(1));e.mul(e).add(t.mul(t)).greaterThan(1).discard()}));let a;if(this.lineColorNode)a=this.lineColorNode;else if(t){const e=zm("instanceColorStart"),t=zm("instanceColorEnd");a=xg.y.lessThan(.5).select(e,t).mul(Cf)}else a=Cf;return uc(a,o)}))()}get worldUnits(){return this.useWorldUnits}set worldUnits(e){this.useWorldUnits!==e&&(this.useWorldUnits=e,this.needsUpdate=!0)}get dashed(){return this.useDash}set dashed(e){this.useDash!==e&&(this.useDash=e,this.needsUpdate=!0)}get alphaToCoverage(){return this.useAlphaToCoverage}set alphaToCoverage(e){this.useAlphaToCoverage!==e&&(this.useAlphaToCoverage=e,this.needsUpdate=!0)}}Nx.type=bx("Line2",Nx);const Rx=e=>Du(e).mul(.5).add(.5),Cx=e=>Du(e).mul(2).sub(1),Ex=new El;class Bx extends xx{constructor(e){super(),this.lights=!1,this.isMeshNormalNodeMaterial=!0,this.setDefaultValues(Ex),this.setValues(e)}setupDiffuseColor(){const e=this.opacityNode?Ku(this.opacityNode):If;Pc.assign(uc(Rx(Fg),e))}}Bx.type=bx("MeshNormal",Bx);class Ix extends iu{constructor(e=_g){super("vec2"),this.dirNode=e}setup(){const e=this.dirNode,t=e.z.atan2(e.x).mul(1/(2*Math.PI)).add(.5),s=e.y.clamp(-1,1).asin().mul(1/Math.PI).add(.5);return sc(t,s)}}Ix.type=Ql("EquirectUV",Ix);const Px=Wu(Ix);class Fx extends so{constructor(e=1,t={}){super(e,t),this.isCubeRenderTarget=!0}fromEquirectangularTexture(e,t){const s=t.minFilter,i=t.generateMipmaps;t.generateMipmaps=!0,this.texture.type=t.type,this.texture.colorSpace=t.colorSpace,this.texture.generateMipmaps=t.generateMipmaps,this.texture.minFilter=t.minFilter,this.texture.magFilter=t.magFilter;const r=new jn(5,5,5),n=Px(_g),o=new xx;o.colorNode=Gm(t,n,0),o.side=d,o.blending=m;const a=new Wn(r,o),h=new no;h.add(a),t.minFilter===Se&&(t.minFilter=Te);const l=new eo(1,10,this),u=e.getMRT();return e.setMRT(null),l.update(e,h),e.setMRT(u),t.minFilter=s,t.currentGenerateMipmaps=i,a.geometry.dispose(),a.material.dispose(),this}}const zx=new WeakMap;class Ux extends iu{constructor(e){super("vec3"),this.envNode=e,this._cubeTexture=null,this._cubeTextureNode=Wg();const t=new to;t.isRenderTargetTexture=!0,this._defaultTexture=t,this.updateBeforeType=Hl.RENDER}updateBefore(e){const{renderer:t,material:s}=e,i=this.envNode;if(i.isTextureNode||i.isMaterialReferenceNode){const e=i.isTextureNode?i.value:s[i.property];if(e&&e.isTexture){const s=e.mapping;if(s===ue||s===ce){if(zx.has(e)){const t=zx.get(e);Ox(t,e.mapping),this._cubeTexture=t}else{const s=e.image;if(function(e){return null!=e&&e.height>0}(s)){const i=new Fx(s.height);i.fromEquirectangularTexture(t,e),Ox(i.texture,e.mapping),this._cubeTexture=i.texture,zx.set(e,i.texture),e.addEventListener("dispose",Lx)}else this._cubeTexture=this._defaultTexture}this._cubeTextureNode.value=this._cubeTexture}else this._cubeTextureNode=this.envNode}}}setup(e){return this.updateBefore(e),this._cubeTextureNode}}function Lx(e){const t=e.target;t.removeEventListener("dispose",Lx);const s=zx.get(t);void 0!==s&&(zx.delete(t),s.dispose())}function Ox(e,t){t===ue?e.mapping=he:t===ce&&(e.mapping=le)}Ux.type=Ql("CubeMap",Ux);const Vx=Wu(Ux);class Dx extends Dy{constructor(e=null){super(),this.envNode=e}setup(e){e.context.environment=Vx(this.envNode)}}Dx.type=Ql("BasicEnvironment",Dx);class kx extends Dy{constructor(e=null){super(),this.lightMapNode=e}setup(e){const t=Ku(1/Math.PI);e.context.irradianceLightMap=this.lightMapNode.mul(t)}}kx.type=Ql("BasicLightMap",kx);class Gx{start(){}finish(){}direct(){}directRectArea(){}indirect(){}ambientOcclusion(){}}class Wx extends Gx{constructor(){super()}indirect(e,t,s){const i=e.ambientOcclusion,r=e.reflectedLight,n=s.context.irradianceLightMap;r.indirectDiffuse.assign(uc(0)),n?r.indirectDiffuse.addAssign(n):r.indirectDiffuse.addAssign(uc(1,1,1,0)),r.indirectDiffuse.mulAssign(i),r.indirectDiffuse.mulAssign(Pc.rgb)}finish(e,t,s){const i=s.material,r=e.outgoingLight,n=s.context.environment;if(n)switch(i.combine){case 0:r.rgb.assign(Up(r.rgb,r.rgb.mul(n.rgb),Uf.mul(Lf)));break;case 1:r.rgb.assign(Up(r.rgb,n.rgb,Uf.mul(Lf)));break;case 2:r.rgb.addAssign(n.rgb.mul(Uf.mul(Lf)));break;default:console.warn("THREE.BasicLightingModel: Unsupported .combine value:",i.combine)}}}const Hx=new Qr;class jx extends xx{constructor(e){super(),this.isMeshBasicNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Hx),this.setValues(e)}setupNormal(){return Ig}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new Dx(t):null}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new kx(ly)),t}setupOutgoingLight(){return Pc.rgb}setupLightingModel(){return new Wx}}jx.type=bx("MeshBasic",jx);const qx=ju((({f0:e,f90:t,dotVH:s})=>{const i=s.mul(-5.55473).sub(6.98316).mul(s).exp2();return e.mul(i.oneMinus()).add(t.mul(i))})),$x=ju((e=>e.diffuseColor.mul(1/Math.PI))),Xx=ju((({dotNH:e})=>Jc.mul(Ku(.5)).add(1).mul(Ku(1/Math.PI)).mul(e.pow(Jc)))),Yx=ju((({lightDirection:e})=>{const t=e.add(Sg).normalize(),s=Fg.dot(t).clamp(),i=Sg.dot(t).clamp(),r=qx({f0:Xc,f90:1,dotVH:i}),n=Ku(.25),o=Xx({dotNH:s});return r.mul(n).mul(o)}));class Jx extends Wx{constructor(e=!0){super(),this.specular=e}direct({lightDirection:e,lightColor:t,reflectedLight:s}){const i=Fg.dot(e).clamp().mul(t);s.directDiffuse.addAssign(i.mul($x({diffuseColor:Pc.rgb}))),!0===this.specular&&s.directSpecular.addAssign(i.mul(Yx({lightDirection:e})).mul(Uf))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:s}){s.indirectDiffuse.addAssign(t.mul($x({diffuseColor:Pc}))),s.indirectDiffuse.mulAssign(e)}}const Zx=new Bl;class Kx extends xx{constructor(e){super(),this.isMeshLambertNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Zx),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new Dx(t):null}setupLightingModel(){return new Jx(!1)}}Kx.type=bx("MeshLambert",Kx);const Qx=new Rl;class eb extends xx{constructor(e){super(),this.isMeshPhongNodeMaterial=!0,this.lights=!0,this.shininessNode=null,this.specularNode=null,this.setDefaultValues(Qx),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new Dx(t):null}setupLightingModel(){return new Jx}setupVariants(){const e=(this.shininessNode?Ku(this.shininessNode):Ef).max(1e-4);Jc.assign(e);const t=this.specularNode||Pf;Xc.assign(t)}copy(e){return this.shininessNode=e.shininessNode,this.specularNode=e.specularNode,super.copy(e)}}eb.type=bx("MeshPhong",eb);const tb=ju((()=>{const e=Ig.dFdx().abs().max(Ig.dFdy().abs());return e.x.max(e.y).max(e.z)})),sb=ju((e=>{const{roughness:t}=e,s=tb();let i=t.max(.0525);return i=i.add(s),i=i.min(1),i})),ib=ju((({alpha:e,dotNL:t,dotNV:s})=>{const i=e.pow2(),r=t.mul(i.add(i.oneMinus().mul(s.pow2())).sqrt()),n=s.mul(i.add(i.oneMinus().mul(t.pow2())).sqrt());return gd(.5,r.add(n).max(zd))})).setLayout({name:"V_GGX_SmithCorrelated",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNL",type:"float"},{name:"dotNV",type:"float"}]}),rb=ju((({alphaT:e,alphaB:t,dotTV:s,dotBV:i,dotTL:r,dotBL:n,dotNV:o,dotNL:a})=>{const h=a.mul(oc(e.mul(s),t.mul(i),o).length()),l=o.mul(oc(e.mul(r),t.mul(n),a).length());return gd(.5,h.add(l)).saturate()})).setLayout({name:"V_GGX_SmithCorrelated_Anisotropic",type:"float",inputs:[{name:"alphaT",type:"float",qualifier:"in"},{name:"alphaB",type:"float",qualifier:"in"},{name:"dotTV",type:"float",qualifier:"in"},{name:"dotBV",type:"float",qualifier:"in"},{name:"dotTL",type:"float",qualifier:"in"},{name:"dotBL",type:"float",qualifier:"in"},{name:"dotNV",type:"float",qualifier:"in"},{name:"dotNL",type:"float",qualifier:"in"}]}),nb=ju((({alpha:e,dotNH:t})=>{const s=e.pow2(),i=t.pow2().mul(s.oneMinus()).oneMinus();return s.div(i.pow2()).mul(1/Math.PI)})).setLayout({name:"D_GGX",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNH",type:"float"}]}),ob=Ku(1/Math.PI),ab=ju((({alphaT:e,alphaB:t,dotNH:s,dotTH:i,dotBH:r})=>{const n=e.mul(t),o=oc(t.mul(i),e.mul(r),n.mul(s)),a=o.dot(o),h=n.div(a);return ob.mul(n.mul(h.pow2()))})).setLayout({name:"D_GGX_Anisotropic",type:"float",inputs:[{name:"alphaT",type:"float",qualifier:"in"},{name:"alphaB",type:"float",qualifier:"in"},{name:"dotNH",type:"float",qualifier:"in"},{name:"dotTH",type:"float",qualifier:"in"},{name:"dotBH",type:"float",qualifier:"in"}]}),hb=ju((e=>{const{lightDirection:t,f0:s,f90:i,roughness:r,f:n,USE_IRIDESCENCE:o,USE_ANISOTROPY:a}=e,h=e.normalView||Fg,l=r.pow2(),u=t.add(Sg).normalize(),c=h.dot(t).clamp(),d=h.dot(Sg).clamp(),p=h.dot(u).clamp(),m=Sg.dot(u).clamp();let g,f,y=qx({f0:s,f90:i,dotVH:m});if(Lu(o)&&(y=kc.mix(y,n)),Lu(a)){const e=qc.dot(t),s=qc.dot(Sg),i=qc.dot(u),r=$c.dot(t),n=$c.dot(Sg),o=$c.dot(u);g=rb({alphaT:Hc,alphaB:l,dotTV:s,dotBV:n,dotTL:e,dotBL:r,dotNV:d,dotNL:c}),f=ab({alphaT:Hc,alphaB:l,dotNH:p,dotTH:i,dotBH:o})}else g=ib({alpha:l,dotNL:c,dotNV:d}),f=nb({alpha:l,dotNH:p});return y.mul(g).mul(f)})),lb=ju((({roughness:e,dotNV:t})=>{const s=uc(-1,-.0275,-.572,.022),i=uc(1,.0425,1.04,-.04),r=e.mul(s).add(i),n=r.x.mul(r.x).min(t.mul(-9.28).exp2()).mul(r.x).add(r.y);return sc(-1.04,1.04).mul(n).add(r.zw)})).setLayout({name:"DFGApprox",type:"vec2",inputs:[{name:"roughness",type:"float"},{name:"dotNV",type:"vec3"}]}),ub=ju((e=>{const{dotNV:t,specularColor:s,specularF90:i,roughness:r}=e,n=lb({dotNV:t,roughness:r});return s.mul(n.x).add(i.mul(n.y))})),cb=ju((({f:e,f90:t,dotVH:s})=>{const i=s.oneMinus().saturate(),r=i.mul(i),n=i.mul(r,r).clamp(0,.9999);return e.sub(oc(t).mul(n)).div(n.oneMinus())})).setLayout({name:"Schlick_to_F0",type:"vec3",inputs:[{name:"f",type:"vec3"},{name:"f90",type:"float"},{name:"dotVH",type:"float"}]}),db=ju((({roughness:e,dotNH:t})=>{const s=e.pow2(),i=Ku(1).div(s),r=t.pow2().oneMinus().max(.0078125);return Ku(2).add(i).mul(r.pow(i.mul(.5))).div(2*Math.PI)})).setLayout({name:"D_Charlie",type:"float",inputs:[{name:"roughness",type:"float"},{name:"dotNH",type:"float"}]}),pb=ju((({dotNV:e,dotNL:t})=>Ku(1).div(Ku(4).mul(t.add(e).sub(t.mul(e)))))).setLayout({name:"V_Neubelt",type:"float",inputs:[{name:"dotNV",type:"float"},{name:"dotNL",type:"float"}]}),mb=ju((({lightDirection:e})=>{const t=e.add(Sg).normalize(),s=Fg.dot(e).clamp(),i=Fg.dot(Sg).clamp(),r=Fg.dot(t).clamp(),n=db({roughness:Dc,dotNH:r}),o=pb({dotNV:i,dotNL:s});return Vc.mul(n).mul(o)})),gb=ju((({N:e,V:t,roughness:s})=>{const i=e.dot(t).saturate(),r=sc(s,i.oneMinus().sqrt());return r.assign(r.mul(.984375).add(.0078125)),r})).setLayout({name:"LTC_Uv",type:"vec2",inputs:[{name:"N",type:"vec3"},{name:"V",type:"vec3"},{name:"roughness",type:"float"}]}),fb=ju((({f:e})=>{const t=e.length();return Tp(t.mul(t).add(e.z).div(t.add(1)),0)})).setLayout({name:"LTC_ClippedSphereFormFactor",type:"float",inputs:[{name:"f",type:"vec3"}]}),yb=ju((({v1:e,v2:t})=>{const s=e.dot(t),i=s.abs().toVar(),r=i.mul(.0145206).add(.4965155).mul(i).add(.8543985).toVar(),n=i.add(4.1616724).mul(i).add(3.417594).toVar(),o=r.div(n),a=s.greaterThan(0).select(o,Tp(s.mul(s).oneMinus(),1e-7).inverseSqrt().mul(.5).sub(o));return e.cross(t).mul(a)})).setLayout({name:"LTC_EdgeVectorFormFactor",type:"vec3",inputs:[{name:"v1",type:"vec3"},{name:"v2",type:"vec3"}]}),xb=ju((({N:e,V:t,P:s,mInv:i,p0:r,p1:n,p2:o,p3:a})=>{const h=n.sub(r).toVar(),l=a.sub(r).toVar(),u=h.cross(l),c=oc().toVar();return Yu(u.dot(s.sub(r)).greaterThanEqual(0),(()=>{const h=t.sub(e.mul(t.dot(e))).normalize(),l=e.cross(h).negate(),u=i.mul(gc(h,l,e).transpose()).toVar(),d=u.mul(r.sub(s)).normalize().toVar(),p=u.mul(n.sub(s)).normalize().toVar(),m=u.mul(o.sub(s)).normalize().toVar(),g=u.mul(a.sub(s)).normalize().toVar(),f=oc(0).toVar();f.addAssign(yb({v1:d,v2:p})),f.addAssign(yb({v1:p,v2:m})),f.addAssign(yb({v1:m,v2:g})),f.addAssign(yb({v1:g,v2:d})),c.assign(oc(fb({f:f})))})),c})).setLayout({name:"LTC_Evaluate",type:"vec3",inputs:[{name:"N",type:"vec3"},{name:"V",type:"vec3"},{name:"P",type:"vec3"},{name:"mInv",type:"mat3"},{name:"p0",type:"vec3"},{name:"p1",type:"vec3"},{name:"p2",type:"vec3"},{name:"p3",type:"vec3"}]}),bb=1/6,vb=e=>md(bb,md(e,md(e,e.negate().add(3)).sub(3)).add(1)),Tb=e=>md(bb,md(e,md(e,md(3,e).sub(6))).add(4)),_b=e=>md(bb,md(e,md(e,md(-3,e).add(3)).add(3)).add(1)),wb=e=>md(bb,Cp(e,3)),Sb=e=>vb(e).add(Tb(e)),Mb=e=>_b(e).add(wb(e)),Ab=e=>dd(-1,Tb(e).div(vb(e).add(Tb(e)))),Nb=e=>dd(1,wb(e).div(_b(e).add(wb(e)))),Rb=(e,t,s)=>{const i=e.uvNode,r=md(i,t.zw).add(.5),n=Jd(r),o=Qd(r),a=Sb(o.x),h=Mb(o.x),l=Ab(o.x),u=Nb(o.x),c=Ab(o.y),d=Nb(o.y),p=sc(n.x.add(l),n.y.add(c)).sub(.5).mul(t.xy),m=sc(n.x.add(u),n.y.add(c)).sub(.5).mul(t.xy),g=sc(n.x.add(l),n.y.add(d)).sub(.5).mul(t.xy),f=sc(n.x.add(u),n.y.add(d)).sub(.5).mul(t.xy),y=Sb(o.y).mul(dd(a.mul(e.uv(p).level(s)),h.mul(e.uv(m).level(s)))),x=Mb(o.y).mul(dd(a.mul(e.uv(g).level(s)),h.mul(e.uv(f).level(s))));return y.add(x)},Cb=ju((([e,t=Ku(3)])=>{const s=sc(e.size(Qu(t))),i=sc(e.size(Qu(t.add(1)))),r=gd(1,s),n=gd(1,i),o=Rb(e,uc(r,s),Jd(t)),a=Rb(e,uc(n,i),Zd(t));return Qd(t).mix(o,a)})),Eb=ju((([e,t,s,i,r])=>{const n=oc(Vp(t.negate(),Kd(e),gd(1,i))),o=oc(hp(r[0].xyz),hp(r[1].xyz),hp(r[2].xyz));return Kd(n).mul(s.mul(o))})).setLayout({name:"getVolumeTransmissionRay",type:"vec3",inputs:[{name:"n",type:"vec3"},{name:"v",type:"vec3"},{name:"thickness",type:"float"},{name:"ior",type:"float"},{name:"modelMatrix",type:"mat4"}]}),Bb=ju((([e,t])=>e.mul(Lp(t.mul(2).sub(2),0,1)))).setLayout({name:"applyIorToRoughness",type:"float",inputs:[{name:"roughness",type:"float"},{name:"ior",type:"float"}]}),Ib=ix(),Pb=ju((([e,t,s])=>{const i=Ib.uv(e),r=$d(Ku(Yy.x)).mul(Bb(t,s));return Cb(i,r)})),Fb=ju((([e,t,s])=>(Yu(s.notEqual(0),(()=>{const i=qd(t).negate().div(s);return Hd(i.negate().mul(e))})),oc(1)))).setLayout({name:"volumeAttenuation",type:"vec3",inputs:[{name:"transmissionDistance",type:"float"},{name:"attenuationColor",type:"vec3"},{name:"attenuationDistance",type:"float"}]}),zb=ju((([e,t,s,i,r,n,o,a,h,l,u,c,d,p,m])=>{let g,f;if(m){g=uc().toVar(),f=oc().toVar();const r=u.sub(1).mul(m.mul(.025)),n=oc(u.sub(r),u,u.add(r));Cy({start:0,end:3},(({i:r})=>{const u=n.element(r),m=Eb(e,t,c,u,a),y=o.add(m),x=l.mul(h.mul(uc(y,1))),b=sc(x.xy.div(x.w)).toVar();b.addAssign(1),b.divAssign(2),b.assign(sc(b.x,b.y.oneMinus()));const v=Pb(b,s,u);g.element(r).assign(v.element(r)),g.a.addAssign(v.a),f.element(r).assign(i.element(r).mul(Fb(hp(m),d,p).element(r)))})),g.a.divAssign(3)}else{const r=Eb(e,t,c,u,a),n=o.add(r),m=l.mul(h.mul(uc(n,1))),y=sc(m.xy.div(m.w)).toVar();y.addAssign(1),y.divAssign(2),y.assign(sc(y.x,y.y.oneMinus())),g=Pb(y,s,u),f=i.mul(Fb(hp(r),d,p))}const y=f.rgb.mul(g.rgb),x=e.dot(t).clamp(),b=oc(ub({dotNV:x,specularColor:r,specularF90:n,roughness:s})),v=f.r.add(f.g,f.b).div(3);return uc(b.oneMinus().mul(y),g.a.oneMinus().mul(v).oneMinus())})),Ub=gc(3.2404542,-.969266,.0556434,-1.5371385,1.8760108,-.2040259,-.4985314,.041556,1.0572252),Lb=(e,t)=>e.sub(t).div(e.add(t)).pow2(),Ob=(e,t)=>{const s=e.mul(2*Math.PI*1e-9),i=oc(54856e-17,44201e-17,52481e-17),r=oc(1681e3,1795300,2208400),n=oc(43278e5,93046e5,66121e5),o=Ku(9747e-17*Math.sqrt(2*Math.PI*45282e5)).mul(s.mul(2239900).add(t.x).cos()).mul(s.pow2().mul(-45282e5).exp());let a=i.mul(n.mul(2*Math.PI).sqrt()).mul(r.mul(s).add(t).cos()).mul(s.pow2().negate().mul(n).exp());a=oc(a.x.add(o),a.y,a.z).div(1.0685e-7);return Ub.mul(a)},Vb=ju((({outsideIOR:e,eta2:t,cosTheta1:s,thinFilmThickness:i,baseF0:r})=>{const n=Up(e,t,Dp(0,.03,i)),o=e.div(n).pow2().mul(Ku(1).sub(s.pow2())),a=Ku(1).sub(o).sqrt(),h=Lb(n,e),l=qx({f0:h,f90:1,dotVH:s}),u=l.oneMinus(),c=n.lessThan(e).select(Math.PI,0),d=Ku(Math.PI).sub(c),p=(e=>{const t=e.sqrt();return oc(1).add(t).div(oc(1).sub(t))})(r.clamp(0,.9999)),m=Lb(p,n.toVec3()),g=qx({f0:m,f90:1,dotVH:a}),f=oc(p.x.lessThan(n).select(Math.PI,0),p.y.lessThan(n).select(Math.PI,0),p.z.lessThan(n).select(Math.PI,0)),y=n.mul(i,a,2),x=oc(d).add(f),b=l.mul(g).clamp(1e-5,.9999),v=b.sqrt(),T=u.pow2().mul(g).div(oc(1).sub(b));let _=l.add(T),w=T.sub(u);for(let e=1;e<=2;++e){w=w.mul(v);const t=Ob(Ku(e).mul(y),Ku(e).mul(x)).mul(2);_=_.add(w.mul(t))}return _.max(oc(0))})).setLayout({name:"evalIridescence",type:"vec3",inputs:[{name:"outsideIOR",type:"float"},{name:"eta2",type:"float"},{name:"cosTheta1",type:"float"},{name:"thinFilmThickness",type:"float"},{name:"baseF0",type:"vec3"}]}),Db=ju((({normal:e,viewDir:t,roughness:s})=>{const i=e.dot(t).saturate(),r=s.pow2(),n=qp(s.lessThan(.25),Ku(-339.2).mul(r).add(Ku(161.4).mul(s)).sub(25.9),Ku(-8.48).mul(r).add(Ku(14.3).mul(s)).sub(9.95)),o=qp(s.lessThan(.25),Ku(44).mul(r).sub(Ku(23.7).mul(s)).add(3.26),Ku(1.97).mul(r).sub(Ku(3.27).mul(s)).add(.72));return qp(s.lessThan(.25),0,Ku(.1).mul(s).sub(.025)).add(n.mul(i).add(o).exp()).mul(1/Math.PI).saturate()})),kb=oc(.04),Gb=Ku(1);class Wb extends Gx{constructor(e=!1,t=!1,s=!1,i=!1,r=!1,n=!1){super(),this.clearcoat=e,this.sheen=t,this.iridescence=s,this.anisotropy=i,this.transmission=r,this.dispersion=n,this.clearcoatRadiance=null,this.clearcoatSpecularDirect=null,this.clearcoatSpecularIndirect=null,this.sheenSpecularDirect=null,this.sheenSpecularIndirect=null,this.iridescenceFresnel=null,this.iridescenceF0=null}start(e){if(!0===this.clearcoat&&(this.clearcoatRadiance=oc().toVar("clearcoatRadiance"),this.clearcoatSpecularDirect=oc().toVar("clearcoatSpecularDirect"),this.clearcoatSpecularIndirect=oc().toVar("clearcoatSpecularIndirect")),!0===this.sheen&&(this.sheenSpecularDirect=oc().toVar("sheenSpecularDirect"),this.sheenSpecularIndirect=oc().toVar("sheenSpecularIndirect")),!0===this.iridescence){const e=Fg.dot(Sg).clamp();this.iridescenceFresnel=Vb({outsideIOR:Ku(1),eta2:Gc,cosTheta1:e,thinFilmThickness:Wc,baseF0:Xc}),this.iridescenceF0=cb({f:this.iridescenceFresnel,f90:1,dotVH:e})}if(!0===this.transmission){const t=Tg,s=eg.sub(Tg).normalize(),i=zg;e.backdrop=zb(i,s,zc,Pc,Xc,Yc,t,pg,Zm,Ym,td,id,nd,rd,this.dispersion?od:null),e.backdropAlpha=sd,Pc.a.mulAssign(Up(1,e.backdrop.a,sd))}}computeMultiscattering(e,t,s){const i=Fg.dot(Sg).clamp(),r=lb({roughness:zc,dotNV:i}),n=(this.iridescenceF0?kc.mix(Xc,this.iridescenceF0):Xc).mul(r.x).add(s.mul(r.y)),o=r.x.add(r.y).oneMinus(),a=Xc.add(Xc.oneMinus().mul(.047619)),h=n.mul(a).div(o.mul(a).oneMinus());e.addAssign(n),t.addAssign(h.mul(o))}direct({lightDirection:e,lightColor:t,reflectedLight:s}){const i=Fg.dot(e).clamp().mul(t);if(!0===this.sheen&&this.sheenSpecularDirect.addAssign(i.mul(mb({lightDirection:e}))),!0===this.clearcoat){const s=Ug.dot(e).clamp().mul(t);this.clearcoatSpecularDirect.addAssign(s.mul(hb({lightDirection:e,f0:kb,f90:Gb,roughness:Oc,normalView:Ug})))}s.directDiffuse.addAssign(i.mul($x({diffuseColor:Pc.rgb}))),s.directSpecular.addAssign(i.mul(hb({lightDirection:e,f0:Xc,f90:1,roughness:zc,iridescence:this.iridescence,f:this.iridescenceFresnel,USE_IRIDESCENCE:this.iridescence,USE_ANISOTROPY:this.anisotropy})))}directRectArea({lightColor:e,lightPosition:t,halfWidth:s,halfHeight:i,reflectedLight:r,ltc_1:n,ltc_2:o}){const a=t.add(s).sub(i),h=t.sub(s).sub(i),l=t.sub(s).add(i),u=t.add(s).add(i),c=Fg,d=Sg,p=wg.toVar(),m=gb({N:c,V:d,roughness:zc}),g=n.uv(m).toVar(),f=o.uv(m).toVar(),y=gc(oc(g.x,0,g.y),oc(0,1,0),oc(g.z,0,g.w)).toVar(),x=Xc.mul(f.x).add(Xc.oneMinus().mul(f.y)).toVar();r.directSpecular.addAssign(e.mul(x).mul(xb({N:c,V:d,P:p,mInv:y,p0:a,p1:h,p2:l,p3:u}))),r.directDiffuse.addAssign(e.mul(Pc).mul(xb({N:c,V:d,P:p,mInv:gc(1,0,0,0,1,0,0,0,1),p0:a,p1:h,p2:l,p3:u})))}indirect(e,t,s){this.indirectDiffuse(e,t,s),this.indirectSpecular(e,t,s),this.ambientOcclusion(e,t,s)}indirectDiffuse({irradiance:e,reflectedLight:t}){t.indirectDiffuse.addAssign(e.mul($x({diffuseColor:Pc})))}indirectSpecular({radiance:e,iblIrradiance:t,reflectedLight:s}){if(!0===this.sheen&&this.sheenSpecularIndirect.addAssign(t.mul(Vc,Db({normal:Fg,viewDir:Sg,roughness:Dc}))),!0===this.clearcoat){const e=Ug.dot(Sg).clamp(),t=ub({dotNV:e,specularColor:kb,specularF90:Gb,roughness:Oc});this.clearcoatSpecularIndirect.addAssign(this.clearcoatRadiance.mul(t))}const i=oc().toVar("singleScattering"),r=oc().toVar("multiScattering"),n=t.mul(1/Math.PI);this.computeMultiscattering(i,r,Yc);const o=i.add(r),a=Pc.mul(o.r.max(o.g).max(o.b).oneMinus());s.indirectSpecular.addAssign(e.mul(i)),s.indirectSpecular.addAssign(r.mul(n)),s.indirectDiffuse.addAssign(a.mul(n))}ambientOcclusion({ambientOcclusion:e,reflectedLight:t}){const s=Fg.dot(Sg).clamp().add(e),i=zc.mul(-16).oneMinus().negate().exp2(),r=e.sub(s.pow(i).oneMinus()).clamp();!0===this.clearcoat&&this.clearcoatSpecularIndirect.mulAssign(e),!0===this.sheen&&this.sheenSpecularIndirect.mulAssign(e),t.indirectDiffuse.mulAssign(e),t.indirectSpecular.mulAssign(r)}finish(e){const{outgoingLight:t}=e;if(!0===this.clearcoat){const e=Ug.dot(Sg).clamp(),s=qx({dotVH:e,f0:kb,f90:Gb}),i=t.mul(Lc.mul(s).oneMinus()).add(this.clearcoatSpecularDirect.add(this.clearcoatSpecularIndirect).mul(Lc));t.assign(i)}if(!0===this.sheen){const e=Vc.r.max(Vc.g).max(Vc.b).mul(.157).oneMinus(),s=t.mul(e).add(this.sheenSpecularDirect,this.sheenSpecularIndirect);t.assign(s)}}}const Hb=Ku(1),jb=Ku(-2),qb=Ku(.8),$b=Ku(-1),Xb=Ku(.4),Yb=Ku(2),Jb=Ku(.305),Zb=Ku(3),Kb=Ku(.21),Qb=Ku(4),ev=Ku(4),tv=Ku(16),sv=ju((([e])=>{const t=oc(op(e)).toVar(),s=Ku(-1).toVar();return Yu(t.x.greaterThan(t.z),(()=>{Yu(t.x.greaterThan(t.y),(()=>{s.assign(qp(e.x.greaterThan(0),0,3))})).Else((()=>{s.assign(qp(e.y.greaterThan(0),1,4))}))})).Else((()=>{Yu(t.z.greaterThan(t.y),(()=>{s.assign(qp(e.z.greaterThan(0),2,5))})).Else((()=>{s.assign(qp(e.y.greaterThan(0),1,4))}))})),s})).setLayout({name:"getFace",type:"float",inputs:[{name:"direction",type:"vec3"}]}),iv=ju((([e,t])=>{const s=sc().toVar();return Yu(t.equal(0),(()=>{s.assign(sc(e.z,e.y).div(op(e.x)))})).ElseIf(t.equal(1),(()=>{s.assign(sc(e.x.negate(),e.z.negate()).div(op(e.y)))})).ElseIf(t.equal(2),(()=>{s.assign(sc(e.x.negate(),e.y).div(op(e.z)))})).ElseIf(t.equal(3),(()=>{s.assign(sc(e.z.negate(),e.y).div(op(e.x)))})).ElseIf(t.equal(4),(()=>{s.assign(sc(e.x.negate(),e.z).div(op(e.y)))})).Else((()=>{s.assign(sc(e.x,e.y).div(op(e.z)))})),md(.5,s.add(1))})).setLayout({name:"getUV",type:"vec2",inputs:[{name:"direction",type:"vec3"},{name:"face",type:"float"}]}),rv=ju((([e])=>{const t=Ku(0).toVar();return Yu(e.greaterThanEqual(qb),(()=>{t.assign(Hb.sub(e).mul($b.sub(jb)).div(Hb.sub(qb)).add(jb))})).ElseIf(e.greaterThanEqual(Xb),(()=>{t.assign(qb.sub(e).mul(Yb.sub($b)).div(qb.sub(Xb)).add($b))})).ElseIf(e.greaterThanEqual(Jb),(()=>{t.assign(Xb.sub(e).mul(Zb.sub(Yb)).div(Xb.sub(Jb)).add(Yb))})).ElseIf(e.greaterThanEqual(Kb),(()=>{t.assign(Jb.sub(e).mul(Qb.sub(Zb)).div(Jb.sub(Kb)).add(Zb))})).Else((()=>{t.assign(Ku(-2).mul($d(md(1.16,e))))})),t})).setLayout({name:"roughnessToMip",type:"float",inputs:[{name:"roughness",type:"float"}]}),nv=ju((([e,t])=>{const s=e.toVar();s.assign(md(2,s).sub(1));const i=oc(s,1).toVar();return Yu(t.equal(0),(()=>{i.assign(i.zyx)})).ElseIf(t.equal(1),(()=>{i.assign(i.xzy),i.xz.mulAssign(-1)})).ElseIf(t.equal(2),(()=>{i.x.mulAssign(-1)})).ElseIf(t.equal(3),(()=>{i.assign(i.zyx),i.xz.mulAssign(-1)})).ElseIf(t.equal(4),(()=>{i.assign(i.xzy),i.xy.mulAssign(-1)})).ElseIf(t.equal(5),(()=>{i.z.mulAssign(-1)})),i})).setLayout({name:"getDirection",type:"vec3",inputs:[{name:"uv",type:"vec2"},{name:"face",type:"float"}]}),ov=ju((([e,t,s,i,r,n])=>{const o=Ku(s),a=oc(t),h=Lp(rv(o),jb,n),l=Qd(h),u=Jd(h),c=oc(av(e,a,u,i,r,n)).toVar();return Yu(l.notEqual(0),(()=>{const t=oc(av(e,a,u.add(1),i,r,n)).toVar();c.assign(Up(c,t,l))})),c})),av=ju((([e,t,s,i,r,n])=>{const o=Ku(s).toVar(),a=oc(t),h=Ku(sv(a)).toVar(),l=Ku(Tp(ev.sub(o),0)).toVar();o.assign(Tp(o,ev));const u=Ku(jd(o)).toVar(),c=sc(iv(a,h).mul(u.sub(2)).add(1)).toVar();return Yu(h.greaterThan(2),(()=>{c.y.addAssign(u),h.subAssign(3)})),c.x.addAssign(h.mul(u)),c.x.addAssign(l.mul(md(3,tv))),c.y.addAssign(md(4,jd(n).sub(u))),c.x.mulAssign(i),c.y.mulAssign(r),e.uv(c).grad(sc(),sc())})),hv=ju((({envMap:e,mipInt:t,outputDirection:s,theta:i,axis:r,CUBEUV_TEXEL_WIDTH:n,CUBEUV_TEXEL_HEIGHT:o,CUBEUV_MAX_MIP:a})=>{const h=tp(i),l=s.mul(h).add(r.cross(s).mul(ep(i))).add(r.mul(r.dot(s).mul(h.oneMinus())));return av(e,l,t,n,o,a)})),lv=ju((({n:e,latitudinal:t,poleAxis:s,outputDirection:i,weights:r,samples:n,dTheta:o,mipInt:a,envMap:h,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:u,CUBEUV_MAX_MIP:c})=>{const d=oc(qp(t,s,Rp(s,i))).toVar();Yu(Vd(d.equals(oc(0))),(()=>{d.assign(oc(i.z,0,i.x.negate()))})),d.assign(Kd(d));const p=oc().toVar();return p.addAssign(r.element(Qu(0)).mul(hv({theta:0,axis:d,outputDirection:i,mipInt:a,envMap:h,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:u,CUBEUV_MAX_MIP:c}))),Cy({start:Qu(1),end:e},(({i:e})=>{Yu(e.greaterThanEqual(n),(()=>{By()}));const t=Ku(o.mul(Ku(e))).toVar();p.addAssign(r.element(e).mul(hv({theta:t.mul(-1),axis:d,outputDirection:i,mipInt:a,envMap:h,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:u,CUBEUV_MAX_MIP:c}))),p.addAssign(r.element(e).mul(hv({theta:t,axis:d,outputDirection:i,mipInt:a,envMap:h,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:u,CUBEUV_MAX_MIP:c})))})),uc(p,1)}));let uv=null;const cv=new WeakMap;function dv(e){let t=cv.get(e);if((void 0!==t?t.pmremVersion:-1)!==e.pmremVersion){const s=e.image;if(e.isCubeTexture){if(!function(e){if(null==e)return!1;let t=0;const s=6;for(let i=0;i0}(s))return null;t=uv.fromEquirectangular(e,t)}t.pmremVersion=e.pmremVersion,cv.set(e,t)}return t.texture}class pv extends iu{constructor(e,t=null,s=null){super("vec3"),this._value=e,this._pmrem=null,this.uvNode=t,this.levelNode=s,this._generator=null;const i=new Ti;i.isRenderTargetTexture=!0,this._texture=Gm(i),this._width=Cc(0),this._height=Cc(0),this._maxMip=Cc(0),this.updateBeforeType=Hl.RENDER}set value(e){this._value=e,this._pmrem=null}get value(){return this._value}updateFromTexture(e){const t=function(e){const t=Math.log2(e)-2,s=1/e;return{texelWidth:1/(3*Math.max(Math.pow(2,t),112)),texelHeight:s,maxMip:t}}(e.image.height);this._texture.value=e,this._width.value=t.texelWidth,this._height.value=t.texelHeight,this._maxMip.value=t.maxMip}updateBefore(){let e=this._pmrem;const t=e?e.pmremVersion:-1,s=this._value;t!==s.pmremVersion&&(e=!0===s.isPMREMTexture?s:dv(s),null!==e&&(this._pmrem=e,this.updateFromTexture(e)))}setup(e){null===uv&&(uv=e.createPMREMGenerator()),this.updateBefore(e);let t=this.uvNode;null===t&&e.context.getUV&&(t=e.context.getUV(this));const s=this.value;e.renderer.coordinateSystem===Vs&&!0!==s.isPMREMTexture&&!0===s.isRenderTargetTexture&&(t=oc(t.x.negate(),t.yz));let i=this.levelNode;return null===i&&e.context.getTextureLevel&&(i=e.context.getTextureLevel(this)),ov(this._texture,t,i,this._width,this._height,this._maxMip)}}pv.type=Ql("PMREM",pv);const mv=Wu(pv),gv=new WeakMap;class fv extends Dy{constructor(e=null){super(),this.envNode=e}setup(e){const{material:t}=e;let s=this.envNode;if(s.isTextureNode||s.isMaterialReferenceNode){const e=s.isTextureNode?s.value:t[s.property];let i=gv.get(e);void 0===i&&(i=mv(e),gv.set(e,i)),s=i}const i=t.envMap?Zg("envMapIntensity","float",e.material):Zg("environmentIntensity","float",e.scene),r=!0===t.useAnisotropy||t.anisotropy>0?xf:Fg,n=s.context(yv(zc,r)).mul(i),o=s.context(xv(zg)).mul(Math.PI).mul(i),a=Tm(n),h=Tm(o);e.context.radiance.addAssign(a),e.context.iblIrradiance.addAssign(h);const l=e.context.lightingModel.clearcoatRadiance;if(l){const e=s.context(yv(Oc,Ug)).mul(i),t=Tm(e);l.addAssign(t)}}}fv.type=Ql("Environment",fv);const yv=(e,t)=>{let s=null;return{getUV:()=>(null===s&&(s=Sg.negate().reflect(t),s=e.mul(e).mix(s,t).normalize(),s=s.transformDirection(Zm)),s),getTextureLevel:()=>e}},xv=e=>({getUV:()=>e,getTextureLevel:()=>Ku(1)}),bv=new Al;class vv extends xx{constructor(e){super(),this.isMeshStandardNodeMaterial=!0,this.lights=!0,this.emissiveNode=null,this.metalnessNode=null,this.roughnessNode=null,this.setDefaultValues(bv),this.setValues(e)}setupEnvironment(e){let t=super.setupEnvironment(e);return null===t&&e.environmentNode&&(t=e.environmentNode),t?new fv(t):null}setupLightingModel(){return new Wb}setupSpecular(){const e=Up(oc(.04),Pc.rgb,Uc);Xc.assign(e),Yc.assign(1)}setupVariants(){const e=this.metalnessNode?Ku(this.metalnessNode):Vf;Uc.assign(e);let t=this.roughnessNode?Ku(this.roughnessNode):Of;t=sb({roughness:t}),zc.assign(t),this.setupSpecular(),Pc.assign(uc(Pc.rgb.mul(e.oneMinus()),Pc.a))}copy(e){return this.emissiveNode=e.emissiveNode,this.metalnessNode=e.metalnessNode,this.roughnessNode=e.roughnessNode,super.copy(e)}}vv.type=bx("MeshStandard",vv);const Tv=new Nl;class _v extends vv{constructor(e){super(),this.isMeshPhysicalNodeMaterial=!0,this.clearcoatNode=null,this.clearcoatRoughnessNode=null,this.clearcoatNormalNode=null,this.sheenNode=null,this.sheenRoughnessNode=null,this.iridescenceNode=null,this.iridescenceIORNode=null,this.iridescenceThicknessNode=null,this.specularIntensityNode=null,this.specularColorNode=null,this.iorNode=null,this.transmissionNode=null,this.thicknessNode=null,this.attenuationDistanceNode=null,this.attenuationColorNode=null,this.dispersionNode=null,this.anisotropyNode=null,this.setDefaultValues(Tv),this.setValues(e)}get useClearcoat(){return this.clearcoat>0||null!==this.clearcoatNode}get useIridescence(){return this.iridescence>0||null!==this.iridescenceNode}get useSheen(){return this.sheen>0||null!==this.sheenNode}get useAnisotropy(){return this.anisotropy>0||null!==this.anisotropyNode}get useTransmission(){return this.transmission>0||null!==this.transmissionNode}get useDispersion(){return this.dispersion>0||null!==this.dispersionNode}setupSpecular(){const e=this.iorNode?Ku(this.iorNode):Qf;td.assign(e),Xc.assign(Up(vp(Ep(td.sub(1).div(td.add(1))).mul(zf),oc(1)).mul(Ff),Pc.rgb,Uc)),Yc.assign(Up(Ff,1,Uc))}setupLightingModel(){return new Wb(this.useClearcoat,this.useSheen,this.useIridescence,this.useAnisotropy,this.useTransmission,this.useDispersion)}setupVariants(e){if(super.setupVariants(e),this.useClearcoat){const e=this.clearcoatNode?Ku(this.clearcoatNode):kf,t=this.clearcoatRoughnessNode?Ku(this.clearcoatRoughnessNode):Gf;Lc.assign(e),Oc.assign(sb({roughness:t}))}if(this.useSheen){const e=this.sheenNode?oc(this.sheenNode):jf,t=this.sheenRoughnessNode?Ku(this.sheenRoughnessNode):qf;Vc.assign(e),Dc.assign(t)}if(this.useIridescence){const e=this.iridescenceNode?Ku(this.iridescenceNode):Xf,t=this.iridescenceIORNode?Ku(this.iridescenceIORNode):Yf,s=this.iridescenceThicknessNode?Ku(this.iridescenceThicknessNode):Jf;kc.assign(e),Gc.assign(t),Wc.assign(s)}if(this.useAnisotropy){const e=(this.anisotropyNode?sc(this.anisotropyNode):$f).toVar();jc.assign(e.length()),Yu(jc.equal(0),(()=>{e.assign(sc(1,0))})).Else((()=>{e.divAssign(sc(jc)),jc.assign(jc.saturate())})),Hc.assign(jc.pow2().mix(zc.pow2(),1)),qc.assign(gf[0].mul(e.x).add(gf[1].mul(e.y))),$c.assign(gf[1].mul(e.x).sub(gf[0].mul(e.y)))}if(this.useTransmission){const e=this.transmissionNode?Ku(this.transmissionNode):Zf,t=this.thicknessNode?Ku(this.thicknessNode):Kf,s=this.attenuationDistanceNode?Ku(this.attenuationDistanceNode):ey,i=this.attenuationColorNode?oc(this.attenuationColorNode):ty;if(sd.assign(e),id.assign(t),rd.assign(s),nd.assign(i),this.useDispersion){const e=this.dispersionNode?Ku(this.dispersionNode):hy;od.assign(e)}}}setupClearcoatNormal(){return this.clearcoatNormalNode?oc(this.clearcoatNormalNode):Wf}setup(e){e.context.setupClearcoatNormal=()=>this.setupClearcoatNormal(e),super.setup(e)}copy(e){return this.clearcoatNode=e.clearcoatNode,this.clearcoatRoughnessNode=e.clearcoatRoughnessNode,this.clearcoatNormalNode=e.clearcoatNormalNode,this.sheenNode=e.sheenNode,this.sheenRoughnessNode=e.sheenRoughnessNode,this.iridescenceNode=e.iridescenceNode,this.iridescenceIORNode=e.iridescenceIORNode,this.iridescenceThicknessNode=e.iridescenceThicknessNode,this.specularIntensityNode=e.specularIntensityNode,this.specularColorNode=e.specularColorNode,this.transmissionNode=e.transmissionNode,this.thicknessNode=e.thicknessNode,this.attenuationDistanceNode=e.attenuationDistanceNode,this.attenuationColorNode=e.attenuationColorNode,this.dispersionNode=e.dispersionNode,this.anisotropyNode=e.anisotropyNode,super.copy(e)}}_v.type=bx("MeshPhysical",_v);class wv extends Wb{constructor(e,t,s,i){super(e,t,s),this.useSSS=i}direct({lightDirection:e,lightColor:t,reflectedLight:s},i,r){if(!0===this.useSSS){const i=r.material,{thicknessColorNode:n,thicknessDistortionNode:o,thicknessAmbientNode:a,thicknessAttenuationNode:h,thicknessPowerNode:l,thicknessScaleNode:u}=i,c=e.add(Fg.mul(o)).normalize(),d=Ku(Sg.dot(c.negate()).saturate().pow(l).mul(u)),p=oc(d.add(a).mul(n));s.directDiffuse.addAssign(p.mul(h.mul(t)))}super.direct({lightDirection:e,lightColor:t,reflectedLight:s},i,r)}}class Sv extends _v{constructor(e){super(e),this.thicknessColorNode=null,this.thicknessDistortionNode=Ku(.1),this.thicknessAmbientNode=Ku(0),this.thicknessAttenuationNode=Ku(.1),this.thicknessPowerNode=Ku(2),this.thicknessScaleNode=Ku(10)}get useSSS(){return null!==this.thicknessColorNode}setupLightingModel(){return new wv(this.useClearcoat,this.useSheen,this.useIridescence,this.useSSS)}copy(e){return this.thicknessColorNode=e.thicknessColorNode,this.thicknessDistortionNode=e.thicknessDistortionNode,this.thicknessAmbientNode=e.thicknessAmbientNode,this.thicknessAttenuationNode=e.thicknessAttenuationNode,this.thicknessPowerNode=e.thicknessPowerNode,this.thicknessScaleNode=e.thicknessScaleNode,super.copy(e)}}Sv.type=bx("MeshSSS",Sv);const Mv=ju((({normal:e,lightDirection:t,builder:s})=>{const i=e.dot(t),r=sc(i.mul(.5).add(.5),0);if(s.material.gradientMap){const e=ef("gradientMap","texture").context({getUV:()=>r});return oc(e.r)}{const e=r.fwidth().mul(.5);return Up(oc(.7),oc(1),Dp(Ku(.7).sub(e.x),Ku(.7).add(e.x),r.x))}}));class Av extends Gx{direct({lightDirection:e,lightColor:t,reflectedLight:s},i,r){const n=Mv({normal:Rg,lightDirection:e,builder:r}).mul(t);s.directDiffuse.addAssign(n.mul($x({diffuseColor:Pc.rgb})))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:s}){s.indirectDiffuse.addAssign(t.mul($x({diffuseColor:Pc}))),s.indirectDiffuse.mulAssign(e)}}const Nv=new Cl;class Rv extends xx{constructor(e){super(),this.isMeshToonNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Nv),this.setValues(e)}setupLightingModel(){return new Av}}Rv.type=bx("MeshToon",Rv);class Cv extends iu{constructor(){super("vec2")}setup(){const e=oc(Sg.z,0,Sg.x.negate()).normalize(),t=Sg.cross(e);return sc(e.dot(Fg),t.dot(Fg)).mul(.495).add(.5)}}Cv.type=Ql("MatcapUV",Cv);const Ev=Hu(Cv),Bv=new Fl;class Iv extends xx{constructor(e){super(),this.lights=!1,this.isMeshMatcapNodeMaterial=!0,this.setDefaultValues(Bv),this.setValues(e)}setupVariants(e){const t=Ev;let s;s=e.material.matcap?ef("matcap","texture").context({getUV:()=>t}):oc(Up(.2,.8,t.y)),Pc.rgb.mulAssign(s.rgb)}}Iv.type=bx("MeshMatcap",Iv);const Pv=new Va;class Fv extends xx{constructor(e){super(),this.isPointsNodeMaterial=!0,this.lights=!1,this.transparent=!0,this.sizeNode=null,this.setDefaultValues(Pv),this.setValues(e)}copy(e){return this.sizeNode=e.sizeNode,super.copy(e)}}Fv.type=bx("Points",Fv);class zv extends iu{constructor(e,t){super(),this.positionNode=e,this.rotationNode=t}getNodeType(e){return this.positionNode.getNodeType(e)}setup(e){const{rotationNode:t,positionNode:s}=this;if("vec2"===this.getNodeType(e)){const e=t.cos(),i=t.sin();return mc(e,i,i.negate(),e).mul(s)}{const e=t,i=fc(uc(1,0,0,0),uc(0,tp(e.x),ep(e.x).negate(),0),uc(0,ep(e.x),tp(e.x),0),uc(0,0,0,1)),r=fc(uc(tp(e.y),0,ep(e.y),0),uc(0,1,0,0),uc(ep(e.y).negate(),0,tp(e.y),0),uc(0,0,0,1)),n=fc(uc(tp(e.z),ep(e.z).negate(),0,0),uc(ep(e.z),tp(e.z),0,0),uc(0,0,1,0),uc(0,0,0,1));return i.mul(r).mul(n).mul(uc(s,1)).xyz}}}zv.type=Ql("Rotate",zv);const Uv=Wu(zv),Lv=new lo;class Ov extends xx{constructor(e){super(),this.isSpriteNodeMaterial=!0,this.lights=!1,this.positionNode=null,this.rotationNode=null,this.scaleNode=null,this.setDefaultValues(Lv),this.setValues(e)}setupPosition({object:e,context:t}){const{positionNode:s,rotationNode:i,scaleNode:r}=this,n=bg;let o=cg.mul(oc(s||0)),a=sc(pg[0].xyz.length(),pg[1].xyz.length());null!==r&&(a=a.mul(r));let h=n.xy;e.center&&!0===e.center.isVector2&&(h=h.sub(Cc(e.center).sub(.5))),h=h.mul(a);const l=Ku(i||Hf),u=Uv(h,l);o=uc(o.xy.add(u),o.zw);const c=Ym.mul(o);return t.vertex=n,c}copy(e){return this.positionNode=e.positionNode,this.rotationNode=e.rotationNode,this.scaleNode=e.scaleNode,super.copy(e)}}Ov.type=bx("Sprite",Ov);class Vv extends Gx{constructor(){super(),this.shadowNode=Ku(1).toVar("shadowMask")}direct({shadowMask:e}){this.shadowNode.mulAssign(e)}finish(e){Pc.a.mulAssign(this.shadowNode.oneMinus()),e.outgoingLight.rgb.assign(Pc.rgb)}}const Dv=new Sl;class kv extends xx{constructor(e){super(),this.isShadowNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Dv),this.setValues(e)}setupLightingModel(){return new Vv}}kv.type=bx("Shadow",kv);const Gv=ju((({texture:e,uv:t})=>{const s=1e-4,i=oc().temp();return Yu(t.x.lessThan(s),(()=>{i.assign(oc(1,0,0))})).ElseIf(t.y.lessThan(s),(()=>{i.assign(oc(0,1,0))})).ElseIf(t.z.lessThan(s),(()=>{i.assign(oc(0,0,1))})).ElseIf(t.x.greaterThan(.9999),(()=>{i.assign(oc(-1,0,0))})).ElseIf(t.y.greaterThan(.9999),(()=>{i.assign(oc(0,-1,0))})).ElseIf(t.z.greaterThan(.9999),(()=>{i.assign(oc(0,0,-1))})).Else((()=>{const s=.01,r=e.uv(t.add(oc(-.01,0,0))).r.sub(e.uv(t.add(oc(s,0,0))).r),n=e.uv(t.add(oc(0,-.01,0))).r.sub(e.uv(t.add(oc(0,s,0))).r),o=e.uv(t.add(oc(0,0,-.01))).r.sub(e.uv(t.add(oc(0,0,s))).r);i.assign(oc(r,n,o))})),i.normalize()}));class Wv extends km{constructor(e,t=null,s=null){super(e,t,s),this.isTexture3DNode=!0}getInputType(){return"texture3D"}getDefaultUV(){return oc(.5,.5,.5)}setUpdateMatrix(){}setupUV(e,t){return t}generateUV(e,t){return t.build(e,"vec3")}normal(e){return Gv({texture:this,uv:e})}}Wv.type=Ql("Texture3D",Wv);const Hv=Wu(Wv);class jv extends xx{constructor(e={}){super(),this.lights=!1,this.isVolumeNodeMaterial=!0,this.testNode=null,this.setValues(e)}setup(e){const t=Hv(this.map,null,0),s=ju((({orig:e,dir:t})=>{const s=oc(-.5),i=oc(.5),r=t.reciprocal(),n=s.sub(e).mul(r),o=i.sub(e).mul(r),a=vp(n,o),h=Tp(n,o),l=Tp(a.x,Tp(a.y,a.z)),u=vp(h.x,vp(h.y,h.z));return sc(l,u)}));this.fragmentNode=ju((()=>{const e=em(oc(yg.mul(uc(eg,1)))),i=em(xg.sub(e)).normalize(),r=Bc("vec2","bounds").assign(s({orig:e,dir:i}));r.x.greaterThan(r.y).discard(),r.assign(sc(Tp(r.x,0),r.y));const n=Bc("vec3","p").assign(e.add(r.x.mul(i))),o=Bc("vec3","inc").assign(oc(i.abs().reciprocal())),a=Bc("float","delta").assign(vp(o.x,vp(o.y,o.z)));a.divAssign(ef("steps","float"));const h=Bc("vec4","ac").assign(uc(ef("base","color"),0));return Cy({type:"float",start:r.x,end:r.y,update:"+= delta"},(()=>{const e=Bc("float","d").assign(t.uv(n.add(.5)).r);null!==this.testNode?this.testNode({map:t,mapValue:e,probe:n,finalColor:h}).append():(h.a.assign(1),By()),n.addAssign(i.mul(a))})),h.a.equal(0).discard(),uc(h)}))(),super.setup(e)}}function qv(e,t,s){return!e||!s&&e.constructor===t?e:"number"==typeof t.BYTES_PER_ELEMENT?new t(e):Array.prototype.slice.call(e)}function $v(e){return ArrayBuffer.isView(e)&&!(e instanceof DataView)}function Xv(e){const t=e.length,s=new Array(t);for(let e=0;e!==t;++e)s[e]=e;return s.sort((function(t,s){return e[t]-e[s]})),s}function Yv(e,t,s){const i=e.length,r=new e.constructor(i);for(let n=0,o=0;o!==i;++n){const i=s[n]*t;for(let s=0;s!==t;++s)r[o++]=e[i+s]}return r}function Jv(e,t,s,i){let r=1,n=e[0];for(;void 0!==n&&void 0===n[i];)n=e[r++];if(void 0===n)return;let o=n[i];if(void 0!==o)if(Array.isArray(o))do{o=n[i],void 0!==o&&(t.push(n.time),s.push.apply(s,o)),n=e[r++]}while(void 0!==n);else if(void 0!==o.toArray)do{o=n[i],void 0!==o&&(t.push(n.time),o.toArray(s,s.length)),n=e[r++]}while(void 0!==n);else do{o=n[i],void 0!==o&&(t.push(n.time),s.push(o)),n=e[r++]}while(void 0!==n)}jv.type=bx("Volume",jv);const Zv={convertArray:qv,isTypedArray:$v,getKeyframeOrder:Xv,sortedArray:Yv,flattenJSON:Jv,subclip:function(e,t,s,i,r=30){const n=e.clone();n.name=t;const o=[];for(let e=0;e=i)){h.push(t.times[e]);for(let s=0;sn.tracks[e].times[0]&&(a=n.tracks[e].times[0]);for(let e=0;e=i.times[c]){const e=c*h+a,t=e+h-a;d=i.values.slice(e,t)}else{const e=i.createInterpolant(),t=a,s=h-a;e.evaluate(n),d=e.resultBuffer.slice(t,s)}if("quaternion"===r){(new Ci).fromArray(d).normalize().conjugate().toArray(d)}const p=o.times.length;for(let e=0;e=r)break e;{const o=t[1];e=r)break t}n=s,s=0}}for(;s>>1;et;)--n;if(++n,0!==r||n!==i){r>=n&&(n=Math.max(n,1),r=n-1);const e=this.getValueSize();this.times=s.slice(r,n),this.values=this.values.slice(r*e,n*e)}return this}validate(){let e=!0;const t=this.getValueSize();t-Math.floor(t)!=0&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),e=!1);const s=this.times,i=this.values,r=s.length;0===r&&(console.error("THREE.KeyframeTrack: Track is empty.",this),e=!1);let n=null;for(let t=0;t!==r;t++){const i=s[t];if("number"==typeof i&&isNaN(i)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,t,i),e=!1;break}if(null!==n&&n>i){console.error("THREE.KeyframeTrack: Out of order keys.",this,t,i,n),e=!1;break}n=i}if(void 0!==i&&$v(i))for(let t=0,s=i.length;t!==s;++t){const s=i[t];if(isNaN(s)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,t,s),e=!1;break}}return e}optimize(){const e=this.times.slice(),t=this.values.slice(),s=this.getValueSize(),i=this.getInterpolation()===Ft,r=e.length-1;let n=1;for(let o=1;o0){e[n]=e[r];for(let e=r*s,i=n*s,o=0;o!==s;++o)t[i+o]=t[e+o];++n}return n!==e.length?(this.times=e.slice(0,n),this.values=t.slice(0,n*s)):(this.times=e,this.values=t),this}clone(){const e=this.times.slice(),t=this.values.slice(),s=new(0,this.constructor)(this.name,e,t);return s.createInterpolant=this.createInterpolant,s}}sT.prototype.TimeBufferType=Float32Array,sT.prototype.ValueBufferType=Float32Array,sT.prototype.DefaultInterpolation=Pt;class iT extends sT{constructor(e,t,s){super(e,t,s)}}iT.prototype.ValueTypeName="bool",iT.prototype.ValueBufferType=Array,iT.prototype.DefaultInterpolation=It,iT.prototype.InterpolantFactoryMethodLinear=void 0,iT.prototype.InterpolantFactoryMethodSmooth=void 0;class rT extends sT{}rT.prototype.ValueTypeName="color";class nT extends sT{}nT.prototype.ValueTypeName="number";class oT extends Kv{constructor(e,t,s,i){super(e,t,s,i)}interpolate_(e,t,s,i){const r=this.resultBuffer,n=this.sampleValues,o=this.valueSize,a=(s-t)/(i-t);let h=e*o;for(let e=h+o;h!==e;h+=4)Ci.slerpFlat(r,0,n,h-o,n,h,a);return r}}class aT extends sT{InterpolantFactoryMethodLinear(e){return new oT(this.times,this.values,this.getValueSize(),e)}}aT.prototype.ValueTypeName="quaternion",aT.prototype.InterpolantFactoryMethodSmooth=void 0;class hT extends sT{constructor(e,t,s){super(e,t,s)}}hT.prototype.ValueTypeName="string",hT.prototype.ValueBufferType=Array,hT.prototype.DefaultInterpolation=It,hT.prototype.InterpolantFactoryMethodLinear=void 0,hT.prototype.InterpolantFactoryMethodSmooth=void 0;class lT extends sT{}lT.prototype.ValueTypeName="vector";class uT{constructor(e="",t=-1,s=[],i=2500){this.name=e,this.tracks=s,this.duration=t,this.blendMode=i,this.uuid=qs(),this.duration<0&&this.resetDuration()}static parse(e){const t=[],s=e.tracks,i=1/(e.fps||1);for(let e=0,r=s.length;e!==r;++e)t.push(cT(s[e]).scale(i));const r=new this(e.name,e.duration,t,e.blendMode);return r.uuid=e.uuid,r}static toJSON(e){const t=[],s=e.tracks,i={name:e.name,duration:e.duration,tracks:t,uuid:e.uuid,blendMode:e.blendMode};for(let e=0,i=s.length;e!==i;++e)t.push(sT.toJSON(s[e]));return i}static CreateFromMorphTargetSequence(e,t,s,i){const r=t.length,n=[];for(let e=0;e1){const e=n[1];let t=i[e];t||(i[e]=t=[]),t.push(s)}}const n=[];for(const e in i)n.push(this.CreateFromMorphTargetSequence(e,i[e],t,s));return n}static parseAnimation(e,t){if(!e)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;const s=function(e,t,s,i,r){if(0!==s.length){const n=[],o=[];Jv(s,n,o,i),0!==n.length&&r.push(new e(t,n,o))}},i=[],r=e.name||"default",n=e.fps||30,o=e.blendMode;let a=e.length||-1;const h=e.hierarchy||[];for(let e=0;e{t&&t(r),this.manager.itemEnd(e)}),0),r;if(void 0!==fT[e])return void fT[e].push({onLoad:t,onProgress:s,onError:i});fT[e]=[],fT[e].push({onLoad:t,onProgress:s,onError:i});const n=new Request(e,{headers:new Headers(this.requestHeader),credentials:this.withCredentials?"include":"same-origin"}),o=this.mimeType,a=this.responseType;fetch(n).then((t=>{if(200===t.status||0===t.status){if(0===t.status&&console.warn("THREE.FileLoader: HTTP Status 0 received."),"undefined"==typeof ReadableStream||void 0===t.body||void 0===t.body.getReader)return t;const s=fT[e],i=t.body.getReader(),r=t.headers.get("X-File-Size")||t.headers.get("Content-Length"),n=r?parseInt(r):0,o=0!==n;let a=0;const h=new ReadableStream({start(e){!function t(){i.read().then((({done:i,value:r})=>{if(i)e.close();else{a+=r.byteLength;const i=new ProgressEvent("progress",{lengthComputable:o,loaded:a,total:n});for(let e=0,t=s.length;e{e.error(t)}))}()}});return new Response(h)}throw new yT(`fetch for "${t.url}" responded with ${t.status}: ${t.statusText}`,t)})).then((e=>{switch(a){case"arraybuffer":return e.arrayBuffer();case"blob":return e.blob();case"document":return e.text().then((e=>(new DOMParser).parseFromString(e,o)));case"json":return e.json();default:if(void 0===o)return e.text();{const t=/charset="?([^;"\s]*)"?/i.exec(o),s=t&&t[1]?t[1].toLowerCase():void 0,i=new TextDecoder(s);return e.arrayBuffer().then((e=>i.decode(e)))}}})).then((t=>{dT.add(e,t);const s=fT[e];delete fT[e];for(let e=0,i=s.length;e{const s=fT[e];if(void 0===s)throw this.manager.itemError(e),t;delete fT[e];for(let e=0,i=s.length;e{this.manager.itemEnd(e)})),this.manager.itemStart(e)}setResponseType(e){return this.responseType=e,this}setMimeType(e){return this.mimeType=e,this}}class bT extends gT{constructor(e){super(e)}load(e,t,s,i){const r=this,n=new xT(this.manager);n.setPath(this.path),n.setRequestHeader(this.requestHeader),n.setWithCredentials(this.withCredentials),n.load(e,(function(s){try{t(r.parse(JSON.parse(s)))}catch(t){i?i(t):console.error(t),r.manager.itemError(e)}}),s,i)}parse(e){const t=[];for(let s=0;s0:i.vertexColors=e.vertexColors),void 0!==e.uniforms)for(const t in e.uniforms){const r=e.uniforms[t];switch(i.uniforms[t]={},r.type){case"t":i.uniforms[t].value=s(r.value);break;case"c":i.uniforms[t].value=(new Yr).setHex(r.value);break;case"v2":i.uniforms[t].value=(new Qs).fromArray(r.value);break;case"v3":i.uniforms[t].value=(new Ei).fromArray(r.value);break;case"v4":i.uniforms[t].value=(new _i).fromArray(r.value);break;case"m3":i.uniforms[t].value=(new ei).fromArray(r.value);break;case"m4":i.uniforms[t].value=(new or).fromArray(r.value);break;default:i.uniforms[t].value=r.value}}if(void 0!==e.defines&&(i.defines=e.defines),void 0!==e.vertexShader&&(i.vertexShader=e.vertexShader),void 0!==e.fragmentShader&&(i.fragmentShader=e.fragmentShader),void 0!==e.glslVersion&&(i.glslVersion=e.glslVersion),void 0!==e.extensions)for(const t in e.extensions)i.extensions[t]=e.extensions[t];if(void 0!==e.lights&&(i.lights=e.lights),void 0!==e.clipping&&(i.clipping=e.clipping),void 0!==e.size&&(i.size=e.size),void 0!==e.sizeAttenuation&&(i.sizeAttenuation=e.sizeAttenuation),void 0!==e.map&&(i.map=s(e.map)),void 0!==e.matcap&&(i.matcap=s(e.matcap)),void 0!==e.alphaMap&&(i.alphaMap=s(e.alphaMap)),void 0!==e.bumpMap&&(i.bumpMap=s(e.bumpMap)),void 0!==e.bumpScale&&(i.bumpScale=e.bumpScale),void 0!==e.normalMap&&(i.normalMap=s(e.normalMap)),void 0!==e.normalMapType&&(i.normalMapType=e.normalMapType),void 0!==e.normalScale){let t=e.normalScale;!1===Array.isArray(t)&&(t=[t,t]),i.normalScale=(new Qs).fromArray(t)}return void 0!==e.displacementMap&&(i.displacementMap=s(e.displacementMap)),void 0!==e.displacementScale&&(i.displacementScale=e.displacementScale),void 0!==e.displacementBias&&(i.displacementBias=e.displacementBias),void 0!==e.roughnessMap&&(i.roughnessMap=s(e.roughnessMap)),void 0!==e.metalnessMap&&(i.metalnessMap=s(e.metalnessMap)),void 0!==e.emissiveMap&&(i.emissiveMap=s(e.emissiveMap)),void 0!==e.emissiveIntensity&&(i.emissiveIntensity=e.emissiveIntensity),void 0!==e.specularMap&&(i.specularMap=s(e.specularMap)),void 0!==e.specularIntensityMap&&(i.specularIntensityMap=s(e.specularIntensityMap)),void 0!==e.specularColorMap&&(i.specularColorMap=s(e.specularColorMap)),void 0!==e.envMap&&(i.envMap=s(e.envMap)),void 0!==e.envMapRotation&&i.envMapRotation.fromArray(e.envMapRotation),void 0!==e.envMapIntensity&&(i.envMapIntensity=e.envMapIntensity),void 0!==e.reflectivity&&(i.reflectivity=e.reflectivity),void 0!==e.refractionRatio&&(i.refractionRatio=e.refractionRatio),void 0!==e.lightMap&&(i.lightMap=s(e.lightMap)),void 0!==e.lightMapIntensity&&(i.lightMapIntensity=e.lightMapIntensity),void 0!==e.aoMap&&(i.aoMap=s(e.aoMap)),void 0!==e.aoMapIntensity&&(i.aoMapIntensity=e.aoMapIntensity),void 0!==e.gradientMap&&(i.gradientMap=s(e.gradientMap)),void 0!==e.clearcoatMap&&(i.clearcoatMap=s(e.clearcoatMap)),void 0!==e.clearcoatRoughnessMap&&(i.clearcoatRoughnessMap=s(e.clearcoatRoughnessMap)),void 0!==e.clearcoatNormalMap&&(i.clearcoatNormalMap=s(e.clearcoatNormalMap)),void 0!==e.clearcoatNormalScale&&(i.clearcoatNormalScale=(new Qs).fromArray(e.clearcoatNormalScale)),void 0!==e.iridescenceMap&&(i.iridescenceMap=s(e.iridescenceMap)),void 0!==e.iridescenceThicknessMap&&(i.iridescenceThicknessMap=s(e.iridescenceThicknessMap)),void 0!==e.transmissionMap&&(i.transmissionMap=s(e.transmissionMap)),void 0!==e.thicknessMap&&(i.thicknessMap=s(e.thicknessMap)),void 0!==e.anisotropyMap&&(i.anisotropyMap=s(e.anisotropyMap)),void 0!==e.sheenColorMap&&(i.sheenColorMap=s(e.sheenColorMap)),void 0!==e.sheenRoughnessMap&&(i.sheenRoughnessMap=s(e.sheenRoughnessMap)),i}setTextures(e){return this.textures=e,this}static createMaterialFromType(e){return new{ShadowMaterial:Sl,SpriteMaterial:lo,RawShaderMaterial:Ml,ShaderMaterial:$n,PointsMaterial:Va,MeshPhysicalMaterial:Nl,MeshStandardMaterial:Al,MeshPhongMaterial:Rl,MeshToonMaterial:Cl,MeshNormalMaterial:El,MeshLambertMaterial:Bl,MeshDepthMaterial:Il,MeshDistanceMaterial:Pl,MeshBasicMaterial:Qr,MeshMatcapMaterial:Fl,LineDashedMaterial:zl,LineBasicMaterial:Ma,Material:Kr}[e]}}class qT{static decodeText(e){if(console.warn("THREE.LoaderUtils: decodeText() has been deprecated with r165 and will be removed with r175. Use TextDecoder instead."),"undefined"!=typeof TextDecoder)return(new TextDecoder).decode(e);let t="";for(let s=0,i=e.length;s0){const s=new pT(t);r=new TT(s),r.setCrossOrigin(this.crossOrigin);for(let t=0,s=e.length;t0){i=new TT(this.manager),i.setCrossOrigin(this.crossOrigin);for(let t=0,i=e.length;t{const t=new Pi;t.min.fromArray(e.boxMin),t.max.fromArray(e.boxMax);const s=new Zi;return s.radius=e.sphereRadius,s.center.fromArray(e.sphereCenter),{boxInitialized:e.boxInitialized,box:t,sphereInitialized:e.sphereInitialized,sphere:s}})),n._maxInstanceCount=e.maxInstanceCount,n._maxVertexCount=e.maxVertexCount,n._maxIndexCount=e.maxIndexCount,n._geometryInitialized=e.geometryInitialized,n._geometryCount=e.geometryCount,n._matricesTexture=u(e.matricesTexture.uuid),void 0!==e.colorsTexture&&(n._colorsTexture=u(e.colorsTexture.uuid));break;case"LOD":n=new Ro;break;case"Line":n=new Pa(h(e.geometry),l(e.material));break;case"LineLoop":n=new Oa(h(e.geometry),l(e.material));break;case"LineSegments":n=new La(h(e.geometry),l(e.material));break;case"PointCloud":case"Points":n=new Ha(h(e.geometry),l(e.material));break;case"Sprite":n=new So(l(e.material));break;case"Group":n=new qa;break;case"Bone":n=new Vo;break;default:n=new Pr}if(n.uuid=e.uuid,void 0!==e.name&&(n.name=e.name),void 0!==e.matrix?(n.matrix.fromArray(e.matrix),void 0!==e.matrixAutoUpdate&&(n.matrixAutoUpdate=e.matrixAutoUpdate),n.matrixAutoUpdate&&n.matrix.decompose(n.position,n.quaternion,n.scale)):(void 0!==e.position&&n.position.fromArray(e.position),void 0!==e.rotation&&n.rotation.fromArray(e.rotation),void 0!==e.quaternion&&n.quaternion.fromArray(e.quaternion),void 0!==e.scale&&n.scale.fromArray(e.scale)),void 0!==e.up&&n.up.fromArray(e.up),void 0!==e.castShadow&&(n.castShadow=e.castShadow),void 0!==e.receiveShadow&&(n.receiveShadow=e.receiveShadow),e.shadow&&(void 0!==e.shadow.intensity&&(n.shadow.intensity=e.shadow.intensity),void 0!==e.shadow.bias&&(n.shadow.bias=e.shadow.bias),void 0!==e.shadow.normalBias&&(n.shadow.normalBias=e.shadow.normalBias),void 0!==e.shadow.radius&&(n.shadow.radius=e.shadow.radius),void 0!==e.shadow.mapSize&&n.shadow.mapSize.fromArray(e.shadow.mapSize),void 0!==e.shadow.camera&&(n.shadow.camera=this.parseObject(e.shadow.camera))),void 0!==e.visible&&(n.visible=e.visible),void 0!==e.frustumCulled&&(n.frustumCulled=e.frustumCulled),void 0!==e.renderOrder&&(n.renderOrder=e.renderOrder),void 0!==e.userData&&(n.userData=e.userData),void 0!==e.layers&&(n.layers.mask=e.layers),void 0!==e.children){const o=e.children;for(let e=0;e{t&&t(s),r.manager.itemEnd(e)})).catch((e=>{i&&i(e)})):(setTimeout((function(){t&&t(n),r.manager.itemEnd(e)}),0),n);const o={};o.credentials="anonymous"===this.crossOrigin?"same-origin":"include",o.headers=this.requestHeader;const a=fetch(e,o).then((function(e){return e.blob()})).then((function(e){return createImageBitmap(e,Object.assign(r.options,{colorSpaceConversion:"none"}))})).then((function(s){return dT.add(e,s),t&&t(s),r.manager.itemEnd(e),s})).catch((function(t){i&&i(t),dT.remove(e),r.manager.itemError(e),r.manager.itemEnd(e)}));dT.add(e,a),r.manager.itemStart(e)}}let e_;class t_{static getContext(){return void 0===e_&&(e_=new(window.AudioContext||window.webkitAudioContext)),e_}static setContext(e){e_=e}}class s_ extends gT{constructor(e){super(e)}load(e,t,s,i){const r=this,n=new xT(this.manager);function o(t){i?i(t):console.error(t),r.manager.itemError(e)}n.setResponseType("arraybuffer"),n.setPath(this.path),n.setRequestHeader(this.requestHeader),n.setWithCredentials(this.withCredentials),n.load(e,(function(e){try{const s=e.slice(0);t_.getContext().decodeAudioData(s,(function(e){t(e)})).catch(o)}catch(e){o(e)}}),s,i)}}const i_=new or,r_=new or,n_=new or;class o_{constructor(){this.type="StereoCamera",this.aspect=1,this.eyeSep=.064,this.cameraL=new Kn,this.cameraL.layers.enable(1),this.cameraL.matrixAutoUpdate=!1,this.cameraR=new Kn,this.cameraR.layers.enable(2),this.cameraR.matrixAutoUpdate=!1,this._cache={focus:null,fov:null,aspect:null,near:null,far:null,zoom:null,eyeSep:null}}update(e){const t=this._cache;if(t.focus!==e.focus||t.fov!==e.fov||t.aspect!==e.aspect*this.aspect||t.near!==e.near||t.far!==e.far||t.zoom!==e.zoom||t.eyeSep!==this.eyeSep){t.focus=e.focus,t.fov=e.fov,t.aspect=e.aspect*this.aspect,t.near=e.near,t.far=e.far,t.zoom=e.zoom,t.eyeSep=this.eyeSep,n_.copy(e.projectionMatrix);const s=t.eyeSep/2,i=s*t.near/t.focus,r=t.near*Math.tan(Hs*t.fov*.5)/t.zoom;let n,o;r_.elements[12]=-s,i_.elements[12]=s,n=-r*t.aspect+i,o=r*t.aspect+i,n_.elements[0]=2*t.near/(o-n),n_.elements[8]=(o+n)/(o-n),this.cameraL.projectionMatrix.copy(n_),n=-r*t.aspect-i,o=r*t.aspect-i,n_.elements[0]=2*t.near/(o-n),n_.elements[8]=(o+n)/(o-n),this.cameraR.projectionMatrix.copy(n_)}this.cameraL.matrixWorld.copy(e.matrixWorld).multiply(r_),this.cameraR.matrixWorld.copy(e.matrixWorld).multiply(i_)}}class a_ extends Kn{constructor(e=[]){super(),this.isArrayCamera=!0,this.cameras=e}}class h_{constructor(e=!0){this.autoStart=e,this.startTime=0,this.oldTime=0,this.elapsedTime=0,this.running=!1}start(){this.startTime=l_(),this.oldTime=this.startTime,this.elapsedTime=0,this.running=!0}stop(){this.getElapsedTime(),this.running=!1,this.autoStart=!1}getElapsedTime(){return this.getDelta(),this.elapsedTime}getDelta(){let e=0;if(this.autoStart&&!this.running)return this.start(),0;if(this.running){const t=l_();e=(t-this.oldTime)/1e3,this.oldTime=t,this.elapsedTime+=e}return e}}function l_(){return("undefined"==typeof performance?Date:performance).now()}const u_=new Ei,c_=new Ci,d_=new Ei,p_=new Ei;class m_ extends Pr{constructor(){super(),this.type="AudioListener",this.context=t_.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._clock=new h_}getInput(){return this.gain}removeFilter(){return null!==this.filter&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null),this}getFilter(){return this.filter}setFilter(e){return null!==this.filter?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination),this.filter=e,this.gain.connect(this.filter),this.filter.connect(this.context.destination),this}getMasterVolume(){return this.gain.gain.value}setMasterVolume(e){return this.gain.gain.setTargetAtTime(e,this.context.currentTime,.01),this}updateMatrixWorld(e){super.updateMatrixWorld(e);const t=this.context.listener,s=this.up;if(this.timeDelta=this._clock.getDelta(),this.matrixWorld.decompose(u_,c_,d_),p_.set(0,0,-1).applyQuaternion(c_),t.positionX){const e=this.context.currentTime+this.timeDelta;t.positionX.linearRampToValueAtTime(u_.x,e),t.positionY.linearRampToValueAtTime(u_.y,e),t.positionZ.linearRampToValueAtTime(u_.z,e),t.forwardX.linearRampToValueAtTime(p_.x,e),t.forwardY.linearRampToValueAtTime(p_.y,e),t.forwardZ.linearRampToValueAtTime(p_.z,e),t.upX.linearRampToValueAtTime(s.x,e),t.upY.linearRampToValueAtTime(s.y,e),t.upZ.linearRampToValueAtTime(s.z,e)}else t.setPosition(u_.x,u_.y,u_.z),t.setOrientation(p_.x,p_.y,p_.z,s.x,s.y,s.z)}}class g_ extends Pr{constructor(e){super(),this.type="Audio",this.listener=e,this.context=e.context,this.gain=this.context.createGain(),this.gain.connect(e.getInput()),this.autoplay=!1,this.buffer=null,this.detune=0,this.loop=!1,this.loopStart=0,this.loopEnd=0,this.offset=0,this.duration=void 0,this.playbackRate=1,this.isPlaying=!1,this.hasPlaybackControl=!0,this.source=null,this.sourceType="empty",this._startedAt=0,this._progress=0,this._connected=!1,this.filters=[]}getOutput(){return this.gain}setNodeSource(e){return this.hasPlaybackControl=!1,this.sourceType="audioNode",this.source=e,this.connect(),this}setMediaElementSource(e){return this.hasPlaybackControl=!1,this.sourceType="mediaNode",this.source=this.context.createMediaElementSource(e),this.connect(),this}setMediaStreamSource(e){return this.hasPlaybackControl=!1,this.sourceType="mediaStreamNode",this.source=this.context.createMediaStreamSource(e),this.connect(),this}setBuffer(e){return this.buffer=e,this.sourceType="buffer",this.autoplay&&this.play(),this}play(e=0){if(!0===this.isPlaying)return void console.warn("THREE.Audio: Audio is already playing.");if(!1===this.hasPlaybackControl)return void console.warn("THREE.Audio: this Audio has no playback control.");this._startedAt=this.context.currentTime+e;const t=this.context.createBufferSource();return t.buffer=this.buffer,t.loop=this.loop,t.loopStart=this.loopStart,t.loopEnd=this.loopEnd,t.onended=this.onEnded.bind(this),t.start(this._startedAt,this._progress+this.offset,this.duration),this.isPlaying=!0,this.source=t,this.setDetune(this.detune),this.setPlaybackRate(this.playbackRate),this.connect()}pause(){if(!1!==this.hasPlaybackControl)return!0===this.isPlaying&&(this._progress+=Math.max(this.context.currentTime-this._startedAt,0)*this.playbackRate,!0===this.loop&&(this._progress=this._progress%(this.duration||this.buffer.duration)),this.source.stop(),this.source.onended=null,this.isPlaying=!1),this;console.warn("THREE.Audio: this Audio has no playback control.")}stop(){if(!1!==this.hasPlaybackControl)return this._progress=0,null!==this.source&&(this.source.stop(),this.source.onended=null),this.isPlaying=!1,this;console.warn("THREE.Audio: this Audio has no playback control.")}connect(){if(this.filters.length>0){this.source.connect(this.filters[0]);for(let e=1,t=this.filters.length;e0){this.source.disconnect(this.filters[0]);for(let e=1,t=this.filters.length;e0&&this._mixBufferRegionAdditive(s,i,this._addIndex*t,1,t);for(let e=t,r=t+t;e!==r;++e)if(s[e]!==s[e+t]){o.setValue(s,i);break}}saveOriginalState(){const e=this.binding,t=this.buffer,s=this.valueSize,i=s*this._origIndex;e.getValue(t,i);for(let e=s,r=i;e!==r;++e)t[e]=t[i+e%s];this._setIdentity(),this.cumulativeWeight=0,this.cumulativeWeightAdditive=0}restoreOriginalState(){const e=3*this.valueSize;this.binding.setValue(this.buffer,e)}_setAdditiveIdentityNumeric(){const e=this._addIndex*this.valueSize,t=e+this.valueSize;for(let s=e;s=.5)for(let i=0;i!==r;++i)e[t+i]=e[s+i]}_slerp(e,t,s,i){Ci.slerpFlat(e,t,e,t,e,s,i)}_slerpAdditive(e,t,s,i,r){const n=this._workIndex*r;Ci.multiplyQuaternionsFlat(e,n,e,t,e,s),Ci.slerpFlat(e,t,e,t,e,n,i)}_lerp(e,t,s,i,r){const n=1-i;for(let o=0;o!==r;++o){const r=t+o;e[r]=e[r]*n+e[s+o]*i}}_lerpAdditive(e,t,s,i,r){for(let n=0;n!==r;++n){const r=t+n;e[r]=e[r]+e[s+n]*i}}}const w_="\\[\\]\\.:\\/",S_=new RegExp("["+w_+"]","g"),M_="[^"+w_+"]",A_="[^"+w_.replace("\\.","")+"]",N_=new RegExp("^"+/((?:WC+[\/:])*)/.source.replace("WC",M_)+/(WCOD+)?/.source.replace("WCOD",A_)+/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",M_)+/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",M_)+"$"),R_=["material","materials","bones","map"];class C_{constructor(e,t,s){this.path=t,this.parsedPath=s||C_.parseTrackName(t),this.node=C_.findNode(e,this.parsedPath.nodeName),this.rootNode=e,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(e,t,s){return e&&e.isAnimationObjectGroup?new C_.Composite(e,t,s):new C_(e,t,s)}static sanitizeNodeName(e){return e.replace(/\s/g,"_").replace(S_,"")}static parseTrackName(e){const t=N_.exec(e);if(null===t)throw new Error("PropertyBinding: Cannot parse trackName: "+e);const s={nodeName:t[2],objectName:t[3],objectIndex:t[4],propertyName:t[5],propertyIndex:t[6]},i=s.nodeName&&s.nodeName.lastIndexOf(".");if(void 0!==i&&-1!==i){const e=s.nodeName.substring(i+1);-1!==R_.indexOf(e)&&(s.nodeName=s.nodeName.substring(0,i),s.objectName=e)}if(null===s.propertyName||0===s.propertyName.length)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+e);return s}static findNode(e,t){if(void 0===t||""===t||"."===t||-1===t||t===e.name||t===e.uuid)return e;if(e.skeleton){const s=e.skeleton.getBoneByName(t);if(void 0!==s)return s}if(e.children){const s=function(e){for(let i=0;i=r){const n=r++,l=e[n];t[l.uuid]=h,e[h]=l,t[a]=n,e[n]=o;for(let e=0,t=i;e!==t;++e){const t=s[e],i=t[n],r=t[h];t[h]=i,t[n]=r}}}this.nCachedObjects_=r}uncache(){const e=this._objects,t=this._indicesByUUID,s=this._bindings,i=s.length;let r=this.nCachedObjects_,n=e.length;for(let o=0,a=arguments.length;o!==a;++o){const a=arguments[o].uuid,h=t[a];if(void 0!==h)if(delete t[a],h0&&(t[o.uuid]=h),e[h]=o,e.pop();for(let e=0,t=i;e!==t;++e){const t=s[e];t[h]=t[r],t.pop()}}}this.nCachedObjects_=r}subscribe_(e,t){const s=this._bindingsIndicesByPath;let i=s[e];const r=this._bindings;if(void 0!==i)return r[i];const n=this._paths,o=this._parsedPaths,a=this._objects,h=a.length,l=this.nCachedObjects_,u=new Array(h);i=r.length,s[e]=i,n.push(e),o.push(t),r.push(u);for(let s=l,i=a.length;s!==i;++s){const i=a[s];u[s]=new C_(i,e,t)}return u}unsubscribe_(e){const t=this._bindingsIndicesByPath,s=t[e];if(void 0!==s){const i=this._paths,r=this._parsedPaths,n=this._bindings,o=n.length-1,a=n[o];t[e[o]]=s,n[s]=a,n.pop(),r[s]=r[o],r.pop(),i[s]=i[o],i.pop()}}}class B_{constructor(e,t,s=null,i=t.blendMode){this._mixer=e,this._clip=t,this._localRoot=s,this.blendMode=i;const r=t.tracks,n=r.length,o=new Array(n),a={endingStart:zt,endingEnd:zt};for(let e=0;e!==n;++e){const t=r[e].createInterpolant(null);o[e]=t,t.settings=a}this._interpolantSettings=a,this._interpolants=o,this._propertyBindings=new Array(n),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=2201,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}play(){return this._mixer._activateAction(this),this}stop(){return this._mixer._deactivateAction(this),this.reset()}reset(){return this.paused=!1,this.enabled=!0,this.time=0,this._loopCount=-1,this._startTime=null,this.stopFading().stopWarping()}isRunning(){return this.enabled&&!this.paused&&0!==this.timeScale&&null===this._startTime&&this._mixer._isActiveAction(this)}isScheduled(){return this._mixer._isActiveAction(this)}startAt(e){return this._startTime=e,this}setLoop(e,t){return this.loop=e,this.repetitions=t,this}setEffectiveWeight(e){return this.weight=e,this._effectiveWeight=this.enabled?e:0,this.stopFading()}getEffectiveWeight(){return this._effectiveWeight}fadeIn(e){return this._scheduleFading(e,0,1)}fadeOut(e){return this._scheduleFading(e,1,0)}crossFadeFrom(e,t,s){if(e.fadeOut(t),this.fadeIn(t),s){const s=this._clip.duration,i=e._clip.duration,r=i/s,n=s/i;e.warp(1,r,t),this.warp(n,1,t)}return this}crossFadeTo(e,t,s){return e.crossFadeFrom(this,t,s)}stopFading(){const e=this._weightInterpolant;return null!==e&&(this._weightInterpolant=null,this._mixer._takeBackControlInterpolant(e)),this}setEffectiveTimeScale(e){return this.timeScale=e,this._effectiveTimeScale=this.paused?0:e,this.stopWarping()}getEffectiveTimeScale(){return this._effectiveTimeScale}setDuration(e){return this.timeScale=this._clip.duration/e,this.stopWarping()}syncWith(e){return this.time=e.time,this.timeScale=e.timeScale,this.stopWarping()}halt(e){return this.warp(this._effectiveTimeScale,0,e)}warp(e,t,s){const i=this._mixer,r=i.time,n=this.timeScale;let o=this._timeScaleInterpolant;null===o&&(o=i._lendControlInterpolant(),this._timeScaleInterpolant=o);const a=o.parameterPositions,h=o.sampleValues;return a[0]=r,a[1]=r+s,h[0]=e/n,h[1]=t/n,this}stopWarping(){const e=this._timeScaleInterpolant;return null!==e&&(this._timeScaleInterpolant=null,this._mixer._takeBackControlInterpolant(e)),this}getMixer(){return this._mixer}getClip(){return this._clip}getRoot(){return this._localRoot||this._mixer._root}_update(e,t,s,i){if(!this.enabled)return void this._updateWeight(e);const r=this._startTime;if(null!==r){const i=(e-r)*s;i<0||0===s?t=0:(this._startTime=null,t=s*i)}t*=this._updateTimeScale(e);const n=this._updateTime(t),o=this._updateWeight(e);if(o>0){const e=this._interpolants,t=this._propertyBindings;if(this.blendMode===Vt)for(let s=0,i=e.length;s!==i;++s)e[s].evaluate(n),t[s].accumulateAdditive(o);else for(let s=0,r=e.length;s!==r;++s)e[s].evaluate(n),t[s].accumulate(i,o)}}_updateWeight(e){let t=0;if(this.enabled){t=this.weight;const s=this._weightInterpolant;if(null!==s){const i=s.evaluate(e)[0];t*=i,e>s.parameterPositions[1]&&(this.stopFading(),0===i&&(this.enabled=!1))}}return this._effectiveWeight=t,t}_updateTimeScale(e){let t=0;if(!this.paused){t=this.timeScale;const s=this._timeScaleInterpolant;if(null!==s){t*=s.evaluate(e)[0],e>s.parameterPositions[1]&&(this.stopWarping(),0===t?this.paused=!0:this.timeScale=t)}}return this._effectiveTimeScale=t,t}_updateTime(e){const t=this._clip.duration,s=this.loop;let i=this.time+e,r=this._loopCount;const n=2202===s;if(0===e)return-1===r?i:n&&1==(1&r)?t-i:i;if(2200===s){-1===r&&(this._loopCount=0,this._setEndings(!0,!0,!1));e:{if(i>=t)i=t;else{if(!(i<0)){this.time=i;break e}i=0}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:e<0?-1:1})}}else{if(-1===r&&(e>=0?(r=0,this._setEndings(!0,0===this.repetitions,n)):this._setEndings(0===this.repetitions,!0,n)),i>=t||i<0){const s=Math.floor(i/t);i-=t*s,r+=Math.abs(s);const o=this.repetitions-r;if(o<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,i=e>0?t:0,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:e>0?1:-1});else{if(1===o){const t=e<0;this._setEndings(t,!t,n)}else this._setEndings(!1,!1,n);this._loopCount=r,this.time=i,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:s})}}else this.time=i;if(n&&1==(1&r))return t-i}return i}_setEndings(e,t,s){const i=this._interpolantSettings;s?(i.endingStart=Ut,i.endingEnd=Ut):(i.endingStart=e?this.zeroSlopeAtStart?Ut:zt:Lt,i.endingEnd=t?this.zeroSlopeAtEnd?Ut:zt:Lt)}_scheduleFading(e,t,s){const i=this._mixer,r=i.time;let n=this._weightInterpolant;null===n&&(n=i._lendControlInterpolant(),this._weightInterpolant=n);const o=n.parameterPositions,a=n.sampleValues;return o[0]=r,a[0]=t,o[1]=r+e,a[1]=s,this}}const I_=new Float32Array(1);class P_ extends ks{constructor(e){super(),this._root=e,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}_bindAction(e,t){const s=e._localRoot||this._root,i=e._clip.tracks,r=i.length,n=e._propertyBindings,o=e._interpolants,a=s.uuid,h=this._bindingsByRootAndName;let l=h[a];void 0===l&&(l={},h[a]=l);for(let e=0;e!==r;++e){const r=i[e],h=r.name;let u=l[h];if(void 0!==u)++u.referenceCount,n[e]=u;else{if(u=n[e],void 0!==u){null===u._cacheIndex&&(++u.referenceCount,this._addInactiveBinding(u,a,h));continue}const i=t&&t._propertyBindings[e].binding.parsedPath;u=new __(C_.create(s,h,i),r.ValueTypeName,r.getValueSize()),++u.referenceCount,this._addInactiveBinding(u,a,h),n[e]=u}o[e].resultBuffer=u.buffer}}_activateAction(e){if(!this._isActiveAction(e)){if(null===e._cacheIndex){const t=(e._localRoot||this._root).uuid,s=e._clip.uuid,i=this._actionsByClip[s];this._bindAction(e,i&&i.knownActions[0]),this._addInactiveAction(e,s,t)}const t=e._propertyBindings;for(let e=0,s=t.length;e!==s;++e){const s=t[e];0==s.useCount++&&(this._lendBinding(s),s.saveOriginalState())}this._lendAction(e)}}_deactivateAction(e){if(this._isActiveAction(e)){const t=e._propertyBindings;for(let e=0,s=t.length;e!==s;++e){const s=t[e];0==--s.useCount&&(s.restoreOriginalState(),this._takeBackBinding(s))}this._takeBackAction(e)}}_initMemoryManager(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;const e=this;this.stats={actions:{get total(){return e._actions.length},get inUse(){return e._nActiveActions}},bindings:{get total(){return e._bindings.length},get inUse(){return e._nActiveBindings}},controlInterpolants:{get total(){return e._controlInterpolants.length},get inUse(){return e._nActiveControlInterpolants}}}}_isActiveAction(e){const t=e._cacheIndex;return null!==t&&t=0;--t)e[t].stop();return this}update(e){e*=this.timeScale;const t=this._actions,s=this._nActiveActions,i=this.time+=e,r=Math.sign(e),n=this._accuIndex^=1;for(let o=0;o!==s;++o){t[o]._update(i,e,r,n)}const o=this._bindings,a=this._nActiveBindings;for(let e=0;e!==a;++e)o[e].apply(n);return this}setTime(e){this.time=0;for(let e=0;e=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y))}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,j_).distanceTo(e)}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}const $_=new Ei,X_=new Ei;class Y_{constructor(e=new Ei,t=new Ei){this.start=e,this.end=t}set(e,t){return this.start.copy(e),this.end.copy(t),this}copy(e){return this.start.copy(e.start),this.end.copy(e.end),this}getCenter(e){return e.addVectors(this.start,this.end).multiplyScalar(.5)}delta(e){return e.subVectors(this.end,this.start)}distanceSq(){return this.start.distanceToSquared(this.end)}distance(){return this.start.distanceTo(this.end)}at(e,t){return this.delta(t).multiplyScalar(e).add(this.start)}closestPointToPointParameter(e,t){$_.subVectors(e,this.start),X_.subVectors(this.end,this.start);const s=X_.dot(X_);let i=X_.dot($_)/s;return t&&(i=$s(i,0,1)),i}closestPointToPoint(e,t,s){const i=this.closestPointToPointParameter(e,t);return this.delta(s).multiplyScalar(i).add(this.start)}applyMatrix4(e){return this.start.applyMatrix4(e),this.end.applyMatrix4(e),this}equals(e){return e.start.equals(this.start)&&e.end.equals(this.end)}clone(){return(new this.constructor).copy(this)}}const J_=new Ei;class Z_ extends Pr{constructor(e,t){super(),this.light=e,this.matrixAutoUpdate=!1,this.color=t,this.type="SpotLightHelper";const s=new Mn,i=[0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,-1,0,1,0,0,0,0,1,1,0,0,0,0,-1,1];for(let e=0,t=1,s=32;e1)for(let s=0;s.99999)this.quaternion.set(0,0,0,1);else if(e.y<-.99999)this.quaternion.set(1,0,0,0);else{_w.set(e.z,0,-e.x).normalize();const t=Math.acos(e.y);this.quaternion.setFromAxisAngle(_w,t)}}setLength(e,t=.2*e,s=.2*t){this.line.scale.set(1,Math.max(1e-4,e-t),1),this.line.updateMatrix(),this.cone.scale.set(s,t,s),this.cone.position.y=e,this.cone.updateMatrix()}setColor(e){this.line.material.color.set(e),this.cone.material.color.set(e)}copy(e){return super.copy(e,!1),this.line.copy(e.line),this.cone.copy(e.cone),this}dispose(){this.line.geometry.dispose(),this.line.material.dispose(),this.cone.geometry.dispose(),this.cone.material.dispose()}}class Aw extends La{constructor(e=1){const t=[0,0,0,e,0,0,0,0,0,0,e,0,0,0,0,0,0,e],s=new Mn;s.setAttribute("position",new yn(t,3)),s.setAttribute("color",new yn([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1],3));super(s,new Ma({vertexColors:!0,toneMapped:!1})),this.type="AxesHelper"}setColors(e,t,s){const i=new Yr,r=this.geometry.attributes.color.array;return i.set(e),i.toArray(r,0),i.toArray(r,3),i.set(t),i.toArray(r,6),i.toArray(r,9),i.set(s),i.toArray(r,12),i.toArray(r,15),this.geometry.attributes.color.needsUpdate=!0,this}dispose(){this.geometry.dispose(),this.material.dispose()}}class Nw{constructor(){this.type="ShapePath",this.color=new Yr,this.subPaths=[],this.currentPath=null}moveTo(e,t){return this.currentPath=new Th,this.subPaths.push(this.currentPath),this.currentPath.moveTo(e,t),this}lineTo(e,t){return this.currentPath.lineTo(e,t),this}quadraticCurveTo(e,t,s,i){return this.currentPath.quadraticCurveTo(e,t,s,i),this}bezierCurveTo(e,t,s,i,r,n){return this.currentPath.bezierCurveTo(e,t,s,i,r,n),this}splineThru(e){return this.currentPath.splineThru(e),this}toShapes(e){function t(e,t){const s=t.length;let i=!1;for(let r=s-1,n=0;nNumber.EPSILON){if(h<0&&(s=t[n],a=-a,o=t[r],h=-h),e.yo.y)continue;if(e.y===s.y){if(e.x===s.x)return!0}else{const t=h*(e.x-s.x)-a*(e.y-s.y);if(0===t)return!0;if(t<0)continue;i=!i}}else{if(e.y!==s.y)continue;if(o.x<=e.x&&e.x<=s.x||s.x<=e.x&&e.x<=o.x)return!0}}return i}const s=ol.isClockWise,i=this.subPaths;if(0===i.length)return[];let r,n,o;const a=[];if(1===i.length)return n=i[0],o=new Fh,o.curves=n.curves,a.push(o),a;let h=!s(i[0].getPoints());h=e?!h:h;const l=[],u=[];let c,d,p=[],m=0;u[m]=void 0,p[m]=[];for(let t=0,o=i.length;t1){let e=!1,s=0;for(let e=0,t=u.length;e0&&!1===e&&(p=l)}for(let e=0,t=u.length;e{this.requestId=self.requestAnimationFrame(e),!0===this.info.autoReset&&this.info.reset(),this.nodes.nodeFrame.update(),this.info.frame=this.nodes.nodeFrame.frameId,null!==this.animationLoop&&this.animationLoop(t,s)};e()}dispose(){self.cancelAnimationFrame(this.requestId),this.requestId=null}setAnimationLoop(e){this.animationLoop=e}}class Bw{constructor(){this.weakMap=new WeakMap}get(e){let t=this.weakMap;for(let s=0;s{this.dispose()},this.material.addEventListener("dispose",this.onMaterialDispose)}updateClipping(e){const t=this.material;let s=this.clippingContext;Array.isArray(t.clippingPlanes)?(s!==e&&s||(s=new Pw,this.clippingContext=s),s.update(e,t)):this.clippingContext!==e&&(this.clippingContext=e)}get clippingNeedsUpdate(){return this.clippingContext.version!==this.clippingContextVersion&&(this.clippingContextVersion=this.clippingContext.version,!0)}getNodeBuilderState(){return this._nodeBuilderState||(this._nodeBuilderState=this._nodes.getForRender(this))}getBindings(){return this._bindings||(this._bindings=this.getNodeBuilderState().createBindings())}getIndex(){return this._geometries.getIndex(this)}getChainArray(){return[this.object,this.material,this.context,this.lightsNode]}getAttributes(){if(null!==this.attributes)return this.attributes;const e=this.getNodeBuilderState().nodeAttributes,t=this.geometry,s=[],i=new Set;for(const r of e){const e=r.node&&r.node.attribute?r.node.attribute:t.getAttribute(r.name);if(void 0===e)continue;s.push(e);const n=e.isInterleavedBufferAttribute?e.data:e;i.add(n)}return this.attributes=s,this.vertexBuffers=Array.from(i.values()),s}getVertexBuffers(){return null===this.vertexBuffers&&this.getAttributes(),this.vertexBuffers}getMaterialCacheKey(){const{object:e,material:t}=this;let s=t.customProgramCacheKey();for(const e of function(e){const t=Object.keys(e);let s=Object.getPrototypeOf(e);for(;s;){const e=Object.getOwnPropertyDescriptors(s);for(const s in e)if(void 0!==e[s]){const i=e[s];i&&"function"==typeof i.get&&t.push(s)}s=Object.getPrototypeOf(s)}return t}(t)){if(/^(is[A-Z]|_)|^(visible|version|uuid|name|opacity|userData)$/.test(e))continue;const i=t[e];let r;if(null!==i){const e=typeof i;"number"===e?r=0!==i?"1":"0":"object"===e?(r="{",i.isTexture&&(r+=i.mapping),r+="}"):r=String(i)}else r=String(i);s+=r+","}return s+=this.clippingContext.cacheKey+",",e.skeleton&&(s+=e.skeleton.bones.length+","),e.morphTargetInfluences&&(s+=e.morphTargetInfluences.length+","),e.isBatchedMesh&&(s+=e._matricesTexture.uuid+",",null!==e._colorsTexture&&(s+=e._colorsTexture.uuid+",")),e.count>1&&(s+=e.count+","+e.uuid+","),s}get needsUpdate(){return this.initialNodesCacheKey!==this.getDynamicCacheKey()||this.clippingNeedsUpdate}getDynamicCacheKey(){return this.object.receiveShadow+","+this._nodes.getCacheKey(this.scene,this.lightsNode)}getCacheKey(){return this.getMaterialCacheKey()+","+this.getDynamicCacheKey()}dispose(){this.material.removeEventListener("dispose",this.onMaterialDispose),this.onDispose()}}class Uw{constructor(e,t,s,i,r,n){this.renderer=e,this.nodes=t,this.geometries=s,this.pipelines=i,this.bindings=r,this.info=n,this.chainMaps={}}get(e,t,s,i,r,n,o){const a=this.getChainMap(o),h=[e,t,n,r];let l=a.get(h);return void 0===l?(l=this.createRenderObject(this.nodes,this.geometries,this.renderer,e,t,s,i,r,n,o),a.set(h,l)):(l.updateClipping(n.clippingContext),(l.version!==t.version||l.needsUpdate)&&(l.initialCacheKey!==l.getCacheKey()?(l.dispose(),l=this.get(e,t,s,i,r,n,o)):l.version=t.version)),l}getChainMap(e="default"){return this.chainMaps[e]||(this.chainMaps[e]=new Bw)}dispose(){this.chainMaps={}}createRenderObject(e,t,s,i,r,n,o,a,h,l){const u=this.getChainMap(l),c=new zw(e,t,s,i,r,n,o,a,h);return c.onDispose=()=>{this.pipelines.delete(c),this.bindings.delete(c),this.nodes.delete(c),u.delete(c.getChainArray())},c}}class Lw{constructor(){this.data=new WeakMap}get(e){let t=this.data.get(e);return void 0===t&&(t={},this.data.set(e,t)),t}delete(e){let t;return this.data.has(e)&&(t=this.data.get(e),this.data.delete(e)),t}has(e){return this.data.has(e)}dispose(){this.data=new WeakMap}}const Ow=1,Vw=2,Dw=4,kw=16;class Gw extends Lw{constructor(e){super(),this.backend=e}delete(e){const t=super.delete(e);return void 0!==t&&this.backend.destroyAttribute(e),t}update(e,t){const s=this.get(e);if(void 0===s.version)t===Ow?this.backend.createAttribute(e):t===Vw?this.backend.createIndexAttribute(e):t===Dw&&this.backend.createStorageAttribute(e),s.version=this._getBufferAttribute(e).version;else{const t=this._getBufferAttribute(e);(s.version=0;--t)if(e[t]>=65535)return!0;return!1}(t)?gn:pn)(t,1);return r.version=Ww(e),r}class jw extends Lw{constructor(e,t){super(),this.attributes=e,this.info=t,this.wireframes=new WeakMap,this.attributeCall=new WeakMap}has(e){const t=e.geometry;return super.has(t)&&!0===this.get(t).initialized}updateForRender(e){!1===this.has(e)&&this.initGeometry(e),this.updateAttributes(e)}initGeometry(e){const t=e.geometry;this.get(t).initialized=!0,this.info.memory.geometries++;const s=()=>{this.info.memory.geometries--;const i=t.index,r=e.getAttributes();null!==i&&this.attributes.delete(i);for(const e of r)this.attributes.delete(e);const n=this.wireframes.get(t);void 0!==n&&this.attributes.delete(n),t.removeEventListener("dispose",s)};t.addEventListener("dispose",s)}updateAttributes(e){const t=e.getAttributes();for(const e of t)e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute?this.updateAttribute(e,Dw):this.updateAttribute(e,Ow);const s=this.getIndex(e);null!==s&&this.updateAttribute(s,Vw)}updateAttribute(e,t){const s=this.info.render.calls;e.isInterleavedBufferAttribute?void 0===this.attributeCall.get(e)?(this.attributes.update(e,t),this.attributeCall.set(e,s)):this.attributeCall.get(e.data)!==s&&(this.attributes.update(e,t),this.attributeCall.set(e.data,s),this.attributeCall.set(e,s)):this.attributeCall.get(e)!==s&&(this.attributes.update(e,t),this.attributeCall.set(e,s))}getIndex(e){const{geometry:t,material:s}=e;let i=t.index;if(!0===s.wireframe){const e=this.wireframes;let s=e.get(t);void 0===s?(s=Hw(t),e.set(t,s)):s.version!==Ww(t)&&(this.attributes.delete(s),s=Hw(t),e.set(t,s)),i=s}return i}}class qw{constructor(){this.autoReset=!0,this.frame=0,this.calls=0,this.render={calls:0,frameCalls:0,drawCalls:0,triangles:0,points:0,lines:0,timestamp:0,previousFrameCalls:0,timestampCalls:0},this.compute={calls:0,frameCalls:0,timestamp:0,previousFrameCalls:0,timestampCalls:0},this.memory={geometries:0,textures:0}}update(e,t,s){this.render.drawCalls++,e.isMesh||e.isSprite?this.render.triangles+=s*(t/3):e.isPoints?this.render.points+=s*t:e.isLineSegments?this.render.lines+=s*(t/2):e.isLine?this.render.lines+=s*(t-1):console.error("THREE.WebGPUInfo: Unknown object type.")}updateTimestamp(e,t){0===this[e].timestampCalls&&(this[e].timestamp=0),this[e].timestamp+=t,this[e].timestampCalls++,this[e].timestampCalls>=this[e].previousFrameCalls&&(this[e].timestampCalls=0)}reset(){const e=this.render.frameCalls;this.render.previousFrameCalls=e;const t=this.compute.frameCalls;this.compute.previousFrameCalls=t,this.render.drawCalls=0,this.render.frameCalls=0,this.compute.frameCalls=0,this.render.triangles=0,this.render.points=0,this.render.lines=0}dispose(){this.reset(),this.calls=0,this.render.calls=0,this.compute.calls=0,this.render.timestamp=0,this.compute.timestamp=0,this.memory.geometries=0,this.memory.textures=0}}class $w{constructor(e){this.cacheKey=e,this.usedTimes=0}}class Xw extends $w{constructor(e,t,s){super(e),this.vertexProgram=t,this.fragmentProgram=s}}class Yw extends $w{constructor(e,t){super(e),this.computeProgram=t,this.isComputePipeline=!0}}let Jw=0;class Zw{constructor(e,t,s=null,i=null){this.id=Jw++,this.code=e,this.stage=t,this.transforms=s,this.attributes=i,this.usedTimes=0}}class Kw extends Lw{constructor(e,t){super(),this.backend=e,this.nodes=t,this.bindings=null,this.caches=new Map,this.programs={vertex:new Map,fragment:new Map,compute:new Map}}getForCompute(e,t){const{backend:s}=this,i=this.get(e);if(this._needsComputeUpdate(e)){const r=i.pipeline;r&&(r.usedTimes--,r.computeProgram.usedTimes--);const n=this.nodes.getForCompute(e);let o=this.programs.compute.get(n.computeShader);void 0===o&&(r&&0===r.computeProgram.usedTimes&&this._releaseProgram(r.computeProgram),o=new Zw(n.computeShader,"compute",n.transforms,n.nodeAttributes),this.programs.compute.set(n.computeShader,o),s.createProgram(o));const a=this._getComputeCacheKey(e,o);let h=this.caches.get(a);void 0===h&&(r&&0===r.usedTimes&&this._releasePipeline(r),h=this._getComputePipeline(e,o,a,t)),h.usedTimes++,o.usedTimes++,i.version=e.version,i.pipeline=h}return i.pipeline}getForRender(e,t=null){const{backend:s}=this,i=this.get(e);if(this._needsRenderUpdate(e)){const r=i.pipeline;r&&(r.usedTimes--,r.vertexProgram.usedTimes--,r.fragmentProgram.usedTimes--);const n=e.getNodeBuilderState();let o=this.programs.vertex.get(n.vertexShader);void 0===o&&(r&&0===r.vertexProgram.usedTimes&&this._releaseProgram(r.vertexProgram),o=new Zw(n.vertexShader,"vertex"),this.programs.vertex.set(n.vertexShader,o),s.createProgram(o));let a=this.programs.fragment.get(n.fragmentShader);void 0===a&&(r&&0===r.fragmentProgram.usedTimes&&this._releaseProgram(r.fragmentProgram),a=new Zw(n.fragmentShader,"fragment"),this.programs.fragment.set(n.fragmentShader,a),s.createProgram(a));const h=this._getRenderCacheKey(e,o,a);let l=this.caches.get(h);void 0===l?(r&&0===r.usedTimes&&this._releasePipeline(r),l=this._getRenderPipeline(e,o,a,h,t)):e.pipeline=l,l.usedTimes++,o.usedTimes++,a.usedTimes++,i.pipeline=l}return i.pipeline}delete(e){const t=this.get(e).pipeline;return t&&(t.usedTimes--,0===t.usedTimes&&this._releasePipeline(t),t.isComputePipeline?(t.computeProgram.usedTimes--,0===t.computeProgram.usedTimes&&this._releaseProgram(t.computeProgram)):(t.fragmentProgram.usedTimes--,t.vertexProgram.usedTimes--,0===t.vertexProgram.usedTimes&&this._releaseProgram(t.vertexProgram),0===t.fragmentProgram.usedTimes&&this._releaseProgram(t.fragmentProgram))),super.delete(e)}dispose(){super.dispose(),this.caches=new Map,this.programs={vertex:new Map,fragment:new Map,compute:new Map}}updateForRender(e){this.getForRender(e)}_getComputePipeline(e,t,s,i){s=s||this._getComputeCacheKey(e,t);let r=this.caches.get(s);return void 0===r&&(r=new Yw(s,t),this.caches.set(s,r),this.backend.createComputePipeline(r,i)),r}_getRenderPipeline(e,t,s,i,r){i=i||this._getRenderCacheKey(e,t,s);let n=this.caches.get(i);return void 0===n&&(n=new Xw(i,t,s),this.caches.set(i,n),e.pipeline=n,this.backend.createRenderPipeline(e,r)),n}_getComputeCacheKey(e,t){return e.id+","+t.id}_getRenderCacheKey(e,t,s){return t.id+","+s.id+","+this.backend.getRenderCacheKey(e)}_releasePipeline(e){this.caches.delete(e.cacheKey)}_releaseProgram(e){const t=e.code,s=e.stage;this.programs[s].delete(t)}_needsComputeUpdate(e){const t=this.get(e);return void 0===t.pipeline||t.version!==e.version}_needsRenderUpdate(e){return void 0===this.get(e).pipeline||this.backend.needsRenderUpdate(e)}}class Qw extends Lw{constructor(e,t,s,i,r,n){super(),this.backend=e,this.textures=s,this.pipelines=r,this.attributes=i,this.nodes=t,this.info=n,this.pipelines.bindings=this}getForRender(e){const t=e.getBindings();for(const e of t){const s=this.get(e);void 0===s.bindGroup&&(this._init(e),this.backend.createBindings(e,t),s.bindGroup=e)}return t}getForCompute(e){const t=this.nodes.getForCompute(e).bindings;for(const e of t){const s=this.get(e);void 0===s.bindGroup&&(this._init(e),this.backend.createBindings(e,t),s.bindGroup=e)}return t}updateForCompute(e){this._updateBindings(this.getForCompute(e))}updateForRender(e){this._updateBindings(this.getForRender(e))}_updateBindings(e){for(const t of e)this._update(t,e)}_init(e){for(const t of e.bindings)if(t.isSampledTexture)this.textures.updateTexture(t.texture);else if(t.isStorageBuffer){const e=t.attribute;this.attributes.update(e,Dw)}}_update(e,t){const{backend:s}=this;let i=!1;for(const t of e.bindings){if(t.isNodeUniformsGroup){if(!this.nodes.updateGroup(t))continue}if(t.isUniformBuffer){t.update()&&s.updateBinding(t)}else if(t.isSampler)t.update();else if(t.isSampledTexture){t.needsBindingsUpdate(this.textures.get(t.texture).generation)&&(i=!0);const e=t.update(),r=t.texture;e&&this.textures.updateTexture(r);const n=s.get(r);if(!0===s.isWebGPUBackend&&void 0===n.texture&&void 0===n.externalTexture&&(console.error("Bindings._update: binding should be available:",t,e,r,t.textureNode.value,i),this.textures.updateTexture(r),i=!0),!0===r.isStorageTexture){const e=this.get(r);!0===t.store?e.needsMipmap=!0:!0===r.generateMipmaps&&this.textures.needsMipmaps(r)&&!0===e.needsMipmap&&(this.backend.generateMipmaps(r),e.needsMipmap=!1)}}}!0===i&&this.backend.updateBindings(e,t)}}class eS{constructor(e,t,s=null){this.isNodeAttribute=!0,this.name=e,this.type=t,this.node=s}}class tS{constructor(e,t,s){this.isNodeUniform=!0,this.name=e,this.type=t,this.node=s.getSelf()}get value(){return this.node.value}set value(e){this.node.value=e}get id(){return this.node.id}get groupNode(){return this.node.groupNode}}class sS{constructor(e,t){this.isNodeVar=!0,this.name=e,this.type=t}}class iS extends sS{constructor(e,t){super(e,t),this.needsInterpolation=!1,this.isNodeVarying=!0}}class rS{constructor(e,t,s=""){this.name=e,this.type=t,this.code=s,Object.defineProperty(this,"isNodeCode",{value:!0})}}let nS=0;class oS{constructor(e=null){this.id=nS++,this.nodesData=new WeakMap,this.parent=e}getData(e){let t=this.nodesData.get(e);return void 0===t&&null!==this.parent&&(t=this.parent.getData(e)),t}setData(e,t){this.nodesData.set(e,t)}}class aS extends Ec{constructor(e,t=null){super(e,t),this.isParameterNode=!0}getHash(){return this.uuid}generate(){return this.name}}aS.type=Ql("Parameter",aS);const hS=(e,t)=>Du(new aS(e,t));class lS extends Kl{constructor(e="",t=[],s=""){super("code"),this.isCodeNode=!0,this.code=e,this.language=s,this.includes=t}isGlobal(){return!0}setIncludes(e){return this.includes=e,this}getIncludes(){return this.includes}generate(e){const t=this.getIncludes(e);for(const s of t)s.build(e);const s=e.getCodeFromNode(this,this.getNodeType(e));return s.code=this.code,s.code}serialize(e){super.serialize(e),e.code=this.code,e.language=this.language}deserialize(e){super.deserialize(e),this.code=e.code,this.language=e.language}}lS.type=Ql("Code",lS);const uS=Wu(lS),cS=(e,t)=>uS(e,t,"js"),dS=(e,t)=>uS(e,t,"wgsl"),pS=(e,t)=>uS(e,t,"glsl");class mS extends lS{constructor(e="",t=[],s=""){super(e,t,s)}getNodeType(e){return this.getNodeFunction(e).type}getInputs(e){return this.getNodeFunction(e).inputs}getNodeFunction(e){const t=e.getDataFromNode(this);let s=t.nodeFunction;return void 0===s&&(s=e.parser.parseFunction(this.code),t.nodeFunction=s),s}generate(e,t){super.generate(e);const s=this.getNodeFunction(e),i=s.name,r=s.type,n=e.getCodeFromNode(this,r);""!==i&&(n.name=i);const o=e.getPropertyName(n),a=this.getNodeFunction(e).getCode(o);return n.code=a+"\n","property"===t?o:e.format(`${o}()`,r,t)}}mS.type=Ql("Function",mS);const gS=(e,t=[],s="")=>{for(let e=0;ei.call(...e);return r.functionNode=i,r},fS=(e,t)=>gS(e,t,"glsl"),yS=(e,t)=>gS(e,t,"wgsl");class xS{constructor(e,t){this.name=e,this.value=t,this.boundary=0,this.itemSize=0,this.offset=0}setValue(e){this.value=e}getValue(){return this.value}}class bS extends xS{constructor(e,t=0){super(e,t),this.isNumberUniform=!0,this.boundary=4,this.itemSize=1}}class vS extends xS{constructor(e,t=new Qs){super(e,t),this.isVector2Uniform=!0,this.boundary=8,this.itemSize=2}}class TS extends xS{constructor(e,t=new Ei){super(e,t),this.isVector3Uniform=!0,this.boundary=16,this.itemSize=3}}class _S extends xS{constructor(e,t=new _i){super(e,t),this.isVector4Uniform=!0,this.boundary=16,this.itemSize=4}}class wS extends xS{constructor(e,t=new Yr){super(e,t),this.isColorUniform=!0,this.boundary=16,this.itemSize=3}}class SS extends xS{constructor(e,t=new ei){super(e,t),this.isMatrix3Uniform=!0,this.boundary=48,this.itemSize=12}}class MS extends xS{constructor(e,t=new or){super(e,t),this.isMatrix4Uniform=!0,this.boundary=64,this.itemSize=16}}class AS extends bS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class NS extends vS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class RS extends TS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class CS extends _S{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class ES extends wS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class BS extends SS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class IS extends MS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class PS extends Kl{constructor(e=null){super(),this.nodes=[],this.outputNode=null,this.parent=e,this._currentCond=null,this.isStackNode=!0}getNodeType(e){return this.outputNode?this.outputNode.getNodeType(e):"void"}add(e){return this.nodes.push(e),this}If(e,t){const s=new Vu(t);return this._currentCond=qp(e,s),this.add(this._currentCond)}ElseIf(e,t){const s=new Vu(t),i=qp(e,s);return this._currentCond.elseNode=i,this._currentCond=i,this}Else(e){return this._currentCond.elseNode=new Vu(e),this}build(e,...t){const s=Xu();$u(this);for(const t of this.nodes)t.build(e,"void");return $u(s),this.outputNode?this.outputNode.build(e,...t):super.build(e,...t)}else(...e){return console.warn("TSL.StackNode: .else() has been renamed to .Else()."),this.Else(...e)}elseif(...e){return console.warn("TSL.StackNode: .elseif() has been renamed to .ElseIf()."),this.ElseIf(...e)}}PS.type=Ql("Stack",PS);const FS=Wu(PS),zS=[.125,.215,.35,.446,.526,.582],US=20,LS=new OT(-1,1,1,-1,0,1),OS=new Kn(90,1),VS=new Yr;let DS=null,kS=0,GS=0;const WS=(1+Math.sqrt(5))/2,HS=1/WS,jS=[new Ei(-WS,HS,0),new Ei(WS,HS,0),new Ei(-HS,0,WS),new Ei(HS,0,WS),new Ei(0,WS,-HS),new Ei(0,WS,HS),new Ei(-1,1,-1),new Ei(1,1,-1),new Ei(-1,1,1),new Ei(1,1,1)],qS=[3,1,5,0,4,2],$S=nv(Um(),zm("faceIndex")).normalize(),XS=oc($S.x,$S.y.negate(),$S.z);class YS{constructor(e){this._renderer=e,this._pingPongRenderTarget=null,this._lodMax=0,this._cubeSize=0,this._lodPlanes=[],this._sizeLods=[],this._sigmas=[],this._lodMeshes=[],this._blurMaterial=null,this._cubemapMaterial=null,this._equirectMaterial=null,this._backgroundBox=null}fromScene(e,t=0,s=.1,i=100){DS=this._renderer.getRenderTarget(),kS=this._renderer.getActiveCubeFace(),GS=this._renderer.getActiveMipmapLevel(),this._setSize(256);const r=this._allocateTargets();return r.depthBuffer=!0,this._sceneToCubeUV(e,s,i,r),t>0&&this._blur(r,0,0,t),this._applyPMREM(r),this._cleanup(r),r}fromEquirectangular(e,t=null){return this._fromTexture(e,t)}fromCubemap(e,t=null){return this._fromTexture(e,t)}compileCubemapShader(){null===this._cubemapMaterial&&(this._cubemapMaterial=QS(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){null===this._equirectMaterial&&(this._equirectMaterial=eM(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),null!==this._cubemapMaterial&&this._cubemapMaterial.dispose(),null!==this._equirectMaterial&&this._equirectMaterial.dispose(),null!==this._backgroundBox&&(this._backgroundBox.geometry.dispose(),this._backgroundBox.material.dispose())}_setSize(e){this._lodMax=Math.floor(Math.log2(e)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){null!==this._blurMaterial&&this._blurMaterial.dispose(),null!==this._pingPongRenderTarget&&this._pingPongRenderTarget.dispose();for(let e=0;ee-4?h=zS[a-e+4-1]:0===a&&(h=0),i.push(h);const l=1/(o-2),u=-l,c=1+l,d=[u,u,c,u,c,c,u,u,c,c,u,c],p=6,m=6,g=3,f=2,y=1,x=new Float32Array(g*m*p),b=new Float32Array(f*m*p),v=new Float32Array(y*m*p);for(let e=0;e2?0:-1,i=[t,s,0,t+2/3,s,0,t+2/3,s+1,0,t,s,0,t+2/3,s+1,0,t,s+1,0],r=qS[e];x.set(i,g*m*r),b.set(d,f*m*r);const n=[r,r,r,r,r,r];v.set(n,y*m*r)}const T=new Mn;T.setAttribute("position",new hn(x,g)),T.setAttribute("uv",new hn(b,f)),T.setAttribute("faceIndex",new hn(v,y)),t.push(T),r.push(new Wn(T,null)),n>4&&n--}return{lodPlanes:t,sizeLods:s,sigmas:i,lodMeshes:r}}(i)),this._blurMaterial=function(e,t,s){const i=Xg(new Array(US).fill(0)),r=Cc(new Ei(0,1,0)),n=Cc(0),o=Ku(US),a=Cc(0),h=Cc(1),l=Gm(null),u=Cc(0),c=Ku(1/t),d=Ku(1/s),p=Ku(e),m={n:o,latitudinal:a,weights:i,poleAxis:r,outputDirection:XS,dTheta:n,samples:h,envMap:l,mipInt:u,CUBEUV_TEXEL_WIDTH:c,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:p},g=KS("blur");return g.uniforms=m,g.fragmentNode=lv({...m,latitudinal:a.equal(1)}),g}(i,e,t)}return i}_compileMaterial(e){const t=this._lodMeshes[0];t.material=e,this._renderer.compile(t,LS)}_sceneToCubeUV(e,t,s,i){const r=OS;r.near=t,r.far=s;const n=[-1,1,-1,-1,-1,-1],o=[1,1,1,-1,-1,-1],a=this._renderer,h=a.autoClear;a.getClearColor(VS),a.autoClear=!1;let l=this._backgroundBox;if(null===l){const e=new Qr({name:"PMREM.Background",side:d,depthWrite:!1,depthTest:!1});l=new Wn(new jn,e)}let u=!1;const c=e.background;c?c.isColor&&(l.material.color.copy(c),e.background=null,u=!0):(l.material.color.copy(VS),u=!0),a.setRenderTarget(i),a.clear(),u&&a.render(l,r);for(let t=0;t<6;t++){const s=t%3;0===s?(r.up.set(0,n[t],0),r.lookAt(o[t],0,0)):1===s?(r.up.set(0,0,n[t]),r.lookAt(0,o[t],0)):(r.up.set(0,n[t],0),r.lookAt(0,0,o[t]));const h=this._cubeSize;ZS(i,s*h,t>2?h:0,h,h),a.render(e,r)}a.autoClear=h,e.background=c}_textureToCubeUV(e,t){const s=this._renderer,i=e.mapping===he||e.mapping===le;i?null===this._cubemapMaterial&&(this._cubemapMaterial=QS(e)):null===this._equirectMaterial&&(this._equirectMaterial=eM(e));const r=i?this._cubemapMaterial:this._equirectMaterial;r.fragmentNode.value=e;const n=this._lodMeshes[0];n.material=r;const o=this._cubeSize;ZS(t,0,0,3*o,2*o),s.setRenderTarget(t),s.render(n,LS)}_applyPMREM(e){const t=this._renderer,s=t.autoClear;t.autoClear=!1;const i=this._lodPlanes.length;for(let t=1;tUS&&console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${m} samples when the maximum is set to 20`);const g=[];let f=0;for(let e=0;ey-4?i-y+4:0),4*(this._cubeSize-x),3*x,2*x),a.setRenderTarget(t),a.render(l,LS)}}function JS(e,t,s){const i=new wi(e,t,s);return i.texture.mapping=306,i.texture.name="PMREM.cubeUv",i.texture.isPMREMTexture=!0,i.scissorTest=!0,i}function ZS(e,t,s,i,r){e.viewport.set(t,s,i,r),e.scissor.set(t,s,i,r)}function KS(e){const t=new xx;return t.depthTest=!1,t.depthWrite=!1,t.blending=m,t.name=`PMREM_${e}`,t}function QS(e){const t=KS("cubemap");return t.fragmentNode=Wg(e,XS),t}function eM(e){const t=KS("equirect");return t.fragmentNode=Gm(e,Px(XS),0),t}let tM=0;class sM{constructor(e="",t=[],s=0,i=[]){this.name=e,this.bindings=t,this.index=s,this.bindingsReference=i,this.id=tM++}}const iM=new WeakMap,rM=new Map([[2,"vec2"],[3,"vec3"],[4,"vec4"],[9,"mat3"],[16,"mat4"]]),nM=new Map([[Int8Array,"int"],[Int16Array,"int"],[Int32Array,"int"],[Uint8Array,"uint"],[Uint16Array,"uint"],[Uint32Array,"uint"],[Float32Array,"float"]]),oM=e=>(e=Number(e))+(e%1?"":".0");class aM{constructor(e,t,s){this.object=e,this.material=e&&e.material||null,this.geometry=e&&e.geometry||null,this.renderer=t,this.parser=s,this.scene=null,this.camera=null,this.nodes=[],this.updateNodes=[],this.updateBeforeNodes=[],this.updateAfterNodes=[],this.hashNodes={},this.lightsNode=null,this.environmentNode=null,this.fogNode=null,this.clippingContext=null,this.vertexShader=null,this.fragmentShader=null,this.computeShader=null,this.flowNodes={vertex:[],fragment:[],compute:[]},this.flowCode={vertex:"",fragment:"",compute:""},this.uniforms={vertex:[],fragment:[],compute:[],index:0},this.structs={vertex:[],fragment:[],compute:[],index:0},this.bindings={vertex:{},fragment:{},compute:{}},this.bindingsIndexes={},this.bindGroups=null,this.attributes=[],this.bufferAttributes=[],this.varyings=[],this.codes={},this.vars={},this.flow={code:""},this.chaining=[],this.stack=FS(),this.stacks=[],this.tab="\t",this.instanceBindGroups=!0,this.currentFunctionNode=null,this.context={material:this.material},this.cache=new oS,this.globalCache=this.cache,this.flowsData=new WeakMap,this.shaderStage=null,this.buildStage=null,this.useComparisonMethod=!1}getBindGroupsCache(){let e=iM.get(this.renderer);return void 0===e&&(e=new Bw,iM.set(this.renderer,e)),e}createRenderTarget(e,t,s){return new wi(e,t,s)}createCubeRenderTarget(e,t){return new Fx(e,t)}createPMREMGenerator(){return new YS(this.renderer)}includes(e){return this.nodes.includes(e)}_getBindGroup(e,t){const s=this.getBindGroupsCache(),i=[];let r,n=!0;for(const e of t)i.push(e),n=n&&!0!==e.groupNode.shared;return n?(r=s.get(i),void 0===r&&(r=new sM(e,i,this.bindingsIndexes[e].group,i),s.set(i,r))):r=new sM(e,i,this.bindingsIndexes[e].group,i),r}getBindGroupArray(e,t){const s=this.bindings[t];let i=s[e];return void 0===i&&(void 0===this.bindingsIndexes[e]&&(this.bindingsIndexes[e]={binding:0,group:Object.keys(this.bindingsIndexes).length}),s[e]=i=[]),i}getBindings(){let e=this.bindGroups;if(null===e){const t={},s=this.bindings;for(const e of Xl)for(const i in s[e]){const r=s[e][i];(t[i]||(t[i]=[])).push(...r)}e=[];for(const s in t){const i=t[s],r=this._getBindGroup(s,i);e.push(r)}this.bindGroups=e}return e}setHashNode(e,t){this.hashNodes[t]=e}addNode(e){!1===this.nodes.includes(e)&&(this.nodes.push(e),this.setHashNode(e,e.getHash(this)))}buildUpdateNodes(){for(const e of this.nodes){const t=e.getUpdateType(),s=e.getUpdateBeforeType(),i=e.getUpdateAfterType();t!==Hl.NONE&&this.updateNodes.push(e.getSelf()),s!==Hl.NONE&&this.updateBeforeNodes.push(e),i!==Hl.NONE&&this.updateAfterNodes.push(e)}}get currentNode(){return this.chaining[this.chaining.length-1]}isFilteredTexture(e){return e.magFilter===Te||e.magFilter===_e||e.magFilter===be||e.magFilter===Se||e.minFilter===Te||e.minFilter===_e||e.minFilter===be||e.minFilter===Se}addChain(e){this.chaining.push(e)}removeChain(e){if(this.chaining.pop()!==e)throw new Error("NodeBuilder: Invalid node chaining!")}getMethod(e){return e}getNodeFromHash(e){return this.hashNodes[e]}addFlow(e,t){return this.flowNodes[e].push(t),t}setContext(e){this.context=e}getContext(){return this.context}getSharedContext(){return this.context,this.context}setCache(e){this.cache=e}getCache(){return this.cache}getCacheFromNode(e,t=!0){const s=this.getDataFromNode(e);return void 0===s.cache&&(s.cache=new oS(t?this.getCache():null)),s.cache}isAvailable(){return!1}getVertexIndex(){console.warn("Abstract function.")}getInstanceIndex(){console.warn("Abstract function.")}getDrawIndex(){console.warn("Abstract function.")}getFrontFacing(){console.warn("Abstract function.")}getFragCoord(){console.warn("Abstract function.")}isFlipY(){return!1}increaseUsage(e){const t=this.getDataFromNode(e);return t.usageCount=void 0===t.usageCount?1:t.usageCount+1,t.usageCount}generateTexture(){console.warn("Abstract function.")}generateTextureLod(){console.warn("Abstract function.")}generateConst(e,t=null){if(null===t&&("float"===e||"int"===e||"uint"===e?t=0:"bool"===e?t=!1:"color"===e?t=new Yr:"vec2"===e?t=new Qs:"vec3"===e?t=new Ei:"vec4"===e&&(t=new _i)),"float"===e)return oM(t);if("int"===e)return`${Math.round(t)}`;if("uint"===e)return t>=0?`${Math.round(t)}u`:"0u";if("bool"===e)return t?"true":"false";if("color"===e)return`${this.getType("vec3")}( ${oM(t.r)}, ${oM(t.g)}, ${oM(t.b)} )`;const s=this.getTypeLength(e),i=this.getComponentType(e),r=e=>this.generateConst(i,e);if(2===s)return`${this.getType(e)}( ${r(t.x)}, ${r(t.y)} )`;if(3===s)return`${this.getType(e)}( ${r(t.x)}, ${r(t.y)}, ${r(t.z)} )`;if(4===s)return`${this.getType(e)}( ${r(t.x)}, ${r(t.y)}, ${r(t.z)}, ${r(t.w)} )`;if(s>4&&t&&(t.isMatrix3||t.isMatrix4))return`${this.getType(e)}( ${t.elements.map(r).join(", ")} )`;if(s>4)return`${this.getType(e)}()`;throw new Error(`NodeBuilder: Type '${e}' not found in generate constant attempt.`)}getType(e){return"color"===e?"vec3":e}hasGeometryAttribute(e){return this.geometry&&void 0!==this.geometry.getAttribute(e)}getAttribute(e,t){const s=this.attributes;for(const t of s)if(t.name===e)return t;const i=new eS(e,t);return s.push(i),i}getPropertyName(e){return e.name}isVector(e){return/vec\d/.test(e)}isMatrix(e){return/mat\d/.test(e)}isReference(e){return"void"===e||"property"===e||"sampler"===e||"texture"===e||"cubeTexture"===e||"storageTexture"===e||"depthTexture"===e||"texture3D"===e}needsToWorkingColorSpace(){return!1}getComponentTypeFromTexture(e){const t=e.type;if(e.isDataTexture){if(t===Ee)return"int";if(t===Be)return"uint"}return"float"}getElementType(e){return"mat2"===e?"vec2":"mat3"===e?"vec3":"mat4"===e?"vec4":this.getComponentType(e)}getComponentType(e){if("float"===(e=this.getVectorType(e))||"bool"===e||"int"===e||"uint"===e)return e;const t=/(b|i|u|)(vec|mat)([2-4])/.exec(e);return null===t?null:"b"===t[1]?"bool":"i"===t[1]?"int":"u"===t[1]?"uint":"float"}getVectorType(e){return"color"===e?"vec3":"texture"===e||"cubeTexture"===e||"storageTexture"===e||"texture3D"===e?"vec4":e}getTypeFromLength(e,t="float"){if(1===e)return t;const s=rM.get(e);return("float"===t?"":t[0])+s}getTypeFromArray(e){return nM.get(e.constructor)}getTypeFromAttribute(e){let t=e;e.isInterleavedBufferAttribute&&(t=e.data);const s=t.array,i=e.itemSize,r=e.normalized;let n;return e instanceof fn||!0===r||(n=this.getTypeFromArray(s)),this.getTypeFromLength(i,n)}getTypeLength(e){const t=this.getVectorType(e),s=/vec([2-4])/.exec(t);return null!==s?Number(s[1]):"float"===t||"bool"===t||"int"===t||"uint"===t?1:!0===/mat2/.test(e)?4:!0===/mat3/.test(e)?9:!0===/mat4/.test(e)?16:0}getVectorFromMatrix(e){return e.replace("mat","vec")}changeComponentType(e,t){return this.getTypeFromLength(this.getTypeLength(e),t)}getIntegerType(e){const t=this.getComponentType(e);return"int"===t||"uint"===t?e:this.changeComponentType(e,"int")}addStack(){return this.stack=FS(this.stack),this.stacks.push(Xu()||this.stack),$u(this.stack),this.stack}removeStack(){const e=this.stack;return this.stack=e.parent,$u(this.stacks.pop()),e}getDataFromNode(e,t=this.shaderStage,s=null){let i=(s=null===s?e.isGlobal(this)?this.globalCache:this.cache:s).getData(e);return void 0===i&&(i={},s.setData(e,i)),void 0===i[t]&&(i[t]={}),i[t]}getNodeProperties(e,t="any"){const s=this.getDataFromNode(e,t);return s.properties||(s.properties={outputNode:null})}getBufferAttributeFromNode(e,t){const s=this.getDataFromNode(e);let i=s.bufferAttribute;if(void 0===i){const r=this.uniforms.index++;i=new eS("nodeAttribute"+r,t,e),this.bufferAttributes.push(i),s.bufferAttribute=i}return i}getStructTypeFromNode(e,t=this.shaderStage){const s=this.getDataFromNode(e,t);if(void 0===s.structType){const i=this.structs.index++;e.name=`StructType${i}`,this.structs[t].push(e),s.structType=e}return e}getUniformFromNode(e,t,s=this.shaderStage,i=null){const r=this.getDataFromNode(e,s,this.globalCache);let n=r.uniform;if(void 0===n){const o=this.uniforms.index++;n=new tS(i||"nodeUniform"+o,t,e),this.uniforms[s].push(n),r.uniform=n}return n}getVarFromNode(e,t=null,s=e.getNodeType(this),i=this.shaderStage){const r=this.getDataFromNode(e,i);let n=r.variable;if(void 0===n){const e=this.vars[i]||(this.vars[i]=[]);null===t&&(t="nodeVar"+e.length),n=new sS(t,s),e.push(n),r.variable=n}return n}getVaryingFromNode(e,t=null,s=e.getNodeType(this)){const i=this.getDataFromNode(e,"any");let r=i.varying;if(void 0===r){const e=this.varyings,n=e.length;null===t&&(t="nodeVarying"+n),r=new iS(t,s),e.push(r),i.varying=r}return r}getCodeFromNode(e,t,s=this.shaderStage){const i=this.getDataFromNode(e);let r=i.code;if(void 0===r){const e=this.codes[s]||(this.codes[s]=[]),n=e.length;r=new rS("nodeCode"+n,t),e.push(r),i.code=r}return r}addLineFlowCode(e){return""===e||(e=this.tab+e,/;\s*$/.test(e)||(e+=";\n"),this.flow.code+=e),this}addFlowCode(e){return this.flow.code+=e,this}addFlowTab(){return this.tab+="\t",this}removeFlowTab(){return this.tab=this.tab.slice(0,-1),this}getFlowData(e){return this.flowsData.get(e)}flowNode(e){const t=e.getNodeType(this),s=this.flowChildNode(e,t);return this.flowsData.set(e,s),s}buildFunctionNode(e){const t=new mS,s=this.currentFunctionNode;return this.currentFunctionNode=t,t.code=this.buildFunctionCode(e),this.currentFunctionNode=s,t}flowShaderNode(e){const t=e.layout,s={[Symbol.iterator](){let e=0;const t=Object.values(this);return{next:()=>({value:t[e],done:e++>=t.length})}}};for(const e of t.inputs)s[e.name]=new aS(e.type,e.name);e.layout=null;const i=e.call(s),r=this.flowStagesNode(i,t.type);return e.layout=t,r}flowStagesNode(e,t=null){const s=this.flow,i=this.vars,r=this.cache,n=this.buildStage,o=this.stack,a={code:""};this.flow=a,this.vars={},this.cache=new oS,this.stack=FS();for(const s of $l)this.setBuildStage(s),a.result=e.build(this,t);return a.vars=this.getVars(this.shaderStage),this.flow=s,this.vars=i,this.cache=r,this.stack=o,this.setBuildStage(n),a}getFunctionOperator(){return null}flowChildNode(e,t=null){const s=this.flow,i={code:""};return this.flow=i,i.result=e.build(this,t),this.flow=s,i}flowNodeFromShaderStage(e,t,s=null,i=null){const r=this.shaderStage;this.setShaderStage(e);const n=this.flowChildNode(t,s);return null!==i&&(n.code+=`${this.tab+i} = ${n.result};\n`),this.flowCode[e]=this.flowCode[e]+n.code,this.setShaderStage(r),n}getAttributesArray(){return this.attributes.concat(this.bufferAttributes)}getAttributes(){console.warn("Abstract function.")}getVaryings(){console.warn("Abstract function.")}getVar(e,t){return`${this.getType(e)} ${t}`}getVars(e){let t="";const s=this.vars[e];if(void 0!==s)for(const e of s)t+=`${this.getVar(e.type,e.name)}; `;return t}getUniforms(){console.warn("Abstract function.")}getCodes(e){const t=this.codes[e];let s="";if(void 0!==t)for(const e of t)s+=e.code+"\n";return s}getHash(){return this.vertexShader+this.fragmentShader+this.computeShader}setShaderStage(e){this.shaderStage=e}getShaderStage(){return this.shaderStage}setBuildStage(e){this.buildStage=e}getBuildStage(){return this.buildStage}buildCode(){console.warn("Abstract function.")}build(){const{object:e,material:t,renderer:s}=this;if(null!==t){let e=s.nodes.library.fromMaterial(t);null===e&&(console.error(`NodeMaterial: Material "${t.type}" is not compatible.`),e=new xx),e.build(this)}else this.addFlow("compute",e);for(const e of $l){this.setBuildStage(e),this.context.vertex&&this.context.vertex.isNode&&this.flowNodeFromShaderStage("vertex",this.context.vertex);for(const t of Xl){this.setShaderStage(t);const s=this.flowNodes[t];for(const t of s)"generate"===e?this.flowNode(t):t.build(this)}}return this.setBuildStage(null),this.setShaderStage(null),this.buildCode(),this.buildUpdateNodes(),this}getNodeUniform(e,t){if("float"===t||"int"===t||"uint"===t)return new AS(e);if("vec2"===t||"ivec2"===t||"uvec2"===t)return new NS(e);if("vec3"===t||"ivec3"===t||"uvec3"===t)return new RS(e);if("vec4"===t||"ivec4"===t||"uvec4"===t)return new CS(e);if("color"===t)return new ES(e);if("mat3"===t)return new BS(e);if("mat4"===t)return new IS(e);throw new Error(`Uniform "${t}" not declared.`)}createNodeMaterial(e="NodeMaterial"){throw new Error(`THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${e}() instead.`)}format(e,t,s){if((t=this.getVectorType(t))===(s=this.getVectorType(s))||null===s||this.isReference(s))return e;const i=this.getTypeLength(t),r=this.getTypeLength(s);return 16===i&&9===r?`${this.getType(s)}(${e}[0].xyz, ${e}[1].xyz, ${e}[2].xyz)`:9===i&&4===r?`${this.getType(s)}(${e}[0].xy, ${e}[1].xy)`:i>4||r>4||0===r?e:i===r?`${this.getType(s)}( ${e} )`:i>r?this.format(`${e}.${"xyz".slice(0,r)}`,this.getTypeFromLength(r,this.getComponentType(t)),s):4===r&&i>1?`${this.getType(s)}( ${this.format(e,t,"vec3")}, 1.0 )`:2===i?`${this.getType(s)}( ${this.format(e,t,"vec2")}, 0.0 )`:(1===i&&r>1&&t!==this.getComponentType(s)&&(e=`${this.getType(this.getComponentType(s))}( ${e} )`),`${this.getType(s)}( ${e} )`)}getSignature(){return`// Three.js r${e} - Node System\n`}}class hM{constructor(){this.time=0,this.deltaTime=0,this.frameId=0,this.renderId=0,this.startTime=null,this.updateMap=new WeakMap,this.updateBeforeMap=new WeakMap,this.updateAfterMap=new WeakMap,this.renderer=null,this.material=null,this.camera=null,this.object=null,this.scene=null}_getMaps(e,t){let s=e.get(t);return void 0===s&&(s={renderMap:new WeakMap,frameMap:new WeakMap},e.set(t,s)),s}updateBeforeNode(e){const t=e.getUpdateBeforeType(),s=e.updateReference(this);if(t===Hl.FRAME){const{frameMap:t}=this._getMaps(this.updateBeforeMap,s);t.get(s)!==this.frameId&&!1!==e.updateBefore(this)&&t.set(s,this.frameId)}else if(t===Hl.RENDER){const{renderMap:t}=this._getMaps(this.updateBeforeMap,s);t.get(s)!==this.renderId&&!1!==e.updateBefore(this)&&t.set(s,this.renderId)}else t===Hl.OBJECT&&e.updateBefore(this)}updateAfterNode(e){const t=e.getUpdateAfterType(),s=e.updateReference(this);if(t===Hl.FRAME){const{frameMap:t}=this._getMaps(this.updateAfterMap,s);t.get(s)!==this.frameId&&!1!==e.updateAfter(this)&&t.set(s,this.frameId)}else if(t===Hl.RENDER){const{renderMap:t}=this._getMaps(this.updateAfterMap,s);t.get(s)!==this.renderId&&!1!==e.updateAfter(this)&&t.set(s,this.renderId)}else t===Hl.OBJECT&&e.updateAfter(this)}updateNode(e){const t=e.getUpdateType(),s=e.updateReference(this);if(t===Hl.FRAME){const{frameMap:t}=this._getMaps(this.updateMap,s);t.get(s)!==this.frameId&&!1!==e.update(this)&&t.set(s,this.frameId)}else if(t===Hl.RENDER){const{renderMap:t}=this._getMaps(this.updateMap,s);t.get(s)!==this.renderId&&!1!==e.update(this)&&t.set(s,this.renderId)}else t===Hl.OBJECT&&e.update(this)}update(){this.frameId++,void 0===this.lastTime&&(this.lastTime=performance.now()),this.deltaTime=(performance.now()-this.lastTime)/1e3,this.lastTime=performance.now(),this.time+=this.deltaTime}}class lM{constructor(e,t,s=null,i="",r=!1){this.type=e,this.name=t,this.count=s,this.qualifier=i,this.isConst=r}}lM.isNodeFunctionInput=!0;class uM extends Kl{constructor(e){super(),this.types=e,this.isStructTypeNode=!0}getMemberTypes(){return this.types}}uM.type=Ql("StructType",uM);class cM extends Kl{constructor(...e){super(),this.members=e,this.isOutputStructNode=!0}setup(e){super.setup(e);const t=this.members,s=[];for(let i=0;ir&&(i=s,r=n)}}this._candidateFnCall=s=i(...t)}return s}}fM.type=Ql("FunctionOverloading",fM);const yM=Wu(fM),xM=e=>(...t)=>yM(e,...t);class bM extends Rc{constructor(e=bM.LOCAL,t=1,s=0){super(s),this.scope=e,this.scale=t,this.updateType=Hl.FRAME}update(e){const t=this.scope,s=this.scale;t===bM.LOCAL?this.value+=e.deltaTime*s:t===bM.DELTA?this.value=e.deltaTime*s:t===bM.FRAME?this.value=e.frameId:this.value=e.time*s}serialize(e){super.serialize(e),e.scope=this.scope,e.scale=this.scale}deserialize(e){super.deserialize(e),this.scope=e.scope,this.scale=e.scale}}bM.LOCAL="local",bM.GLOBAL="global",bM.DELTA="delta",bM.FRAME="frame",bM.type=Ql("Timer",bM);const vM=(e,t=0)=>Du(new bM(bM.LOCAL,e,t)),TM=(e,t=0)=>Du(new bM(bM.GLOBAL,e,t)),_M=(e,t=0)=>Du(new bM(bM.DELTA,e,t)),wM=Hu(bM,bM.FRAME).toUint();class SM extends Kl{constructor(e=SM.SINE,t=vM()){super(),this.method=e,this.timeNode=t}getNodeType(e){return this.timeNode.getNodeType(e)}setup(){const e=this.method,t=Du(this.timeNode);let s=null;return e===SM.SINE?s=t.add(.75).mul(2*Math.PI).sin().mul(.5).add(.5):e===SM.SQUARE?s=t.fract().round():e===SM.TRIANGLE?s=t.add(.5).fract().mul(2).sub(1).abs():e===SM.SAWTOOTH&&(s=t.fract()),s}serialize(e){super.serialize(e),e.method=this.method}deserialize(e){super.deserialize(e),this.method=e.method}}SM.SINE="sine",SM.SQUARE="square",SM.TRIANGLE="triangle",SM.SAWTOOTH="sawtooth",SM.type=Ql("Osc",SM);const MM=Wu(SM,SM.SINE),AM=Wu(SM,SM.SQUARE),NM=Wu(SM,SM.TRIANGLE),RM=Wu(SM,SM.SAWTOOTH);class CM extends Kl{constructor(e,t=Um(),s=Ku(0)){super("vec2"),this.countNode=e,this.uvNode=t,this.frameNode=s}setup(){const{frameNode:e,uvNode:t,countNode:s}=this,{width:i,height:r}=s,n=e.mod(i.mul(r)).floor(),o=n.mod(i),a=r.sub(n.add(1).div(i).ceil()),h=s.reciprocal(),l=sc(o,a);return t.add(l).mul(h)}}CM.type=Ql("SpriteSheetUV",CM);const EM=Wu(CM);class BM extends tu{constructor(e,t){super(e,t),this.isStorageArrayElementNode=!0}set storageBufferNode(e){this.node=e}get storageBufferNode(){return this.node}setup(e){return!1===e.isAvailable("storageBuffer")&&(this.node.instanceIndex||!0!==this.node.bufferObject||e.setupPBO(this.node)),super.setup(e)}generate(e,t){let s;const i=e.context.assign;if(!1===e.isAvailable("storageBuffer")){const{node:t}=this;s=t.instanceIndex||!0!==this.node.bufferObject||!0===i?t.build(e):e.generatePBO(this)}else s=super.generate(e);if(!0!==i){const i=this.getNodeType(e);s=e.format(s,i,t)}return s}}BM.type=Ql("StorageArrayElement",BM);const IM=Wu(BM);class PM extends Kl{constructor(e,t=null,s=null,i=Ku(1),r=bg,n=Cg){super("vec4"),this.textureXNode=e,this.textureYNode=t,this.textureZNode=s,this.scaleNode=i,this.positionNode=r,this.normalNode=n}setup(){const{textureXNode:e,textureYNode:t,textureZNode:s,scaleNode:i,positionNode:r,normalNode:n}=this;let o=n.abs().normalize();o=o.div(o.dot(oc(1)));const a=r.yz.mul(i),h=r.zx.mul(i),l=r.xy.mul(i),u=e.value,c=null!==t?t.value:u,d=null!==s?s.value:u,p=Gm(u,a).mul(o.x),m=Gm(c,h).mul(o.y),g=Gm(d,l).mul(o.z);return dd(p,m,g)}}PM.type=Ql("TriplanarTextures",PM);const FM=Wu(PM),zM=(...e)=>FM(...e),UM=new sa,LM=new Ei,OM=new Ei,VM=new Ei,DM=new or,kM=new Ei(0,0,-1),GM=new _i,WM=new Ei,HM=new Ei,jM=new _i,qM=new Qs,$M=new wi,XM=Zy.flipX();let YM=!1;class JM extends km{constructor(e={}){super($M.texture,XM);const{target:t=new Pr,resolution:s=1,generateMipmaps:i=!1,bounces:r=!0}=e;this.target=t,this.resolution=s,this.generateMipmaps=i,this.bounces=r,this.updateBeforeType=r?Hl.RENDER:Hl.FRAME,this.virtualCameras=new WeakMap,this.renderTargets=new WeakMap}_updateResolution(e,t){const s=this.resolution;t.getDrawingBufferSize(qM),e.setSize(Math.round(qM.width*s),Math.round(qM.height*s))}setup(e){return this._updateResolution($M,e.renderer),super.setup(e)}getTextureNode(){return this.textureNode}getVirtualCamera(e){let t=this.virtualCameras.get(e);return void 0===t&&(t=e.clone(),this.virtualCameras.set(e,t)),t}getRenderTarget(e){let t=this.renderTargets.get(e);return void 0===t&&(t=new wi(0,0,{type:Pe}),!0===this.generateMipmaps&&(t.texture.minFilter=1008,t.texture.generateMipmaps=!0),this.renderTargets.set(e,t)),t}updateBefore(e){if(!1===this.bounces&&YM)return!1;YM=!0;const{scene:t,camera:s,renderer:i,material:r}=e,{target:n}=this,o=this.getVirtualCamera(s),a=this.getRenderTarget(o);if(i.getDrawingBufferSize(qM),this._updateResolution(a,i),OM.setFromMatrixPosition(n.matrixWorld),VM.setFromMatrixPosition(s.matrixWorld),DM.extractRotation(n.matrixWorld),LM.set(0,0,1),LM.applyMatrix4(DM),WM.subVectors(OM,VM),WM.dot(LM)>0)return;WM.reflect(LM).negate(),WM.add(OM),DM.extractRotation(s.matrixWorld),kM.set(0,0,-1),kM.applyMatrix4(DM),kM.add(VM),HM.subVectors(OM,kM),HM.reflect(LM).negate(),HM.add(OM),o.coordinateSystem=s.coordinateSystem,o.position.copy(WM),o.up.set(0,1,0),o.up.applyMatrix4(DM),o.up.reflect(LM),o.lookAt(HM),o.near=s.near,o.far=s.far,o.updateMatrixWorld(),o.projectionMatrix.copy(s.projectionMatrix),UM.setFromNormalAndCoplanarPoint(LM,OM),UM.applyMatrix4(o.matrixWorldInverse),GM.set(UM.normal.x,UM.normal.y,UM.normal.z,UM.constant);const h=o.projectionMatrix;jM.x=(Math.sign(GM.x)+h.elements[8])/h.elements[0],jM.y=(Math.sign(GM.y)+h.elements[9])/h.elements[5],jM.z=-1,jM.w=(1+h.elements[10])/h.elements[14],GM.multiplyScalar(1/GM.dot(jM));h.elements[2]=GM.x,h.elements[6]=GM.y,h.elements[10]=GM.z-0,h.elements[14]=GM.w,this.value=a.texture,r.visible=!1;const l=i.getRenderTarget(),u=i.getMRT();i.setMRT(null),i.setRenderTarget(a),i.render(t,o),i.setMRT(u),i.setRenderTarget(l),r.visible=!0,YM=!1}}const ZM=e=>Du(new JM(e));JM.type=Ql("Reflector",JM);const KM=new OT(-1,1,1,-1,0,1);class QM extends Mn{constructor(e=!1){super();const t=!1===e?[0,-1,0,1,2,1]:[0,2,0,0,2,0];this.setAttribute("position",new yn([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new yn(t,2))}}const eA=new QM;class tA extends Wn{constructor(e=null){super(eA,e),this.camera=KM,this.isQuadMesh=!0}renderAsync(e){return e.renderAsync(this,KM)}render(e){e.render(this,KM)}}const sA=new Qs;class iA extends km{constructor(e,t=null,s=null,i={type:Pe}){const r=new wi(t,s,i);super(r.texture,Um()),this.node=e,this.width=t,this.height=s,this.renderTarget=r,this.textureNeedsUpdate=!0,this.autoUpdate=!0,this.updateMap=new WeakMap,this._rttNode=null,this._quadMesh=new tA(new xx),this.updateBeforeType=Hl.RENDER}get autoSize(){return null===this.width}setup(e){return this._rttNode=this.node.context(e.getSharedContext()),this._quadMesh.material.name="RTT",this._quadMesh.material.needsUpdate=!0,super.setup(e)}setSize(e,t){this.width=e,this.height=t;const s=e*this.pixelRatio,i=t*this.pixelRatio;this.renderTarget.setSize(s,i),this.textureNeedsUpdate=!0}setPixelRatio(e){this.pixelRatio=e,this.setSize(this.width,this.height)}updateBefore({renderer:e}){if(!1===this.textureNeedsUpdate&&!1===this.autoUpdate)return;if(this.textureNeedsUpdate=!1,!0===this.autoSize){this.pixelRatio=e.getPixelRatio();const t=e.getSize(sA);this.setSize(t.width,t.height)}this._quadMesh.material.fragmentNode=this._rttNode;const t=e.getRenderTarget();e.setRenderTarget(this.renderTarget),this._quadMesh.render(e),e.setRenderTarget(t)}clone(){const e=new km(this.value,this.uvNode,this.levelNode);return e.sampler=this.sampler,e.referenceNode=this,e}}iA.type=Ql("RTT",iA);const rA=(e,...t)=>Du(new iA(Du(e),...t)),nA=(e,...t)=>e.isTextureNode?e:rA(e,...t);class oA extends Fm{constructor(e=0){super(null,"vec4"),this.isVertexColorNode=!0,this.index=e}getAttributeName(){const e=this.index;return"color"+(e>0?e:"")}generate(e){const t=this.getAttributeName(e);let s;return s=!0===e.hasGeometryAttribute(t)?super.generate(e):e.generateConst(this.nodeType,new _i(1,1,1,1)),s}serialize(e){super.serialize(e),e.index=this.index}deserialize(e){super.deserialize(e),this.index=e.index}}oA.type=Ql("VertexColor",oA);const aA=(...e)=>Du(new oA(...e));class hA extends Kl{constructor(){super("vec2"),this.isPointUVNode=!0}generate(){return"vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )"}}hA.type=Ql("PointUV",hA);const lA=Hu(hA);class uA extends Kl{constructor(e=uA.BACKGROUND_BLURRINESS,t=null){super(),this.scope=e,this.scene=t}setup(e){const t=this.scope,s=null!==this.scene?this.scene:e.scene;let i;return t===uA.BACKGROUND_BLURRINESS?i=Zg("backgroundBlurriness","float",s):t===uA.BACKGROUND_INTENSITY?i=Zg("backgroundIntensity","float",s):console.error("THREE.SceneNode: Unknown scope:",t),i}}uA.BACKGROUND_BLURRINESS="backgroundBlurriness",uA.BACKGROUND_INTENSITY="backgroundIntensity",uA.type=Ql("Scene",uA);const cA=Hu(uA,uA.BACKGROUND_BLURRINESS),dA=Hu(uA,uA.BACKGROUND_INTENSITY),pA="point-list",mA="line-list",gA="line-strip",fA="triangle-list",yA="triangle-strip",xA="never",bA="less",vA="equal",TA="less-equal",_A="greater",wA="not-equal",SA="greater-equal",MA="always",AA="store",NA="load",RA="clear",CA="ccw",EA="none",BA="front",IA="back",PA="uint16",FA="uint32",zA={R8Unorm:"r8unorm",R8Snorm:"r8snorm",R8Uint:"r8uint",R8Sint:"r8sint",R16Uint:"r16uint",R16Sint:"r16sint",R16Float:"r16float",RG8Unorm:"rg8unorm",RG8Snorm:"rg8snorm",RG8Uint:"rg8uint",RG8Sint:"rg8sint",R32Uint:"r32uint",R32Sint:"r32sint",R32Float:"r32float",RG16Uint:"rg16uint",RG16Sint:"rg16sint",RG16Float:"rg16float",RGBA8Unorm:"rgba8unorm",RGBA8UnormSRGB:"rgba8unorm-srgb",RGBA8Snorm:"rgba8snorm",RGBA8Uint:"rgba8uint",RGBA8Sint:"rgba8sint",BGRA8Unorm:"bgra8unorm",BGRA8UnormSRGB:"bgra8unorm-srgb",RGB9E5UFloat:"rgb9e5ufloat",RGB10A2Unorm:"rgb10a2unorm",RG11B10uFloat:"rgb10a2unorm",RG32Uint:"rg32uint",RG32Sint:"rg32sint",RG32Float:"rg32float",RGBA16Uint:"rgba16uint",RGBA16Sint:"rgba16sint",RGBA16Float:"rgba16float",RGBA32Uint:"rgba32uint",RGBA32Sint:"rgba32sint",RGBA32Float:"rgba32float",Stencil8:"stencil8",Depth16Unorm:"depth16unorm",Depth24Plus:"depth24plus",Depth24PlusStencil8:"depth24plus-stencil8",Depth32Float:"depth32float",Depth32FloatStencil8:"depth32float-stencil8",BC1RGBAUnorm:"bc1-rgba-unorm",BC1RGBAUnormSRGB:"bc1-rgba-unorm-srgb",BC2RGBAUnorm:"bc2-rgba-unorm",BC2RGBAUnormSRGB:"bc2-rgba-unorm-srgb",BC3RGBAUnorm:"bc3-rgba-unorm",BC3RGBAUnormSRGB:"bc3-rgba-unorm-srgb",BC4RUnorm:"bc4-r-unorm",BC4RSnorm:"bc4-r-snorm",BC5RGUnorm:"bc5-rg-unorm",BC5RGSnorm:"bc5-rg-snorm",BC6HRGBUFloat:"bc6h-rgb-ufloat",BC6HRGBFloat:"bc6h-rgb-float",BC7RGBAUnorm:"bc7-rgba-unorm",BC7RGBAUnormSRGB:"bc7-rgba-srgb",ETC2RGB8Unorm:"etc2-rgb8unorm",ETC2RGB8UnormSRGB:"etc2-rgb8unorm-srgb",ETC2RGB8A1Unorm:"etc2-rgb8a1unorm",ETC2RGB8A1UnormSRGB:"etc2-rgb8a1unorm-srgb",ETC2RGBA8Unorm:"etc2-rgba8unorm",ETC2RGBA8UnormSRGB:"etc2-rgba8unorm-srgb",EACR11Unorm:"eac-r11unorm",EACR11Snorm:"eac-r11snorm",EACRG11Unorm:"eac-rg11unorm",EACRG11Snorm:"eac-rg11snorm",ASTC4x4Unorm:"astc-4x4-unorm",ASTC4x4UnormSRGB:"astc-4x4-unorm-srgb",ASTC5x4Unorm:"astc-5x4-unorm",ASTC5x4UnormSRGB:"astc-5x4-unorm-srgb",ASTC5x5Unorm:"astc-5x5-unorm",ASTC5x5UnormSRGB:"astc-5x5-unorm-srgb",ASTC6x5Unorm:"astc-6x5-unorm",ASTC6x5UnormSRGB:"astc-6x5-unorm-srgb",ASTC6x6Unorm:"astc-6x6-unorm",ASTC6x6UnormSRGB:"astc-6x6-unorm-srgb",ASTC8x5Unorm:"astc-8x5-unorm",ASTC8x5UnormSRGB:"astc-8x5-unorm-srgb",ASTC8x6Unorm:"astc-8x6-unorm",ASTC8x6UnormSRGB:"astc-8x6-unorm-srgb",ASTC8x8Unorm:"astc-8x8-unorm",ASTC8x8UnormSRGB:"astc-8x8-unorm-srgb",ASTC10x5Unorm:"astc-10x5-unorm",ASTC10x5UnormSRGB:"astc-10x5-unorm-srgb",ASTC10x6Unorm:"astc-10x6-unorm",ASTC10x6UnormSRGB:"astc-10x6-unorm-srgb",ASTC10x8Unorm:"astc-10x8-unorm",ASTC10x8UnormSRGB:"astc-10x8-unorm-srgb",ASTC10x10Unorm:"astc-10x10-unorm",ASTC10x10UnormSRGB:"astc-10x10-unorm-srgb",ASTC12x10Unorm:"astc-12x10-unorm",ASTC12x10UnormSRGB:"astc-12x10-unorm-srgb",ASTC12x12Unorm:"astc-12x12-unorm",ASTC12x12UnormSRGB:"astc-12x12-unorm-srgb"},UA="clamp-to-edge",LA="repeat",OA="mirror-repeat",VA="linear",DA="nearest",kA="zero",GA="one",WA="src",HA="one-minus-src",jA="src-alpha",qA="one-minus-src-alpha",$A="dst",XA="one-minus-dst",YA="dst-alpha",JA="one-minus-dst-alpha",ZA="src-alpha-saturated",KA="constant",QA="one-minus-constant",eN="add",tN="subtract",sN="reverse-subtract",iN="min",rN="max",nN=0,oN=15,aN="keep",hN="zero",lN="replace",uN="invert",cN="increment-clamp",dN="decrement-clamp",pN="increment-wrap",mN="decrement-wrap",gN="storage",fN="read-only-storage",yN="write-only",xN="read-only",bN="float",vN="unfilterable-float",TN="depth",_N="sint",wN="uint",SN="2d",MN="3d",AN="2d",NN="2d-array",RN="cube",CN="3d",EN="all",BN="vertex",IN="instance",PN={DepthClipControl:"depth-clip-control",Depth32FloatStencil8:"depth32float-stencil8",TextureCompressionBC:"texture-compression-bc",TextureCompressionETC2:"texture-compression-etc2",TextureCompressionASTC:"texture-compression-astc",TimestampQuery:"timestamp-query",IndirectFirstInstance:"indirect-first-instance",ShaderF16:"shader-f16",RG11B10UFloat:"rg11b10ufloat-renderable",BGRA8UNormStorage:"bgra8unorm-storage",Float32Filterable:"float32-filterable",ClipDistances:"clip-distances",DualSourceBlending:"dual-source-blending",Subgroups:"subgroups"};class FN extends Hg{constructor(e,t,s=0){super(e,t,s),this.isStorageBufferNode=!0,this.access=gN,this.bufferObject=!1,this.bufferCount=s,this._attribute=null,this._varying=null,this.global=!0,!0!==e.isStorageBufferAttribute&&!0!==e.isStorageInstancedBufferAttribute&&(e.isInstancedBufferAttribute?e.isStorageInstancedBufferAttribute=!0:e.isStorageBufferAttribute=!0)}getHash(e){if(0===this.bufferCount){let t=e.globalCache.getData(this.value);return void 0===t&&(t={node:this},e.globalCache.setData(this.value,t)),t.node.uuid}return this.uuid}getInputType(){return"storageBuffer"}element(e){return IM(this,e)}setBufferObject(e){return this.bufferObject=e,this}setAccess(e){return this.access=e,this}toReadOnly(){return this.setAccess(fN)}generate(e){if(e.isAvailable("storageBuffer"))return super.generate(e);const t=this.getNodeType(e);null===this._attribute&&(this._attribute=mm(this.value),this._varying=em(this._attribute));const s=this._varying.build(e,t);return e.registerTransform(s,this._attribute),s}}FN.type=Ql("StorageBuffer",FN);const zN=(e,t,s)=>Du(new FN(e,t,s)),UN=(e,t,s)=>Du(new FN(e,t,s).setBufferObject(!0));class LN extends km{constructor(e,t,s=null){super(e,t),this.storeNode=s,this.isStorageTextureNode=!0,this.access=yN}getInputType(){return"storageTexture"}setup(e){super.setup(e);e.getNodeProperties(this).storeNode=this.storeNode}setAccess(e){return this.access=e,this}generate(e,t){let s;return s=null!==this.storeNode?this.generateStore(e):super.generate(e,t),s}toReadOnly(){return this.setAccess(xN)}toWriteOnly(){return this.setAccess(yN)}generateStore(e){const t=e.getNodeProperties(this),{uvNode:s,storeNode:i}=t,r=super.generate(e,"property"),n=s.build(e,"uvec2"),o=i.build(e,"vec4"),a=e.generateTextureStore(e,r,n,o);e.addLineFlowCode(a)}}LN.type=Ql("StorageTexture",LN);const ON=Wu(LN),VN=(e,t,s)=>{const i=ON(e,t,s);return null!==s&&i.append(),i};class DN extends Jg{constructor(e,t,s=null){super(e,t,s),this.userData=s}update(e){this.reference=null!==this.userData?this.userData:e.object.userData,super.update(e)}}DN.type=Ql("UserData",DN);const kN=(e,t,s)=>Du(new DN(e,t,s));class GN extends iu{constructor(e,t){super(),this.sourceNode=e,this.stepsNode=t}setup(){const{sourceNode:e,stepsNode:t}=this;return e.mul(t).floor().div(t)}}GN.type=Ql("Posterize",GN);const WN=Wu(GN);let HN=null;class jN extends tx{constructor(e=Zy,t=null){null===HN&&(HN=new Xa),super(e,t,HN)}updateReference(){return this}}jN.type=Ql("ViewportSharedTexture",jN);const qN=Wu(jN),$N=new Qs;class XN extends km{constructor(e,t){super(t),this.passNode=e,this.setUpdateMatrix(!1)}setup(e){return e.object.isQuadMesh&&this.passNode.build(e),super.setup(e)}clone(){return new this.constructor(this.passNode,this.value)}}XN.type=Ql("PassTexture",XN);class YN extends XN{constructor(e,t,s=!1){super(e,null),this.textureName=t,this.previousTexture=s}updateTexture(){this.value=this.previousTexture?this.passNode.getPreviousTexture(this.textureName):this.passNode.getTexture(this.textureName)}setup(e){return this.updateTexture(),super.setup(e)}clone(){return new this.constructor(this.passNode,this.textureName,this.previousTexture)}}YN.type=Ql("PassMultipleTexture",YN);class JN extends iu{constructor(e,t,s,i={}){super("vec4"),this.scope=e,this.scene=t,this.camera=s,this.options=i,this._pixelRatio=1,this._width=1,this._height=1;const r=new Qa;r.isRenderTargetTexture=!0,r.name="depth";const n=new wi(this._width*this._pixelRatio,this._height*this._pixelRatio,{type:Pe,...i});n.texture.name="output",n.depthTexture=r,this.renderTarget=n,this.updateBeforeType=Hl.FRAME,this._textures={output:n.texture,depth:r},this._textureNodes={},this._linearDepthNodes={},this._viewZNodes={},this._previousTextures={},this._previousTextureNodes={},this._cameraNear=Cc(0),this._cameraFar=Cc(0),this._mrt=null,this.isPassNode=!0}setMRT(e){return this._mrt=e,this}getMRT(){return this._mrt}isGlobal(){return!0}getTexture(e){let t=this._textures[e];if(void 0===t){t=this.renderTarget.texture.clone(),t.isRenderTargetTexture=!0,t.name=e,this._textures[e]=t,this.renderTarget.textures.push(t)}return t}getPreviousTexture(e){let t=this._previousTextures[e];return void 0===t&&(t=this.getTexture(e).clone(),t.isRenderTargetTexture=!0,this._previousTextures[e]=t),t}toggleTexture(e){const t=this._previousTextures[e];if(void 0!==t){const s=this._textures[e],i=this.renderTarget.textures.indexOf(s);this.renderTarget.textures[i]=t,this._textures[e]=t,this._previousTextures[e]=s,this._textureNodes[e].updateTexture(),this._previousTextureNodes[e].updateTexture()}}getTextureNode(e="output"){let t=this._textureNodes[e];return void 0===t&&(this._textureNodes[e]=t=Du(new YN(this,e)),this._textureNodes[e].updateTexture()),t}getPreviousTextureNode(e="output"){let t=this._previousTextureNodes[e];return void 0===t&&(void 0===this._textureNodes[e]&&this.getTextureNode(e),this._previousTextureNodes[e]=t=Du(new YN(this,e,!0)),this._previousTextureNodes[e].updateTexture()),t}getViewZNode(e="depth"){let t=this._viewZNodes[e];if(void 0===t){const s=this._cameraNear,i=this._cameraFar;this._viewZNodes[e]=t=cx(this.getTextureNode(e),s,i)}return t}getLinearDepthNode(e="depth"){let t=this._linearDepthNodes[e];if(void 0===t){const s=this._cameraNear,i=this._cameraFar,r=this.getViewZNode(e);this._linearDepthNodes[e]=t=hx(r,s,i)}return t}setup({renderer:e}){return this.renderTarget.samples=void 0===this.options.samples?e.samples:this.options.samples,!0===e.backend.isWebGLBackend&&(this.renderTarget.samples=0),this.renderTarget.depthTexture.isMultisampleRenderTargetTexture=this.renderTarget.samples>1,this.scope===JN.COLOR?this.getTextureNode():this.getLinearDepthNode()}updateBefore(e){const{renderer:t}=e,{scene:s,camera:i}=this;this._pixelRatio=t.getPixelRatio();const r=t.getSize($N);this.setSize(r.width,r.height);const n=t.getRenderTarget(),o=t.getMRT();this._cameraNear.value=i.near,this._cameraFar.value=i.far;for(const e in this._previousTextures)this.toggleTexture(e);t.setRenderTarget(this.renderTarget),t.setMRT(this._mrt),t.render(s,i),t.setRenderTarget(n),t.setMRT(o)}setSize(e,t){this._width=e,this._height=t;const s=this._width*this._pixelRatio,i=this._height*this._pixelRatio;this.renderTarget.setSize(s,i)}setPixelRatio(e){this._pixelRatio=e,this.setSize(this._width,this._height)}dispose(){this.renderTarget.dispose()}}JN.COLOR="color",JN.DEPTH="depth",JN.type=Ql("Pass",JN);const ZN=(e,t,s)=>Du(new JN(JN.COLOR,e,t,s)),KN=(e,t)=>Du(new XN(e,t)),QN=(e,t)=>Du(new JN(JN.DEPTH,e,t)),eR=new tA,tR=new tA;class sR extends iu{constructor(e,t=null,s=2){super("vec4"),this.textureNode=e,this.directionNode=t,this.sigma=s,this._invSize=Cc(new Qs),this._passDirection=Cc(new Qs),this._horizontalRT=new wi,this._horizontalRT.texture.name="GaussianBlurNode.horizontal",this._verticalRT=new wi,this._verticalRT.texture.name="GaussianBlurNode.vertical",this._textureNode=KN(this,this._verticalRT.texture),this.updateBeforeType=Hl.RENDER,this.resolution=new Qs(1,1)}setSize(e,t){e=Math.max(Math.round(e*this.resolution.x),1),t=Math.max(Math.round(t*this.resolution.y),1),this._invSize.value.set(1/e,1/t),this._horizontalRT.setSize(e,t),this._verticalRT.setSize(e,t)}updateBefore(e){const{renderer:t}=e,s=this.textureNode,i=s.value,r=t.getRenderTarget(),n=t.getMRT(),o=s.value;eR.material=this._material,tR.material=this._material,this.setSize(i.image.width,i.image.height);const a=i.type;this._horizontalRT.texture.type=a,this._verticalRT.texture.type=a,t.setMRT(null),t.setRenderTarget(this._horizontalRT),this._passDirection.value.set(1,0),eR.render(t),s.value=this._horizontalRT.texture,t.setRenderTarget(this._verticalRT),this._passDirection.value.set(0,1),tR.render(t),t.setRenderTarget(r),t.setMRT(n),s.value=o}getTextureNode(){return this._textureNode}setup(e){const t=this.textureNode;if(!0!==t.isTextureNode)return console.error("GaussianBlurNode requires a TextureNode."),uc();const s=t.uvNode||Um(),i=sc(this.directionNode||1),r=e=>t.uv(e),n=ju((()=>{const e=3+2*this.sigma,t=this._getCoefficients(e),n=this._invSize,o=i.mul(this._passDirection),a=Ku(t[0]).toVar(),h=uc(r(s).mul(a)).toVar();for(let i=1;iDu(new sR(nA(e),t,s)),rR=new Qs,nR=new tA;class oR extends iu{constructor(e,t=.96){super(e),this.textureNode=e,this.textureNodeOld=Gm(),this.damp=Cc(t),this._compRT=new wi,this._compRT.texture.name="AfterImageNode.comp",this._oldRT=new wi,this._oldRT.texture.name="AfterImageNode.old",this._textureNode=KN(this,this._compRT.texture),this.updateBeforeType=Hl.RENDER}getTextureNode(){return this._textureNode}setSize(e,t){this._compRT.setSize(e,t),this._oldRT.setSize(e,t)}updateBefore(e){const{renderer:t}=e,s=this.textureNode,i=s.value.type;this._compRT.texture.type=i,this._oldRT.texture.type=i,t.getDrawingBufferSize(rR),this.setSize(rR.x,rR.y);const r=t.getRenderTarget(),n=s.value;this.textureNodeOld.value=this._oldRT.texture,t.setRenderTarget(this._compRT),nR.render(t);const o=this._oldRT;this._oldRT=this._compRT,this._compRT=o,t.setRenderTarget(r),s.value=n}setup(e){const t=this.textureNode,s=this.textureNodeOld,i=t.uvNode||Um();s.uvNode=i;const r=ju((([e,t])=>{const s=Ku(t).toVar(),i=uc(e).toVar();return Tp(ap(i.sub(s)),0)})),n=ju((()=>{const e=uc(s),n=uc((e=>t.uv(e))(i));return e.mulAssign(this.damp.mul(r(e,.1))),Tp(n,e)})),o=this._materialComposed||(this._materialComposed=new xx);o.name="AfterImage",o.fragmentNode=n(),nR.material=o;return e.getNodeProperties(this).textureNode=t,this._textureNode}dispose(){this._compRT.dispose(),this._oldRT.dispose()}}const aR=(e,t)=>Du(new oR(nA(e),t)),hR=ju((([e])=>pR(e.rgb))),lR=ju((([e,t=Ku(1)])=>t.mix(pR(e.rgb),e.rgb))),uR=ju((([e,t=Ku(1)])=>{const s=dd(e.r,e.g,e.b).div(3),i=e.r.max(e.g.max(e.b)),r=i.sub(s).mul(t).mul(-3);return Up(e.rgb,i,r)})),cR=ju((([e,t=Ku(1)])=>{const s=oc(.57735,.57735,.57735),i=t.cos();return oc(e.rgb.mul(i).add(s.cross(e.rgb).mul(t.sin()).add(s.mul(Np(s,e.rgb).mul(i.oneMinus())))))})),dR=new Ei,pR=(e,t=oc(...di.getLuminanceCoefficients(dR)))=>Np(e,t),mR=(e,t)=>Up(oc(0),e,pR(e).sub(t).max(0)),gR=new tA;class fR extends iu{constructor(e,t,s,i){super("vec4"),this.textureNode=e,this.tresholdNode=t,this.scaleNode=s,this.colorNode=oc(.1,0,1),this.samples=i,this.resolution=new Qs(1,1),this._renderTarget=new wi,this._renderTarget.texture.name="anamorphic",this._invSize=Cc(new Qs),this._textureNode=KN(this,this._renderTarget.texture),this.updateBeforeType=Hl.RENDER}getTextureNode(){return this._textureNode}setSize(e,t){this._invSize.value.set(1/e,1/t),e=Math.max(Math.round(e*this.resolution.x),1),t=Math.max(Math.round(t*this.resolution.y),1),this._renderTarget.setSize(e,t)}updateBefore(e){const{renderer:t}=e,s=this.textureNode,i=s.value;this._renderTarget.texture.type=i.type;const r=t.getRenderTarget(),n=s.value;gR.material=this._material,this.setSize(i.image.width,i.image.height),t.setRenderTarget(this._renderTarget),gR.render(t),t.setRenderTarget(r),s.value=n}setup(e){const t=this.textureNode,s=t.uvNode||Um(),i=ju((()=>{const e=this.samples,i=Math.floor(e/2),r=oc(0).toVar();return Cy({start:-i,end:i},(({i:e})=>{const n=Ku(e).abs().div(i).oneMinus(),o=(e=>t.uv(e))(sc(s.x.add(this._invSize.x.mul(e).mul(this.scaleNode)),s.y)),a=mR(o,this.tresholdNode).mul(n);r.addAssign(a)})),r.mul(this.colorNode)})),r=this._material||(this._material=new xx);r.name="Anamorphic",r.fragmentNode=i();return e.getNodeProperties(this).textureNode=t,this._textureNode}dispose(){this._renderTarget.dispose()}}const yR=(e,t=.9,s=3,i=32)=>Du(new fR(nA(e),Du(t),Du(s),i));class xR extends iu{constructor(e){super(),this.textureNode=e,this.updateBeforeType=Hl.RENDER,this._invSize=Cc(new Qs)}updateBefore(){const e=this.textureNode.value;this._invSize.value.set(1/e.image.width,1/e.image.height)}setup(){const{textureNode:e}=this,t=e.uvNode||Um(),s=t=>e.uv(t);return ju((()=>{const e=this._invSize,i=gc(-1,-2,-1,0,0,0,1,2,1),r=gc(-1,0,1,-2,0,2,-1,0,1),n=pR(s(t.add(e.mul(sc(-1,-1)))).xyz),o=pR(s(t.add(e.mul(sc(-1,0)))).xyz),a=pR(s(t.add(e.mul(sc(-1,1)))).xyz),h=pR(s(t.add(e.mul(sc(0,-1)))).xyz),l=pR(s(t.add(e.mul(sc(0,0)))).xyz),u=pR(s(t.add(e.mul(sc(0,1)))).xyz),c=pR(s(t.add(e.mul(sc(1,-1)))).xyz),d=pR(s(t.add(e.mul(sc(1,0)))).xyz),p=pR(s(t.add(e.mul(sc(1,1)))).xyz),m=dd(i[0][0].mul(n),i[1][0].mul(h),i[2][0].mul(c),i[0][1].mul(o),i[1][1].mul(l),i[2][1].mul(d),i[0][2].mul(a),i[1][2].mul(u),i[2][2].mul(p)),g=dd(r[0][0].mul(n),r[1][0].mul(h),r[2][0].mul(c),r[0][1].mul(o),r[1][1].mul(l),r[2][1].mul(d),r[0][2].mul(a),r[1][2].mul(u),r[2][2].mul(p)),f=m.mul(m).add(g.mul(g)).sqrt();return uc(oc(f),1)}))()}}xR.type=Ql("SobelOperator",xR);const bR=e=>Du(new xR(nA(e)));class vR extends iu{constructor(e,t,s,i,r){super(),this.textureNode=e,this.viewZNode=t,this.focusNode=s,this.apertureNode=i,this.maxblurNode=r,this._aspect=Cc(0),this.updateBeforeType=Hl.RENDER}updateBefore(){const e=this.textureNode.value;this._aspect.value=e.image.width/e.image.height}setup(){const e=this.textureNode,t=e.uvNode||Um(),s=t=>e.uv(t);return ju((()=>{const e=sc(1,this._aspect),i=this.focusNode.add(this.viewZNode),r=sc(Lp(i.mul(this.apertureNode),this.maxblurNode.negate(),this.maxblurNode)),n=r.mul(.9),o=r.mul(.7),a=r.mul(.4);let h=uc(0);return h=h.add(s(t)),h=h.add(s(t.add(sc(0,.4).mul(e).mul(r)))),h=h.add(s(t.add(sc(.15,.37).mul(e).mul(r)))),h=h.add(s(t.add(sc(.29,.29).mul(e).mul(r)))),h=h.add(s(t.add(sc(-.37,.15).mul(e).mul(r)))),h=h.add(s(t.add(sc(.4,0).mul(e).mul(r)))),h=h.add(s(t.add(sc(.37,-.15).mul(e).mul(r)))),h=h.add(s(t.add(sc(.29,-.29).mul(e).mul(r)))),h=h.add(s(t.add(sc(-.15,-.37).mul(e).mul(r)))),h=h.add(s(t.add(sc(0,-.4).mul(e).mul(r)))),h=h.add(s(t.add(sc(-.15,.37).mul(e).mul(r)))),h=h.add(s(t.add(sc(-.29,.29).mul(e).mul(r)))),h=h.add(s(t.add(sc(.37,.15).mul(e).mul(r)))),h=h.add(s(t.add(sc(-.4,0).mul(e).mul(r)))),h=h.add(s(t.add(sc(-.37,-.15).mul(e).mul(r)))),h=h.add(s(t.add(sc(-.29,-.29).mul(e).mul(r)))),h=h.add(s(t.add(sc(.15,-.37).mul(e).mul(r)))),h=h.add(s(t.add(sc(.15,.37).mul(e).mul(n)))),h=h.add(s(t.add(sc(-.37,.15).mul(e).mul(n)))),h=h.add(s(t.add(sc(.37,-.15).mul(e).mul(n)))),h=h.add(s(t.add(sc(-.15,-.37).mul(e).mul(n)))),h=h.add(s(t.add(sc(-.15,.37).mul(e).mul(n)))),h=h.add(s(t.add(sc(.37,.15).mul(e).mul(n)))),h=h.add(s(t.add(sc(-.37,-.15).mul(e).mul(n)))),h=h.add(s(t.add(sc(.15,-.37).mul(e).mul(n)))),h=h.add(s(t.add(sc(.29,.29).mul(e).mul(o)))),h=h.add(s(t.add(sc(.4,0).mul(e).mul(o)))),h=h.add(s(t.add(sc(.29,-.29).mul(e).mul(o)))),h=h.add(s(t.add(sc(0,-.4).mul(e).mul(o)))),h=h.add(s(t.add(sc(-.29,.29).mul(e).mul(o)))),h=h.add(s(t.add(sc(-.4,0).mul(e).mul(o)))),h=h.add(s(t.add(sc(-.29,-.29).mul(e).mul(o)))),h=h.add(s(t.add(sc(0,.4).mul(e).mul(o)))),h=h.add(s(t.add(sc(.29,.29).mul(e).mul(a)))),h=h.add(s(t.add(sc(.4,0).mul(e).mul(a)))),h=h.add(s(t.add(sc(.29,-.29).mul(e).mul(a)))),h=h.add(s(t.add(sc(0,-.4).mul(e).mul(a)))),h=h.add(s(t.add(sc(-.29,.29).mul(e).mul(a)))),h=h.add(s(t.add(sc(-.4,0).mul(e).mul(a)))),h=h.add(s(t.add(sc(-.29,-.29).mul(e).mul(a)))),h=h.add(s(t.add(sc(0,.4).mul(e).mul(a)))),h=h.div(41),h.a=1,uc(h)}))()}}vR.type=Ql("DepthOfField",vR);const TR=(e,t,s=1,i=.025,r=1)=>Du(new vR(nA(e),Du(t),Du(s),Du(i),Du(r)));class _R extends iu{constructor(e,t=new Qs(.5,.5),s=1.57,i=1){super("vec4"),this.inputNode=e,this.center=Cc(t),this.angle=Cc(s),this.scale=Cc(i)}setup(){const e=this.inputNode,t=ju((()=>{const e=ep(this.angle),t=tp(this.angle),s=Um().mul(Yy).sub(this.center),i=sc(t.mul(s.x).sub(e.mul(s.y)),e.mul(s.x).add(t.mul(s.y))).mul(this.scale);return ep(i.x).mul(ep(i.y)).mul(4)})),s=ju((()=>{const s=e,i=dd(s.r,s.g,s.b).div(3);return uc(oc(i.mul(10).sub(5).add(t())),s.a)}));return s()}}_R.type=Ql("DotScreen",_R);const wR=(e,t,s,i)=>Du(new _R(Du(e),t,s,i));class SR extends iu{constructor(e,t=.005,s=0){super("vec4"),this.textureNode=e,this.amount=Cc(t),this.angle=Cc(s)}setup(){const{textureNode:e}=this,t=e.uvNode||Um(),s=t=>e.uv(t);return ju((()=>{const e=sc(tp(this.angle),ep(this.angle)).mul(this.amount),i=s(t.add(e)),r=s(t),n=s(t.sub(e));return uc(i.r,r.g,n.b,r.a)}))()}}SR.type=Ql("RGBShift",SR);const MR=(e,t,s)=>Du(new SR(nA(e),t,s));class AR extends iu{constructor(e,t=null,s=null){super(),this.inputNode=e,this.intensityNode=t,this.uvNode=s}setup(){const e=this.uvNode||Um(),t=ju((()=>{const t=this.inputNode.rgb,s=Gp(Qd(e.add(vM())));let i=t.add(t.mul(Lp(s.add(.1),0,1)));return null!==this.intensityNode&&(i=Up(t,i,this.intensityNode)),uc(i,this.inputNode.a)}));return t()}}AR.type=Ql("Film",AR);const NR=Wu(AR);class RR extends iu{constructor(e,t,s,i){super(),this.inputNode=e,this.lutNode=t,this.size=Cc(s),this.intensityNode=i}setup(){const{inputNode:e,lutNode:t}=this,s=ju((()=>{const s=e,i=Ku(1).div(this.size),r=Ku(.5).div(this.size),n=oc(r).add(s.rgb.mul(Ku(1).sub(i))),o=uc((e=>t.uv(e))(n).rgb,s.a);return uc(Up(s,o,this.intensityNode))}));return s()}}RR.type=Ql("Lut3D",RR);const CR=(e,t,s,i)=>Du(new RR(Du(e),Du(t),s,Du(i))),ER=new tA,BR=new Yr,IR=new Qs;class PR extends iu{constructor(e,t,s){super(),this.depthNode=e,this.normalNode=t,this.radius=Cc(.25),this.resolution=Cc(new Qs),this.thickness=Cc(1),this.distanceExponent=Cc(1),this.distanceFallOff=Cc(1),this.scale=Cc(1),this.noiseNode=Gm(function(e=5){const t=Math.floor(e)%2==0?Math.floor(e)+1:Math.floor(e),s=function(e){const t=Math.floor(e)%2==0?Math.floor(e)+1:Math.floor(e),s=t*t,i=Array(s).fill(0);let r=Math.floor(t/2),n=t-1;for(let e=1;e<=s;)-1===r&&n===t?(n=t-2,r=0):(n===t&&(n=0),r<0&&(r=t-1)),0===i[r*t+n]?(i[r*t+n]=e++,n++,r--):(n-=2,r++);return i}(t),i=s.length,r=new Uint8Array(4*i);for(let e=0;ethis.depthNode.uv(e).x,i=e=>this.noiseNode.uv(e),r=ju((([e])=>{const t=this.cameraProjectionMatrix.mul(uc(e,1));let i=t.xy.div(t.w).mul(.5).add(.5).toVar();i=sc(i.x,i.y.oneMinus());const r=s(i);return oc(i,r)})),n=ju((([e,t])=>{e=sc(e.x,e.y.oneMinus()).mul(2).sub(1);const s=uc(oc(e,t),1),i=uc(this.cameraProjectionMatrixInverse.mul(s));return i.xyz.div(i.w)})),o=ju((()=>{const e=s(t);e.greaterThanEqual(1).discard();const o=n(t,e),a=this.normalNode.rgb.normalize(),h=this.radius,l=Om(this.noiseNode,0);let u=sc(t.x,t.y.oneMinus());u=u.mul(this.resolution.div(l));const c=i(u),d=c.xyz.mul(2).sub(1),p=oc(d.xy,0).normalize(),m=oc(p.y.mul(-1),p.x,0),g=gc(p,m,oc(0,0,1)),f=this.SAMPLES.lessThan(30).select(3,5),y=dd(this.SAMPLES,f.sub(1)).div(f),x=Ku(0).toVar();return Cy({start:Qu(0),end:f,type:"int",condition:"<"},(({i:e})=>{const t=Ku(e).div(Ku(f)).mul(Ld),s=uc(tp(t),ep(t),0,dd(.5,md(.5,c.w)));s.xyz=Kd(g.mul(s.xyz));const i=Kd(o.xyz.negate()),l=Kd(Rp(s.xyz,i)),u=Rp(l,i),d=Kd(a.sub(l.mul(Np(a,l)))),p=Rp(d,l),m=sc(Np(i,p),Np(i,p.negate())).toVar();Cy({end:y,type:"int",name:"j",condition:"<"},(({j:e})=>{const t=s.xyz.mul(h).mul(s.w).mul(Cp(gd(Ku(e).add(1),Ku(y)),this.distanceExponent)),a=r(o.add(t)),l=n(a.xy,a.z).sub(o);Yu(op(l.z).lessThan(this.thickness),(()=>{const t=Np(i,Kd(l));m.x.addAssign(Tp(0,md(t.sub(m.x),Up(1,Ku(2).div(Ku(e).add(2)),this.distanceFallOff))))}));const u=r(o.sub(t)),c=n(u.xy,u.z).sub(o);Yu(op(c.z).lessThan(this.thickness),(()=>{const t=Np(i,Kd(c));m.y.addAssign(Tp(0,md(t.sub(m.y),Up(1,Ku(2).div(Ku(e).add(2)),this.distanceFallOff))))}))}));const b=Xd(pd(1,m.mul(m))),v=Np(d,u),T=Np(d,i),_=md(.5,rp(m.y).sub(rp(m.x)).add(b.x.mul(m.x).sub(b.y.mul(m.y)))),w=md(.5,pd(2,m.x.mul(m.x)).sub(m.y.mul(m.y))),S=v.mul(_).add(T.mul(w));x.addAssign(S)})),x.assign(Lp(x.div(f),0,1)),x.assign(Cp(x,this.scale)),uc(oc(x),1)})),a=this._material||(this._material=new xx);return a.fragmentNode=o().context(e.getSharedContext()),a.name="GTAO",a.needsUpdate=!0,this._textureNode}dispose(){this._aoRenderTarget.dispose()}}PR.type=Ql("GTAO",PR);const FR=(e,t,s)=>Du(new PR(Du(e),Du(t),s));class zR extends iu{constructor(e,t,s,i,r){super(),this.textureNode=e,this.depthNode=t,this.normalNode=s,this.noiseNode=i,this.cameraProjectionMatrixInverse=Cc(r.projectionMatrixInverse),this.lumaPhi=Cc(5),this.depthPhi=Cc(5),this.normalPhi=Cc(5),this.radius=Cc(5),this.index=Cc(0),this._resolution=Cc(new Qs),this._sampleVectors=Xg(function(e,t,s){const i=function(e,t,s){const i=[];for(let r=0;rthis.textureNode.uv(e),s=e=>this.depthNode.uv(e).x,i=e=>this.normalNode.uv(e),r=e=>this.noiseNode.uv(e),n=ju((([e,t])=>{e=sc(e.x,e.y.oneMinus()).mul(2).sub(1);const s=uc(oc(e,t),1),i=uc(this.cameraProjectionMatrixInverse.mul(s));return i.xyz.div(i.w)})),o=ju((([e,r,o,a])=>{const h=t(a),l=s(a),u=i(a).rgb.normalize(),c=h.rgb,d=n(a,l),p=Np(r,u).toVar(),m=Cp(Tp(p,0),this.normalPhi).toVar(),g=op(pR(c).sub(pR(e))).toVar(),f=Tp(Ku(1).sub(g.div(this.lumaPhi)),0).toVar(),y=op(Np(o.sub(d),r)).toVar(),x=Tp(Ku(1).sub(y.div(this.depthPhi)),0),b=f.mul(x).mul(m);return uc(c.mul(b),b)})),a=ju((([e])=>{const a=s(e),h=i(e).rgb.normalize(),l=t(e);Yu(a.greaterThanEqual(1).or(Np(h,h).equal(0)),(()=>l));const u=oc(l.rgb),c=n(e,a),d=Om(this.noiseNode,0);let p=sc(e.x,e.y.oneMinus());p=p.mul(this._resolution.div(d));const m=r(p),g=ep(m.element(this.index.mod(4).mul(2).mul(Ld))),f=tp(m.element(this.index.mod(4).mul(2).mul(Ld))),y=sc(g,f),x=mc(y.x,y.y.negate(),y.x,y.y),b=Ku(1).toVar(),v=oc(l.rgb).toVar();return Cy({start:Qu(0),end:Qu(16),type:"int",condition:"<"},(({i:t})=>{const s=this._sampleVectors.element(t).toVar(),i=x.mul(s.xy.mul(Ku(1).add(s.z.mul(this.radius.sub(1))))).div(this._resolution).toVar(),r=e.add(i).toVar(),n=o(u,h,c,r);v.addAssign(n.xyz),b.addAssign(n.w)})),Yu(b.greaterThan(Ku(0)),(()=>{v.divAssign(b)})),uc(v,l.a)})).setLayout({name:"denoise",type:"vec4",inputs:[{name:"uv",type:"vec2"}]});return ju((()=>a(e)))()}}zR.type=Ql("Denoise",zR);const UR=(e,t,s,i,r)=>Du(new zR(nA(e),Du(t),Du(s),Du(i),r));class LR extends iu{constructor(e){super(),this.textureNode=e,this.updateBeforeType=Hl.RENDER,this._invSize=Cc(new Qs)}updateBefore(){const e=this.textureNode.value;this._invSize.value.set(1/e.image.width,1/e.image.height)}setup(){const e=this.textureNode.bias(-100),t=e.uvNode||Um(),s=t=>e.uv(t),i=(t,s,i)=>e.uv(t.add(s.mul(i))),r=Qu(5),n=ju((([e,t])=>{const s=uc(t).toVar(),i=uc(e).toVar(),r=uc(op(i.sub(s))).toVar();return Tp(Tp(Tp(r.r,r.g),r.b),r.a)})),o=ju((([e,t,o,a])=>{const h=s(e).toVar(),l=i(e,sc(0,-1),t.xy).toVar(),u=i(e,sc(1,0),t.xy).toVar(),c=i(e,sc(0,1),t.xy).toVar(),d=i(e,sc(-1,0),t.xy).toVar(),p=n(h,c).toVar(),m=n(h,l).toVar(),g=n(h,u).toVar(),f=n(h,d).toVar(),y=Tp(p,Tp(m,Tp(g,f))).toVar();Yu(y.lessThan(o),(()=>h));const x=pd(p.add(m),g.add(f)).toVar();x.mulAssign(a),Yu(op(x).lessThan(.3),(()=>{const s=g.greaterThan(f).select(1,-1).toVar(),r=m.greaterThan(p).select(1,-1).toVar(),o=sc(s,r).toVar(),y=i(e,sc(o.x,o.y),t.xy),b=n(h,y).toVar(),v=i(e,sc(o.x.negate(),o.y.negate()),t.xy),T=n(h,v).toVar();x.assign(T.sub(b)),x.mulAssign(a),Yu(op(x).lessThan(.3),(()=>{const e=c.add(l).add(u).add(d);return Up(h,e.mul(.25),.4)}))}));const b=sc().toVar();Yu(x.lessThanEqual(0),(()=>{c.assign(d),l.assign(u),b.x.assign(0),b.y.assign(t.y)})).Else((()=>{b.x.assign(t.x),b.y.assign(0)}));const v=n(h,c).toVar(),T=n(h,l).toVar();Yu(v.lessThanEqual(T),(()=>{c.assign(l)}));const _=Qu(0).toVar(),w=Qu(0).toVar(),S=Ku(0).toVar(),M=Ku(0).toVar(),A=sc(e).toVar(),N=sc(e).toVar(),R=Qu(0).toVar(),C=Qu(0).toVar();Cy(r,(({i:t})=>{const i=t.add(1).toVar();Yu(_.equal(0),(()=>{S.addAssign(i),A.assign(e.add(b.mul(S)));const r=s(A.xy),o=n(r,h).toVar(),a=n(r,c).toVar();Yu(o.greaterThan(a),(()=>{_.assign(1)})),R.assign(t)})),Yu(w.equal(0),(()=>{M.addAssign(i),N.assign(e.sub(b.mul(M)));const r=s(N.xy),o=n(r,h).toVar(),a=n(r,c).toVar();Yu(o.greaterThan(a),(()=>{w.assign(1)})),C.assign(t)})),Yu(_.equal(1).or(w.equal(1)),(()=>{By()}))})),Yu(_.equal(0).and(w.equal(0)),(()=>h));const E=Ku(1).toVar(),B=Ku(1).toVar();Yu(_.equal(1),(()=>{E.assign(Ku(R).div(Ku(r.sub(1))))})),Yu(w.equal(1),(()=>{B.assign(Ku(C).div(Ku(r.sub(1))))}));const I=vp(E,B);return I.assign(Cp(I,.5)),I.assign(Ku(1).sub(I)),Up(h,c,I.mul(.5))})).setLayout({name:"FxaaPixelShader",type:"vec4",inputs:[{name:"uv",type:"vec2"},{name:"fxaaQualityRcpFrame",type:"vec2"},{name:"fxaaQualityEdgeThreshold",type:"float"},{name:"fxaaQualityinvEdgeThreshold",type:"float"}]});return ju((()=>{const e=Ku(.2),s=Ku(1).div(e);return o(t,this._invSize,e,s)}))()}}LR.type=Ql("FXAA",LR);const OR=e=>Du(new LR(nA(e))),VR=new tA,DR=new Yr(0,0,0),kR=new Yr,GR=new Qs,WR=new Qs(1,0),HR=new Qs(0,1);class jR extends iu{constructor(e,t=1,s=0,i=0){super(),this.inputNode=e,this.strength=Cc(t),this.radius=Cc(s),this.threshold=Cc(i),this.smoothWidth=Cc(.01),this._renderTargetsHorizontal=[],this._renderTargetsVertical=[],this._nMips=5,this._renderTargetBright=new wi(1,1,{type:Pe}),this._renderTargetBright.texture.name="UnrealBloomPass.bright",this._renderTargetBright.texture.generateMipmaps=!1;for(let e=0;e{const e=this.inputNode,t=pR(e.rgb),s=Dp(this.threshold,this.threshold.add(this.smoothWidth),t);return Up(uc(0),e,s)}));this._highPassFilterMaterial=this._highPassFilterMaterial||new xx,this._highPassFilterMaterial.fragmentNode=t().context(e.getSharedContext()),this._highPassFilterMaterial.name="Bloom_highPass",this._highPassFilterMaterial.needsUpdate=!0;const s=[3,5,7,9,11];for(let t=0;t{const s=Ku(1.2).sub(e);return Up(e,s,t)})).setLayout({name:"lerpBloomFactor",type:"float",inputs:[{name:"factor",type:"float"},{name:"radius",type:"float"}]}),o=ju((()=>{const e=n(i.element(0),this.radius).mul(uc(r.element(0),1)).mul(this._textureNodeBlur0),t=n(i.element(1),this.radius).mul(uc(r.element(1),1)).mul(this._textureNodeBlur1),s=n(i.element(2),this.radius).mul(uc(r.element(2),1)).mul(this._textureNodeBlur2),o=n(i.element(3),this.radius).mul(uc(r.element(3),1)).mul(this._textureNodeBlur3),a=n(i.element(4),this.radius).mul(uc(r.element(4),1)).mul(this._textureNodeBlur4);return e.add(t).add(s).add(o).add(a).mul(this.strength)}));return this._compositeMaterial=this._compositeMaterial||new xx,this._compositeMaterial.fragmentNode=o().context(e.getSharedContext()),this._compositeMaterial.name="Bloom_comp",this._compositeMaterial.needsUpdate=!0,this._textureOutput}dispose(){for(let e=0;ei.uv(e),l=ju((()=>{const e=r.element(0).toVar(),s=h(a).rgb.mul(e).toVar();return Cy({start:Qu(1),end:Qu(t),type:"int",condition:"<"},(({i:t})=>{const i=Ku(t),l=r.element(t),u=o.mul(n).mul(i),c=h(a.add(u)).rgb,d=h(a.sub(u)).rgb;s.addAssign(dd(c,d).mul(l)),e.addAssign(Ku(2).mul(l))})),uc(s.div(e),1)})),u=new xx;return u.fragmentNode=l().context(e.getSharedContext()),u.name="Bloom_seperable",u.needsUpdate=!0,u.colorTexture=i,u.direction=o,u.invSize=n,u}}const qR=(e,t,s,i)=>Du(new jR(Du(e),t,s,i));class $R extends iu{constructor(e,t,s,i,r,n){super(),this.textureNodeA=e,this.textureNodeB=t,this.mixTextureNode=s,this.mixRatioNode=i,this.thresholdNode=r,this.useTextureNode=n}setup(){const{textureNodeA:e,textureNodeB:t,mixTextureNode:s,mixRatioNode:i,thresholdNode:r,useTextureNode:n}=this,o=e=>{const t=e.uvNode||Um();return e.uv(t)},a=ju((()=>{const a=o(e),h=o(t),l=uc().toVar();return Yu(n.equal(Qu(1)),(()=>{const e=o(s),t=i.mul(r.mul(2).add(1)).sub(r),n=Lp(pd(e.r,t).mul(Ku(1).div(r)),0,1);l.assign(Up(a,h,n))})).Else((()=>{l.assign(Up(h,a,i))})),l}));return a()}}$R.type=Ql("Transition",$R);const XR=(e,t,s,i=0,r=.1,n=0)=>Du(new $R(nA(e),nA(t),nA(s),Du(i),Du(r),Du(n)));class YR extends iu{constructor(e,t,s,i,r,n){super(),this.textureNode=e,this.depthNode=t,this.normalNode=s,this.pixelSize=i,this.normalEdgeStrength=r,this.depthEdgeStrength=n,this._resolution=Cc(new _i),this.updateBeforeType=Hl.RENDER}updateBefore(){const e=this.textureNode.value,t=e.image.width,s=e.image.height;this._resolution.value.set(t,s,1/t,1/s)}setup(){const{textureNode:e,depthNode:t,normalNode:s}=this,i=e.uvNode||Um(),r=t.uvNode||Um(),n=s.uvNode||Um(),o=(e,s)=>t.uv(r.add(sc(e,s).mul(this._resolution.zw))).r,a=(e,t)=>s.uv(n.add(sc(e,t).mul(this._resolution.zw))).rgb.normalize(),h=(e,t,s,i)=>{const r=o(e,t).sub(s),n=a(e,t),h=oc(1,1,1),l=Np(i.sub(n),h),u=Lp(Dp(-.01,.01,l),0,1),c=Lp(ap(r.mul(.25).add(.0025)),0,1);return Ku(1).sub(Np(i,n)).mul(c).mul(u)},l=ju((()=>{const t=e.uv(i),s=Bc("float","depth"),r=Bc("vec3","normal");Yu(this.depthEdgeStrength.greaterThan(0).or(this.normalEdgeStrength.greaterThan(0)),(()=>{s.assign(o(0,0)),r.assign(a(0,0))}));const n=Bc("float","dei");Yu(this.depthEdgeStrength.greaterThan(0),(()=>{n.assign((e=>{const t=Bc("float","diff");return t.addAssign(Lp(o(1,0).sub(e))),t.addAssign(Lp(o(-1,0).sub(e))),t.addAssign(Lp(o(0,1).sub(e))),t.addAssign(Lp(o(0,-1).sub(e))),Jd(Dp(.01,.02,t).mul(2)).div(2)})(s))}));const l=Bc("float","nei");Yu(this.normalEdgeStrength.greaterThan(0),(()=>{l.assign(((e,t)=>{const s=Bc("float","indicator");return s.addAssign(h(0,-1,e,t)),s.addAssign(h(0,1,e,t)),s.addAssign(h(-1,0,e,t)),s.addAssign(h(1,0,e,t)),wp(.1,s)})(s,r))}));const u=n.greaterThan(0).select(Ku(1).sub(n.mul(this.depthEdgeStrength)),l.mul(this.normalEdgeStrength).add(1));return t.mul(u)}));return l()}}YR.type=Ql("Pixelation",YR);class JR extends JN{constructor(e,t,s=6,i=.3,r=.4){super("color",e,t,{minFilter:fe,magFilter:fe}),this.pixelSize=s,this.normalEdgeStrength=i,this.depthEdgeStrength=r,this.isPixelationPassNode=!0,this._mrt=gM({output:Zc,normal:Ig})}setSize(e,t){const s=this.pixelSize.value?this.pixelSize.value:this.pixelSize,i=Math.floor(e/s),r=Math.floor(t/s);super.setSize(i,r)}setup(){return((e,t,s,i=6,r=.3,n=.4)=>Du(new YR(nA(e),nA(t),nA(s),Du(i),Du(r),Du(n))))(super.getTextureNode("output"),super.getTextureNode("depth"),super.getTextureNode("normal"),this.pixelSize,this.normalEdgeStrength,this.depthEdgeStrength)}}const ZR=(e,t,s,i,r)=>Du(new JR(e,t,s,i,r));JR.type=Ql("PixelationPass",JR);const KR=new Qs;class QR extends JN{constructor(e,t){super(JN.COLOR,e,t),this.isSSAAPassNode=!0,this.sampleLevel=4,this.unbiased=!0,this.clearColor=new Yr(0),this.clearAlpha=0,this._currentClearColor=new Yr,this.sampleWeight=Cc(1),this.sampleRenderTarget=null,this._quadMesh=new tA}updateBefore(e){const{renderer:t}=e,{scene:s,camera:i}=this;this._pixelRatio=t.getPixelRatio();const r=t.getSize(KR);this.setSize(r.width,r.height),this.sampleRenderTarget.setSize(this.renderTarget.width,this.renderTarget.height),t.getClearColor(this._currentClearColor);const n=t.getClearAlpha(),o=t.getRenderTarget(),a=t.getMRT(),h=t.autoClear;this._cameraNear.value=i.near,this._cameraFar.value=i.far,t.setMRT(this.getMRT()),t.autoClear=!1;const l=eC[Math.max(0,Math.min(this.sampleLevel,5))],u=1/l.length,c={fullWidth:this.renderTarget.width,fullHeight:this.renderTarget.height,offsetX:0,offsetY:0,width:this.renderTarget.width,height:this.renderTarget.height},d=Object.assign({},i.view);d.enabled&&Object.assign(c,d);for(let e=0;e=0&&(e[t]=Gm(this.sampleRenderTarget.textures[s]).mul(this.sampleWeight))}t=gM(e)}else t=Gm(this.sampleRenderTarget.texture).mul(this.sampleWeight);return this._quadMesh.material=new xx,this._quadMesh.material.fragmentNode=t,this._quadMesh.material.transparent=!0,this._quadMesh.material.depthTest=!1,this._quadMesh.material.depthWrite=!1,this._quadMesh.material.premultipliedAlpha=!0,this._quadMesh.material.blending=2,this._quadMesh.material.normals=!1,this._quadMesh.material.name="SSAA",super.setup(e)}dispose(){super.dispose(),null!==this.sampleRenderTarget&&this.sampleRenderTarget.dispose()}}QR.type=Ql("SSAAPass",QR);const eC=[[[0,0]],[[4,4],[-4,-4]],[[-2,-6],[6,-2],[-6,2],[2,6]],[[1,-3],[-1,3],[5,1],[-3,-5],[-5,5],[-7,-1],[3,7],[7,-7]],[[1,1],[-1,-3],[-3,2],[4,-1],[-5,-2],[2,5],[5,3],[3,-5],[-2,6],[0,-7],[-4,-6],[-6,4],[-8,0],[7,-4],[6,7],[-7,-8]],[[-4,-7],[-7,-5],[-3,-5],[-5,-4],[-1,-4],[-2,-2],[-6,-1],[-4,0],[-7,1],[-1,2],[-6,3],[-3,3],[-7,6],[-3,6],[-5,7],[-1,7],[5,-7],[1,-6],[6,-5],[4,-4],[2,-3],[7,-2],[1,-1],[4,-1],[2,1],[6,2],[0,4],[4,4],[2,5],[7,5],[5,6],[3,7]]],tC=(e,t)=>Du(new QR(e,t)),sC=new Qs;class iC extends JN{constructor(e,t){super(JN.COLOR,e,t),this.isStereoPassNode=!0,this.stereo=new o_,this.stereo.aspect=.5}updateBefore(e){const{renderer:t}=e,{scene:s,camera:i,stereo:r,renderTarget:n}=this;this._pixelRatio=t.getPixelRatio(),r.cameraL.coordinateSystem=t.coordinateSystem,r.cameraR.coordinateSystem=t.coordinateSystem,r.update(i);const o=t.getSize(sC);this.setSize(o.width,o.height);const a=t.autoClear;t.autoClear=!1;const h=t.getRenderTarget(),l=t.getMRT();this._cameraNear.value=i.near,this._cameraFar.value=i.far;for(const e in this._previousTextures)this.toggleTexture(e);t.setRenderTarget(n),t.setMRT(this._mrt),t.clear(),n.scissorTest=!0,n.scissor.set(0,0,n.width/2,n.height),n.viewport.set(0,0,n.width/2,n.height),t.render(s,r.cameraL),n.scissor.set(n.width/2,0,n.width/2,n.height),n.viewport.set(n.width/2,0,n.width/2,n.height),t.render(s,r.cameraR),n.scissorTest=!1,t.setRenderTarget(h),t.setMRT(l),t.autoClear=a}}iC.type=Ql("StereoPass",iC);const rC=(e,t)=>Du(new iC(e,t)),nC=new Qs,oC=new tA;class aC extends JN{constructor(e,t){super(JN.COLOR,e,t),this.isStereoCompositePassNode=!0,this.stereo=new o_;const s={minFilter:Te,magFilter:fe,type:Pe};this._renderTargetL=new wi(1,1,s),this._renderTargetR=new wi(1,1,s),this._mapLeft=Gm(this._renderTargetL.texture),this._mapRight=Gm(this._renderTargetR.texture),this._material=null}updateStereoCamera(e){this.stereo.cameraL.coordinateSystem=e,this.stereo.cameraR.coordinateSystem=e,this.stereo.update(this.camera)}setSize(e,t){super.setSize(e,t),this._renderTargetL.setSize(this.renderTarget.width,this.renderTarget.height),this._renderTargetR.setSize(this.renderTarget.width,this.renderTarget.height)}updateBefore(e){const{renderer:t}=e,{scene:s,stereo:i,renderTarget:r}=this;this._pixelRatio=t.getPixelRatio(),this.updateStereoCamera(t.coordinateSystem);const n=t.getSize(nC);this.setSize(n.width,n.height);const o=t.getRenderTarget();t.setRenderTarget(this._renderTargetL),t.render(s,i.cameraL),t.setRenderTarget(this._renderTargetR),t.render(s,i.cameraR),t.setRenderTarget(r),oC.material=this._material,oC.render(t),t.setRenderTarget(o)}dispose(){super.dispose(),this._renderTargetL.dispose(),this._renderTargetR.dispose(),null!==this._material&&this._material.dispose()}}aC.type=Ql("StereoCompositePass",aC);class hC extends aC{constructor(e,t){super(e,t),this.isAnaglyphPassNode=!0,this._colorMatrixLeft=Cc((new ei).fromArray([.4561,-.0400822,-.0152161,.500484,-.0378246,-.0205971,.176381,-.0157589,-.00546856])),this._colorMatrixRight=Cc((new ei).fromArray([-.0434706,.378476,-.0721527,-.0879388,.73364,-.112961,-.00155529,-.0184503,1.2264]))}setup(e){const t=Um(),s=ju((()=>{const e=this._mapLeft.uv(t),s=this._mapRight.uv(t),i=Lp(this._colorMatrixLeft.mul(e.rgb).add(this._colorMatrixRight.mul(s.rgb)));return uc(i.rgb,Tp(e.a,s.a))})),i=this._material||(this._material=new xx);return i.fragmentNode=s().context(e.getSharedContext()),i.name="Anaglyph",i.needsUpdate=!0,super.setup(e)}}const lC=(e,t)=>Du(new hC(e,t));class uC extends aC{constructor(e,t){super(e,t),this.isParallaxBarrierPassNode=!0}setup(e){const t=Um(),s=ju((()=>{const e=uc().toVar();return Yu(_p(Xy.y,2).greaterThan(1),(()=>{e.assign(this._mapLeft.uv(t))})).Else((()=>{e.assign(this._mapRight.uv(t))})),e})),i=this._material||(this._material=new xx);return i.fragmentNode=s().context(e.getSharedContext()),i.needsUpdate=!0,super.setup(e)}}uC.type=Ql("ParallaxBarrierPass",uC);const cC=(e,t)=>Du(new uC(e,t));class dC extends Kl{constructor(e=null){super(),this._value=e,this._cache=null,this.inputType=null,this.outpuType=null,this.events=new ks,this.isScriptableValueNode=!0}get isScriptableOutputNode(){return null!==this.outputType}set value(e){this._value!==e&&(this._cache&&"URL"===this.inputType&&this.value.value instanceof ArrayBuffer&&(URL.revokeObjectURL(this._cache),this._cache=null),this._value=e,this.events.dispatchEvent({type:"change"}),this.refresh())}get value(){return this._value}refresh(){this.events.dispatchEvent({type:"refresh"})}getValue(){const e=this.value;if(e&&null===this._cache&&"URL"===this.inputType&&e.value instanceof ArrayBuffer)this._cache=URL.createObjectURL(new Blob([e.value]));else if(e&&null!==e.value&&void 0!==e.value&&(("URL"===this.inputType||"String"===this.inputType)&&"string"==typeof e.value||"Number"===this.inputType&&"number"==typeof e.value||"Vector2"===this.inputType&&e.value.isVector2||"Vector3"===this.inputType&&e.value.isVector3||"Vector4"===this.inputType&&e.value.isVector4||"Color"===this.inputType&&e.value.isColor||"Matrix3"===this.inputType&&e.value.isMatrix3||"Matrix4"===this.inputType&&e.value.isMatrix4))return e.value;return this._cache||e}getNodeType(e){return this.value&&this.value.isNode?this.value.getNodeType(e):"float"}setup(){return this.value&&this.value.isNode?this.value:Ku()}serialize(e){super.serialize(e),null!==this.value?"ArrayBuffer"===this.inputType?e.value=Dl(this.value):e.value=this.value?this.value.toJSON(e.meta).uuid:null:e.value=null,e.inputType=this.inputType,e.outputType=this.outputType}deserialize(e){super.deserialize(e);let t=null;null!==e.value&&(t="ArrayBuffer"===e.inputType?kl(e.value):"Texture"===e.inputType?e.meta.textures[e.value]:e.meta.nodes[e.value]||null),this.value=t,this.inputType=e.inputType,this.outputType=e.outputType}}dC.type=Ql("ScriptableValue",dC);const pC=Wu(dC);class mC extends Map{get(e,t=null,...s){if(this.has(e))return super.get(e);if(null!==t){const i=t(...s);return this.set(e,i),i}}}class gC{constructor(e){this.scriptableNode=e}get parameters(){return this.scriptableNode.parameters}get layout(){return this.scriptableNode.getLayout()}getInputLayout(e){return this.scriptableNode.getInputLayout(e)}get(e){const t=this.parameters[e];return t?t.getValue():null}}const fC=new mC;class yC extends Kl{constructor(e=null,t={}){super(),this.codeNode=e,this.parameters=t,this._local=new mC,this._output=pC(),this._outputs={},this._source=this.source,this._method=null,this._object=null,this._value=null,this._needsOutputUpdate=!0,this.onRefresh=this.onRefresh.bind(this),this.isScriptableNode=!0}get source(){return this.codeNode?this.codeNode.code:""}setLocal(e,t){return this._local.set(e,t)}getLocal(e){return this._local.get(e)}onRefresh(){this._refresh()}getInputLayout(e){for(const t of this.getLayout())if(t.inputType&&(t.id===e||t.name===e))return t}getOutputLayout(e){for(const t of this.getLayout())if(t.outputType&&(t.id===e||t.name===e))return t}setOutput(e,t){const s=this._outputs;return void 0===s[e]?s[e]=pC(t):s[e].value=t,this}getOutput(e){return this._outputs[e]}getParameter(e){return this.parameters[e]}setParameter(e,t){const s=this.parameters;return t&&t.isScriptableNode?(this.deleteParameter(e),s[e]=t,s[e].getDefaultOutput().events.addEventListener("refresh",this.onRefresh)):t&&t.isScriptableValueNode?(this.deleteParameter(e),s[e]=t,s[e].events.addEventListener("refresh",this.onRefresh)):void 0===s[e]?(s[e]=pC(t),s[e].events.addEventListener("refresh",this.onRefresh)):s[e].value=t,this}getValue(){return this.getDefaultOutput().getValue()}deleteParameter(e){let t=this.parameters[e];return t&&(t.isScriptableNode&&(t=t.getDefaultOutput()),t.events.removeEventListener("refresh",this.onRefresh)),this}clearParameters(){for(const e of Object.keys(this.parameters))this.deleteParameter(e);return this.needsUpdate=!0,this}call(e,...t){const s=this.getObject()[e];if("function"==typeof s)return s(...t)}async callAsync(e,...t){const s=this.getObject()[e];if("function"==typeof s)return"AsyncFunction"===s.constructor.name?await s(...t):s(...t)}getNodeType(e){return this.getDefaultOutputNode().getNodeType(e)}refresh(e=null){null!==e?this.getOutput(e).refresh():this._refresh()}getObject(){if(this.needsUpdate&&this.dispose(),null!==this._object)return this._object;const e=new gC(this),t=fC.get("THREE"),s=fC.get("TSL"),i=this.getMethod(this.codeNode),r=[e,this._local,fC,()=>this.refresh(),(e,t)=>this.setOutput(e,t),t,s];this._object=i(...r);const n=this._object.layout;if(n&&(!1===n.cache&&this._local.clear(),this._output.outputType=n.outputType||null,Array.isArray(n.elements)))for(const e of n.elements){const t=e.id||e.name;e.inputType&&(void 0===this.getParameter(t)&&this.setParameter(t,null),this.getParameter(t).inputType=e.inputType),e.outputType&&(void 0===this.getOutput(t)&&this.setOutput(t,null),this.getOutput(t).outputType=e.outputType)}return this._object}deserialize(e){super.deserialize(e);for(const e in this.parameters){let t=this.parameters[e];t.isScriptableNode&&(t=t.getDefaultOutput()),t.events.addEventListener("refresh",this.onRefresh)}}getLayout(){return this.getObject().layout}getDefaultOutputNode(){const e=this.getDefaultOutput().value;return e&&e.isNode?e:Ku()}getDefaultOutput(){return this._exec()._output}getMethod(){if(this.needsUpdate&&this.dispose(),null!==this._method)return this._method;const e=["layout","init","main","dispose"].join(", "),t="\nreturn { ...output, "+e+" };",s="var "+e+"; var output = {};\n"+this.codeNode.code+t;return this._method=new Function(...["parameters","local","global","refresh","setOutput","THREE","TSL"],s),this._method}dispose(){null!==this._method&&(this._object&&"function"==typeof this._object.dispose&&this._object.dispose(),this._method=null,this._object=null,this._source=null,this._value=null,this._needsOutputUpdate=!0,this._output.value=null,this._outputs={})}setup(){return this.getDefaultOutputNode()}getCacheKey(e){const t=[this.source,this.getDefaultOutputNode().getCacheKey(e)];for(const s in this.parameters)t.push(this.parameters[s].getCacheKey(e));return t.join(",")}set needsUpdate(e){!0===e&&this.dispose()}get needsUpdate(){return this.source!==this._source}_exec(){return null===this.codeNode||(!0===this._needsOutputUpdate&&(this._value=this.call("main"),this._needsOutputUpdate=!1),this._output.value=this._value),this}_refresh(){this.needsUpdate=!0,this._exec(),this._output.refresh()}}yC.type=Ql("Scriptable",yC);const xC=Wu(yC);class bC extends Kl{constructor(e,t){super("float"),this.isFogNode=!0,this.colorNode=e,this.factorNode=t}getViewZNode(e){let t;const s=e.context.getViewZ;return void 0!==s&&(t=s(this)),(t||wg.z).negate()}setup(){return this.factorNode}}bC.type=Ql("Fog",bC);const vC=Wu(bC);class TC extends bC{constructor(e,t,s){super(e),this.isFogRangeNode=!0,this.nearNode=t,this.farNode=s}setup(e){const t=this.getViewZNode(e);return Dp(this.nearNode,this.farNode,t)}}TC.type=Ql("FogRange",TC);const _C=Wu(TC);class wC extends bC{constructor(e,t){super(e),this.isFogExp2Node=!0,this.densityNode=t}setup(e){const t=this.getViewZNode(e),s=this.densityNode;return s.mul(s,t,t).negate().exp().oneMinus()}}wC.type=Ql("FogExp2",wC);const SC=Wu(wC);let MC=null,AC=null;class NC extends Kl{constructor(e=Ku(),t=Ku()){super(),this.minNode=e,this.maxNode=t}getVectorLength(e){const t=e.getTypeLength(Ol(this.minNode.value)),s=e.getTypeLength(Ol(this.maxNode.value));return t>s?t:s}getNodeType(e){return e.object.count>1?e.getTypeFromLength(this.getVectorLength(e)):"float"}setup(e){const t=e.object;let s=null;if(t.count>1){const i=this.minNode.value,r=this.maxNode.value,n=e.getTypeLength(Ol(i)),o=e.getTypeLength(Ol(r));MC=MC||new _i,AC=AC||new _i,MC.setScalar(0),AC.setScalar(0),1===n?MC.setScalar(i):i.isColor?MC.set(i.r,i.g,i.b):MC.set(i.x,i.y,i.z||0,i.w||0),1===o?AC.setScalar(r):r.isColor?AC.set(r.r,r.g,r.b):AC.set(r.x,r.y,r.z||0,r.w||0);const a=4,h=a*t.count,l=new Float32Array(h);for(let e=0;eGm(e,t.xy).compare(t.z))),IC=ju((({depthTexture:e,shadowCoord:t,shadow:s})=>{const i=(t,s)=>Gm(e,t).compare(s),r=Zg("mapSize","vec2",s),n=Zg("radius","float",s),o=sc(1).div(r),a=o.x.negate().mul(n),h=o.y.negate().mul(n),l=o.x.mul(n),u=o.y.mul(n),c=a.div(2),d=h.div(2),p=l.div(2),m=u.div(2);return dd(i(t.xy.add(sc(a,h)),t.z),i(t.xy.add(sc(0,h)),t.z),i(t.xy.add(sc(l,h)),t.z),i(t.xy.add(sc(c,d)),t.z),i(t.xy.add(sc(0,d)),t.z),i(t.xy.add(sc(p,d)),t.z),i(t.xy.add(sc(a,0)),t.z),i(t.xy.add(sc(c,0)),t.z),i(t.xy,t.z),i(t.xy.add(sc(p,0)),t.z),i(t.xy.add(sc(l,0)),t.z),i(t.xy.add(sc(c,m)),t.z),i(t.xy.add(sc(0,m)),t.z),i(t.xy.add(sc(p,m)),t.z),i(t.xy.add(sc(a,u)),t.z),i(t.xy.add(sc(0,u)),t.z),i(t.xy.add(sc(l,u)),t.z)).mul(1/17)})),PC=ju((({depthTexture:e,shadowCoord:t,shadow:s})=>{const i=(t,s)=>Gm(e,t).compare(s),r=Zg("mapSize","vec2",s),n=sc(1).div(r),o=n.x,a=n.y,h=t.xy,l=Qd(h.mul(r).add(.5));return h.subAssign(l.mul(n)),dd(i(h,t.z),i(h.add(sc(o,0)),t.z),i(h.add(sc(0,a)),t.z),i(h.add(n),t.z),Up(i(h.add(sc(o.negate(),0)),t.z),i(h.add(sc(o.mul(2),0)),t.z),l.x),Up(i(h.add(sc(o.negate(),a)),t.z),i(h.add(sc(o.mul(2),a)),t.z),l.x),Up(i(h.add(sc(0,a.negate())),t.z),i(h.add(sc(0,a.mul(2))),t.z),l.y),Up(i(h.add(sc(o,a.negate())),t.z),i(h.add(sc(o,a.mul(2))),t.z),l.y),Up(Up(i(h.add(sc(o.negate(),a.negate())),t.z),i(h.add(sc(o.mul(2),a.negate())),t.z),l.x),Up(i(h.add(sc(o.negate(),a.mul(2))),t.z),i(h.add(sc(o.mul(2),a.mul(2))),t.z),l.x),l.y)).mul(1/9)})),FC=[BC,IC,PC];let zC=null;class UC extends Dy{constructor(e=null){super(),this.updateType=Hl.FRAME,this.light=e,this.color=new Yr,this.colorNode=Cc(this.color),this.baseColorNode=null,this.shadowMap=null,this.shadowNode=null,this.shadowColorNode=null,this.isAnalyticLightNode=!0}getCacheKey(){return super.getCacheKey()+"-"+this.light.id+"-"+(this.light.castShadow?"1":"0")}getHash(){return this.light.uuid}setupShadow(e){const{object:t,renderer:s}=e;let i=this.shadowColorNode;if(null===i){null===zC&&(zC=new xx,zC.fragmentNode=uc(0,0,0,1),zC.isShadowNodeMaterial=!0,zC.name="ShadowMaterial");const r=new Qa;r.compareFunction=Ts;const n=this.light.shadow,o=e.createRenderTarget(n.mapSize.width,n.mapSize.height);o.depthTexture=r,n.camera.updateProjectionMatrix();const a=Zg("intensity","float",n),h=Zg("bias","float",n),l=Zg("normalBias","float",n),u=t.material.shadowPositionNode||Tg;let c=Cc(n.matrix).mul(u.add(Pg.mul(l)));c=c.xyz.div(c.w);let d=c.z.add(h);s.coordinateSystem===Ds&&(d=d.mul(2).sub(1)),c=oc(c.x,c.y.oneMinus(),d);const p=c.x.greaterThanEqual(0).and(c.x.lessThanEqual(1)).and(c.y.greaterThanEqual(0)).and(c.y.lessThanEqual(1)).and(c.z.lessThanEqual(1)),m=n.filterNode||FC[s.shadowMap.type]||null;if(null===m)throw new Error("THREE.WebGPURenderer: Shadow map type not supported yet.");const g=Gm(o.texture,c),f=p.select(m({depthTexture:r,shadowCoord:c,shadow:n}),Ku(1));this.shadowMap=o,this.shadowNode=f,this.shadowColorNode=i=this.colorNode.mul(Up(1,f.rgb.mix(g,1),a.mul(g.a))),this.baseColorNode=this.colorNode}this.colorNode=i,this.updateBeforeType=Hl.RENDER}setup(e){this.colorNode=this.baseColorNode||this.colorNode,this.light.castShadow?e.object.receiveShadow&&this.setupShadow(e):null!==this.shadowNode&&this.disposeShadow()}updateShadow(e){const{shadowMap:t,light:s}=this,{renderer:i,scene:r,camera:n}=e,o=t.depthTexture.version;this._depthVersionCached=o;const a=r.overrideMaterial;r.overrideMaterial=zC,t.setSize(s.shadow.mapSize.width,s.shadow.mapSize.height),s.shadow.updateMatrices(s),s.shadow.camera.layers.mask=n.layers.mask;const h=i.getRenderTarget(),l=i.getRenderObjectFunction();i.setRenderObjectFunction(((e,...t)=>{!0===e.castShadow&&i.renderObject(e,...t)})),i.setRenderTarget(t),i.render(r,s.shadow.camera),i.setRenderTarget(h),i.setRenderObjectFunction(l),r.overrideMaterial=a}disposeShadow(){this.shadowMap.dispose(),this.shadowMap=null,this.shadowNode=null,this.shadowColorNode=null,this.baseColorNode=null,this.updateBeforeType=Hl.NONE}updateBefore(e){const t=this.light.shadow;(t.needsUpdate||t.autoUpdate)&&(this.updateShadow(e),this.shadowMap.depthTexture.version===this._depthVersionCached&&(t.needsUpdate=!1))}update(){const{light:e}=this;this.color.copy(e.color).multiplyScalar(e.intensity)}}UC.type=Ql("AnalyticLight",UC);const LC=ju((e=>{const{lightDistance:t,cutoffDistance:s,decayExponent:i}=e,r=t.pow(i).max(.01).reciprocal();return s.greaterThan(0).select(r.mul(t.div(s).pow4().oneMinus().clamp().pow2()),r)}));class OC extends UC{constructor(e=null){super(e),this.cutoffDistanceNode=Cc(0),this.decayExponentNode=Cc(0)}update(e){const{light:t}=this;super.update(e),this.cutoffDistanceNode.value=t.distance,this.decayExponentNode.value=t.decay}setup(e){const{colorNode:t,cutoffDistanceNode:s,decayExponentNode:i,light:r}=this,n=e.context.lightingModel,o=hg(r).sub(wg),a=o.normalize(),h=o.length(),l=LC({lightDistance:h,cutoffDistance:s,decayExponent:i}),u=t.mul(l),c=e.context.reflectedLight;n.direct({lightDirection:a,lightColor:u,reflectedLight:c},e.stack,e)}}OC.type=Ql("PointLight",OC);class VC extends UC{constructor(e=null){super(e)}setup(e){super.setup(e);const t=e.context.lightingModel,s=this.colorNode,i=EC(this.light),r=e.context.reflectedLight;t.direct({lightDirection:i,lightColor:s,reflectedLight:r},e.stack,e)}}VC.type=Ql("DirectionalLight",VC);const DC=new or,kC=new or;let GC=null;class WC extends UC{constructor(e=null){super(e),this.halfHeight=Cc(new Ei),this.halfWidth=Cc(new Ei)}update(e){super.update(e);const{light:t}=this,s=e.camera.matrixWorldInverse;kC.identity(),DC.copy(t.matrixWorld),DC.premultiply(s),kC.extractRotation(DC),this.halfWidth.value.set(.5*t.width,0,0),this.halfHeight.value.set(0,.5*t.height,0),this.halfWidth.value.applyMatrix4(kC),this.halfHeight.value.applyMatrix4(kC)}setup(e){let t,s;super.setup(e),e.isAvailable("float32Filterable")?(t=Gm(GC.LTC_FLOAT_1),s=Gm(GC.LTC_FLOAT_2)):(t=Gm(GC.LTC_HALF_1),s=Gm(GC.LTC_HALF_2));const{colorNode:i,light:r}=this,n=e.context.lightingModel,o=hg(r),a=e.context.reflectedLight;n.directRectArea({lightColor:i,lightPosition:o,halfWidth:this.halfWidth,halfHeight:this.halfHeight,reflectedLight:a,ltc_1:t,ltc_2:s},e.stack,e)}static setLTC(e){GC=e}}WC.type=Ql("RectAreaLight",WC);class HC extends UC{constructor(e=null){super(e),this.coneCosNode=Cc(0),this.penumbraCosNode=Cc(0),this.cutoffDistanceNode=Cc(0),this.decayExponentNode=Cc(0)}update(e){super.update(e);const{light:t}=this;this.coneCosNode.value=Math.cos(t.angle),this.penumbraCosNode.value=Math.cos(t.angle*(1-t.penumbra)),this.cutoffDistanceNode.value=t.distance,this.decayExponentNode.value=t.decay}getSpotAttenuation(e){const{coneCosNode:t,penumbraCosNode:s}=this;return Dp(t,s,e)}setup(e){super.setup(e);const t=e.context.lightingModel,{colorNode:s,cutoffDistanceNode:i,decayExponentNode:r,light:n}=this,o=hg(n).sub(wg),a=o.normalize(),h=a.dot(EC(n)),l=this.getSpotAttenuation(h),u=o.length(),c=LC({lightDistance:u,cutoffDistance:i,decayExponent:r}),d=s.mul(l).mul(c),p=e.context.reflectedLight;t.direct({lightDirection:a,lightColor:d,reflectedLight:p},e.stack,e)}}HC.type=Ql("SpotLight",HC);class jC extends HC{getSpotAttenuation(e){const t=this.light.iesMap;let s=null;if(t&&!0===t.isTexture){const i=e.acos().mul(1/Math.PI);s=Gm(t,sc(i,0),0).r}else s=super.getSpotAttenuation(e);return s}}jC.type=Ql("IESSpotLight",jC);class qC extends UC{constructor(e=null){super(e)}setup({context:e}){e.irradiance.addAssign(this.colorNode)}}qC.type=Ql("AmbientLight",qC);class $C extends UC{constructor(e=null){super(e),this.lightPositionNode=og(e),this.lightDirectionNode=this.lightPositionNode.normalize(),this.groundColorNode=Cc(new Yr)}update(e){const{light:t}=this;super.update(e),this.lightPositionNode.object3d=t,this.groundColorNode.value.copy(t.groundColor).multiplyScalar(t.intensity)}setup(e){const{colorNode:t,groundColorNode:s,lightDirectionNode:i}=this,r=Ig.dot(i).mul(.5).add(.5),n=Up(s,t,r);e.context.irradiance.addAssign(n)}}$C.type=Ql("HemisphereLight",$C);class XC extends UC{constructor(e=null){super(e);const t=[];for(let e=0;e<9;e++)t.push(new Ei);this.lightProbe=Xg(t)}update(e){const{light:t}=this;super.update(e);for(let e=0;e<9;e++)this.lightProbe.array[e].copy(t.sh.coefficients[e]).multiplyScalar(t.intensity)}setup(e){const t=YC(Pg,this.lightProbe);e.context.irradiance.addAssign(t)}}XC.type=Ql("LightProbe",XC);const YC=ju((([e,t])=>{const s=e.x,i=e.y,r=e.z,n=t.element(0).mul(.886227);return n.addAssign(t.element(1).mul(1.023328).mul(i)),n.addAssign(t.element(2).mul(1.023328).mul(r)),n.addAssign(t.element(3).mul(1.023328).mul(s)),n.addAssign(t.element(4).mul(.858086).mul(s).mul(i)),n.addAssign(t.element(5).mul(.858086).mul(i).mul(r)),n.addAssign(t.element(6).mul(r.mul(r).mul(.743125).sub(.247708))),n.addAssign(t.element(7).mul(.858086).mul(s).mul(r)),n.addAssign(t.element(8).mul(.429043).mul(md(s,s).sub(md(i,i)))),n}));class JC{parseFunction(){console.warn("Abstract function.")}}class ZC{constructor(e,t,s="",i=""){this.type=e,this.inputs=t,this.name=s,this.precision=i}getCode(){console.warn("Abstract function.")}}ZC.isNodeFunction=!0;const KC=/^\s*(highp|mediump|lowp)?\s*([a-z_0-9]+)\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)/i,QC=/[a-z_0-9]+/gi,eE="#pragma main";class tE extends ZC{constructor(e){const{type:t,inputs:s,name:i,precision:r,inputsCode:n,blockCode:o,headerCode:a}=(e=>{const t=(e=e.trim()).indexOf(eE),s=-1!==t?e.slice(t+12):e,i=s.match(KC);if(null!==i&&5===i.length){const r=i[4],n=[];let o=null;for(;null!==(o=QC.exec(r));)n.push(o);const a=[];let h=0;for(;h0?this.transparent:this.opaque).push(o)}unshift(e,t,s,i,r,n){const o=this.getNextRenderItem(e,t,s,i,r,n);(!0===s.transparent?this.transparent:this.opaque).unshift(o)}pushBundle(e){this.bundles.push(e)}pushLight(e){this.lightsArray.push(e)}getLightsNode(){return this.lightsNode.fromLights(this.lightsArray)}sort(e,t){this.opaque.length>1&&this.opaque.sort(e||iE),this.transparent.length>1&&this.transparent.sort(t||rE)}finish(){this.lightsNode.setLights(this.lightsArray);for(let e=this.renderItemsIndex,t=this.renderItems.length;e>t,h=o.height>>t;let l=e.depthTexture||r[t],u=!1;void 0===l&&(l=new Qa,l.format=e.stencilBuffer?He:We,l.type=e.stencilBuffer?Ue:Be,l.image.width=a,l.image.height=h,r[t]=l),s.width===o.width&&o.height===s.height||(u=!0,l.needsUpdate=!0,l.image.width=a,l.image.height=h),s.width=o.width,s.height=o.height,s.textures=n,s.depthTexture=l,s.depth=e.depthBuffer,s.stencil=e.stencilBuffer,s.renderTarget=e,s.sampleCount!==i&&(u=!0,l.needsUpdate=!0,s.sampleCount=i);const c={sampleCount:i};for(let e=0;e{e.removeEventListener("dispose",t);for(let e=0;e0){const i=e.image;if(void 0===i)console.warn("THREE.Renderer: Texture marked for update but image is undefined.");else if(!1===i.complete)console.warn("THREE.Renderer: Texture marked for update but image is incomplete.");else{if(e.images){const s=[];for(const t of e.images)s.push(t);t.images=s}else t.image=i;void 0!==s.isDefaultTexture&&!0!==s.isDefaultTexture||(r.createTexture(e,t),s.isDefaultTexture=!1,s.generation=e.version),!0===e.source.dataReady&&r.updateTexture(e,t),t.needsMipmaps&&0===e.mipmaps.length&&r.generateMipmaps(e)}}else r.createDefaultTexture(e),s.isDefaultTexture=!0,s.generation=e.version}if(!0!==s.initialized){s.initialized=!0,s.generation=e.version,this.info.memory.textures++;const t=()=>{e.removeEventListener("dispose",t),this._destroyTexture(e),this.info.memory.textures--};e.addEventListener("dispose",t)}s.version=e.version}getSize(e,t=cE){let s=e.images?e.images[0]:e.image;return s?(void 0!==s.image&&(s=s.image),t.width=s.width,t.height=s.height,t.depth=e.isCubeTexture?6:s.depth||1):t.width=t.height=t.depth=1,t}getMipLevels(e,t,s){let i;return i=e.isCompressedTexture?e.mipmaps.length:Math.floor(Math.log2(Math.max(t,s)))+1,i}needsMipmaps(e){return!!this.isEnvironmentTexture(e)||(!0===e.isCompressedTexture||e.minFilter!==fe&&e.minFilter!==Te)}isEnvironmentTexture(e){const t=e.mapping;return t===ue||t===ce||t===he||t===le}_destroyTexture(e){this.backend.destroySampler(e),this.backend.destroyTexture(e),this.delete(e)}}class pE extends Yr{constructor(e,t,s,i=1){super(e,t,s),this.a=i}set(e,t,s,i=1){return this.a=i,super.set(e,t,s)}copy(e){return void 0!==e.a&&(this.a=e.a),super.copy(e)}clone(){return new this.constructor(this.r,this.g,this.b,this.a)}}const mE=ju((([e])=>{const t=e.toUint().mul(747796405).add(2891336453),s=t.shiftRight(t.shiftRight(28).add(4)).bitXor(t).mul(277803737);return s.shiftRight(22).bitXor(s).toFloat().mul(1/2**32)})),gE=(e,t)=>Cp(md(4,e.mul(pd(1,e))),t),fE=(e,t)=>e.lessThan(.5)?gE(e.mul(2),t).div(2):pd(1,gE(md(pd(1,e),2),t).div(2)),yE=(e,t,s)=>Cp(gd(Cp(e,t),dd(Cp(e,t),Cp(pd(1,e),s))),1/t),xE=(e,t)=>ep(Ld.mul(t.mul(e).sub(1))).div(Ld.mul(t.mul(e).sub(1))),bE=ju((([e])=>e.fract().sub(.5).abs())).setLayout({name:"tri",type:"float",inputs:[{name:"x",type:"float"}]}),vE=ju((([e])=>oc(bE(e.z.add(bE(e.y.mul(1)))),bE(e.z.add(bE(e.x.mul(1)))),bE(e.y.add(bE(e.x.mul(1))))))).setLayout({name:"tri3",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),TE=ju((([e,t,s])=>{const i=oc(e).toVar(),r=Ku(1.4).toVar(),n=Ku(0).toVar(),o=oc(i).toVar();return Cy({start:Ku(0),end:Ku(3),type:"float",condition:"<="},(()=>{const e=oc(vE(o.mul(2))).toVar();i.addAssign(e.add(s.mul(Ku(.1).mul(t)))),o.mulAssign(1.8),r.mulAssign(1.5),i.mulAssign(1.2);const a=Ku(bE(i.z.add(bE(i.x.add(bE(i.y)))))).toVar();n.addAssign(a.div(r)),o.addAssign(.14)})),n})).setLayout({name:"triNoise3D",type:"float",inputs:[{name:"p",type:"vec3"},{name:"spd",type:"float"},{name:"time",type:"float"}]}),_E=ju((([e,t,s=sc(.5)])=>Uv(e.sub(s),t).add(s))),wE=ju((([e,t,s=sc(.5)])=>{const i=e.sub(s),r=i.dot(i),n=r.mul(r).mul(t);return e.add(i.mul(n))})),SE=ju((({position:e=null,horizontal:t=!0,vertical:s=!1})=>{let i;null!==e?(i=pg.toVar(),i[3][0]=e.x,i[3][1]=e.y,i[3][2]=e.z):i=pg;const r=Zm.mul(i);return Lu(t)&&(r[0][0]=pg[0].length(),r[0][1]=0,r[0][2]=0),Lu(s)&&(r[1][0]=0,r[1][1]=pg[1].length(),r[1][2]=0),r[2][0]=0,r[2][1]=0,r[2][2]=1,Ym.mul(r).mul(bg)})),ME=ju((([e=null])=>{const t=mx();return mx(ox(e)).sub(t).lessThan(0).select(Zy,e)})),AE=new WeakMap;class NE extends iu{constructor(){super("vec2"),this.updateType=Hl.OBJECT,this.updateAfterType=Hl.OBJECT,this.previousProjectionMatrix=Cc(new or),this.previousModelViewMatrix=Cc(new or)}update({camera:e,object:t}){const s=RE(t),i=RE(e);this.previousModelViewMatrix.value.copy(s),this.previousProjectionMatrix.value.copy(i)}updateAfter({camera:e,object:t}){const s=RE(t),i=RE(e);s.copy(t.modelViewMatrix),i.copy(e.projectionMatrix)}setup(){const e=Ym.mul(cg).mul(bg),t=this.previousProjectionMatrix.mul(this.previousModelViewMatrix).mul(vg),s=e.xy.div(e.w),i=t.xy.div(t.w);return pd(s,i)}}function RE(e){let t=AE.get(e);return void 0===t&&(t=new or,AE.set(e,t)),t}NE.type=Ql("Velocity",NE);const CE=Hu(NE),EE=ju((([e,t])=>vp(1,e.oneMinus().div(t)).oneMinus())).setLayout({name:"burnBlend",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),BE=ju((([e,t])=>vp(e.div(t.oneMinus()),1))).setLayout({name:"dodgeBlend",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),IE=ju((([e,t])=>e.oneMinus().mul(t.oneMinus()).oneMinus())).setLayout({name:"screenBlend",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),PE=ju((([e,t])=>Up(e.mul(2).mul(t),e.oneMinus().mul(2).mul(t.oneMinus()).oneMinus(),wp(.5,e)))).setLayout({name:"overlayBlend",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),FE=ju((([e,t,s=Qu(16)])=>{const i=t=>e.uv(t),r=Um(),n=i(r).toVar(),o=Ku(s);return Cy({start:Qu(1),end:s,type:"int",condition:"<="},(({i:e})=>{const s=t.mul(Ku(e).div(o.sub(1)).sub(.5));n.addAssign(i(r.add(s)))})),n.divAssign(o),n})),zE=ju((([e,t=1])=>{const s=e,i=pR(s.rgb),r=oc(i),n=vp(1,Tp(0,Ku(10).mul(i.sub(.45)))),o=r.mul(s.rgb).mul(2),a=Ku(2).mul(r.oneMinus()).mul(s.rgb.oneMinus()).oneMinus(),h=Up(o,a,n),l=s.a.mul(t),u=l.mul(h.rgb);return u.addAssign(s.rgb.mul(l.oneMinus())),uc(u,s.a)})),UE=ju((([e])=>{const t=oc(e);return uc(Np(t,oc(.393,.769,.189)),Np(t,oc(.349,.686,.168)),Np(t,oc(.272,.534,.131)),e.a)})),LE=ju((([e])=>{const t=e.mul(.9478672986).add(.0521327014).pow(2.4),s=e.mul(.0773993808),i=e.lessThanEqual(.04045);return Up(t,s,i)})).setLayout({name:"sRGBToLinear",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),OE=ju((([e])=>{const t=e.pow(.41666).mul(1.055).sub(.055),s=e.mul(12.92),i=e.lessThanEqual(.0031308);return Up(t,s,i)})).setLayout({name:"LinearTosRGB",type:"vec3",inputs:[{name:"color",type:"vec3"}]});var VE=Object.freeze({__proto__:null,LinearTosRGB:OE,sRGBToLinear:LE});const DE=ju((([e,t])=>e.mul(t).clamp())).setLayout({name:"LinearToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),kE=ju((([e,t])=>(e=e.mul(t)).div(e.add(1)).clamp())).setLayout({name:"ReinhardToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),GE=ju((([e,t])=>{const s=(e=(e=e.mul(t)).sub(.004).max(0)).mul(e.mul(6.2).add(.5)),i=e.mul(e.mul(6.2).add(1.7)).add(.06);return s.div(i).pow(2.2)})).setLayout({name:"CineonToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),WE=ju((([e])=>{const t=e.mul(e.add(.0245786)).sub(90537e-9),s=e.mul(e.add(.432951).mul(.983729)).add(.238081);return t.div(s)})),HE=ju((([e,t])=>{const s=gc(.59719,.35458,.04823,.076,.90834,.01566,.0284,.13383,.83777),i=gc(1.60475,-.53108,-.07367,-.10208,1.10813,-.00605,-.00327,-.07276,1.07602);return e=e.mul(t).div(.6),e=s.mul(e),e=WE(e),(e=i.mul(e)).clamp()})).setLayout({name:"ACESFilmicToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),jE=gc(oc(1.6605,-.1246,-.0182),oc(-.5876,1.1329,-.1006),oc(-.0728,-.0083,1.1187)),qE=gc(oc(.6274,.0691,.0164),oc(.3293,.9195,.088),oc(.0433,.0113,.8956)),$E=ju((([e])=>{const t=oc(e).toVar(),s=oc(t.mul(t)).toVar(),i=oc(s.mul(s)).toVar();return Ku(15.5).mul(i.mul(s)).sub(md(40.14,i.mul(t))).add(md(31.96,i).sub(md(6.868,s.mul(t))).add(md(.4298,s).add(md(.1191,t).sub(.00232))))})),XE=ju((([e,t])=>{const s=oc(e).toVar(),i=gc(oc(.856627153315983,.137318972929847,.11189821299995),oc(.0951212405381588,.761241990602591,.0767994186031903),oc(.0482516061458583,.101439036467562,.811302368396859)),r=gc(oc(1.1271005818144368,-.1413297634984383,-.14132976349843826),oc(-.11060664309660323,1.157823702216272,-.11060664309660294),oc(-.016493938717834573,-.016493938717834257,1.2519364065950405)),n=Ku(-12.47393),o=Ku(4.026069);return s.mulAssign(t),s.assign(qE.mul(s)),s.assign(i.mul(s)),s.assign(Tp(s,1e-10)),s.assign($d(s)),s.assign(s.sub(n).div(o.sub(n))),s.assign(Lp(s,0,1)),s.assign($E(s)),s.assign(r.mul(s)),s.assign(Cp(Tp(oc(0),s),oc(2.2))),s.assign(jE.mul(s)),s.assign(Lp(s,0,1)),s})).setLayout({name:"AgXToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),YE=ju((([e,t])=>{const s=Ku(.76),i=Ku(.15);e=e.mul(t);const r=vp(e.r,vp(e.g,e.b)),n=qp(r.lessThan(.08),r.sub(md(6.25,r.mul(r))),.04);e.subAssign(n);const o=Tp(e.r,Tp(e.g,e.b));Yu(o.lessThan(s),(()=>e));const a=pd(1,s),h=pd(1,a.mul(a).div(o.add(a.sub(s))));e.mulAssign(h.div(o));const l=pd(1,gd(1,i.mul(o.sub(h)).add(1)));return Up(e,oc(h),l)})).setLayout({name:"NeutralToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]});var JE=Object.freeze({__proto__:null,ACESFilmicToneMapping:HE,AgXToneMapping:XE,CineonToneMapping:GE,LinearToneMapping:DE,NeutralToneMapping:YE,ReinhardToneMapping:kE});const ZE=ju((([e=t()])=>{const t=e.mul(2),s=t.x.floor(),i=t.y.floor();return s.add(i).mod(2).sign()})),KE=ju((([e,t,s])=>{const i=Ku(s).toVar(),r=Ku(t).toVar(),n=tc(e).toVar();return qp(n,r,i)})).setLayout({name:"mx_select",type:"float",inputs:[{name:"b",type:"bool"},{name:"t",type:"float"},{name:"f",type:"float"}]}),QE=ju((([e,t])=>{const s=tc(t).toVar(),i=Ku(e).toVar();return qp(s,i.negate(),i)})).setLayout({name:"mx_negate_if",type:"float",inputs:[{name:"val",type:"float"},{name:"b",type:"bool"}]}),eB=ju((([e])=>{const t=Ku(e).toVar();return Qu(Jd(t))})).setLayout({name:"mx_floor",type:"int",inputs:[{name:"x",type:"float"}]}),tB=ju((([e,t])=>{const s=Ku(e).toVar();return t.assign(eB(s)),s.sub(Ku(t))})),sB=xM([ju((([e,t,s,i,r,n])=>{const o=Ku(n).toVar(),a=Ku(r).toVar(),h=Ku(i).toVar(),l=Ku(s).toVar(),u=Ku(t).toVar(),c=Ku(e).toVar(),d=Ku(pd(1,a)).toVar();return pd(1,o).mul(c.mul(d).add(u.mul(a))).add(o.mul(l.mul(d).add(h.mul(a))))})).setLayout({name:"mx_bilerp_0",type:"float",inputs:[{name:"v0",type:"float"},{name:"v1",type:"float"},{name:"v2",type:"float"},{name:"v3",type:"float"},{name:"s",type:"float"},{name:"t",type:"float"}]}),ju((([e,t,s,i,r,n])=>{const o=Ku(n).toVar(),a=Ku(r).toVar(),h=oc(i).toVar(),l=oc(s).toVar(),u=oc(t).toVar(),c=oc(e).toVar(),d=Ku(pd(1,a)).toVar();return pd(1,o).mul(c.mul(d).add(u.mul(a))).add(o.mul(l.mul(d).add(h.mul(a))))})).setLayout({name:"mx_bilerp_1",type:"vec3",inputs:[{name:"v0",type:"vec3"},{name:"v1",type:"vec3"},{name:"v2",type:"vec3"},{name:"v3",type:"vec3"},{name:"s",type:"float"},{name:"t",type:"float"}]})]),iB=xM([ju((([e,t,s,i,r,n,o,a,h,l,u])=>{const c=Ku(u).toVar(),d=Ku(l).toVar(),p=Ku(h).toVar(),m=Ku(a).toVar(),g=Ku(o).toVar(),f=Ku(n).toVar(),y=Ku(r).toVar(),x=Ku(i).toVar(),b=Ku(s).toVar(),v=Ku(t).toVar(),T=Ku(e).toVar(),_=Ku(pd(1,p)).toVar(),w=Ku(pd(1,d)).toVar();return Ku(pd(1,c)).toVar().mul(w.mul(T.mul(_).add(v.mul(p))).add(d.mul(b.mul(_).add(x.mul(p))))).add(c.mul(w.mul(y.mul(_).add(f.mul(p))).add(d.mul(g.mul(_).add(m.mul(p))))))})).setLayout({name:"mx_trilerp_0",type:"float",inputs:[{name:"v0",type:"float"},{name:"v1",type:"float"},{name:"v2",type:"float"},{name:"v3",type:"float"},{name:"v4",type:"float"},{name:"v5",type:"float"},{name:"v6",type:"float"},{name:"v7",type:"float"},{name:"s",type:"float"},{name:"t",type:"float"},{name:"r",type:"float"}]}),ju((([e,t,s,i,r,n,o,a,h,l,u])=>{const c=Ku(u).toVar(),d=Ku(l).toVar(),p=Ku(h).toVar(),m=oc(a).toVar(),g=oc(o).toVar(),f=oc(n).toVar(),y=oc(r).toVar(),x=oc(i).toVar(),b=oc(s).toVar(),v=oc(t).toVar(),T=oc(e).toVar(),_=Ku(pd(1,p)).toVar(),w=Ku(pd(1,d)).toVar();return Ku(pd(1,c)).toVar().mul(w.mul(T.mul(_).add(v.mul(p))).add(d.mul(b.mul(_).add(x.mul(p))))).add(c.mul(w.mul(y.mul(_).add(f.mul(p))).add(d.mul(g.mul(_).add(m.mul(p))))))})).setLayout({name:"mx_trilerp_1",type:"vec3",inputs:[{name:"v0",type:"vec3"},{name:"v1",type:"vec3"},{name:"v2",type:"vec3"},{name:"v3",type:"vec3"},{name:"v4",type:"vec3"},{name:"v5",type:"vec3"},{name:"v6",type:"vec3"},{name:"v7",type:"vec3"},{name:"s",type:"float"},{name:"t",type:"float"},{name:"r",type:"float"}]})]),rB=ju((([e,t,s])=>{const i=Ku(s).toVar(),r=Ku(t).toVar(),n=ec(e).toVar(),o=ec(n.bitAnd(ec(7))).toVar(),a=Ku(KE(o.lessThan(ec(4)),r,i)).toVar(),h=Ku(md(2,KE(o.lessThan(ec(4)),i,r))).toVar();return QE(a,tc(o.bitAnd(ec(1)))).add(QE(h,tc(o.bitAnd(ec(2)))))})).setLayout({name:"mx_gradient_float_0",type:"float",inputs:[{name:"hash",type:"uint"},{name:"x",type:"float"},{name:"y",type:"float"}]}),nB=ju((([e,t,s,i])=>{const r=Ku(i).toVar(),n=Ku(s).toVar(),o=Ku(t).toVar(),a=ec(e).toVar(),h=ec(a.bitAnd(ec(15))).toVar(),l=Ku(KE(h.lessThan(ec(8)),o,n)).toVar(),u=Ku(KE(h.lessThan(ec(4)),n,KE(h.equal(ec(12)).or(h.equal(ec(14))),o,r))).toVar();return QE(l,tc(h.bitAnd(ec(1)))).add(QE(u,tc(h.bitAnd(ec(2)))))})).setLayout({name:"mx_gradient_float_1",type:"float",inputs:[{name:"hash",type:"uint"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]}),oB=xM([rB,nB]),aB=ju((([e,t,s])=>{const i=Ku(s).toVar(),r=Ku(t).toVar(),n=hc(e).toVar();return oc(oB(n.x,r,i),oB(n.y,r,i),oB(n.z,r,i))})).setLayout({name:"mx_gradient_vec3_0",type:"vec3",inputs:[{name:"hash",type:"uvec3"},{name:"x",type:"float"},{name:"y",type:"float"}]}),hB=ju((([e,t,s,i])=>{const r=Ku(i).toVar(),n=Ku(s).toVar(),o=Ku(t).toVar(),a=hc(e).toVar();return oc(oB(a.x,o,n,r),oB(a.y,o,n,r),oB(a.z,o,n,r))})).setLayout({name:"mx_gradient_vec3_1",type:"vec3",inputs:[{name:"hash",type:"uvec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]}),lB=xM([aB,hB]),uB=ju((([e])=>{const t=Ku(e).toVar();return md(.6616,t)})).setLayout({name:"mx_gradient_scale2d_0",type:"float",inputs:[{name:"v",type:"float"}]}),cB=ju((([e])=>{const t=Ku(e).toVar();return md(.982,t)})).setLayout({name:"mx_gradient_scale3d_0",type:"float",inputs:[{name:"v",type:"float"}]}),dB=xM([uB,ju((([e])=>{const t=oc(e).toVar();return md(.6616,t)})).setLayout({name:"mx_gradient_scale2d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),pB=xM([cB,ju((([e])=>{const t=oc(e).toVar();return md(.982,t)})).setLayout({name:"mx_gradient_scale3d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),mB=ju((([e,t])=>{const s=Qu(t).toVar(),i=ec(e).toVar();return i.shiftLeft(s).bitOr(i.shiftRight(Qu(32).sub(s)))})).setLayout({name:"mx_rotl32",type:"uint",inputs:[{name:"x",type:"uint"},{name:"k",type:"int"}]}),gB=ju((([e,t,s])=>{e.subAssign(s),e.bitXorAssign(mB(s,Qu(4))),s.addAssign(t),t.subAssign(e),t.bitXorAssign(mB(e,Qu(6))),e.addAssign(s),s.subAssign(t),s.bitXorAssign(mB(t,Qu(8))),t.addAssign(e),e.subAssign(s),e.bitXorAssign(mB(s,Qu(16))),s.addAssign(t),t.subAssign(e),t.bitXorAssign(mB(e,Qu(19))),e.addAssign(s),s.subAssign(t),s.bitXorAssign(mB(t,Qu(4))),t.addAssign(e)})),fB=ju((([e,t,s])=>{const i=ec(s).toVar(),r=ec(t).toVar(),n=ec(e).toVar();return i.bitXorAssign(r),i.subAssign(mB(r,Qu(14))),n.bitXorAssign(i),n.subAssign(mB(i,Qu(11))),r.bitXorAssign(n),r.subAssign(mB(n,Qu(25))),i.bitXorAssign(r),i.subAssign(mB(r,Qu(16))),n.bitXorAssign(i),n.subAssign(mB(i,Qu(4))),r.bitXorAssign(n),r.subAssign(mB(n,Qu(14))),i.bitXorAssign(r),i.subAssign(mB(r,Qu(24))),i})).setLayout({name:"mx_bjfinal",type:"uint",inputs:[{name:"a",type:"uint"},{name:"b",type:"uint"},{name:"c",type:"uint"}]}),yB=ju((([e])=>{const t=ec(e).toVar();return Ku(t).div(Ku(ec(Qu(4294967295))))})).setLayout({name:"mx_bits_to_01",type:"float",inputs:[{name:"bits",type:"uint"}]}),xB=ju((([e])=>{const t=Ku(e).toVar();return t.mul(t).mul(t).mul(t.mul(t.mul(6).sub(15)).add(10))})).setLayout({name:"mx_fade",type:"float",inputs:[{name:"t",type:"float"}]}),bB=xM([ju((([e])=>{const t=Qu(e).toVar(),s=ec(ec(1)).toVar(),i=ec(ec(Qu(3735928559)).add(s.shiftLeft(ec(2))).add(ec(13))).toVar();return fB(i.add(ec(t)),i,i)})).setLayout({name:"mx_hash_int_0",type:"uint",inputs:[{name:"x",type:"int"}]}),ju((([e,t])=>{const s=Qu(t).toVar(),i=Qu(e).toVar(),r=ec(ec(2)).toVar(),n=ec().toVar(),o=ec().toVar(),a=ec().toVar();return n.assign(o.assign(a.assign(ec(Qu(3735928559)).add(r.shiftLeft(ec(2))).add(ec(13))))),n.addAssign(ec(i)),o.addAssign(ec(s)),fB(n,o,a)})).setLayout({name:"mx_hash_int_1",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),ju((([e,t,s])=>{const i=Qu(s).toVar(),r=Qu(t).toVar(),n=Qu(e).toVar(),o=ec(ec(3)).toVar(),a=ec().toVar(),h=ec().toVar(),l=ec().toVar();return a.assign(h.assign(l.assign(ec(Qu(3735928559)).add(o.shiftLeft(ec(2))).add(ec(13))))),a.addAssign(ec(n)),h.addAssign(ec(r)),l.addAssign(ec(i)),fB(a,h,l)})).setLayout({name:"mx_hash_int_2",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]}),ju((([e,t,s,i])=>{const r=Qu(i).toVar(),n=Qu(s).toVar(),o=Qu(t).toVar(),a=Qu(e).toVar(),h=ec(ec(4)).toVar(),l=ec().toVar(),u=ec().toVar(),c=ec().toVar();return l.assign(u.assign(c.assign(ec(Qu(3735928559)).add(h.shiftLeft(ec(2))).add(ec(13))))),l.addAssign(ec(a)),u.addAssign(ec(o)),c.addAssign(ec(n)),gB(l,u,c),l.addAssign(ec(r)),fB(l,u,c)})).setLayout({name:"mx_hash_int_3",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"},{name:"xx",type:"int"}]}),ju((([e,t,s,i,r])=>{const n=Qu(r).toVar(),o=Qu(i).toVar(),a=Qu(s).toVar(),h=Qu(t).toVar(),l=Qu(e).toVar(),u=ec(ec(5)).toVar(),c=ec().toVar(),d=ec().toVar(),p=ec().toVar();return c.assign(d.assign(p.assign(ec(Qu(3735928559)).add(u.shiftLeft(ec(2))).add(ec(13))))),c.addAssign(ec(l)),d.addAssign(ec(h)),p.addAssign(ec(a)),gB(c,d,p),c.addAssign(ec(o)),d.addAssign(ec(n)),fB(c,d,p)})).setLayout({name:"mx_hash_int_4",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"},{name:"xx",type:"int"},{name:"yy",type:"int"}]})]),vB=xM([ju((([e,t])=>{const s=Qu(t).toVar(),i=Qu(e).toVar(),r=ec(bB(i,s)).toVar(),n=hc().toVar();return n.x.assign(r.bitAnd(Qu(255))),n.y.assign(r.shiftRight(Qu(8)).bitAnd(Qu(255))),n.z.assign(r.shiftRight(Qu(16)).bitAnd(Qu(255))),n})).setLayout({name:"mx_hash_vec3_0",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),ju((([e,t,s])=>{const i=Qu(s).toVar(),r=Qu(t).toVar(),n=Qu(e).toVar(),o=ec(bB(n,r,i)).toVar(),a=hc().toVar();return a.x.assign(o.bitAnd(Qu(255))),a.y.assign(o.shiftRight(Qu(8)).bitAnd(Qu(255))),a.z.assign(o.shiftRight(Qu(16)).bitAnd(Qu(255))),a})).setLayout({name:"mx_hash_vec3_1",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]})]),TB=xM([ju((([e])=>{const t=sc(e).toVar(),s=Qu().toVar(),i=Qu().toVar(),r=Ku(tB(t.x,s)).toVar(),n=Ku(tB(t.y,i)).toVar(),o=Ku(xB(r)).toVar(),a=Ku(xB(n)).toVar(),h=Ku(sB(oB(bB(s,i),r,n),oB(bB(s.add(Qu(1)),i),r.sub(1),n),oB(bB(s,i.add(Qu(1))),r,n.sub(1)),oB(bB(s.add(Qu(1)),i.add(Qu(1))),r.sub(1),n.sub(1)),o,a)).toVar();return dB(h)})).setLayout({name:"mx_perlin_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"}]}),ju((([e])=>{const t=oc(e).toVar(),s=Qu().toVar(),i=Qu().toVar(),r=Qu().toVar(),n=Ku(tB(t.x,s)).toVar(),o=Ku(tB(t.y,i)).toVar(),a=Ku(tB(t.z,r)).toVar(),h=Ku(xB(n)).toVar(),l=Ku(xB(o)).toVar(),u=Ku(xB(a)).toVar(),c=Ku(iB(oB(bB(s,i,r),n,o,a),oB(bB(s.add(Qu(1)),i,r),n.sub(1),o,a),oB(bB(s,i.add(Qu(1)),r),n,o.sub(1),a),oB(bB(s.add(Qu(1)),i.add(Qu(1)),r),n.sub(1),o.sub(1),a),oB(bB(s,i,r.add(Qu(1))),n,o,a.sub(1)),oB(bB(s.add(Qu(1)),i,r.add(Qu(1))),n.sub(1),o,a.sub(1)),oB(bB(s,i.add(Qu(1)),r.add(Qu(1))),n,o.sub(1),a.sub(1)),oB(bB(s.add(Qu(1)),i.add(Qu(1)),r.add(Qu(1))),n.sub(1),o.sub(1),a.sub(1)),h,l,u)).toVar();return pB(c)})).setLayout({name:"mx_perlin_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"}]})]),_B=xM([ju((([e])=>{const t=sc(e).toVar(),s=Qu().toVar(),i=Qu().toVar(),r=Ku(tB(t.x,s)).toVar(),n=Ku(tB(t.y,i)).toVar(),o=Ku(xB(r)).toVar(),a=Ku(xB(n)).toVar(),h=oc(sB(lB(vB(s,i),r,n),lB(vB(s.add(Qu(1)),i),r.sub(1),n),lB(vB(s,i.add(Qu(1))),r,n.sub(1)),lB(vB(s.add(Qu(1)),i.add(Qu(1))),r.sub(1),n.sub(1)),o,a)).toVar();return dB(h)})).setLayout({name:"mx_perlin_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),ju((([e])=>{const t=oc(e).toVar(),s=Qu().toVar(),i=Qu().toVar(),r=Qu().toVar(),n=Ku(tB(t.x,s)).toVar(),o=Ku(tB(t.y,i)).toVar(),a=Ku(tB(t.z,r)).toVar(),h=Ku(xB(n)).toVar(),l=Ku(xB(o)).toVar(),u=Ku(xB(a)).toVar(),c=oc(iB(lB(vB(s,i,r),n,o,a),lB(vB(s.add(Qu(1)),i,r),n.sub(1),o,a),lB(vB(s,i.add(Qu(1)),r),n,o.sub(1),a),lB(vB(s.add(Qu(1)),i.add(Qu(1)),r),n.sub(1),o.sub(1),a),lB(vB(s,i,r.add(Qu(1))),n,o,a.sub(1)),lB(vB(s.add(Qu(1)),i,r.add(Qu(1))),n.sub(1),o,a.sub(1)),lB(vB(s,i.add(Qu(1)),r.add(Qu(1))),n,o.sub(1),a.sub(1)),lB(vB(s.add(Qu(1)),i.add(Qu(1)),r.add(Qu(1))),n.sub(1),o.sub(1),a.sub(1)),h,l,u)).toVar();return pB(c)})).setLayout({name:"mx_perlin_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"}]})]),wB=xM([ju((([e])=>{const t=Ku(e).toVar(),s=Qu(eB(t)).toVar();return yB(bB(s))})).setLayout({name:"mx_cell_noise_float_0",type:"float",inputs:[{name:"p",type:"float"}]}),ju((([e])=>{const t=sc(e).toVar(),s=Qu(eB(t.x)).toVar(),i=Qu(eB(t.y)).toVar();return yB(bB(s,i))})).setLayout({name:"mx_cell_noise_float_1",type:"float",inputs:[{name:"p",type:"vec2"}]}),ju((([e])=>{const t=oc(e).toVar(),s=Qu(eB(t.x)).toVar(),i=Qu(eB(t.y)).toVar(),r=Qu(eB(t.z)).toVar();return yB(bB(s,i,r))})).setLayout({name:"mx_cell_noise_float_2",type:"float",inputs:[{name:"p",type:"vec3"}]}),ju((([e])=>{const t=uc(e).toVar(),s=Qu(eB(t.x)).toVar(),i=Qu(eB(t.y)).toVar(),r=Qu(eB(t.z)).toVar(),n=Qu(eB(t.w)).toVar();return yB(bB(s,i,r,n))})).setLayout({name:"mx_cell_noise_float_3",type:"float",inputs:[{name:"p",type:"vec4"}]})]),SB=xM([ju((([e])=>{const t=Ku(e).toVar(),s=Qu(eB(t)).toVar();return oc(yB(bB(s,Qu(0))),yB(bB(s,Qu(1))),yB(bB(s,Qu(2))))})).setLayout({name:"mx_cell_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"float"}]}),ju((([e])=>{const t=sc(e).toVar(),s=Qu(eB(t.x)).toVar(),i=Qu(eB(t.y)).toVar();return oc(yB(bB(s,i,Qu(0))),yB(bB(s,i,Qu(1))),yB(bB(s,i,Qu(2))))})).setLayout({name:"mx_cell_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),ju((([e])=>{const t=oc(e).toVar(),s=Qu(eB(t.x)).toVar(),i=Qu(eB(t.y)).toVar(),r=Qu(eB(t.z)).toVar();return oc(yB(bB(s,i,r,Qu(0))),yB(bB(s,i,r,Qu(1))),yB(bB(s,i,r,Qu(2))))})).setLayout({name:"mx_cell_noise_vec3_2",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),ju((([e])=>{const t=uc(e).toVar(),s=Qu(eB(t.x)).toVar(),i=Qu(eB(t.y)).toVar(),r=Qu(eB(t.z)).toVar(),n=Qu(eB(t.w)).toVar();return oc(yB(bB(s,i,r,n,Qu(0))),yB(bB(s,i,r,n,Qu(1))),yB(bB(s,i,r,n,Qu(2))))})).setLayout({name:"mx_cell_noise_vec3_3",type:"vec3",inputs:[{name:"p",type:"vec4"}]})]),MB=ju((([e,t,s,i])=>{const r=Ku(i).toVar(),n=Ku(s).toVar(),o=Qu(t).toVar(),a=oc(e).toVar(),h=Ku(0).toVar(),l=Ku(1).toVar();return Cy(o,(()=>{h.addAssign(l.mul(TB(a))),l.mulAssign(r),a.mulAssign(n)})),h})).setLayout({name:"mx_fractal_noise_float",type:"float",inputs:[{name:"p",type:"vec3"},{name:"octaves",type:"int"},{name:"lacunarity",type:"float"},{name:"diminish",type:"float"}]}),AB=ju((([e,t,s,i])=>{const r=Ku(i).toVar(),n=Ku(s).toVar(),o=Qu(t).toVar(),a=oc(e).toVar(),h=oc(0).toVar(),l=Ku(1).toVar();return Cy(o,(()=>{h.addAssign(l.mul(_B(a))),l.mulAssign(r),a.mulAssign(n)})),h})).setLayout({name:"mx_fractal_noise_vec3",type:"vec3",inputs:[{name:"p",type:"vec3"},{name:"octaves",type:"int"},{name:"lacunarity",type:"float"},{name:"diminish",type:"float"}]}),NB=ju((([e,t,s,i])=>{const r=Ku(i).toVar(),n=Ku(s).toVar(),o=Qu(t).toVar(),a=oc(e).toVar();return sc(MB(a,o,n,r),MB(a.add(oc(Qu(19),Qu(193),Qu(17))),o,n,r))})).setLayout({name:"mx_fractal_noise_vec2",type:"vec2",inputs:[{name:"p",type:"vec3"},{name:"octaves",type:"int"},{name:"lacunarity",type:"float"},{name:"diminish",type:"float"}]}),RB=ju((([e,t,s,i])=>{const r=Ku(i).toVar(),n=Ku(s).toVar(),o=Qu(t).toVar(),a=oc(e).toVar(),h=oc(AB(a,o,n,r)).toVar(),l=Ku(MB(a.add(oc(Qu(19),Qu(193),Qu(17))),o,n,r)).toVar();return uc(h,l)})).setLayout({name:"mx_fractal_noise_vec4",type:"vec4",inputs:[{name:"p",type:"vec3"},{name:"octaves",type:"int"},{name:"lacunarity",type:"float"},{name:"diminish",type:"float"}]}),CB=ju((([e,t,s,i,r,n,o])=>{const a=Qu(o).toVar(),h=Ku(n).toVar(),l=Qu(r).toVar(),u=Qu(i).toVar(),c=Qu(s).toVar(),d=Qu(t).toVar(),p=sc(e).toVar(),m=oc(SB(sc(d.add(u),c.add(l)))).toVar(),g=sc(m.x,m.y).toVar();g.subAssign(.5),g.mulAssign(h),g.addAssign(.5);const f=sc(sc(Ku(d),Ku(c)).add(g)).toVar(),y=sc(f.sub(p)).toVar();return Yu(a.equal(Qu(2)),(()=>op(y.x).add(op(y.y)))),Yu(a.equal(Qu(3)),(()=>Tp(op(y.x),op(y.y)))),Np(y,y)})).setLayout({name:"mx_worley_distance_0",type:"float",inputs:[{name:"p",type:"vec2"},{name:"x",type:"int"},{name:"y",type:"int"},{name:"xoff",type:"int"},{name:"yoff",type:"int"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),EB=xM([CB,ju((([e,t,s,i,r,n,o,a,h])=>{const l=Qu(h).toVar(),u=Ku(a).toVar(),c=Qu(o).toVar(),d=Qu(n).toVar(),p=Qu(r).toVar(),m=Qu(i).toVar(),g=Qu(s).toVar(),f=Qu(t).toVar(),y=oc(e).toVar(),x=oc(SB(oc(f.add(p),g.add(d),m.add(c)))).toVar();x.subAssign(.5),x.mulAssign(u),x.addAssign(.5);const b=oc(oc(Ku(f),Ku(g),Ku(m)).add(x)).toVar(),v=oc(b.sub(y)).toVar();return Yu(l.equal(Qu(2)),(()=>op(v.x).add(op(v.y)).add(op(v.z)))),Yu(l.equal(Qu(3)),(()=>Tp(Tp(op(v.x),op(v.y)),op(v.z)))),Np(v,v)})).setLayout({name:"mx_worley_distance_1",type:"float",inputs:[{name:"p",type:"vec3"},{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"},{name:"xoff",type:"int"},{name:"yoff",type:"int"},{name:"zoff",type:"int"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),BB=ju((([e,t,s])=>{const i=Qu(s).toVar(),r=Ku(t).toVar(),n=sc(e).toVar(),o=Qu().toVar(),a=Qu().toVar(),h=sc(tB(n.x,o),tB(n.y,a)).toVar(),l=Ku(1e6).toVar();return Cy({start:-1,end:Qu(1),name:"x",condition:"<="},(({x:e})=>{Cy({start:-1,end:Qu(1),name:"y",condition:"<="},(({y:t})=>{const s=Ku(EB(h,e,t,o,a,r,i)).toVar();l.assign(vp(l,s))}))})),Yu(i.equal(Qu(0)),(()=>{l.assign(Xd(l))})),l})).setLayout({name:"mx_worley_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),IB=ju((([e,t,s])=>{const i=Qu(s).toVar(),r=Ku(t).toVar(),n=sc(e).toVar(),o=Qu().toVar(),a=Qu().toVar(),h=sc(tB(n.x,o),tB(n.y,a)).toVar(),l=sc(1e6,1e6).toVar();return Cy({start:-1,end:Qu(1),name:"x",condition:"<="},(({x:e})=>{Cy({start:-1,end:Qu(1),name:"y",condition:"<="},(({y:t})=>{const s=Ku(EB(h,e,t,o,a,r,i)).toVar();Yu(s.lessThan(l.x),(()=>{l.y.assign(l.x),l.x.assign(s)})).ElseIf(s.lessThan(l.y),(()=>{l.y.assign(s)}))}))})),Yu(i.equal(Qu(0)),(()=>{l.assign(Xd(l))})),l})).setLayout({name:"mx_worley_noise_vec2_0",type:"vec2",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),PB=ju((([e,t,s])=>{const i=Qu(s).toVar(),r=Ku(t).toVar(),n=sc(e).toVar(),o=Qu().toVar(),a=Qu().toVar(),h=sc(tB(n.x,o),tB(n.y,a)).toVar(),l=oc(1e6,1e6,1e6).toVar();return Cy({start:-1,end:Qu(1),name:"x",condition:"<="},(({x:e})=>{Cy({start:-1,end:Qu(1),name:"y",condition:"<="},(({y:t})=>{const s=Ku(EB(h,e,t,o,a,r,i)).toVar();Yu(s.lessThan(l.x),(()=>{l.z.assign(l.y),l.y.assign(l.x),l.x.assign(s)})).ElseIf(s.lessThan(l.y),(()=>{l.z.assign(l.y),l.y.assign(s)})).ElseIf(s.lessThan(l.z),(()=>{l.z.assign(s)}))}))})),Yu(i.equal(Qu(0)),(()=>{l.assign(Xd(l))})),l})).setLayout({name:"mx_worley_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),FB=xM([BB,ju((([e,t,s])=>{const i=Qu(s).toVar(),r=Ku(t).toVar(),n=oc(e).toVar(),o=Qu().toVar(),a=Qu().toVar(),h=Qu().toVar(),l=oc(tB(n.x,o),tB(n.y,a),tB(n.z,h)).toVar(),u=Ku(1e6).toVar();return Cy({start:-1,end:Qu(1),name:"x",condition:"<="},(({x:e})=>{Cy({start:-1,end:Qu(1),name:"y",condition:"<="},(({y:t})=>{Cy({start:-1,end:Qu(1),name:"z",condition:"<="},(({z:s})=>{const n=Ku(EB(l,e,t,s,o,a,h,r,i)).toVar();u.assign(vp(u,n))}))}))})),Yu(i.equal(Qu(0)),(()=>{u.assign(Xd(u))})),u})).setLayout({name:"mx_worley_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),zB=xM([IB,ju((([e,t,s])=>{const i=Qu(s).toVar(),r=Ku(t).toVar(),n=oc(e).toVar(),o=Qu().toVar(),a=Qu().toVar(),h=Qu().toVar(),l=oc(tB(n.x,o),tB(n.y,a),tB(n.z,h)).toVar(),u=sc(1e6,1e6).toVar();return Cy({start:-1,end:Qu(1),name:"x",condition:"<="},(({x:e})=>{Cy({start:-1,end:Qu(1),name:"y",condition:"<="},(({y:t})=>{Cy({start:-1,end:Qu(1),name:"z",condition:"<="},(({z:s})=>{const n=Ku(EB(l,e,t,s,o,a,h,r,i)).toVar();Yu(n.lessThan(u.x),(()=>{u.y.assign(u.x),u.x.assign(n)})).ElseIf(n.lessThan(u.y),(()=>{u.y.assign(n)}))}))}))})),Yu(i.equal(Qu(0)),(()=>{u.assign(Xd(u))})),u})).setLayout({name:"mx_worley_noise_vec2_1",type:"vec2",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),UB=xM([PB,ju((([e,t,s])=>{const i=Qu(s).toVar(),r=Ku(t).toVar(),n=oc(e).toVar(),o=Qu().toVar(),a=Qu().toVar(),h=Qu().toVar(),l=oc(tB(n.x,o),tB(n.y,a),tB(n.z,h)).toVar(),u=oc(1e6,1e6,1e6).toVar();return Cy({start:-1,end:Qu(1),name:"x",condition:"<="},(({x:e})=>{Cy({start:-1,end:Qu(1),name:"y",condition:"<="},(({y:t})=>{Cy({start:-1,end:Qu(1),name:"z",condition:"<="},(({z:s})=>{const n=Ku(EB(l,e,t,s,o,a,h,r,i)).toVar();Yu(n.lessThan(u.x),(()=>{u.z.assign(u.y),u.y.assign(u.x),u.x.assign(n)})).ElseIf(n.lessThan(u.y),(()=>{u.z.assign(u.y),u.y.assign(n)})).ElseIf(n.lessThan(u.z),(()=>{u.z.assign(n)}))}))}))})),Yu(i.equal(Qu(0)),(()=>{u.assign(Xd(u))})),u})).setLayout({name:"mx_worley_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),LB=ju((([e])=>{const t=e.y,s=e.z,i=oc().toVar();return Yu(t.lessThan(1e-4),(()=>{i.assign(oc(s,s,s))})).Else((()=>{let r=e.x;r=r.sub(Jd(r)).mul(6).toVar();const n=Qu(gp(r)),o=r.sub(Ku(n)),a=s.mul(t.oneMinus()),h=s.mul(t.mul(o).oneMinus()),l=s.mul(t.mul(o.oneMinus()).oneMinus());Yu(n.equal(Qu(0)),(()=>{i.assign(oc(s,l,a))})).ElseIf(n.equal(Qu(1)),(()=>{i.assign(oc(h,s,a))})).ElseIf(n.equal(Qu(2)),(()=>{i.assign(oc(a,s,l))})).ElseIf(n.equal(Qu(3)),(()=>{i.assign(oc(a,h,s))})).ElseIf(n.equal(Qu(4)),(()=>{i.assign(oc(l,a,s))})).Else((()=>{i.assign(oc(s,a,h))}))})),i})).setLayout({name:"mx_hsvtorgb",type:"vec3",inputs:[{name:"hsv",type:"vec3"}]}),OB=ju((([e])=>{const t=oc(e).toVar(),s=Ku(t.x).toVar(),i=Ku(t.y).toVar(),r=Ku(t.z).toVar(),n=Ku(vp(s,vp(i,r))).toVar(),o=Ku(Tp(s,Tp(i,r))).toVar(),a=Ku(o.sub(n)).toVar(),h=Ku().toVar(),l=Ku().toVar(),u=Ku().toVar();return u.assign(o),Yu(o.greaterThan(0),(()=>{l.assign(a.div(o))})).Else((()=>{l.assign(0)})),Yu(l.lessThanEqual(0),(()=>{h.assign(0)})).Else((()=>{Yu(s.greaterThanEqual(o),(()=>{h.assign(i.sub(r).div(a))})).ElseIf(i.greaterThanEqual(o),(()=>{h.assign(dd(2,r.sub(s).div(a)))})).Else((()=>{h.assign(dd(4,s.sub(i).div(a)))})),h.mulAssign(1/6),Yu(h.lessThan(0),(()=>{h.addAssign(1)}))})),oc(h,l,u)})).setLayout({name:"mx_rgbtohsv",type:"vec3",inputs:[{name:"c",type:"vec3"}]}),VB=ju((([e])=>{const t=oc(e).toVar(),s=lc(vd(t,oc(.04045))).toVar(),i=oc(t.div(12.92)).toVar(),r=oc(Cp(Tp(t.add(oc(.055)),oc(0)).div(1.055),oc(2.4))).toVar();return Up(i,r,s)})).setLayout({name:"mx_srgb_texture_to_lin_rec709",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),DB=(e,t)=>{e=Ku(e),t=Ku(t);const s=sc(t.dFdx(),t.dFdy()).length().mul(.7071067811865476);return Dp(e.sub(s),e.add(s),t)},kB=(e,t,s,i)=>Up(e,t,s[i].clamp()),GB=(e,t,s=Um())=>kB(e,t,s,"x"),WB=(e,t,s=Um())=>kB(e,t,s,"y"),HB=(e,t,s,i,r)=>Up(e,t,DB(s,i[r])),jB=(e,t,s,i=Um())=>HB(e,t,s,i,"x"),qB=(e,t,s,i=Um())=>HB(e,t,s,i,"y"),$B=(e=1,t=0,s=Um())=>s.mul(e).add(t),XB=(e,t=1)=>(e=Ku(e)).abs().pow(t).mul(e.sign()),YB=(e,t=1,s=.5)=>Ku(e).sub(s).mul(t).add(s),JB=(e=Um(),t=1,s=0)=>TB(e.convert("vec2|vec3")).mul(t).add(s),ZB=(e=Um(),t=1,s=0)=>_B(e.convert("vec2|vec3")).mul(t).add(s),KB=(e=Um(),t=1,s=0)=>{e=e.convert("vec2|vec3");return uc(_B(e),TB(e.add(sc(19,73)))).mul(t).add(s)},QB=(e=Um(),t=1)=>FB(e.convert("vec2|vec3"),t,Qu(1)),eI=(e=Um(),t=1)=>zB(e.convert("vec2|vec3"),t,Qu(1)),tI=(e=Um(),t=1)=>UB(e.convert("vec2|vec3"),t,Qu(1)),sI=(e=Um())=>wB(e.convert("vec2|vec3")),iI=(e=Um(),t=3,s=2,i=.5,r=1)=>MB(e,Qu(t),s,i).mul(r),rI=(e=Um(),t=3,s=2,i=.5,r=1)=>NB(e,Qu(t),s,i).mul(r),nI=(e=Um(),t=3,s=2,i=.5,r=1)=>AB(e,Qu(t),s,i).mul(r),oI=(e=Um(),t=3,s=2,i=.5,r=1)=>RB(e,Qu(t),s,i).mul(r),aI=new pE;class hI extends Lw{constructor(e,t){super(),this.renderer=e,this.nodes=t}update(e,t,s){const i=this.renderer,r=this.nodes.getBackgroundNode(e)||e.background;let n=!1;if(null===r)i._clearColor.getRGB(aI,Zt),aI.a=i._clearColor.a;else if(!0===r.isColor)r.getRGB(aI,Zt),aI.a=1,n=!0;else if(!0===r.isNode){const s=this.get(e),n=r;aI.copy(i._clearColor);let o=s.backgroundMesh;if(void 0===o){const e=Yp(uc(n).mul(dA),{getUV:()=>Pg,getTextureLevel:()=>cA});let t=py();t=t.setZ(t.w);const i=new xx;i.name="Background.material",i.side=d,i.depthTest=!1,i.depthWrite=!1,i.fog=!1,i.lights=!1,i.vertexNode=t,i.colorNode=e,s.backgroundMeshNode=e,s.backgroundMesh=o=new Wn(new fl(1,32,32),i),o.frustumCulled=!1,o.name="Background.mesh",o.onBeforeRender=function(e,t,s){this.matrixWorld.copyPosition(s.matrixWorld)}}const a=n.getCacheKey();s.backgroundCacheKey!==a&&(s.backgroundMeshNode.node=uc(n).mul(dA),s.backgroundMeshNode.needsUpdate=!0,o.material.needsUpdate=!0,s.backgroundCacheKey=a),t.unshift(o,o.geometry,o.material,0,0,null)}else console.error("THREE.Renderer: Unsupported background configuration.",r);if(!0===i.autoClear||!0===n){aI.multiplyScalar(aI.a);const e=s.clearColorValue;e.r=aI.r,e.g=aI.g,e.b=aI.b,e.a=aI.a,s.depthClearValue=i._clearDepth,s.stencilClearValue=i._clearStencil,s.clearColor=!0===i.autoClearColor,s.clearDepth=!0===i.autoClearDepth,s.clearStencil=!0===i.autoClearStencil}else s.clearColor=!1,s.clearDepth=!1,s.clearStencil=!1}}class lI{constructor(e,t,s,i,r,n,o,a,h=!0,l=[]){this.vertexShader=e,this.fragmentShader=t,this.computeShader=s,this.transforms=l,this.nodeAttributes=i,this.bindings=r,this.updateNodes=n,this.updateBeforeNodes=o,this.updateAfterNodes=a,this.instanceBindGroups=h,this.usedTimes=0}createBindings(){const e=[];for(const t of this.bindings){if(!0!==(this.instanceBindGroups&&t.bindings[0].groupNode.shared)){const s=new sM(t.name,[],t.index,t);e.push(s);for(const e of t.bindings)s.bindings.push(e.clone())}else e.push(t)}return e}}const uI=new WeakMap;class cI extends Lw{constructor(e,t){super(),this.renderer=e,this.backend=t,this.nodeFrame=new hM,this.nodeBuilderCache=new Map,this.callHashCache=new Bw,this.groupsData=new Bw}updateGroup(e){const t=e.groupNode,s=t.name;if(s===Nc.name)return!0;if(s===Ac.name){const t=this.get(e),s=this.nodeFrame.renderId;return t.renderId!==s&&(t.renderId=s,!0)}if(s===Mc.name){const t=this.get(e),s=this.nodeFrame.frameId;return t.frameId!==s&&(t.frameId=s,!0)}const i=[t,e];let r=this.groupsData.get(i);return void 0===r&&this.groupsData.set(i,r={}),r.version!==t.version&&(r.version=t.version,!0)}getForRenderCacheKey(e){return e.initialCacheKey}getForRender(e){const t=this.get(e);let s=t.nodeBuilderState;if(void 0===s){const{nodeBuilderCache:i}=this,r=this.getForRenderCacheKey(e);if(s=i.get(r),void 0===s){const t=this.backend.createNodeBuilder(e.object,this.renderer);t.scene=e.scene,t.material=e.material,t.camera=e.camera,t.context.material=e.material,t.lightsNode=e.lightsNode,t.environmentNode=this.getEnvironmentNode(e.scene),t.fogNode=this.getFogNode(e.scene),t.clippingContext=e.clippingContext,t.build(),s=this._createNodeBuilderState(t),i.set(r,s)}s.usedTimes++,t.nodeBuilderState=s}return s}delete(e){if(e.isRenderObject){const t=this.get(e).nodeBuilderState;t.usedTimes--,0===t.usedTimes&&this.nodeBuilderCache.delete(this.getForRenderCacheKey(e))}return super.delete(e)}getForCompute(e){const t=this.get(e);let s=t.nodeBuilderState;if(void 0===s){const i=this.backend.createNodeBuilder(e,this.renderer);i.build(),s=this._createNodeBuilderState(i),t.nodeBuilderState=s}return s}_createNodeBuilderState(e){return new lI(e.vertexShader,e.fragmentShader,e.computeShader,e.getAttributesArray(),e.getBindings(),e.updateNodes,e.updateBeforeNodes,e.updateAfterNodes,e.instanceBindGroups,e.transforms)}getEnvironmentNode(e){return e.environmentNode||this.get(e).environmentNode||null}getBackgroundNode(e){return e.backgroundNode||this.get(e).backgroundNode||null}getFogNode(e){return e.fogNode||this.get(e).fogNode||null}getCacheKey(e,t){const s=[e,t],i=this.renderer.info.calls;let r=this.callHashCache.get(s);if(void 0===r||r.callId!==i){const n=this.getEnvironmentNode(e),o=this.getFogNode(e),a=[];t&&a.push(t.getCacheKey(!0)),n&&a.push(n.getCacheKey()),o&&a.push(o.getCacheKey()),r={callId:i,cacheKey:a.join(",")},this.callHashCache.set(s,r)}return r.cacheKey}updateScene(e){this.updateEnvironment(e),this.updateFog(e),this.updateBackground(e)}get isToneMappingState(){return!this.renderer.getRenderTarget()}updateBackground(e){const t=this.get(e),s=e.background;if(s){const i=0===e.backgroundBlurriness&&t.backgroundBlurriness>0||e.backgroundBlurriness>0&&0===t.backgroundBlurriness;if(t.background!==s||i){let i=null;if(!0===s.isCubeTexture||s.mapping===ue||s.mapping===ce)if(e.backgroundBlurriness>0)i=mv(s,Pg);else{let e;e=!0===s.isCubeTexture?Wg(s):Gm(s),i=Vx(e)}else!0===s.isTexture?i=Gm(s,Zy.flipY()).setUpdateMatrix(!0):!0!==s.isColor&&console.error("WebGPUNodes: Unsupported background configuration.",s);t.backgroundNode=i,t.background=s,t.backgroundBlurriness=e.backgroundBlurriness}}else t.backgroundNode&&(delete t.backgroundNode,delete t.background)}updateFog(e){const t=this.get(e),s=e.fog;if(s){if(t.fog!==s){let e=null;s.isFogExp2?e=SC(Zg("color","color",s),Zg("density","float",s)):s.isFog?e=_C(Zg("color","color",s),Zg("near","float",s),Zg("far","float",s)):console.error("WebGPUNodes: Unsupported fog configuration.",s),t.fogNode=e,t.fog=s}}else delete t.fogNode,delete t.fog}updateEnvironment(e){const t=this.get(e),s=e.environment;if(s){if(t.environment!==s){let e=null;!0===s.isCubeTexture?e=Wg(s):!0===s.isTexture?e=Gm(s):console.error("Nodes: Unsupported environment configuration.",s),t.environmentNode=e,t.environment=s}}else t.environmentNode&&(delete t.environmentNode,delete t.environment)}getNodeFrame(e=this.renderer,t=null,s=null,i=null,r=null){const n=this.nodeFrame;return n.renderer=e,n.scene=t,n.object=s,n.camera=i,n.material=r,n}getNodeFrameForRender(e){return this.getNodeFrame(e.renderer,e.scene,e.object,e.camera,e.material)}getOutputCacheKey(){const e=this.renderer;return e.toneMapping+","+e.currentColorSpace}hasOutputChange(e){return uI.get(e)!==this.getOutputCacheKey()}getOutputNode(e){const t=this.renderer,s=this.getOutputCacheKey(),i=Gm(e,Zy).renderOutput(t.toneMapping,t.currentColorSpace);return uI.set(e,s),i}updateBefore(e){const t=e.getNodeBuilderState();for(const s of t.updateBeforeNodes)this.getNodeFrameForRender(e).updateBeforeNode(s)}updateAfter(e){const t=e.getNodeBuilderState();for(const s of t.updateAfterNodes)this.getNodeFrameForRender(e).updateAfterNode(s)}updateForCompute(e){const t=this.getNodeFrame(),s=this.getForCompute(e);for(const e of s.updateNodes)t.updateNode(e)}updateForRender(e){const t=this.getNodeFrameForRender(e),s=e.getNodeBuilderState();for(const e of s.updateNodes)t.updateNode(e)}dispose(){super.dispose(),this.nodeFrame=new hM,this.nodeBuilderCache=new Map}}class dI{constructor(e,t){this.scene=e,this.camera=t}clone(){return Object.assign(new this.constructor,this)}}class pI{constructor(){this.lists=new Bw}get(e,t){const s=this.lists,i=[e,t];let r=s.get(i);return void 0===r&&(r=new dI(e,t),s.set(i,r)),r}dispose(){this.lists=new Bw}}class mI{constructor(){this.lightNodes=new WeakMap,this.materialNodes=new Map,this.toneMappingNodes=new Map,this.colorSpaceNodes=new Map}fromMaterial(e){if(e.isNodeMaterial)return e;let t=null;const s=this.getMaterialNodeClass(e.type);if(null!==s){t=new s;for(const s in e)t[s]=e[s]}return t}addColorSpace(e,t){this.addType(e,t,this.colorSpaceNodes)}getColorSpaceFunction(e){return this.colorSpaceNodes.get(e)||null}addToneMapping(e,t){this.addType(e,t,this.toneMappingNodes)}getToneMappingFunction(e){return this.toneMappingNodes.get(e)||null}getMaterialNodeClass(e){return this.materialNodes.get(e)||null}addMaterial(e,t){this.addType(e,t.name,this.materialNodes)}getLightNodeClass(e){return this.lightNodes.get(e)||null}addLight(e,t){this.addClass(e,t,this.lightNodes)}addType(e,t,s){if(s.has(t))console.warn(`Redefinition of node ${t}`);else{if("function"!=typeof e)throw new Error(`Node class ${e.name} is not a class.`);if("function"==typeof t||"object"==typeof t)throw new Error(`Base class ${t} is not a class.`);s.set(t,e)}}addClass(e,t,s){if(s.has(t))console.warn(`Redefinition of node ${t.name}`);else{if("function"!=typeof e)throw new Error(`Node class ${e.name} is not a class.`);if("function"!=typeof t)throw new Error(`Base class ${t.name} is not a class.`);s.set(t,e)}}}const gI=new no,fI=new Qs,yI=new _i,xI=new na,bI=new or,vI=new Ei;class TI{constructor(e,t={}){this.isRenderer=!0;const{logarithmicDepthBuffer:s=!1,alpha:i=!0,antialias:r=!1,samples:n=0,getFallback:o=null}=t;this.domElement=e.getDomElement(),this.backend=e,this.samples=n||!0===r?4:0,this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.alpha=i,this.logarithmicDepthBuffer=s,this.outputColorSpace=Jt,this.toneMapping=0,this.toneMappingExposure=1,this.sortObjects=!0,this.depth=!0,this.stencil=!1,this.clippingPlanes=[],this.info=new qw,this.nodes={library:new mI},this._getFallback=o,this._pixelRatio=1,this._width=this.domElement.width,this._height=this.domElement.height,this._viewport=new _i(0,0,this._width,this._height),this._scissor=new _i(0,0,this._width,this._height),this._scissorTest=!1,this._attributes=null,this._geometries=null,this._nodes=null,this._animation=null,this._bindings=null,this._objects=null,this._pipelines=null,this._bundles=null,this._renderLists=null,this._renderContexts=null,this._textures=null,this._background=null,this._quad=new tA(new xx),this._quad.material.type="Renderer_output",this._currentRenderContext=null,this._opaqueSort=null,this._transparentSort=null,this._frameBufferTarget=null;const a=!0===this.alpha?0:1;this._clearColor=new pE(0,0,0,a),this._clearDepth=1,this._clearStencil=0,this._renderTarget=null,this._activeCubeFace=0,this._activeMipmapLevel=0,this._mrt=null,this._renderObjectFunction=null,this._currentRenderObjectFunction=null,this._currentRenderBundle=null,this._handleObjectFunction=this._renderObjectDirect,this._initialized=!1,this._initPromise=null,this._compilationPromises=null,this.transparent=!0,this.opaque=!0,this.shadowMap={enabled:!1,type:1},this.xr={enabled:!1},this.debug={checkShaderErrors:!0,onShaderError:null,getShaderAsync:async(e,t,s)=>{await this.compileAsync(e,t);const i=this._renderLists.get(e,t),r=this._renderContexts.get(e,t,this._renderTarget),n=e.overrideMaterial||s.material,o=this._objects.get(s,n,e,t,i.lightsNode,r),{fragmentShader:a,vertexShader:h}=o.getNodeBuilderState();return{fragmentShader:a,vertexShader:h}}}}async init(){if(this._initialized)throw new Error("Renderer: Backend has already been initialized.");return null!==this._initPromise||(this._initPromise=new Promise((async(e,t)=>{let s=this.backend;try{await s.init(this)}catch(e){if(null===this._getFallback)return void t(e);try{this.backend=s=this._getFallback(e),await s.init(this)}catch(e){return void t(e)}}this._nodes=new cI(this,s),this._animation=new Ew(this._nodes,this.info),this._attributes=new Gw(s),this._background=new hI(this,this._nodes),this._geometries=new jw(this._attributes,this.info),this._textures=new dE(this,s,this.info),this._pipelines=new Kw(s,this._nodes),this._bindings=new Qw(s,this._nodes,this._textures,this._attributes,this._pipelines,this.info),this._objects=new Uw(this,this._nodes,this._geometries,this._pipelines,this._bindings,this.info),this._renderLists=new oE,this._bundles=new pI,this._renderContexts=new uE,this._initialized=!0,e()}))),this._initPromise}get coordinateSystem(){return this.backend.coordinateSystem}async compileAsync(e,t,s=null){!1===this._initialized&&await this.init();const i=this._nodes.nodeFrame,r=i.renderId,n=this._currentRenderContext,o=this._currentRenderObjectFunction,a=this._compilationPromises,h=!0===e.isScene?e:gI;null===s&&(s=e);const l=this._renderTarget,u=this._renderContexts.get(s,t,l),c=this._activeMipmapLevel,d=[];this._currentRenderContext=u,this._currentRenderObjectFunction=this.renderObject,this._handleObjectFunction=this._createObjectPipeline,this._compilationPromises=d,i.renderId++,i.update(),u.depth=this.depth,u.stencil=this.stencil,u.clippingContext||(u.clippingContext=new Pw),u.clippingContext.updateGlobal(this,t),h.onBeforeRender(this,e,t,l);const p=this._renderLists.get(e,t);if(p.begin(),this._projectObject(e,t,0,p),s!==e&&s.traverseVisible((function(e){e.isLight&&e.layers.test(t.layers)&&p.pushLight(e)})),p.finish(),null!==l){this._textures.updateRenderTarget(l,c);const e=this._textures.get(l);u.textures=e.textures,u.depthTexture=e.depthTexture}else u.textures=null,u.depthTexture=null;this._nodes.updateScene(h),this._background.update(h,p,u);const m=p.opaque,g=p.transparent,f=p.lightsNode;!0===this.opaque&&m.length>0&&this._renderObjects(m,t,h,f),!0===this.transparent&&g.length>0&&this._renderObjects(g,t,h,f),i.renderId=r,this._currentRenderContext=n,this._currentRenderObjectFunction=o,this._compilationPromises=a,this._handleObjectFunction=this._renderObjectDirect,await Promise.all(d)}async renderAsync(e,t){!1===this._initialized&&await this.init();const s=this._renderScene(e,t);await this.backend.resolveTimestampAsync(s,"render")}setMRT(e){return this._mrt=e,this}getMRT(){return this._mrt}_renderBundle(e,t,s){const{object:i,camera:r,renderList:n}=e,o=this._currentRenderContext,a=this._bundles.get(i,r),h=this.backend.get(a);void 0===h.renderContexts&&(h.renderContexts=new Set);const l=!1===h.renderContexts.has(o)||!0===i.needsUpdate;if(h.renderContexts.add(o),l){this.backend.beginBundle(o),void 0!==h.renderObjects&&!0!==i.needsUpdate||(h.renderObjects=[]),this._currentRenderBundle=a;const e=n.opaque;e.length>0&&this._renderObjects(e,r,t,s),this._currentRenderBundle=null,this.backend.finishBundle(o,a),i.needsUpdate=!1}else{const e=h.renderObjects;for(let t=0,s=e.length;t>=c,p.viewportValue.height>>=c,p.viewportValue.minDepth=x,p.viewportValue.maxDepth=b,p.viewport=!1===p.viewportValue.equals(yI),p.scissorValue.copy(f).multiplyScalar(y).floor(),p.scissor=this._scissorTest&&!1===p.scissorValue.equals(yI),p.scissorValue.width>>=c,p.scissorValue.height>>=c,p.clippingContext||(p.clippingContext=new Pw),p.clippingContext.updateGlobal(this,t),h.onBeforeRender(this,e,t,d),bI.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),xI.setFromProjectionMatrix(bI,m);const v=this._renderLists.get(e,t);if(v.begin(),this._projectObject(e,t,0,v),v.finish(),!0===this.sortObjects&&v.sort(this._opaqueSort,this._transparentSort),null!==d){this._textures.updateRenderTarget(d,c);const e=this._textures.get(d);p.textures=e.textures,p.depthTexture=e.depthTexture,p.width=e.width,p.height=e.height,p.renderTarget=d,p.depth=d.depthBuffer,p.stencil=d.stencilBuffer}else p.textures=null,p.depthTexture=null,p.width=this.domElement.width,p.height=this.domElement.height,p.depth=this.depth,p.stencil=this.stencil;p.width>>=c,p.height>>=c,p.activeCubeFace=u,p.activeMipmapLevel=c,p.occlusionQueryCount=v.occlusionQueryCount,this._nodes.updateScene(h),this._background.update(h,v,p),this.backend.beginRender(p);const T=v.opaque,_=v.transparent,w=v.bundles,S=v.lightsNode;if(w.length>0&&this._renderBundles(w,h,S),!0===this.opaque&&T.length>0&&this._renderObjects(T,t,h,S),!0===this.transparent&&_.length>0&&this._renderObjects(_,t,h,S),this.backend.finishRender(p),r.renderId=n,this._currentRenderContext=o,this._currentRenderObjectFunction=a,null!==i){this.setRenderTarget(l,u,c);const e=this._quad;this._nodes.hasOutputChange(d.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(d.texture),e.material.needsUpdate=!0),this._renderScene(e,e.camera,!1)}return h.onAfterRender(this,e,t,d),p}getMaxAnisotropy(){return this.backend.getMaxAnisotropy()}getActiveCubeFace(){return this._activeCubeFace}getActiveMipmapLevel(){return this._activeMipmapLevel}async setAnimationLoop(e){!1===this._initialized&&await this.init(),this._animation.setAnimationLoop(e)}async getArrayBufferAsync(e){return await this.backend.getArrayBufferAsync(e)}getContext(){return this.backend.getContext()}getPixelRatio(){return this._pixelRatio}getDrawingBufferSize(e){return e.set(this._width*this._pixelRatio,this._height*this._pixelRatio).floor()}getSize(e){return e.set(this._width,this._height)}setPixelRatio(e=1){this._pixelRatio=e,this.setSize(this._width,this._height,!1)}setDrawingBufferSize(e,t,s){this._width=e,this._height=t,this._pixelRatio=s,this.domElement.width=Math.floor(e*s),this.domElement.height=Math.floor(t*s),this.setViewport(0,0,e,t),this._initialized&&this.backend.updateSize()}setSize(e,t,s=!0){this._width=e,this._height=t,this.domElement.width=Math.floor(e*this._pixelRatio),this.domElement.height=Math.floor(t*this._pixelRatio),!0===s&&(this.domElement.style.width=e+"px",this.domElement.style.height=t+"px"),this.setViewport(0,0,e,t),this._initialized&&this.backend.updateSize()}setOpaqueSort(e){this._opaqueSort=e}setTransparentSort(e){this._transparentSort=e}getScissor(e){const t=this._scissor;return e.x=t.x,e.y=t.y,e.width=t.width,e.height=t.height,e}setScissor(e,t,s,i){const r=this._scissor;e.isVector4?r.copy(e):r.set(e,t,s,i)}getScissorTest(){return this._scissorTest}setScissorTest(e){this._scissorTest=e,this.backend.setScissorTest(e)}getViewport(e){return e.copy(this._viewport)}setViewport(e,t,s,i,r=0,n=1){const o=this._viewport;e.isVector4?o.copy(e):o.set(e,t,s,i),o.minDepth=r,o.maxDepth=n}getClearColor(e){return e.copy(this._clearColor)}setClearColor(e,t=1){this._clearColor.set(e),this._clearColor.a=t}getClearAlpha(){return this._clearColor.a}setClearAlpha(e){this._clearColor.a=e}getClearDepth(){return this._clearDepth}setClearDepth(e){this._clearDepth=e}getClearStencil(){return this._clearStencil}setClearStencil(e){this._clearStencil=e}isOccluded(e){const t=this._currentRenderContext;return t&&this.backend.isOccluded(t,e)}clear(e=!0,t=!0,s=!0){if(!1===this._initialized)return console.warn("THREE.Renderer: .clear() called before the backend is initialized. Try using .clearAsync() instead."),this.clearAsync(e,t,s);const i=this._renderTarget||this._getFrameBufferTarget();let r=null;if(null!==i&&(this._textures.updateRenderTarget(i),r=this._textures.get(i)),this.backend.clear(e,t,s,r),null!==i&&null===this._renderTarget){const e=this._quad;this._nodes.hasOutputChange(i.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(i.texture),e.material.needsUpdate=!0),this._renderScene(e,e.camera,!1)}}clearColor(){return this.clear(!0,!1,!1)}clearDepth(){return this.clear(!1,!0,!1)}clearStencil(){return this.clear(!1,!1,!0)}async clearAsync(e=!0,t=!0,s=!0){!1===this._initialized&&await this.init(),this.clear(e,t,s)}clearColorAsync(){return this.clearAsync(!0,!1,!1)}clearDepthAsync(){return this.clearAsync(!1,!0,!1)}clearStencilAsync(){return this.clearAsync(!1,!1,!0)}get currentToneMapping(){return null!==this._renderTarget?0:this.toneMapping}get currentColorSpace(){return null!==this._renderTarget?Zt:this.outputColorSpace}dispose(){this.info.dispose(),this._animation.dispose(),this._objects.dispose(),this._pipelines.dispose(),this._nodes.dispose(),this._bindings.dispose(),this._renderLists.dispose(),this._renderContexts.dispose(),this._textures.dispose(),this.setRenderTarget(null),this.setAnimationLoop(null)}setRenderTarget(e,t=0,s=0){this._renderTarget=e,this._activeCubeFace=t,this._activeMipmapLevel=s}getRenderTarget(){return this._renderTarget}setRenderObjectFunction(e){this._renderObjectFunction=e}getRenderObjectFunction(){return this._renderObjectFunction}async computeAsync(e){!1===this._initialized&&await this.init();const t=this._nodes.nodeFrame,s=t.renderId;this.info.calls++,this.info.compute.calls++,this.info.compute.frameCalls++,t.renderId=this.info.calls;const i=this.backend,r=this._pipelines,n=this._bindings,o=this._nodes,a=Array.isArray(e)?e:[e];if(void 0===a[0]||!0!==a[0].isComputeNode)throw new Error("THREE.Renderer: .compute() expects a ComputeNode.");i.beginCompute(e);for(const t of a){if(!1===r.has(t)){const e=()=>{t.removeEventListener("dispose",e),r.delete(t),n.delete(t),o.delete(t)};t.addEventListener("dispose",e),t.onInit({renderer:this})}o.updateForCompute(t),n.updateForCompute(t);const s=n.getForCompute(t),a=r.getForCompute(t,s);i.compute(e,t,s,a)}i.finishCompute(e),await this.backend.resolveTimestampAsync(e,"compute"),t.renderId=s}async hasFeatureAsync(e){return!1===this._initialized&&await this.init(),this.backend.hasFeature(e)}hasFeature(e){return!1===this._initialized?(console.warn("THREE.Renderer: .hasFeature() called before the backend is initialized. Try using .hasFeatureAsync() instead."),!1):this.backend.hasFeature(e)}copyFramebufferToTexture(e){const t=this._currentRenderContext;this._textures.updateTexture(e),this.backend.copyFramebufferToTexture(e,t)}copyTextureToTexture(e,t,s=null,i=null,r=0){this._textures.updateTexture(e),this._textures.updateTexture(t),this.backend.copyTextureToTexture(e,t,s,i,r)}readRenderTargetPixelsAsync(e,t,s,i,r,n=0){return this.backend.copyTextureToBuffer(e.textures[n],t,s,i,r)}_projectObject(e,t,s,i){if(!1===e.visible)return;if(e.layers.test(t.layers))if(e.isGroup)s=e.renderOrder;else if(e.isLOD)!0===e.autoUpdate&&e.update(t);else if(e.isLight)i.pushLight(e);else if(e.isSprite){if(!e.frustumCulled||xI.intersectsSprite(e)){!0===this.sortObjects&&vI.setFromMatrixPosition(e.matrixWorld).applyMatrix4(bI);const t=e.geometry,r=e.material;r.visible&&i.push(e,t,r,s,vI.z,null)}}else if(e.isLineLoop)console.error("THREE.Renderer: Objects of type THREE.LineLoop are not supported. Please use THREE.Line or THREE.LineSegments.");else if((e.isMesh||e.isLine||e.isPoints)&&(!e.frustumCulled||xI.intersectsObject(e))){const t=e.geometry,r=e.material;if(!0===this.sortObjects&&(null===t.boundingSphere&&t.computeBoundingSphere(),vI.copy(t.boundingSphere.center).applyMatrix4(e.matrixWorld).applyMatrix4(bI)),Array.isArray(r)){const n=t.groups;for(let o=0,a=n.length;o0?i:"";t=`${e.name} {\n\t${s} ${r.name}[${n}];\n};\n`}else{t=`${this.getVectorType(r.type)} ${this.getPropertyName(r,e)};`,n=!0}const o=r.node.precision;if(null!==o&&(t=VI[o]+" "+t),n){t="\t"+t;const e=r.groupNode.name;(i[e]||(i[e]=[])).push(t)}else t="uniform "+t,s.push(t)}let r="";for(const t in i){const s=i[t];r+=this._getGLSLUniformStruct(e+"_"+t,s.join("\n"))+"\n"}return r+=s.join("\n"),r}getTypeFromAttribute(e){let t=super.getTypeFromAttribute(e);if(/^[iu]/.test(t)&&e.gpuType!==Ee){let s=e;e.isInterleavedBufferAttribute&&(s=e.data);const i=s.array;!1==(i instanceof Uint32Array||i instanceof Int32Array)&&(t=t.slice(1))}return t}getAttributes(e){let t="";if("vertex"===e||"compute"===e){const e=this.getAttributesArray();let s=0;for(const i of e)t+=`layout( location = ${s++} ) in ${i.type} ${i.name};\n`}return t}getStructMembers(e){const t=[],s=e.getMemberTypes();for(let e=0;ee*t),1)}u`}getDrawIndex(){return this.renderer.backend.extensions.has("WEBGL_multi_draw")?"uint( gl_DrawID )":null}getFrontFacing(){return"gl_FrontFacing"}getFragCoord(){return"gl_FragCoord.xy"}getFragDepth(){return"gl_FragDepth"}enableExtension(e,t,s=this.shaderStage){const i=this.extensions[s]||(this.extensions[s]=new Map);!1===i.has(e)&&i.set(e,{name:e,behavior:t})}getExtensions(e){const t=[];if("vertex"===e){const t=this.renderer.backend.extensions;this.object.isBatchedMesh&&t.has("WEBGL_multi_draw")&&this.enableExtension("GL_ANGLE_multi_draw","require",e)}const s=this.extensions[e];if(void 0!==s)for(const{name:e,behavior:i}of s.values())t.push(`#extension ${e} : ${i}`);return t.join("\n")}isAvailable(e){let t=DI[e];if(void 0===t){if("float32Filterable"===e){const e=this.renderer.backend.extensions;e.has("OES_texture_float_linear")?(e.get("OES_texture_float_linear"),t=!0):t=!1}DI[e]=t}return t}isFlipY(){return!0}registerTransform(e,t){this.transforms.push({varyingName:e,attributeNode:t})}getTransforms(){const e=this.transforms;let t="";for(let s=0;s0&&(s+="\n"),s+=`\t// flow -> ${n}\n\t`),s+=`${i.code}\n\t`,e===r&&"compute"!==t&&(s+="// result\n\t","vertex"===t?(s+="gl_Position = ",s+=`${i.result};`):"fragment"===t&&(e.outputNode.isOutputStructNode||(s+="fragColor = ",s+=`${i.result};`)))}const n=e[t];n.extensions=this.getExtensions(t),n.uniforms=this.getUniforms(t),n.attributes=this.getAttributes(t),n.varyings=this.getVaryings(t),n.vars=this.getVars(t),n.structs=this.getStructs(t),n.codes=this.getCodes(t),n.transforms=this.getTransforms(t),n.flow=s}null!==this.material?(this.vertexShader=this._getGLSLVertexCode(e.vertex),this.fragmentShader=this._getGLSLFragmentCode(e.fragment)):this.computeShader=this._getGLSLVertexCode(e.compute)}getUniformFromNode(e,t,s,i=null){const r=super.getUniformFromNode(e,t,s,i),n=this.getDataFromNode(e,s,this.globalCache);let o=n.uniformGPU;if(void 0===o){const i=e.groupNode,a=i.name,h=this.getBindGroupArray(a,s);if("texture"===t)o=new zI(r.name,r.node,i),h.push(o);else if("cubeTexture"===t)o=new UI(r.name,r.node,i),h.push(o);else if("texture3D"===t)o=new LI(r.name,r.node,i),h.push(o);else if("buffer"===t){e.name=`NodeBuffer_${e.id}`,r.name=`buffer${e.id}`;const t=new CI(e,i);t.name=e.name,h.push(t),o=t}else{const e=this.uniformGroups[s]||(this.uniformGroups[s]={});let n=e[a];void 0===n&&(n=new II(s+"_"+a,i),e[a]=n,h.push(n)),o=this.getNodeUniform(r,t),n.addUniform(o)}n.uniformGPU=o}return r}}let WI=null,HI=null,jI=null;class qI{constructor(e={}){this.parameters=Object.assign({},e),this.data=new WeakMap,this.renderer=null,this.domElement=null}async init(e){this.renderer=e}begin(){}finish(){}draw(){}createProgram(){}destroyProgram(){}createBindings(){}updateBindings(){}createRenderPipeline(){}createComputePipeline(){}destroyPipeline(){}needsRenderUpdate(){}getRenderCacheKey(){}createNodeBuilder(){}createSampler(){}createDefaultTexture(){}createTexture(){}copyTextureToBuffer(){}createAttribute(){}createIndexAttribute(){}updateAttribute(){}destroyAttribute(){}getContext(){}updateSize(){}resolveTimestampAsync(){}hasFeatureAsync(){}hasFeature(){}getInstanceCount(e){const{object:t,geometry:s}=e;return s.isInstancedBufferGeometry?s.instanceCount:t.count>1?t.count:1}getDrawingBufferSize(){return WI=WI||new Qs,this.renderer.getDrawingBufferSize(WI)}getScissor(){return HI=HI||new _i,this.renderer.getScissor(HI)}setScissorTest(){}getClearColor(){const e=this.renderer;return jI=jI||new pE,e.getClearColor(jI),jI.getRGB(jI,this.renderer.currentColorSpace),jI}getDomElement(){let t=this.domElement;return null===t&&(t=void 0!==this.parameters.canvas?this.parameters.canvas:ni(),"setAttribute"in t&&t.setAttribute("data-engine",`three.js r${e} webgpu`),this.domElement=t),t}set(e,t){this.data.set(e,t)}get(e){let t=this.data.get(e);return void 0===t&&(t={},this.data.set(e,t)),t}has(e){return this.data.has(e)}delete(e){this.data.delete(e)}}let $I=0;class XI{constructor(e,t){this.buffers=[e.bufferGPU,t],this.type=e.type,this.bufferType=e.bufferType,this.pbo=e.pbo,this.byteLength=e.byteLength,this.bytesPerElement=e.BYTES_PER_ELEMENT,this.version=e.version,this.isInteger=e.isInteger,this.activeBufferIndex=0,this.baseId=e.id}get id(){return`${this.baseId}|${this.activeBufferIndex}`}get bufferGPU(){return this.buffers[this.activeBufferIndex]}get transformBuffer(){return this.buffers[1^this.activeBufferIndex]}switchBuffers(){this.activeBufferIndex^=1}}class YI{constructor(e){this.backend=e}createAttribute(e,t){const s=this.backend,{gl:i}=s,r=e.array,n=e.usage||i.STATIC_DRAW,o=e.isInterleavedBufferAttribute?e.data:e,a=s.get(o);let h,l=a.bufferGPU;if(void 0===l&&(l=this._createBuffer(i,t,r,n),a.bufferGPU=l,a.bufferType=t,a.version=o.version),r instanceof Float32Array)h=i.FLOAT;else if(r instanceof Uint16Array)h=e.isFloat16BufferAttribute?i.HALF_FLOAT:i.UNSIGNED_SHORT;else if(r instanceof Int16Array)h=i.SHORT;else if(r instanceof Uint32Array)h=i.UNSIGNED_INT;else if(r instanceof Int32Array)h=i.INT;else if(r instanceof Int8Array)h=i.BYTE;else if(r instanceof Uint8Array)h=i.UNSIGNED_BYTE;else{if(!(r instanceof Uint8ClampedArray))throw new Error("THREE.WebGLBackend: Unsupported buffer data format: "+r);h=i.UNSIGNED_BYTE}let u={bufferGPU:l,bufferType:t,type:h,byteLength:r.byteLength,bytesPerElement:r.BYTES_PER_ELEMENT,version:e.version,pbo:e.pbo,isInteger:h===i.INT||h===i.UNSIGNED_INT||e.gpuType===Ee,id:$I++};if(e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute){const e=this._createBuffer(i,t,r,n);u=new XI(u,e)}s.set(e,u)}updateAttribute(e){const t=this.backend,{gl:s}=t,i=e.array,r=e.isInterleavedBufferAttribute?e.data:e,n=t.get(r),o=n.bufferType,a=e.isInterleavedBufferAttribute?e.data.updateRanges:e.updateRanges;if(s.bindBuffer(o,n.bufferGPU),0===a.length)s.bufferSubData(o,0,i);else{for(let e=0,t=a.length;e{!function r(){const n=e.clientWaitSync(t,e.SYNC_FLUSH_COMMANDS_BIT,0);if(n===e.WAIT_FAILED)return e.deleteSync(t),void i();n!==e.TIMEOUT_EXPIRED?(e.deleteSync(t),s()):requestAnimationFrame(r)}()}))}}let tP,sP,iP,rP=!1;class nP{constructor(e){this.backend=e,this.gl=e.gl,this.extensions=e.extensions,this.defaultTextures={},!1===rP&&(this._init(this.gl),rP=!0)}_init(e){tP={[pe]:e.REPEAT,[me]:e.CLAMP_TO_EDGE,[ge]:e.MIRRORED_REPEAT},sP={[fe]:e.NEAREST,[ye]:e.NEAREST_MIPMAP_NEAREST,[be]:e.NEAREST_MIPMAP_LINEAR,[Te]:e.LINEAR,[_e]:e.LINEAR_MIPMAP_NEAREST,[Se]:e.LINEAR_MIPMAP_LINEAR},iP={512:e.NEVER,519:e.ALWAYS,[Ts]:e.LESS,515:e.LEQUAL,514:e.EQUAL,518:e.GEQUAL,516:e.GREATER,517:e.NOTEQUAL}}filterFallback(e){const{gl:t}=this;return e===fe||e===ye||e===be?t.NEAREST:t.LINEAR}getGLTextureType(e){const{gl:t}=this;let s;return s=!0===e.isCubeTexture?t.TEXTURE_CUBE_MAP:!0===e.isDataArrayTexture||!0===e.isCompressedArrayTexture?t.TEXTURE_2D_ARRAY:!0===e.isData3DTexture?t.TEXTURE_3D:t.TEXTURE_2D,s}getInternalFormat(e,t,s,i,r=!1){const{gl:n,extensions:o}=this;if(null!==e){if(void 0!==n[e])return n[e];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+e+"'")}let a=t;return t===n.RED&&(s===n.FLOAT&&(a=n.R32F),s===n.HALF_FLOAT&&(a=n.R16F),s===n.UNSIGNED_BYTE&&(a=n.R8),s===n.UNSIGNED_SHORT&&(a=n.R16),s===n.UNSIGNED_INT&&(a=n.R32UI),s===n.BYTE&&(a=n.R8I),s===n.SHORT&&(a=n.R16I),s===n.INT&&(a=n.R32I)),t===n.RED_INTEGER&&(s===n.UNSIGNED_BYTE&&(a=n.R8UI),s===n.UNSIGNED_SHORT&&(a=n.R16UI),s===n.UNSIGNED_INT&&(a=n.R32UI),s===n.BYTE&&(a=n.R8I),s===n.SHORT&&(a=n.R16I),s===n.INT&&(a=n.R32I)),t===n.RG&&(s===n.FLOAT&&(a=n.RG32F),s===n.HALF_FLOAT&&(a=n.RG16F),s===n.UNSIGNED_BYTE&&(a=n.RG8),s===n.UNSIGNED_SHORT&&(a=n.RG16),s===n.UNSIGNED_INT&&(a=n.RG32UI),s===n.BYTE&&(a=n.RG8I),s===n.SHORT&&(a=n.RG16I),s===n.INT&&(a=n.RG32I)),t===n.RG_INTEGER&&(s===n.UNSIGNED_BYTE&&(a=n.RG8UI),s===n.UNSIGNED_SHORT&&(a=n.RG16UI),s===n.UNSIGNED_INT&&(a=n.RG32UI),s===n.BYTE&&(a=n.RG8I),s===n.SHORT&&(a=n.RG16I),s===n.INT&&(a=n.RG32I)),t===n.RGB&&(s===n.FLOAT&&(a=n.RGB32F),s===n.HALF_FLOAT&&(a=n.RGB16F),s===n.UNSIGNED_BYTE&&(a=n.RGB8),s===n.UNSIGNED_SHORT&&(a=n.RGB16),s===n.UNSIGNED_INT&&(a=n.RGB32UI),s===n.BYTE&&(a=n.RGB8I),s===n.SHORT&&(a=n.RGB16I),s===n.INT&&(a=n.RGB32I),s===n.UNSIGNED_BYTE&&(a=i===Jt&&!1===r?n.SRGB8:n.RGB8),s===n.UNSIGNED_SHORT_5_6_5&&(a=n.RGB565),s===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1),s===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGB4),s===n.UNSIGNED_INT_5_9_9_9_REV&&(a=n.RGB9_E5)),t===n.RGB_INTEGER&&(s===n.UNSIGNED_BYTE&&(a=n.RGB8UI),s===n.UNSIGNED_SHORT&&(a=n.RGB16UI),s===n.UNSIGNED_INT&&(a=n.RGB32UI),s===n.BYTE&&(a=n.RGB8I),s===n.SHORT&&(a=n.RGB16I),s===n.INT&&(a=n.RGB32I)),t===n.RGBA&&(s===n.FLOAT&&(a=n.RGBA32F),s===n.HALF_FLOAT&&(a=n.RGBA16F),s===n.UNSIGNED_BYTE&&(a=n.RGBA8),s===n.UNSIGNED_SHORT&&(a=n.RGBA16),s===n.UNSIGNED_INT&&(a=n.RGBA32UI),s===n.BYTE&&(a=n.RGBA8I),s===n.SHORT&&(a=n.RGBA16I),s===n.INT&&(a=n.RGBA32I),s===n.UNSIGNED_BYTE&&(a=i===Jt&&!1===r?n.SRGB8_ALPHA8:n.RGBA8),s===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGBA4),s===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1)),t===n.RGBA_INTEGER&&(s===n.UNSIGNED_BYTE&&(a=n.RGBA8UI),s===n.UNSIGNED_SHORT&&(a=n.RGBA16UI),s===n.UNSIGNED_INT&&(a=n.RGBA32UI),s===n.BYTE&&(a=n.RGBA8I),s===n.SHORT&&(a=n.RGBA16I),s===n.INT&&(a=n.RGBA32I)),t===n.DEPTH_COMPONENT&&(s===n.UNSIGNED_INT&&(a=n.DEPTH24_STENCIL8),s===n.FLOAT&&(a=n.DEPTH_COMPONENT32F)),t===n.DEPTH_STENCIL&&s===n.UNSIGNED_INT_24_8&&(a=n.DEPTH24_STENCIL8),a!==n.R16F&&a!==n.R32F&&a!==n.RG16F&&a!==n.RG32F&&a!==n.RGBA16F&&a!==n.RGBA32F||o.get("EXT_color_buffer_float"),a}setTextureParameters(e,t){const{gl:s,extensions:i,backend:r}=this;s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL,t.flipY),s.pixelStorei(s.UNPACK_PREMULTIPLY_ALPHA_WEBGL,t.premultiplyAlpha),s.pixelStorei(s.UNPACK_ALIGNMENT,t.unpackAlignment),s.pixelStorei(s.UNPACK_COLORSPACE_CONVERSION_WEBGL,s.NONE),s.texParameteri(e,s.TEXTURE_WRAP_S,tP[t.wrapS]),s.texParameteri(e,s.TEXTURE_WRAP_T,tP[t.wrapT]),e!==s.TEXTURE_3D&&e!==s.TEXTURE_2D_ARRAY||s.texParameteri(e,s.TEXTURE_WRAP_R,tP[t.wrapR]),s.texParameteri(e,s.TEXTURE_MAG_FILTER,sP[t.magFilter]);const n=void 0!==t.mipmaps&&t.mipmaps.length>0,o=t.minFilter===Te&&n?Se:t.minFilter;if(s.texParameteri(e,s.TEXTURE_MIN_FILTER,sP[o]),t.compareFunction&&(s.texParameteri(e,s.TEXTURE_COMPARE_MODE,s.COMPARE_REF_TO_TEXTURE),s.texParameteri(e,s.TEXTURE_COMPARE_FUNC,iP[t.compareFunction])),!0===i.has("EXT_texture_filter_anisotropic")){if(t.magFilter===fe)return;if(t.minFilter!==be&&t.minFilter!==Se)return;if(t.type===Ie&&!1===i.has("OES_texture_float_linear"))return;if(t.anisotropy>1){const n=i.get("EXT_texture_filter_anisotropic");s.texParameterf(e,n.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(t.anisotropy,r.getMaxAnisotropy()))}}}createDefaultTexture(e){const{gl:t,backend:s,defaultTextures:i}=this,r=this.getGLTextureType(e);let n=i[r];void 0===n&&(n=t.createTexture(),s.state.bindTexture(r,n),t.texParameteri(r,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(r,t.TEXTURE_MAG_FILTER,t.NEAREST),i[r]=n),s.set(e,{textureGPU:n,glTextureType:r,isDefault:!0})}createTexture(e,t){const{gl:s,backend:i}=this,{levels:r,width:n,height:o,depth:a}=t,h=i.utils.convert(e.format,e.colorSpace),l=i.utils.convert(e.type),u=this.getInternalFormat(e.internalFormat,h,l,e.colorSpace,e.isVideoTexture),c=s.createTexture(),d=this.getGLTextureType(e);i.state.bindTexture(d,c),this.setTextureParameters(d,e),e.isDataArrayTexture||e.isCompressedArrayTexture?s.texStorage3D(s.TEXTURE_2D_ARRAY,r,u,n,o,a):e.isData3DTexture?s.texStorage3D(s.TEXTURE_3D,r,u,n,o,a):e.isVideoTexture||s.texStorage2D(d,r,u,n,o),i.set(e,{textureGPU:c,glTextureType:d,glFormat:h,glType:l,glInternalFormat:u})}copyBufferToTexture(e,t){const{gl:s,backend:i}=this,{textureGPU:r,glTextureType:n,glFormat:o,glType:a}=i.get(t),{width:h,height:l}=t.source.data;s.bindBuffer(s.PIXEL_UNPACK_BUFFER,e),i.state.bindTexture(n,r),s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL,!1),s.pixelStorei(s.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),s.texSubImage2D(n,0,0,0,h,l,o,a,0),s.bindBuffer(s.PIXEL_UNPACK_BUFFER,null),i.state.unbindTexture()}updateTexture(e,t){const{gl:s}=this,{width:i,height:r}=t,{textureGPU:n,glTextureType:o,glFormat:a,glType:h,glInternalFormat:l}=this.backend.get(e);if(e.isRenderTargetTexture||void 0===n)return;const u=e=>e.isDataTexture?e.image.data:e instanceof ImageBitmap||e instanceof OffscreenCanvas||e instanceof HTMLImageElement||e instanceof HTMLCanvasElement?e:e.data;if(this.backend.state.bindTexture(o,n),this.setTextureParameters(o,e),e.isCompressedTexture){const i=e.mipmaps,r=t.image;for(let t=0;t0){let a,h;!0===e.isDepthTexture?(a=s.DEPTH_BUFFER_BIT,h=s.DEPTH_ATTACHMENT,t.stencil&&(a|=s.STENCIL_BUFFER_BIT)):(a=s.COLOR_BUFFER_BIT,h=s.COLOR_ATTACHMENT0);const l=s.createFramebuffer();i.bindFramebuffer(s.DRAW_FRAMEBUFFER,l),s.framebufferTexture2D(s.DRAW_FRAMEBUFFER,h,s.TEXTURE_2D,r,0),s.blitFramebuffer(0,0,n,o,0,0,n,o,a,s.NEAREST),s.deleteFramebuffer(l)}else i.bindTexture(s.TEXTURE_2D,r),s.copyTexSubImage2D(s.TEXTURE_2D,0,0,0,0,0,n,o),i.unbindTexture();e.generateMipmaps&&this.generateMipmaps(e),this.backend._setFramebuffer(t)}setupRenderBufferStorage(e,t){const{gl:s}=this,i=t.renderTarget,{samples:r,depthTexture:n,depthBuffer:o,stencilBuffer:a,width:h,height:l}=i;if(s.bindRenderbuffer(s.RENDERBUFFER,e),o&&!a){let t=s.DEPTH_COMPONENT24;r>0?(n&&n.isDepthTexture&&n.type===s.FLOAT&&(t=s.DEPTH_COMPONENT32F),s.renderbufferStorageMultisample(s.RENDERBUFFER,r,t,h,l)):s.renderbufferStorage(s.RENDERBUFFER,t,h,l),s.framebufferRenderbuffer(s.FRAMEBUFFER,s.DEPTH_ATTACHMENT,s.RENDERBUFFER,e)}else o&&a&&(r>0?s.renderbufferStorageMultisample(s.RENDERBUFFER,r,s.DEPTH24_STENCIL8,h,l):s.renderbufferStorage(s.RENDERBUFFER,s.DEPTH_STENCIL,h,l),s.framebufferRenderbuffer(s.FRAMEBUFFER,s.DEPTH_STENCIL_ATTACHMENT,s.RENDERBUFFER,e))}async copyTextureToBuffer(e,t,s,i,r){const{backend:n,gl:o}=this,{textureGPU:a,glFormat:h,glType:l}=this.backend.get(e),u=o.createFramebuffer();o.bindFramebuffer(o.READ_FRAMEBUFFER,u),o.framebufferTexture2D(o.READ_FRAMEBUFFER,o.COLOR_ATTACHMENT0,o.TEXTURE_2D,a,0);const c=this._getTypedArrayType(l),d=i*r*this._getBytesPerTexel(h),p=o.createBuffer();o.bindBuffer(o.PIXEL_PACK_BUFFER,p),o.bufferData(o.PIXEL_PACK_BUFFER,d,o.STREAM_READ),o.readPixels(t,s,i,r,h,l,0),o.bindBuffer(o.PIXEL_PACK_BUFFER,null),await n.utils._clientWaitAsync();const m=new c(d/c.BYTES_PER_ELEMENT);return o.bindBuffer(o.PIXEL_PACK_BUFFER,p),o.getBufferSubData(o.PIXEL_PACK_BUFFER,0,m),o.bindBuffer(o.PIXEL_PACK_BUFFER,null),o.deleteFramebuffer(u),m}_getTypedArrayType(e){const{gl:t}=this;if(e===t.UNSIGNED_BYTE)return Uint8Array;if(e===t.UNSIGNED_SHORT_4_4_4_4)return Uint16Array;if(e===t.UNSIGNED_SHORT_5_5_5_1)return Uint16Array;if(e===t.UNSIGNED_SHORT_5_6_5)return Uint16Array;if(e===t.UNSIGNED_SHORT)return Uint16Array;if(e===t.UNSIGNED_INT)return Uint32Array;if(e===t.FLOAT)return Float32Array;throw new Error(`Unsupported WebGL type: ${e}`)}_getBytesPerTexel(e){const{gl:t}=this;return e===t.RGBA?4:e===t.RGB?3:e===t.ALPHA?1:void 0}}class oP{constructor(e){this.backend=e,this.gl=this.backend.gl,this.availableExtensions=this.gl.getSupportedExtensions(),this.extensions={}}get(e){let t=this.extensions[e];return void 0===t&&(t=this.gl.getExtension(e),this.extensions[e]=t),t}has(e){return this.availableExtensions.includes(e)}}class aP{constructor(e){this.backend=e,this.maxAnisotropy=null}getMaxAnisotropy(){if(null!==this.maxAnisotropy)return this.maxAnisotropy;const e=this.backend.gl,t=this.backend.extensions;if(!0===t.has("EXT_texture_filter_anisotropic")){const s=t.get("EXT_texture_filter_anisotropic");this.maxAnisotropy=e.getParameter(s.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else this.maxAnisotropy=0;return this.maxAnisotropy}}const hP={WEBGL_multi_draw:"WEBGL_multi_draw",WEBGL_compressed_texture_astc:"texture-compression-astc",WEBGL_compressed_texture_etc:"texture-compression-etc2",WEBGL_compressed_texture_etc1:"texture-compression-etc1",WEBGL_compressed_texture_pvrtc:"texture-compression-pvrtc",WEBKIT_WEBGL_compressed_texture_pvrtc:"texture-compression-pvrtc",WEBGL_compressed_texture_s3tc:"texture-compression-bc",EXT_texture_compression_bptc:"texture-compression-bptc",EXT_disjoint_timer_query_webgl2:"timestamp-query"};class lP{constructor(e){this.gl=e.gl,this.extensions=e.extensions,this.info=e.renderer.info,this.mode=null,this.index=0,this.type=null,this.object=null}render(e,t){const{gl:s,mode:i,object:r,type:n,info:o,index:a}=this;0!==a?s.drawElements(i,t,n,e):s.drawArrays(i,e,t),o.update(r,t,i,1)}renderInstances(e,t,s){const{gl:i,mode:r,type:n,index:o,object:a,info:h}=this;0!==s&&(0!==o?i.drawElementsInstanced(r,t,n,e,s):i.drawArraysInstanced(r,e,t,s),h.update(a,t,r,s))}renderMultiDraw(e,t,s){const{extensions:i,mode:r,object:n,info:o}=this;if(0===s)return;const a=i.get("WEBGL_multi_draw");if(null===a)for(let i=0;i0)){const e=t.queryQueue.shift();this.initTimestampQuery(e)}}async resolveTimestampAsync(e,t="render"){if(!this.disjoint||!this.trackTimestamp)return;const s=this.get(e);s.gpuQueries||(s.gpuQueries=[]);for(let e=0;e0&&(s.currentOcclusionQueries=s.occlusionQueries,s.currentOcclusionQueryObjects=s.occlusionQueryObjects,s.lastOcclusionObject=null,s.occlusionQueries=new Array(i),s.occlusionQueryObjects=new Array(i),s.occlusionQueryIndex=0)}finishRender(e){const{gl:t,state:s}=this,i=this.get(e),r=i.previousContext,n=e.occlusionQueryCount;n>0&&(n>i.occlusionQueryIndex&&t.endQuery(t.ANY_SAMPLES_PASSED),this.resolveOccludedAsync(e));const o=e.textures;if(null!==o)for(let e=0;e0){const r=i.framebuffers[e.getCacheKey()],n=t.COLOR_BUFFER_BIT,o=i.msaaFrameBuffer,a=e.textures;s.bindFramebuffer(t.READ_FRAMEBUFFER,o),s.bindFramebuffer(t.DRAW_FRAMEBUFFER,r);for(let s=0;s{let o=0;for(let t=0;t0&&e.add(i[t]),s[t]=null,r.deleteQuery(n),o++))}o1?f.renderInstances(m,y,x):f.render(m,y),o.bindVertexArray(null)}needsRenderUpdate(){return!1}getRenderCacheKey(){return""}createDefaultTexture(e){this.textureUtils.createDefaultTexture(e)}createTexture(e,t){this.textureUtils.createTexture(e,t)}updateTexture(e,t){this.textureUtils.updateTexture(e,t)}generateMipmaps(e){this.textureUtils.generateMipmaps(e)}destroyTexture(e){this.textureUtils.destroyTexture(e)}copyTextureToBuffer(e,t,s,i,r){return this.textureUtils.copyTextureToBuffer(e,t,s,i,r)}createSampler(){}destroySampler(){}createNodeBuilder(e,t){return new GI(e,t)}createProgram(e){const t=this.gl,{stage:s,code:i}=e,r="fragment"===s?t.createShader(t.FRAGMENT_SHADER):t.createShader(t.VERTEX_SHADER);t.shaderSource(r,i),t.compileShader(r),this.set(e,{shaderGPU:r})}destroyProgram(){console.warn("Abstract class.")}createRenderPipeline(e,t){const s=this.gl,i=e.pipeline,{fragmentProgram:r,vertexProgram:n}=i,o=s.createProgram(),a=this.get(r).shaderGPU,h=this.get(n).shaderGPU;if(s.attachShader(o,a),s.attachShader(o,h),s.linkProgram(o),this.set(i,{programGPU:o,fragmentShader:a,vertexShader:h}),null!==t&&this.parallel){const r=new Promise((t=>{const r=this.parallel,n=()=>{s.getProgramParameter(o,r.COMPLETION_STATUS_KHR)?(this._completeCompile(e,i),t()):requestAnimationFrame(n)};n()}));t.push(r)}else this._completeCompile(e,i)}_handleSource(e,t){const s=e.split("\n"),i=[],r=Math.max(t-6,0),n=Math.min(t+6,s.length);for(let e=r;e":" "} ${r}: ${s[e]}`)}return i.join("\n")}_getShaderErrors(e,t,s){const i=e.getShaderParameter(t,e.COMPILE_STATUS),r=e.getShaderInfoLog(t).trim();if(i&&""===r)return"";const n=/ERROR: 0:(\d+)/.exec(r);if(n){const i=parseInt(n[1]);return s.toUpperCase()+"\n\n"+r+"\n\n"+this._handleSource(e.getShaderSource(t),i)}return r}_logProgramError(e,t,s){if(this.renderer.debug.checkShaderErrors){const i=this.gl,r=i.getProgramInfoLog(e).trim();if(!1===i.getProgramParameter(e,i.LINK_STATUS))if("function"==typeof this.renderer.debug.onShaderError)this.renderer.debug.onShaderError(i,e,s,t);else{const n=this._getShaderErrors(i,s,"vertex"),o=this._getShaderErrors(i,t,"fragment");console.error("THREE.WebGLProgram: Shader Error "+i.getError()+" - VALIDATE_STATUS "+i.getProgramParameter(e,i.VALIDATE_STATUS)+"\n\nProgram Info Log: "+r+"\n"+n+"\n"+o)}else""!==r&&console.warn("THREE.WebGLProgram: Program Info Log:",r)}}_completeCompile(e,t){const{state:s,gl:i}=this,r=this.get(t),{programGPU:n,fragmentShader:o,vertexShader:a}=r;!1===i.getProgramParameter(n,i.LINK_STATUS)&&this._logProgramError(n,o,a),s.useProgram(n);const h=e.getBindings();this._setupBindings(h,n),this.set(t,{programGPU:n})}createComputePipeline(e,t){const{state:s,gl:i}=this,r={stage:"fragment",code:"#version 300 es\nprecision highp float;\nvoid main() {}"};this.createProgram(r);const{computeProgram:n}=e,o=i.createProgram(),a=this.get(r).shaderGPU,h=this.get(n).shaderGPU,l=n.transforms,u=[],c=[];for(let e=0;ehP[t]===e)),s=this.extensions;for(let e=0;e0){if(void 0===u){const i=[];u=t.createFramebuffer(),s.bindFramebuffer(t.FRAMEBUFFER,u);const r=[],l=e.textures;for(let s=0;s,\n\t@location( 0 ) vTex : vec2\n};\n\n@vertex\nfn main( @builtin( vertex_index ) vertexIndex : u32 ) -> VarysStruct {\n\n\tvar Varys : VarysStruct;\n\n\tvar pos = array< vec2, 4 >(\n\t\tvec2( -1.0, 1.0 ),\n\t\tvec2( 1.0, 1.0 ),\n\t\tvec2( -1.0, -1.0 ),\n\t\tvec2( 1.0, -1.0 )\n\t);\n\n\tvar tex = array< vec2, 4 >(\n\t\tvec2( 0.0, 0.0 ),\n\t\tvec2( 1.0, 0.0 ),\n\t\tvec2( 0.0, 1.0 ),\n\t\tvec2( 1.0, 1.0 )\n\t);\n\n\tVarys.vTex = tex[ vertexIndex ];\n\tVarys.Position = vec4( pos[ vertexIndex ], 0.0, 1.0 );\n\n\treturn Varys;\n\n}\n"}),this.mipmapFragmentShaderModule=e.createShaderModule({label:"mipmapFragment",code:"\n@group( 0 ) @binding( 0 )\nvar imgSampler : sampler;\n\n@group( 0 ) @binding( 1 )\nvar img : texture_2d;\n\n@fragment\nfn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 {\n\n\treturn textureSample( img, imgSampler, vTex );\n\n}\n"}),this.flipYFragmentShaderModule=e.createShaderModule({label:"flipYFragment",code:"\n@group( 0 ) @binding( 0 )\nvar imgSampler : sampler;\n\n@group( 0 ) @binding( 1 )\nvar img : texture_2d;\n\n@fragment\nfn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 {\n\n\treturn textureSample( img, imgSampler, vec2( vTex.x, 1.0 - vTex.y ) );\n\n}\n"})}getTransferPipeline(e){let t=this.transferPipelines[e];return void 0===t&&(t=this.device.createRenderPipeline({label:`mipmap-${e}`,vertex:{module:this.mipmapVertexShaderModule,entryPoint:"main"},fragment:{module:this.mipmapFragmentShaderModule,entryPoint:"main",targets:[{format:e}]},primitive:{topology:yA,stripIndexFormat:FA},layout:"auto"}),this.transferPipelines[e]=t),t}getFlipYPipeline(e){let t=this.flipYPipelines[e];return void 0===t&&(t=this.device.createRenderPipeline({label:`flipY-${e}`,vertex:{module:this.mipmapVertexShaderModule,entryPoint:"main"},fragment:{module:this.flipYFragmentShaderModule,entryPoint:"main",targets:[{format:e}]},primitive:{topology:yA,stripIndexFormat:FA},layout:"auto"}),this.flipYPipelines[e]=t),t}flipY(e,t,s=0){const i=t.format,{width:r,height:n}=t.size,o=this.getTransferPipeline(i),a=this.getFlipYPipeline(i),h=this.device.createTexture({size:{width:r,height:n,depthOrArrayLayers:1},format:i,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING}),l=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:AN,baseArrayLayer:s}),u=h.createView({baseMipLevel:0,mipLevelCount:1,dimension:AN,baseArrayLayer:0}),c=this.device.createCommandEncoder({}),d=(e,t,s)=>{const i=e.getBindGroupLayout(0),r=this.device.createBindGroup({layout:i,entries:[{binding:0,resource:this.flipYSampler},{binding:1,resource:t}]}),n=c.beginRenderPass({colorAttachments:[{view:s,loadOp:RA,storeOp:AA,clearValue:[0,0,0,0]}]});n.setPipeline(e),n.setBindGroup(0,r),n.draw(4,1,0,0),n.end()};d(o,l,u),d(a,u,l),this.device.queue.submit([c.finish()]),h.destroy()}generateMipmaps(e,t,s=0){const i=this.get(e);void 0===i.useCount&&(i.useCount=0,i.layers=[]);const r=i.layers[s]||this._mipmapCreateBundles(e,t,s),n=this.device.createCommandEncoder({});this._mipmapRunBundles(n,r),this.device.queue.submit([n.finish()]),0!==i.useCount&&(i.layers[s]=r),i.useCount++}_mipmapCreateBundles(e,t,s){const i=this.getTransferPipeline(t.format),r=i.getBindGroupLayout(0);let n=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:AN,baseArrayLayer:s});const o=[];for(let a=1;a1&&!e.isMultisampleRenderTargetTexture){const e=Object.assign({},p);e.label=e.label+"-msaa",e.sampleCount=u,i.msaaTexture=s.device.createTexture(e)}i.initialized=!0,i.textureDescriptorGPU=p}destroyTexture(e){const t=this.backend,s=t.get(e);s.texture.destroy(),void 0!==s.msaaTexture&&s.msaaTexture.destroy(),t.delete(e)}destroySampler(e){delete this.backend.get(e).sampler}generateMipmaps(e){const t=this.backend.get(e);if(e.isCubeTexture)for(let e=0;e<6;e++)this._generateMipmaps(t.texture,t.textureDescriptorGPU,e);else{const s=e.image.depth||1;for(let e=0;e1;for(let o=0;o]*\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/i,_P=/([a-z_0-9]+)\s*:\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/gi,wP={f32:"float",i32:"int",u32:"uint",bool:"bool","vec2":"vec2","vec2":"ivec2","vec2":"uvec2","vec2":"bvec2",vec2f:"vec2",vec2i:"ivec2",vec2u:"uvec2",vec2b:"bvec2","vec3":"vec3","vec3":"ivec3","vec3":"uvec3","vec3":"bvec3",vec3f:"vec3",vec3i:"ivec3",vec3u:"uvec3",vec3b:"bvec3","vec4":"vec4","vec4":"ivec4","vec4":"uvec4","vec4":"bvec4",vec4f:"vec4",vec4i:"ivec4",vec4u:"uvec4",vec4b:"bvec4","mat2x2":"mat2",mat2x2f:"mat2","mat3x3":"mat3",mat3x3f:"mat3","mat4x4":"mat4",mat4x4f:"mat4",sampler:"sampler",texture_1d:"texture",texture_2d:"texture",texture_2d_array:"texture",texture_multisampled_2d:"cubeTexture",texture_depth_2d:"depthTexture",texture_3d:"texture3D",texture_cube:"cubeTexture",texture_cube_array:"cubeTexture",texture_storage_1d:"storageTexture",texture_storage_2d:"storageTexture",texture_storage_2d_array:"storageTexture",texture_storage_3d:"storageTexture"};class SP extends ZC{constructor(e){const{type:t,inputs:s,name:i,inputsCode:r,blockCode:n,outputType:o}=(e=>{const t=(e=e.trim()).match(TP);if(null!==t&&4===t.length){const s=t[2],i=[];let r=null;for(;null!==(r=_P.exec(s));)i.push({name:r[1],type:r[2]});const n=[];for(let e=0;e "+this.outputType:"";return`fn ${e} ( ${this.inputsCode.trim()} ) ${t}`+this.blockCode}}class MP extends JC{parseFunction(e){return new SP(e)}}const AP=self.GPUShaderStage,NP={vertex:AP?AP.VERTEX:1,fragment:AP?AP.FRAGMENT:2,compute:AP?AP.COMPUTE:4},RP={instance:!0,swizzleAssign:!1,storageBuffer:!0},CP={"^^":"tsl_xor"},EP={float:"f32",int:"i32",uint:"u32",bool:"bool",color:"vec3",vec2:"vec2",ivec2:"vec2",uvec2:"vec2",bvec2:"vec2",vec3:"vec3",ivec3:"vec3",uvec3:"vec3",bvec3:"vec3",vec4:"vec4",ivec4:"vec4",uvec4:"vec4",bvec4:"vec4",mat2:"mat2x2",imat2:"mat2x2",umat2:"mat2x2",bmat2:"mat2x2",mat3:"mat3x3",imat3:"mat3x3",umat3:"mat3x3",bmat3:"mat3x3",mat4:"mat4x4",imat4:"mat4x4",umat4:"mat4x4",bmat4:"mat4x4"},BP={tsl_xor:new lS("fn tsl_xor( a : bool, b : bool ) -> bool { return ( a || b ) && !( a && b ); }"),mod_float:new lS("fn tsl_mod_float( x : f32, y : f32 ) -> f32 { return x - y * floor( x / y ); }"),mod_vec2:new lS("fn tsl_mod_vec2( x : vec2f, y : vec2f ) -> vec2f { return x - y * floor( x / y ); }"),mod_vec3:new lS("fn tsl_mod_vec3( x : vec3f, y : vec3f ) -> vec3f { return x - y * floor( x / y ); }"),mod_vec4:new lS("fn tsl_mod_vec4( x : vec4f, y : vec4f ) -> vec4f { return x - y * floor( x / y ); }"),equals_bool:new lS("fn tsl_equals_bool( a : bool, b : bool ) -> bool { return a == b; }"),equals_bvec2:new lS("fn tsl_equals_bvec2( a : vec2f, b : vec2f ) -> vec2 { return vec2( a.x == b.x, a.y == b.y ); }"),equals_bvec3:new lS("fn tsl_equals_bvec3( a : vec3f, b : vec3f ) -> vec3 { return vec3( a.x == b.x, a.y == b.y, a.z == b.z ); }"),equals_bvec4:new lS("fn tsl_equals_bvec4( a : vec4f, b : vec4f ) -> vec4 { return vec4( a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w ); }"),repeatWrapping:new lS("\nfn tsl_repeatWrapping( uv : vec2, dimension : vec2 ) -> vec2 {\n\n\tlet uvScaled = vec2( uv * vec2( dimension ) );\n\n\treturn ( ( uvScaled % dimension ) + dimension ) % dimension;\n\n}\n"),biquadraticTexture:new lS("\nfn tsl_biquadraticTexture( map : texture_2d, coord : vec2f, level : i32 ) -> vec4f {\n\n\tlet res = vec2f( textureDimensions( map, level ) );\n\n\tlet uvScaled = coord * res;\n\tlet uvWrapping = ( ( uvScaled % res ) + res ) % res;\n\n\t// https://www.shadertoy.com/view/WtyXRy\n\n\tlet uv = uvWrapping - 0.5;\n\tlet iuv = floor( uv );\n\tlet f = fract( uv );\n\n\tlet rg1 = textureLoad( map, vec2i( iuv + vec2( 0.5, 0.5 ) ), level );\n\tlet rg2 = textureLoad( map, vec2i( iuv + vec2( 1.5, 0.5 ) ), level );\n\tlet rg3 = textureLoad( map, vec2i( iuv + vec2( 0.5, 1.5 ) ), level );\n\tlet rg4 = textureLoad( map, vec2i( iuv + vec2( 1.5, 1.5 ) ), level );\n\n\treturn mix( mix( rg1, rg2, f.x ), mix( rg3, rg4, f.x ), f.y );\n\n}\n")},IP={dFdx:"dpdx",dFdy:"- dpdy",mod_float:"tsl_mod_float",mod_vec2:"tsl_mod_vec2",mod_vec3:"tsl_mod_vec3",mod_vec4:"tsl_mod_vec4",equals_bool:"tsl_equals_bool",equals_bvec2:"tsl_equals_bvec2",equals_bvec3:"tsl_equals_bvec3",equals_bvec4:"tsl_equals_bvec4",inversesqrt:"inverseSqrt",bitcast:"bitcast"};/Windows/g.test(navigator.userAgent)&&(BP.pow_float=new lS("fn tsl_pow_float( a : f32, b : f32 ) -> f32 { return select( -pow( -a, b ), pow( a, b ), a > 0.0 ); }"),BP.pow_vec2=new lS("fn tsl_pow_vec2( a : vec2f, b : vec2f ) -> vec2f { return vec2f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ) ); }",[BP.pow_float]),BP.pow_vec3=new lS("fn tsl_pow_vec3( a : vec3f, b : vec3f ) -> vec3f { return vec3f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ), tsl_pow_float( a.z, b.z ) ); }",[BP.pow_float]),BP.pow_vec4=new lS("fn tsl_pow_vec4( a : vec4f, b : vec4f ) -> vec4f { return vec4f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ), tsl_pow_float( a.z, b.z ), tsl_pow_float( a.w, b.w ) ); }",[BP.pow_float]),IP.pow_float="tsl_pow_float",IP.pow_vec2="tsl_pow_vec2",IP.pow_vec3="tsl_pow_vec3",IP.pow_vec4="tsl_pow_vec4");class PP extends aM{constructor(e,t){super(e,t,new MP),this.uniformGroups={},this.builtins={},this.directives={}}needsToWorkingColorSpace(e){return!0===e.isVideoTexture&&e.colorSpace!==Yt}_generateTextureSample(e,t,s,i,r=this.shaderStage){return"fragment"===r?i?`textureSample( ${t}, ${t}_sampler, ${s}, ${i} )`:`textureSample( ${t}, ${t}_sampler, ${s} )`:this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,s):this.generateTextureLod(e,t,s,"0")}_generateVideoSample(e,t,s=this.shaderStage){if("fragment"===s)return`textureSampleBaseClampToEdge( ${e}, ${e}_sampler, vec2( ${t}.x, 1.0 - ${t}.y ) )`;console.error(`WebGPURenderer: THREE.VideoTexture does not support ${s} shader.`)}_generateTextureSampleLevel(e,t,s,i,r,n=this.shaderStage){return"fragment"===n&&!1===this.isUnfilterable(e)?`textureSampleLevel( ${t}, ${t}_sampler, ${s}, ${i} )`:this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,s,i):this.generateTextureLod(e,t,s,i)}generateFilteredTexture(e,t,s,i="0"){return this._include("biquadraticTexture"),`tsl_biquadraticTexture( ${t}, ${s}, i32( ${i} ) )`}generateTextureLod(e,t,s,i="0"){this._include("repeatWrapping");return`textureLoad( ${t}, tsl_repeatWrapping( ${s}, ${!0===e.isMultisampleRenderTargetTexture?`textureDimensions( ${t} )`:`textureDimensions( ${t}, 0 )`} ), i32( ${i} ) )`}generateTextureLoad(e,t,s,i,r="0u"){return i?`textureLoad( ${t}, ${s}, ${i}, ${r} )`:`textureLoad( ${t}, ${s}, ${r} )`}generateTextureStore(e,t,s,i){return`textureStore( ${t}, ${s}, ${i} )`}isUnfilterable(e){return"float"!==this.getComponentTypeFromTexture(e)||!this.isAvailable("float32Filterable")&&!0===e.isDataTexture&&e.type===Ie||!0===e.isMultisampleRenderTargetTexture}generateTexture(e,t,s,i,r=this.shaderStage){let n=null;return n=!0===e.isVideoTexture?this._generateVideoSample(t,s,r):this.isUnfilterable(e)?this.generateTextureLod(e,t,s,"0",i,r):this._generateTextureSample(e,t,s,i,r),n}generateTextureGrad(e,t,s,i,r,n=this.shaderStage){if("fragment"===n)return`textureSampleGrad( ${t}, ${t}_sampler, ${s}, ${i[0]}, ${i[1]} )`;console.error(`WebGPURenderer: THREE.TextureNode.gradient() does not support ${n} shader.`)}generateTextureCompare(e,t,s,i,r,n=this.shaderStage){if("fragment"===n)return`textureSampleCompare( ${t}, ${t}_sampler, ${s}, ${i} )`;console.error(`WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${n} shader.`)}generateTextureLevel(e,t,s,i,r,n=this.shaderStage){let o=null;return o=!0===e.isVideoTexture?this._generateVideoSample(t,s,n):this._generateTextureSampleLevel(e,t,s,i,r,n),o}generateTextureBias(e,t,s,i,r,n=this.shaderStage){if("fragment"===n)return`textureSampleBias( ${t}, ${t}_sampler, ${s}, ${i} )`;console.error(`WebGPURenderer: THREE.TextureNode.biasNode does not support ${n} shader.`)}getPropertyName(e,t=this.shaderStage){if(!0===e.isNodeVarying&&!0===e.needsInterpolation){if("vertex"===t)return`varyings.${e.name}`}else if(!0===e.isNodeUniform){const t=e.name,s=e.type;return"texture"===s||"cubeTexture"===s||"storageTexture"===s||"texture3D"===s?t:"buffer"===s||"storageBuffer"===s?`NodeBuffer_${e.id}.${t}`:e.groupNode.name+"."+t}return super.getPropertyName(e)}getOutputStructName(){return"output"}_getUniformGroupCount(e){return Object.keys(this.uniforms[e]).length}getFunctionOperator(e){const t=CP[e];return void 0!==t?(this._include(t),t):null}getStorageAccess(e){if(e.isStorageTextureNode)switch(e.access){case xN:return"read";case yN:return"write";default:return"read_write"}else switch(e.access){case gN:return"read_write";case fN:return"read";default:return"write"}}getUniformFromNode(e,t,s,i=null){const r=super.getUniformFromNode(e,t,s,i),n=this.getDataFromNode(e,s,this.globalCache);if(void 0===n.uniformGPU){let i;const o=e.groupNode,a=o.name,h=this.getBindGroupArray(a,s);if("texture"===t||"cubeTexture"===t||"storageTexture"===t||"texture3D"===t){let n=null;if("texture"===t||"storageTexture"===t?n=new zI(r.name,r.node,o,e.access?e.access:null):"cubeTexture"===t?n=new UI(r.name,r.node,o,e.access?e.access:null):"texture3D"===t&&(n=new LI(r.name,r.node,o,e.access?e.access:null)),n.store=!0===e.isStorageTextureNode,n.setVisibility(NP[s]),"fragment"===s&&!1===this.isUnfilterable(e.value)&&!1===n.store){const e=new dP(`${r.name}_sampler`,r.node,o);e.setVisibility(NP[s]),h.push(e,n),i=[e,n]}else h.push(n),i=[n]}else if("buffer"===t||"storageBuffer"===t){const r=new("storageBuffer"===t?gP:CI)(e,o);r.setVisibility(NP[s]),h.push(r),i=r}else{const e=this.uniformGroups[s]||(this.uniformGroups[s]={});let n=e[a];void 0===n&&(n=new II(a,o),n.setVisibility(NP[s]),e[a]=n,h.push(n)),i=this.getNodeUniform(r,t),n.addUniform(i)}n.uniformGPU=i}return r}getBuiltin(e,t,s,i=this.shaderStage){const r=this.builtins[i]||(this.builtins[i]=new Map);return!1===r.has(e)&&r.set(e,{name:e,property:t,type:s}),t}getVertexIndex(){return"vertex"===this.shaderStage?this.getBuiltin("vertex_index","vertexIndex","u32","attribute"):"vertexIndex"}buildFunctionCode(e){const t=e.layout,s=this.flowShaderNode(e),i=[];for(const e of t.inputs)i.push(e.name+" : "+this.getType(e.type));let r=`fn ${t.name}( ${i.join(", ")} ) -> ${this.getType(t.type)} {\n${s.vars}\n${s.code}\n`;return s.result&&(r+=`\treturn ${s.result};\n`),r+="\n}\n",r}getInstanceIndex(){return"vertex"===this.shaderStage?this.getBuiltin("instance_index","instanceIndex","u32","attribute"):"instanceIndex"}getInvocationLocalIndex(){return this.getBuiltin("local_invocation_index","invocationLocalIndex","u32","attribute")}getSubgroupSize(){return this.enableSubGroups(),this.getBuiltin("subgroup_size","subgroupSize","u32","attribute")}getSubgroupIndex(){return this.enableSubGroups(),this.getBuiltin("subgroup_invocation_id","subgroupIndex","u32","attribute")}getDrawIndex(){return null}getFrontFacing(){return this.getBuiltin("front_facing","isFront","bool")}getFragCoord(){return this.getBuiltin("position","fragCoord","vec4")+".xy"}getFragDepth(){return"output."+this.getBuiltin("frag_depth","depth","f32","output")}isFlipY(){return!1}enableDirective(e,t=this.shaderStage){(this.directives[t]||(this.directives[t]=new Set)).add(e)}getDirectives(e){const t=[],s=this.directives[e];if(void 0!==s)for(const e of s)t.push(`enable ${e};`);return t.join("\n")}enableSubGroups(){this.enableDirective("subgroups")}enableSubgroupsF16(){this.enableDirective("subgroups-f16")}enableClipDistances(){this.enableDirective("clip_distances")}enableShaderF16(){this.enableDirective("f16")}enableDualSourceBlending(){this.enableDirective("dual_source_blending")}getBuiltins(e){const t=[],s=this.builtins[e];if(void 0!==s)for(const{name:e,property:i,type:r}of s.values())t.push(`@builtin( ${e} ) ${i} : ${r}`);return t.join(",\n\t")}getAttributes(e){const t=[];if("compute"===e&&(this.getBuiltin("global_invocation_id","id","vec3","attribute"),this.getBuiltin("workgroup_id","workgroupId","vec3","attribute"),this.getBuiltin("local_invocation_id","localId","vec3","attribute"),this.getBuiltin("num_workgroups","numWorkgroups","vec3","attribute")),"vertex"===e||"compute"===e){const e=this.getBuiltins("attribute");e&&t.push(e);const s=this.getAttributesArray();for(let e=0,i=s.length;e`)}const i=this.getBuiltins("output");return i&&t.push("\t"+i),t.join(",\n")}getStructs(e){const t=[],s=this.structs[e];for(let e=0,i=s.length;e output : ${r};\n\n`)}return t.join("\n\n")}getVar(e,t){return`var ${t} : ${this.getType(e)}`}getVars(e){const t=[],s=this.vars[e];if(void 0!==s)for(const e of s)t.push(`\t${this.getVar(e.type,e.name)};`);return`\n${t.join("\n")}\n`}getVaryings(e){const t=[];if("vertex"===e&&this.getBuiltin("position","Vertex","vec4","vertex"),"vertex"===e||"fragment"===e){const s=this.varyings,i=this.vars[e];for(let r=0;r";else if(!0===t.isDataArrayTexture||!0===t.isCompressedArrayTexture)i="texture_2d_array";else if(!0===t.isDepthTexture)i=`texture_depth${n}_2d`;else if(!0===t.isVideoTexture)i="texture_external";else if(!0===t.isData3DTexture)i="texture_3d";else if(!0===r.node.isStorageTextureNode){i=`texture_storage_2d<${vP(t)}, ${this.getStorageAccess(r.node)}>`}else{i=`texture${n}_2d<${this.getComponentTypeFromTexture(t).charAt(0)}32>`}s.push(`@binding( ${o.binding++} ) @group( ${o.group} ) var ${r.name} : ${i};`)}else if("buffer"===r.type||"storageBuffer"===r.type){const e=r.node,t=this.getType(e.bufferType),s=e.bufferCount,n=s>0?", "+s:"",a=`\t${r.name} : array< ${t}${n} >\n`,h=e.isStorageBufferNode?`storage, ${this.getStorageAccess(e)}`:"uniform";i.push(this._getWGSLStructBinding("NodeBuffer_"+e.id,a,h,o.binding++,o.group))}else{const e=this.getType(this.getVectorType(r.type)),t=r.groupNode.name;(n[t]||(n[t]={index:o.binding++,id:o.group,snippets:[]})).snippets.push(`\t${r.name} : ${e}`)}}for(const e in n){const t=n[e];r.push(this._getWGSLStructBinding(e,t.snippets.join(",\n"),"uniform",t.index,t.id))}let o=s.join("\n");return o+=i.join("\n"),o+=r.join("\n"),o}buildCode(){const e=null!==this.material?{fragment:{},vertex:{}}:{compute:{}};for(const t in e){const s=e[t];s.uniforms=this.getUniforms(t),s.attributes=this.getAttributes(t),s.varyings=this.getVaryings(t),s.structs=this.getStructs(t),s.vars=this.getVars(t),s.codes=this.getCodes(t),s.directives=this.getDirectives(t);let i="// code\n\n";i+=this.flowCode[t];const r=this.flowNodes[t],n=r[r.length-1],o=n.outputNode,a=void 0!==o&&!0===o.isOutputStructNode;for(const e of r){const r=this.getFlowData(e),h=e.name;if(h&&(i.length>0&&(i+="\n"),i+=`\t// flow -> ${h}\n\t`),i+=`${r.code}\n\t`,e===n&&"compute"!==t)if(i+="// result\n\n\t","vertex"===t)i+=`varyings.Vertex = ${r.result};`;else if("fragment"===t)if(a)s.returnType=o.nodeType,i+=`return ${r.result};`;else{let e="\t@location(0) color: vec4";const t=this.getBuiltins("output");t&&(e+=",\n\t"+t),s.returnType="OutputStruct",s.structs+=this._getWGSLStruct("OutputStruct",e),s.structs+="\nvar output : OutputStruct;\n\n",i+=`output.color = ${r.result};\n\n\treturn output;`}}s.flow=i}null!==this.material?(this.vertexShader=this._getWGSLVertexCode(e.vertex),this.fragmentShader=this._getWGSLFragmentCode(e.fragment)):this.computeShader=this._getWGSLComputeCode(e.compute,(this.object.workgroupSize||[64]).join(", "))}getMethod(e,t=null){let s;return null!==t&&(s=this._getWGSLMethod(e+"_"+t)),void 0===s&&(s=this._getWGSLMethod(e)),s||e}getType(e){return EP[e]||e}isAvailable(e){let t=RP[e];return void 0===t&&("float32Filterable"===e&&(t=this.renderer.hasFeature("float32-filterable")),RP[e]=t),t}_getWGSLMethod(e){return void 0!==BP[e]&&this._include(e),IP[e]}_include(e){const t=BP[e];return t.build(this),null!==this.currentFunctionNode&&this.currentFunctionNode.includes.push(t),t}_getWGSLVertexCode(e){return`${this.getSignature()}\n// directives\n${e.directives}\n\n// uniforms\n${e.uniforms}\n\n// varyings\n${e.varyings}\nvar varyings : VaryingsStruct;\n\n// codes\n${e.codes}\n\n@vertex\nfn main( ${e.attributes} ) -> VaryingsStruct {\n\n\t// vars\n\t${e.vars}\n\n\t// flow\n\t${e.flow}\n\n\treturn varyings;\n\n}\n`}_getWGSLFragmentCode(e){return`${this.getSignature()}\n\ndiagnostic( off, derivative_uniformity );\n\n// uniforms\n${e.uniforms}\n\n// structs\n${e.structs}\n\n// codes\n${e.codes}\n\n@fragment\nfn main( ${e.varyings} ) -> ${e.returnType} {\n\n\t// vars\n\t${e.vars}\n\n\t// flow\n\t${e.flow}\n\n}\n`}_getWGSLComputeCode(e,t){return`${this.getSignature()}\n// directives\n${e.directives}\n\n// system\nvar instanceIndex : u32;\n\n// uniforms\n${e.uniforms}\n\n// codes\n${e.codes}\n\n@compute @workgroup_size( ${t} )\nfn main( ${e.attributes} ) {\n\n\t// system\n\tinstanceIndex = id.x + id.y * numWorkgroups.x * u32(${t}) + id.z * numWorkgroups.x * numWorkgroups.y * u32(${t});\n\n\t// vars\n\t${e.vars}\n\n\t// flow\n\t${e.flow}\n\n}\n`}_getWGSLStruct(e,t){return`\nstruct ${e} {\n${t}\n};`}_getWGSLStructBinding(e,t,s,i=0,r=0){const n=e+"Struct";return`${this._getWGSLStruct(n,t)}\n@binding( ${i} ) @group( ${r} )\nvar<${s}> ${e} : ${n};`}}class FP{constructor(e){this.backend=e}getCurrentDepthStencilFormat(e){let t;return null!==e.depthTexture?t=this.getTextureFormatGPU(e.depthTexture):e.depth&&e.stencil?t=zA.Depth24PlusStencil8:e.depth&&(t=zA.Depth24Plus),t}getTextureFormatGPU(e){return this.backend.get(e).texture.format}getCurrentColorFormat(e){let t;return t=null!==e.textures?this.getTextureFormatGPU(e.textures[0]):this.getPreferredCanvasFormat(),t}getCurrentColorSpace(e){return null!==e.textures?e.textures[0].colorSpace:this.backend.renderer.outputColorSpace}getPrimitiveTopology(e,t){return e.isPoints?pA:e.isLineSegments||e.isMesh&&!0===t.wireframe?mA:e.isLine?gA:e.isMesh?fA:void 0}getSampleCount(e){let t=1;return e>1&&(t=Math.pow(2,Math.floor(Math.log2(e))),2===t&&(t=4)),t}getSampleCountRenderContext(e){return null!==e.textures?this.getSampleCount(e.sampleCount):this.getSampleCount(this.backend.renderer.samples)}getPreferredCanvasFormat(){return navigator.userAgent.includes("Quest")?zA.BGRA8Unorm:navigator.gpu.getPreferredCanvasFormat()}}const zP=new Map([[Int8Array,["sint8","snorm8"]],[Uint8Array,["uint8","unorm8"]],[Int16Array,["sint16","snorm16"]],[Uint16Array,["uint16","unorm16"]],[Int32Array,["sint32","snorm32"]],[Uint32Array,["uint32","unorm32"]],[Float32Array,["float32"]]]),UP=new Map([[fn,["float16"]]]),LP=new Map([[Int32Array,"sint32"],[Int16Array,"sint32"],[Uint32Array,"uint32"],[Uint16Array,"uint32"],[Float32Array,"float32"]]);class OP{constructor(e){this.backend=e}createAttribute(e,t){const s=this._getBufferAttribute(e),i=this.backend,r=i.get(s);let n=r.buffer;if(void 0===n){const o=i.device;let a=s.array;if(!1===e.normalized&&(a.constructor===Int16Array||a.constructor===Uint16Array)){const e=new Uint32Array(a.length);for(let t=0;t{l.createRenderPipelineAsync(M).then((t=>{c.pipeline=t,e()}))}));t.push(e)}}createBundleEncoder(e){const t=this.backend,{utils:s,device:i}=t,r=s.getCurrentDepthStencilFormat(e),n={label:"renderBundleEncoder",colorFormats:[s.getCurrentColorFormat(e)],depthStencilFormat:r,sampleCount:this._getSampleCount(e)};return i.createRenderBundleEncoder(n)}createComputePipeline(e,t){const s=this.backend,i=s.device,r=s.get(e.computeProgram).module,n=s.get(e),o=[];for(const e of t){const t=s.get(e);o.push(t.layout)}n.pipeline=i.createComputePipeline({compute:r,layout:i.createPipelineLayout({bindGroupLayouts:o})})}_getBlending(e){let t,s;const i=e.blending,r=e.blendSrc,n=e.blendDst,o=e.blendEquation;if(5===i){const i=null!==e.blendSrcAlpha?e.blendSrcAlpha:r,a=null!==e.blendDstAlpha?e.blendDstAlpha:n,h=null!==e.blendEquationAlpha?e.blendEquationAlpha:o;t={srcFactor:this._getBlendFactor(r),dstFactor:this._getBlendFactor(n),operation:this._getBlendOperation(o)},s={srcFactor:this._getBlendFactor(i),dstFactor:this._getBlendFactor(a),operation:this._getBlendOperation(h)}}else{const r=(e,i,r,n)=>{t={srcFactor:e,dstFactor:i,operation:eN},s={srcFactor:r,dstFactor:n,operation:eN}};if(e.premultipliedAlpha)switch(i){case 1:r(GA,qA,GA,qA);break;case 2:r(GA,GA,GA,GA);break;case 3:r(kA,HA,kA,GA);break;case 4:r(kA,WA,kA,jA)}else switch(i){case 1:r(jA,qA,GA,qA);break;case 2:r(jA,GA,jA,GA);break;case 3:r(kA,HA,kA,GA);break;case 4:r(kA,WA,kA,WA)}}if(void 0!==t&&void 0!==s)return{color:t,alpha:s};console.error("THREE.WebGPURenderer: Invalid blending: ",i)}_getBlendFactor(e){let t;switch(e){case 200:t=kA;break;case 201:t=GA;break;case 202:t=WA;break;case 203:t=HA;break;case C:t=jA;break;case E:t=qA;break;case 208:t=$A;break;case 209:t=XA;break;case 206:t=YA;break;case 207:t=JA;break;case 210:t=ZA;break;case 211:t=KA;break;case 212:t=QA;break;default:console.error("THREE.WebGPURenderer: Blend factor not supported.",e)}return t}_getStencilCompare(e){let t;const s=e.stencilFunc;switch(s){case 512:t=xA;break;case bs:t=MA;break;case 513:t=bA;break;case 515:t=TA;break;case 514:t=vA;break;case 518:t=SA;break;case 516:t=_A;break;case 517:t=wA;break;default:console.error("THREE.WebGPURenderer: Invalid stencil function.",s)}return t}_getStencilOperation(e){let t;switch(e){case ns:t=aN;break;case 0:t=hN;break;case 7681:t=lN;break;case 5386:t=uN;break;case 7682:t=cN;break;case 7683:t=dN;break;case 34055:t=pN;break;case 34056:t=mN;break;default:console.error("THREE.WebGPURenderer: Invalid stencil operation.",t)}return t}_getBlendOperation(e){let t;switch(e){case v:t=eN;break;case 101:t=tN;break;case 102:t=sN;break;case 103:t=iN;break;case 104:t=rN;break;default:console.error("THREE.WebGPUPipelineUtils: Blend equation not supported.",e)}return t}_getPrimitiveState(e,t,s){const i={},r=this.backend.utils;switch(i.topology=r.getPrimitiveTopology(e,s),null!==t.index&&!0===e.isLine&&!0!==e.isLineSegments&&(i.stripIndexFormat=t.index.array instanceof Uint16Array?PA:FA),s.side){case c:i.frontFace=CA,i.cullMode=IA;break;case d:i.frontFace=CA,i.cullMode=BA;break;case 2:i.frontFace=CA,i.cullMode=EA;break;default:console.error("THREE.WebGPUPipelineUtils: Unknown material.side value.",s.side)}return i}_getColorWriteMask(e){return!0===e.colorWrite?oN:nN}_getDepthCompare(e){let t;if(!1===e.depthTest)t=MA;else{const s=e.depthFunc;switch(s){case 0:t=xA;break;case 1:t=MA;break;case 2:t=bA;break;case 3:t=TA;break;case 4:t=vA;break;case 5:t=SA;break;case 6:t=_A;break;case 7:t=wA;break;default:console.error("THREE.WebGPUPipelineUtils: Invalid depth function.",s)}}return t}}class kP extends qI{constructor(e={}){super(e),this.isWebGPUBackend=!0,this.parameters.alpha=void 0===e.alpha||e.alpha,this.parameters.requiredLimits=void 0===e.requiredLimits?{}:e.requiredLimits,this.trackTimestamp=!0===e.trackTimestamp,this.device=null,this.context=null,this.colorBuffer=null,this.defaultRenderPassdescriptor=null,this.utils=new FP(this),this.attributeUtils=new OP(this),this.bindingUtils=new VP(this),this.pipelineUtils=new DP(this),this.textureUtils=new bP(this),this.occludedResolveCache=new Map}async init(e){await super.init(e);const t=this.parameters;let s;if(void 0===t.device){const e={powerPreference:t.powerPreference},i=await navigator.gpu.requestAdapter(e);if(null===i)throw new Error("WebGPUBackend: Unable to create WebGPU adapter.");const r=Object.values(PN),n=[];for(const e of r)i.features.has(e)&&n.push(e);const o={requiredFeatures:n,requiredLimits:t.requiredLimits};s=await i.requestDevice(o)}else s=t.device;const i=void 0!==t.context?t.context:e.domElement.getContext("webgpu");this.device=s,this.context=i;const r=t.alpha?"premultiplied":"opaque";this.trackTimestamp=this.trackTimestamp&&this.hasFeature(PN.TimestampQuery),this.context.configure({device:this.device,format:this.utils.getPreferredCanvasFormat(),usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC,alphaMode:r}),this.updateSize()}get coordinateSystem(){return Ds}async getArrayBufferAsync(e){return await this.attributeUtils.getArrayBufferAsync(e)}getContext(){return this.context}_getDefaultRenderPassDescriptor(){let e=this.defaultRenderPassdescriptor;if(null===e){const t=this.renderer;e={colorAttachments:[{view:null}],depthStencilAttachment:{view:this.textureUtils.getDepthBuffer(t.depth,t.stencil).createView()}};const s=e.colorAttachments[0];this.renderer.samples>0?s.view=this.colorBuffer.createView():s.resolveTarget=void 0,this.defaultRenderPassdescriptor=e}const t=e.colorAttachments[0];return this.renderer.samples>0?t.resolveTarget=this.context.getCurrentTexture().createView():t.view=this.context.getCurrentTexture().createView(),e}_getRenderPassDescriptor(e){const t=e.renderTarget,s=this.get(t);let i=s.descriptors;if(void 0===i||s.width!==t.width||s.height!==t.height||s.activeMipmapLevel!==t.activeMipmapLevel||s.samples!==t.samples){i={},s.descriptors=i;const e=()=>{t.removeEventListener("dispose",e),this.delete(t)};t.addEventListener("dispose",e)}const r=e.getCacheKey();let n=i[r];if(void 0===n){const o=e.textures,a=[];for(let t=0;t0&&(t.currentOcclusionQuerySet&&t.currentOcclusionQuerySet.destroy(),t.currentOcclusionQueryBuffer&&t.currentOcclusionQueryBuffer.destroy(),t.currentOcclusionQuerySet=t.occlusionQuerySet,t.currentOcclusionQueryBuffer=t.occlusionQueryBuffer,t.currentOcclusionQueryObjects=t.occlusionQueryObjects,r=s.createQuerySet({type:"occlusion",count:i}),t.occlusionQuerySet=r,t.occlusionQueryIndex=0,t.occlusionQueryObjects=new Array(i),t.lastOcclusionObject=null),n=null===e.textures?this._getDefaultRenderPassDescriptor():this._getRenderPassDescriptor(e),this.initTimestampQuery(e,n),n.occlusionQuerySet=r;const o=n.depthStencilAttachment;if(null!==e.textures){const t=n.colorAttachments;for(let s=0;s0&&t.currentPass.executeBundles(t.renderBundles),s>t.occlusionQueryIndex&&t.currentPass.endOcclusionQuery(),t.currentPass.end(),s>0){const i=8*s;let r=this.occludedResolveCache.get(i);void 0===r&&(r=this.device.createBuffer({size:i,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),this.occludedResolveCache.set(i,r));const n=this.device.createBuffer({size:i,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});t.encoder.resolveQuerySet(t.occlusionQuerySet,0,s,r,0),t.encoder.copyBufferToBuffer(r,0,n,0,i),t.occlusionQueryBuffer=n,this.resolveOccludedAsync(e)}if(this.prepareTimestampBuffer(e,t.encoder),this.device.queue.submit([t.encoder.finish()]),null!==e.textures){const t=e.textures;for(let e=0;eo?(h.x=Math.min(t.dispatchCount,o),h.y=Math.ceil(t.dispatchCount/o)):h.x=t.dispatchCount,r.dispatchWorkgroups(h.x,h.y,h.z)}finishCompute(e){const t=this.get(e);t.passEncoderGPU.end(),this.prepareTimestampBuffer(e,t.cmdEncoderGPU),this.device.queue.submit([t.cmdEncoderGPU.finish()])}draw(e,t){const{object:s,geometry:i,context:r,pipeline:n}=e,o=e.getBindings(),a=this.get(r),h=this.get(n).pipeline,l=a.currentSets,u=a.currentPass;l.pipeline!==h&&(u.setPipeline(h),l.pipeline=h);for(let e=0,t=o.length;e1?0:s;u.drawIndexed(t[s],i,e[s]/n,0,o)}}else if(!0===d){const e=m.count!==1/0?m.count:c.count;u.drawIndexed(e,f,g,0,0),t.update(s,e,f)}else{const e=i.attributes.position,r=m.count!==1/0?m.count:e.count;u.draw(r,f,g,0),t.update(s,r,f)}}needsRenderUpdate(e){const t=this.get(e),{object:s,material:i}=e,r=this.utils,n=r.getSampleCountRenderContext(e.context),o=r.getCurrentColorSpace(e.context),a=r.getCurrentColorFormat(e.context),h=r.getCurrentDepthStencilFormat(e.context),l=r.getPrimitiveTopology(s,i);let u=!1;return t.material===i&&t.materialVersion===i.version&&t.transparent===i.transparent&&t.blending===i.blending&&t.premultipliedAlpha===i.premultipliedAlpha&&t.blendSrc===i.blendSrc&&t.blendDst===i.blendDst&&t.blendEquation===i.blendEquation&&t.blendSrcAlpha===i.blendSrcAlpha&&t.blendDstAlpha===i.blendDstAlpha&&t.blendEquationAlpha===i.blendEquationAlpha&&t.colorWrite===i.colorWrite&&t.depthWrite===i.depthWrite&&t.depthTest===i.depthTest&&t.depthFunc===i.depthFunc&&t.stencilWrite===i.stencilWrite&&t.stencilFunc===i.stencilFunc&&t.stencilFail===i.stencilFail&&t.stencilZFail===i.stencilZFail&&t.stencilZPass===i.stencilZPass&&t.stencilFuncMask===i.stencilFuncMask&&t.stencilWriteMask===i.stencilWriteMask&&t.side===i.side&&t.alphaToCoverage===i.alphaToCoverage&&t.sampleCount===n&&t.colorSpace===o&&t.colorFormat===a&&t.depthStencilFormat===h&&t.primitiveTopology===l&&t.clippingContextCacheKey===e.clippingContext.cacheKey||(t.material=i,t.materialVersion=i.version,t.transparent=i.transparent,t.blending=i.blending,t.premultipliedAlpha=i.premultipliedAlpha,t.blendSrc=i.blendSrc,t.blendDst=i.blendDst,t.blendEquation=i.blendEquation,t.blendSrcAlpha=i.blendSrcAlpha,t.blendDstAlpha=i.blendDstAlpha,t.blendEquationAlpha=i.blendEquationAlpha,t.colorWrite=i.colorWrite,t.depthWrite=i.depthWrite,t.depthTest=i.depthTest,t.depthFunc=i.depthFunc,t.stencilWrite=i.stencilWrite,t.stencilFunc=i.stencilFunc,t.stencilFail=i.stencilFail,t.stencilZFail=i.stencilZFail,t.stencilZPass=i.stencilZPass,t.stencilFuncMask=i.stencilFuncMask,t.stencilWriteMask=i.stencilWriteMask,t.side=i.side,t.alphaToCoverage=i.alphaToCoverage,t.sampleCount=n,t.colorSpace=o,t.colorFormat=a,t.depthStencilFormat=h,t.primitiveTopology=l,t.clippingContextCacheKey=e.clippingContext.cacheKey,u=!0),u}getRenderCacheKey(e){const{object:t,material:s}=e,i=this.utils,r=e.context;return[s.transparent,s.blending,s.premultipliedAlpha,s.blendSrc,s.blendDst,s.blendEquation,s.blendSrcAlpha,s.blendDstAlpha,s.blendEquationAlpha,s.colorWrite,s.depthWrite,s.depthTest,s.depthFunc,s.stencilWrite,s.stencilFunc,s.stencilFail,s.stencilZFail,s.stencilZPass,s.stencilFuncMask,s.stencilWriteMask,s.side,i.getSampleCountRenderContext(r),i.getCurrentColorSpace(r),i.getCurrentColorFormat(r),i.getCurrentDepthStencilFormat(r),i.getPrimitiveTopology(t,s),e.clippingContext.cacheKey].join()}createSampler(e){this.textureUtils.createSampler(e)}destroySampler(e){this.textureUtils.destroySampler(e)}createDefaultTexture(e){this.textureUtils.createDefaultTexture(e)}createTexture(e,t){this.textureUtils.createTexture(e,t)}updateTexture(e,t){this.textureUtils.updateTexture(e,t)}generateMipmaps(e){this.textureUtils.generateMipmaps(e)}destroyTexture(e){this.textureUtils.destroyTexture(e)}copyTextureToBuffer(e,t,s,i,r){return this.textureUtils.copyTextureToBuffer(e,t,s,i,r)}initTimestampQuery(e,t){if(!this.trackTimestamp)return;const s=this.get(e);if(!s.timeStampQuerySet){const e=this.device.createQuerySet({type:"timestamp",count:2}),i={querySet:e,beginningOfPassWriteIndex:0,endOfPassWriteIndex:1};Object.assign(t,{timestampWrites:i}),s.timeStampQuerySet=e}}prepareTimestampBuffer(e,t){if(!this.trackTimestamp)return;const s=this.get(e),i=2*BigInt64Array.BYTES_PER_ELEMENT;void 0===s.currentTimestampQueryBuffers&&(s.currentTimestampQueryBuffers={resolveBuffer:this.device.createBuffer({label:"timestamp resolve buffer",size:i,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),resultBuffer:this.device.createBuffer({label:"timestamp result buffer",size:i,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),isMappingPending:!1});const{resolveBuffer:r,resultBuffer:n,isMappingPending:o}=s.currentTimestampQueryBuffers;!0!==o&&(t.resolveQuerySet(s.timeStampQuerySet,0,2,r,0),t.copyBufferToBuffer(r,0,n,0,i))}async resolveTimestampAsync(e,t="render"){if(!this.trackTimestamp)return;const s=this.get(e);if(void 0===s.currentTimestampQueryBuffers)return;const{resultBuffer:i,isMappingPending:r}=s.currentTimestampQueryBuffers;!0!==r&&(s.currentTimestampQueryBuffers.isMappingPending=!0,i.mapAsync(GPUMapMode.READ).then((()=>{const e=new BigUint64Array(i.getMappedRange()),r=Number(e[1]-e[0])/1e6;this.renderer.info.updateTimestamp(t,r),i.unmap(),s.currentTimestampQueryBuffers.isMappingPending=!1})))}createNodeBuilder(e,t){return new PP(e,t)}createProgram(e){this.get(e).module={module:this.device.createShaderModule({code:e.code,label:e.stage}),entryPoint:"main"}}destroyProgram(e){this.delete(e)}createRenderPipeline(e,t){this.pipelineUtils.createRenderPipeline(e,t)}createComputePipeline(e,t){this.pipelineUtils.createComputePipeline(e,t)}beginBundle(e){const t=this.get(e);t._currentPass=t.currentPass,t._currentSets=t.currentSets,t.currentSets={attributes:{},pipeline:null,index:null},t.currentPass=this.pipelineUtils.createBundleEncoder(e)}finishBundle(e,t){const s=this.get(e),i=s.currentPass.finish();this.get(t).bundleGPU=i,s.currentSets=s._currentSets,s.currentPass=s._currentPass}addBundle(e,t){this.get(e).renderBundles.push(this.get(t).bundleGPU)}createBindings(e){this.bindingUtils.createBindings(e)}updateBindings(e){this.bindingUtils.createBindings(e)}updateBinding(e){this.bindingUtils.updateBinding(e)}createIndexAttribute(e){this.attributeUtils.createAttribute(e,GPUBufferUsage.INDEX|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST)}createAttribute(e){this.attributeUtils.createAttribute(e,GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST)}createStorageAttribute(e){this.attributeUtils.createAttribute(e,GPUBufferUsage.STORAGE|GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST)}updateAttribute(e){this.attributeUtils.updateAttribute(e)}destroyAttribute(e){this.attributeUtils.destroyAttribute(e)}updateSize(){this.colorBuffer=this.textureUtils.getColorBuffer(),this.defaultRenderPassdescriptor=null}getMaxAnisotropy(){return 16}hasFeature(e){return this.device.features.has(e)}copyTextureToTexture(e,t,s=null,i=null,r=0){let n=0,o=0,a=0,h=0,l=e.image.width,u=e.image.height;null!==s&&(a=s.x,h=s.y,l=s.width,u=s.height),null!==i&&(n=i.x,o=i.y);const c=this.device.createCommandEncoder({label:"copyTextureToTexture_"+e.id+"_"+t.id}),d=this.get(e).texture,p=this.get(t).texture;c.copyTextureToTexture({texture:d,mipLevel:r,origin:{x:a,y:h,z:0}},{texture:p,mipLevel:r,origin:{x:n,y:o,z:0}},[l,u]),this.device.queue.submit([c.finish()])}copyFramebufferToTexture(e,t){const s=this.get(t),{encoder:i,descriptor:r}=s;let n=null;n=t.renderTarget?e.isDepthTexture?this.get(t.depthTexture).texture:this.get(t.textures[0]).texture:e.isDepthTexture?this.textureUtils.getDepthBuffer(t.depth,t.stencil):this.context.getCurrentTexture();const o=this.get(e).texture;if(n.format===o.format){s.currentPass.end(),i.copyTextureToTexture({texture:n,origin:{x:0,y:0,z:0}},{texture:o},[e.image.width,e.image.height]),e.generateMipmaps&&this.textureUtils.generateMipmaps(e);for(let e=0;e(console.warn("THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend."),new uP(e)));super(new t(e),e),this.isWebGPURenderer=!0}}const WP=new xx,HP=new tA(WP);class jP{constructor(e,t=uc(0,0,1,1)){this.renderer=e,this.outputNode=t,this.outputColorTransform=!0,this.needsUpdate=!0,WP.name="PostProcessing"}render(){this.update();const e=this.renderer,t=e.toneMapping,s=e.outputColorSpace;e.toneMapping=0,e.outputColorSpace=Zt,HP.render(e),e.toneMapping=t,e.outputColorSpace=s}update(){if(!0===this.needsUpdate){const e=this.renderer,t=e.toneMapping,s=e.outputColorSpace;HP.material.fragmentNode=!0===this.outputColorTransform?Im(this.outputNode,t,s):this.outputNode.context({toneMapping:t,outputColorSpace:s}),HP.material.needsUpdate=!0,this.needsUpdate=!1}}async renderAsync(){this.update();const e=this.renderer,t=e.toneMapping,s=e.outputColorSpace;e.toneMapping=0,e.outputColorSpace=Zt,await HP.renderAsync(e),e.toneMapping=t,e.outputColorSpace=s}}class qP extends Ti{constructor(e=1,t=1){super(),this.image={width:e,height:t},this.magFilter=Te,this.minFilter=Te,this.isStorageTexture=!0}}class $P extends hn{constructor(e,t,s=Float32Array){!1===ArrayBuffer.isView(e)&&(e=new s(e*t)),super(e,t),this.isStorageBufferAttribute=!0}}class XP extends Ho{constructor(e,t,s=Float32Array){!1===ArrayBuffer.isView(e)&&(e=new s(e*t)),super(e,t),this.isStorageInstancedBufferAttribute=!0}}class YP extends gT{constructor(e){super(e),this.textures={}}load(e,t,s,i){const r=new xT(this.manager);r.setPath(this.path),r.setRequestHeader(this.requestHeader),r.setWithCredentials(this.withCredentials),r.load(e,(s=>{try{t(this.parse(JSON.parse(s)))}catch(t){i?i(t):console.error(t),this.manager.itemError(e)}}),s,i)}parseNodes(e){const t={};if(void 0!==e){for(const s of e){const{uuid:e,type:i}=s;t[e]=Du(eu(i)),t[e].uuid=e}const s={nodes:t,textures:this.textures};for(const i of e){i.meta=s;t[i.uuid].deserialize(i),delete i.meta}}return t}parse(e){const t=Du(eu(e.type));t.uuid=e.uuid;const s={nodes:this.parseNodes(e.nodes),textures:this.textures};return e.meta=s,t.deserialize(e),delete e.meta,t}setTextures(e){return this.textures=e,this}}const JP=jT.createMaterialFromType;jT.createMaterialFromType=function(e){const t=function(e){const t=yx.get(e);if(void 0!==t)return new t}(e);return void 0!==t?t:JP.call(this,e)};class ZP extends jT{constructor(e){super(e),this.nodes={}}parse(e){const t=super.parse(e),s=this.nodes,i=e.inputNodes;for(const e in i){const r=i[e];t[e]=s[r]}return t}setNodes(e){return this.nodes=e,this}}class KP extends YT{constructor(e){super(e),this._nodesJSON=null}parse(e,t){this._nodesJSON=e.nodes;const s=super.parse(e,t);return this._nodesJSON=null,s}parseNodes(e,t){if(void 0!==e){const s=new YP;return s.setTextures(t),s.parseNodes(e)}return{}}parseMaterials(e,t){const s={};if(void 0!==e){const i=this.parseNodes(this._nodesJSON,t),r=new ZP;r.setTextures(t),r.setNodes(i);for(let t=0,i=e.length;t>8&255]+Gs[e>>16&255]+Gs[e>>24&255]+"-"+Gs[255&t]+Gs[t>>8&255]+"-"+Gs[t>>16&15|64]+Gs[t>>24&255]+"-"+Gs[63&s|128]+Gs[s>>8&255]+"-"+Gs[s>>16&255]+Gs[s>>24&255]+Gs[255&i]+Gs[i>>8&255]+Gs[i>>16&255]+Gs[i>>24&255]).toLowerCase()}function $s(e,t,s){return Math.max(t,Math.min(s,e))}function Xs(e,t){return(e%t+t)%t}function Ys(e,t,s){return(1-s)*e+s*t}function Zs(e,t){switch(t.constructor){case Float32Array:return e;case Uint32Array:return e/4294967295;case Uint16Array:return e/65535;case Uint8Array:return e/255;case Int32Array:return Math.max(e/2147483647,-1);case Int16Array:return Math.max(e/32767,-1);case Int8Array:return Math.max(e/127,-1);default:throw new Error("Invalid component type.")}}function Js(e,t){switch(t.constructor){case Float32Array:return e;case Uint32Array:return Math.round(4294967295*e);case Uint16Array:return Math.round(65535*e);case Uint8Array:return Math.round(255*e);case Int32Array:return Math.round(2147483647*e);case Int16Array:return Math.round(32767*e);case Int8Array:return Math.round(127*e);default:throw new Error("Invalid component type.")}}const Ks={DEG2RAD:js,RAD2DEG:Hs,generateUUID:qs,clamp:$s,euclideanModulo:Xs,mapLinear:function(e,t,s,i,r){return i+(e-t)*(r-i)/(s-t)},inverseLerp:function(e,t,s){return e!==t?(s-e)/(t-e):0},lerp:Ys,damp:function(e,t,s,i){return Ys(e,t,1-Math.exp(-s*i))},pingpong:function(e,t=1){return t-Math.abs(Xs(e,2*t)-t)},smoothstep:function(e,t,s){return e<=t?0:e>=s?1:(e=(e-t)/(s-t))*e*(3-2*e)},smootherstep:function(e,t,s){return e<=t?0:e>=s?1:(e=(e-t)/(s-t))*e*e*(e*(6*e-15)+10)},randInt:function(e,t){return e+Math.floor(Math.random()*(t-e+1))},randFloat:function(e,t){return e+Math.random()*(t-e)},randFloatSpread:function(e){return e*(.5-Math.random())},seededRandom:function(e){void 0!==e&&(Ws=e);let t=Ws+=1831565813;return t=Math.imul(t^t>>>15,1|t),t^=t+Math.imul(t^t>>>7,61|t),((t^t>>>14)>>>0)/4294967296},degToRad:function(e){return e*js},radToDeg:function(e){return e*Hs},isPowerOfTwo:function(e){return 0==(e&e-1)&&0!==e},ceilPowerOfTwo:function(e){return Math.pow(2,Math.ceil(Math.log(e)/Math.LN2))},floorPowerOfTwo:function(e){return Math.pow(2,Math.floor(Math.log(e)/Math.LN2))},setQuaternionFromProperEuler:function(e,t,s,i,r){const n=Math.cos,o=Math.sin,a=n(s/2),h=o(s/2),u=n((t+i)/2),l=o((t+i)/2),c=n((t-i)/2),d=o((t-i)/2),p=n((i-t)/2),m=o((i-t)/2);switch(r){case"XYX":e.set(a*l,h*c,h*d,a*u);break;case"YZY":e.set(h*d,a*l,h*c,a*u);break;case"ZXZ":e.set(h*c,h*d,a*l,a*u);break;case"XZX":e.set(a*l,h*m,h*p,a*u);break;case"YXY":e.set(h*p,a*l,h*m,a*u);break;case"ZYZ":e.set(h*m,h*p,a*l,a*u);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+r)}},normalize:Js,denormalize:Zs};class Qs{constructor(e=0,t=0){Qs.prototype.isVector2=!0,this.x=e,this.y=t}get width(){return this.x}set width(e){this.x=e}get height(){return this.y}set height(e){this.y=e}set(e,t){return this.x=e,this.y=t,this}setScalar(e){return this.x=e,this.y=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}addScalar(e){return this.x+=e,this.y+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this}subScalar(e){return this.x-=e,this.y-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this}multiply(e){return this.x*=e.x,this.y*=e.y,this}multiplyScalar(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e.x,this.y/=e.y,this}divideScalar(e){return this.multiplyScalar(1/e)}applyMatrix3(e){const t=this.x,s=this.y,i=e.elements;return this.x=i[0]*t+i[3]*s+i[6],this.y=i[1]*t+i[4]*s+i[7],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this}clampLength(e,t){const s=this.length();return this.divideScalar(s||1).multiplyScalar(Math.max(e,Math.min(t,s)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(e){return this.x*e.x+this.y*e.y}cross(e){return this.x*e.y-this.y*e.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(0===t)return Math.PI/2;const s=this.dot(e)/t;return Math.acos($s(s,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,s=this.y-e.y;return t*t+s*s}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this}lerpVectors(e,t,s){return this.x=e.x+(t.x-e.x)*s,this.y=e.y+(t.y-e.y)*s,this}equals(e){return e.x===this.x&&e.y===this.y}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this}rotateAround(e,t){const s=Math.cos(t),i=Math.sin(t),r=this.x-e.x,n=this.y-e.y;return this.x=r*s-n*i+e.x,this.y=r*i+n*s+e.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class ei{constructor(e,t,s,i,r,n,o,a,h){ei.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],void 0!==e&&this.set(e,t,s,i,r,n,o,a,h)}set(e,t,s,i,r,n,o,a,h){const u=this.elements;return u[0]=e,u[1]=i,u[2]=o,u[3]=t,u[4]=r,u[5]=a,u[6]=s,u[7]=n,u[8]=h,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(e){const t=this.elements,s=e.elements;return t[0]=s[0],t[1]=s[1],t[2]=s[2],t[3]=s[3],t[4]=s[4],t[5]=s[5],t[6]=s[6],t[7]=s[7],t[8]=s[8],this}extractBasis(e,t,s){return e.setFromMatrix3Column(this,0),t.setFromMatrix3Column(this,1),s.setFromMatrix3Column(this,2),this}setFromMatrix4(e){const t=e.elements;return this.set(t[0],t[4],t[8],t[1],t[5],t[9],t[2],t[6],t[10]),this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const s=e.elements,i=t.elements,r=this.elements,n=s[0],o=s[3],a=s[6],h=s[1],u=s[4],l=s[7],c=s[2],d=s[5],p=s[8],m=i[0],g=i[3],f=i[6],y=i[1],x=i[4],b=i[7],v=i[2],T=i[5],_=i[8];return r[0]=n*m+o*y+a*v,r[3]=n*g+o*x+a*T,r[6]=n*f+o*b+a*_,r[1]=h*m+u*y+l*v,r[4]=h*g+u*x+l*T,r[7]=h*f+u*b+l*_,r[2]=c*m+d*y+p*v,r[5]=c*g+d*x+p*T,r[8]=c*f+d*b+p*_,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[3]*=e,t[6]*=e,t[1]*=e,t[4]*=e,t[7]*=e,t[2]*=e,t[5]*=e,t[8]*=e,this}determinant(){const e=this.elements,t=e[0],s=e[1],i=e[2],r=e[3],n=e[4],o=e[5],a=e[6],h=e[7],u=e[8];return t*n*u-t*o*h-s*r*u+s*o*a+i*r*h-i*n*a}invert(){const e=this.elements,t=e[0],s=e[1],i=e[2],r=e[3],n=e[4],o=e[5],a=e[6],h=e[7],u=e[8],l=u*n-o*h,c=o*a-u*r,d=h*r-n*a,p=t*l+s*c+i*d;if(0===p)return this.set(0,0,0,0,0,0,0,0,0);const m=1/p;return e[0]=l*m,e[1]=(i*h-u*s)*m,e[2]=(o*s-i*n)*m,e[3]=c*m,e[4]=(u*t-i*a)*m,e[5]=(i*r-o*t)*m,e[6]=d*m,e[7]=(s*a-h*t)*m,e[8]=(n*t-s*r)*m,this}transpose(){let e;const t=this.elements;return e=t[1],t[1]=t[3],t[3]=e,e=t[2],t[2]=t[6],t[6]=e,e=t[5],t[5]=t[7],t[7]=e,this}getNormalMatrix(e){return this.setFromMatrix4(e).invert().transpose()}transposeIntoArray(e){const t=this.elements;return e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8],this}setUvTransform(e,t,s,i,r,n,o){const a=Math.cos(r),h=Math.sin(r);return this.set(s*a,s*h,-s*(a*n+h*o)+n+e,-i*h,i*a,-i*(-h*n+a*o)+o+t,0,0,1),this}scale(e,t){return this.premultiply(ti.makeScale(e,t)),this}rotate(e){return this.premultiply(ti.makeRotation(-e)),this}translate(e,t){return this.premultiply(ti.makeTranslation(e,t)),this}makeTranslation(e,t){return e.isVector2?this.set(1,0,e.x,0,1,e.y,0,0,1):this.set(1,0,e,0,1,t,0,0,1),this}makeRotation(e){const t=Math.cos(e),s=Math.sin(e);return this.set(t,-s,0,s,t,0,0,0,1),this}makeScale(e,t){return this.set(e,0,0,0,t,0,0,0,1),this}equals(e){const t=this.elements,s=e.elements;for(let e=0;e<9;e++)if(t[e]!==s[e])return!1;return!0}fromArray(e,t=0){for(let s=0;s<9;s++)this.elements[s]=e[s+t];return this}toArray(e=[],t=0){const s=this.elements;return e[t]=s[0],e[t+1]=s[1],e[t+2]=s[2],e[t+3]=s[3],e[t+4]=s[4],e[t+5]=s[5],e[t+6]=s[6],e[t+7]=s[7],e[t+8]=s[8],e}clone(){return(new this.constructor).fromArray(this.elements)}}const ti=new ei;const si={Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:Uint8ClampedArray,Int16Array:Int16Array,Uint16Array:Uint16Array,Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array};function ii(e,t){return new si[e](t)}function ri(e){return document.createElementNS("http://www.w3.org/1999/xhtml",e)}function ni(){const e=ri("canvas");return e.style.display="block",e}const oi={};const ai=(new ei).set(.8224621,.177538,0,.0331941,.9668058,0,.0170827,.0723974,.9105199),hi=(new ei).set(1.2249401,-.2249404,0,-.0420569,1.0420571,0,-.0196376,-.0786361,1.0982735),ui={[Jt]:{transfer:es,primaries:ss,luminanceCoefficients:[.2126,.7152,.0722],toReference:e=>e,fromReference:e=>e},[Zt]:{transfer:ts,primaries:ss,luminanceCoefficients:[.2126,.7152,.0722],toReference:e=>e.convertSRGBToLinear(),fromReference:e=>e.convertLinearToSRGB()},[Qt]:{transfer:es,primaries:is,luminanceCoefficients:[.2289,.6917,.0793],toReference:e=>e.applyMatrix3(hi),fromReference:e=>e.applyMatrix3(ai)},[Kt]:{transfer:ts,primaries:is,luminanceCoefficients:[.2289,.6917,.0793],toReference:e=>e.convertSRGBToLinear().applyMatrix3(hi),fromReference:e=>e.applyMatrix3(ai).convertLinearToSRGB()}},li=new Set([Jt,Qt]),ci={enabled:!0,_workingColorSpace:Jt,get workingColorSpace(){return this._workingColorSpace},set workingColorSpace(e){if(!li.has(e))throw new Error(`Unsupported working color space, "${e}".`);this._workingColorSpace=e},convert:function(e,t,s){if(!1===this.enabled||t===s||!t||!s)return e;const i=ui[t].toReference;return(0,ui[s].fromReference)(i(e))},fromWorkingColorSpace:function(e,t){return this.convert(e,this._workingColorSpace,t)},toWorkingColorSpace:function(e,t){return this.convert(e,t,this._workingColorSpace)},getPrimaries:function(e){return ui[e].primaries},getTransfer:function(e){return e===Yt?es:ui[e].transfer},getLuminanceCoefficients:function(e,t=this._workingColorSpace){return e.fromArray(ui[t].luminanceCoefficients)}};function di(e){return e<.04045?.0773993808*e:Math.pow(.9478672986*e+.0521327014,2.4)}function pi(e){return e<.0031308?12.92*e:1.055*Math.pow(e,.41666)-.055}let mi;class gi{static getDataURL(e){if(/^data:/i.test(e.src))return e.src;if("undefined"==typeof HTMLCanvasElement)return e.src;let t;if(e instanceof HTMLCanvasElement)t=e;else{void 0===mi&&(mi=ri("canvas")),mi.width=e.width,mi.height=e.height;const s=mi.getContext("2d");e instanceof ImageData?s.putImageData(e,0,0):s.drawImage(e,0,0,e.width,e.height),t=mi}return t.width>2048||t.height>2048?(console.warn("THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons",e),t.toDataURL("image/jpeg",.6)):t.toDataURL("image/png")}static sRGBToLinear(e){if("undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap){const t=ri("canvas");t.width=e.width,t.height=e.height;const s=t.getContext("2d");s.drawImage(e,0,0,e.width,e.height);const i=s.getImageData(0,0,e.width,e.height),r=i.data;for(let e=0;e0&&(s.userData=this.userData),t||(e.textures[this.uuid]=s),s}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(e){if(this.mapping!==ae)return e;if(e.applyMatrix3(this.matrix),e.x<0||e.x>1)switch(this.wrapS){case pe:e.x=e.x-Math.floor(e.x);break;case me:e.x=e.x<0?0:1;break;case ge:1===Math.abs(Math.floor(e.x)%2)?e.x=Math.ceil(e.x)-e.x:e.x=e.x-Math.floor(e.x)}if(e.y<0||e.y>1)switch(this.wrapT){case pe:e.y=e.y-Math.floor(e.y);break;case me:e.y=e.y<0?0:1;break;case ge:1===Math.abs(Math.floor(e.y)%2)?e.y=Math.ceil(e.y)-e.y:e.y=e.y-Math.floor(e.y)}return this.flipY&&(e.y=1-e.y),e}set needsUpdate(e){!0===e&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(e){!0===e&&this.pmremVersion++}}vi.DEFAULT_IMAGE=null,vi.DEFAULT_MAPPING=ae,vi.DEFAULT_ANISOTROPY=1;class Ti{constructor(e=0,t=0,s=0,i=1){Ti.prototype.isVector4=!0,this.x=e,this.y=t,this.z=s,this.w=i}get width(){return this.z}set width(e){this.z=e}get height(){return this.w}set height(e){this.w=e}set(e,t,s,i){return this.x=e,this.y=t,this.z=s,this.w=i,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this.w=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setW(e){return this.w=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;case 3:this.w=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=void 0!==e.w?e.w:1,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this.w+=e.w,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this.w+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this.w=e.w+t.w,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this.w+=e.w*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this.w-=e.w,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this.w-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this.w=e.w-t.w,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this.w*=e.w,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this.w*=e,this}applyMatrix4(e){const t=this.x,s=this.y,i=this.z,r=this.w,n=e.elements;return this.x=n[0]*t+n[4]*s+n[8]*i+n[12]*r,this.y=n[1]*t+n[5]*s+n[9]*i+n[13]*r,this.z=n[2]*t+n[6]*s+n[10]*i+n[14]*r,this.w=n[3]*t+n[7]*s+n[11]*i+n[15]*r,this}divideScalar(e){return this.multiplyScalar(1/e)}setAxisAngleFromQuaternion(e){this.w=2*Math.acos(e.w);const t=Math.sqrt(1-e.w*e.w);return t<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=e.x/t,this.y=e.y/t,this.z=e.z/t),this}setAxisAngleFromRotationMatrix(e){let t,s,i,r;const n=.01,o=.1,a=e.elements,h=a[0],u=a[4],l=a[8],c=a[1],d=a[5],p=a[9],m=a[2],g=a[6],f=a[10];if(Math.abs(u-c)a&&e>y?ey?a=0?1:-1,i=1-t*t;if(i>Number.EPSILON){const r=Math.sqrt(i),n=Math.atan2(r,t*s);e=Math.sin(e*n)/r,o=Math.sin(o*n)/r}const r=o*s;if(a=a*e+c*r,h=h*e+d*r,u=u*e+p*r,l=l*e+m*r,e===1-o){const e=1/Math.sqrt(a*a+h*h+u*u+l*l);a*=e,h*=e,u*=e,l*=e}}e[t]=a,e[t+1]=h,e[t+2]=u,e[t+3]=l}static multiplyQuaternionsFlat(e,t,s,i,r,n){const o=s[i],a=s[i+1],h=s[i+2],u=s[i+3],l=r[n],c=r[n+1],d=r[n+2],p=r[n+3];return e[t]=o*p+u*l+a*d-h*c,e[t+1]=a*p+u*c+h*l-o*d,e[t+2]=h*p+u*d+o*c-a*l,e[t+3]=u*p-o*l-a*c-h*d,e}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get w(){return this._w}set w(e){this._w=e,this._onChangeCallback()}set(e,t,s,i){return this._x=e,this._y=t,this._z=s,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(e){return this._x=e.x,this._y=e.y,this._z=e.z,this._w=e.w,this._onChangeCallback(),this}setFromEuler(e,t=!0){const s=e._x,i=e._y,r=e._z,n=e._order,o=Math.cos,a=Math.sin,h=o(s/2),u=o(i/2),l=o(r/2),c=a(s/2),d=a(i/2),p=a(r/2);switch(n){case"XYZ":this._x=c*u*l+h*d*p,this._y=h*d*l-c*u*p,this._z=h*u*p+c*d*l,this._w=h*u*l-c*d*p;break;case"YXZ":this._x=c*u*l+h*d*p,this._y=h*d*l-c*u*p,this._z=h*u*p-c*d*l,this._w=h*u*l+c*d*p;break;case"ZXY":this._x=c*u*l-h*d*p,this._y=h*d*l+c*u*p,this._z=h*u*p+c*d*l,this._w=h*u*l-c*d*p;break;case"ZYX":this._x=c*u*l-h*d*p,this._y=h*d*l+c*u*p,this._z=h*u*p-c*d*l,this._w=h*u*l+c*d*p;break;case"YZX":this._x=c*u*l+h*d*p,this._y=h*d*l+c*u*p,this._z=h*u*p-c*d*l,this._w=h*u*l-c*d*p;break;case"XZY":this._x=c*u*l-h*d*p,this._y=h*d*l-c*u*p,this._z=h*u*p+c*d*l,this._w=h*u*l+c*d*p;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+n)}return!0===t&&this._onChangeCallback(),this}setFromAxisAngle(e,t){const s=t/2,i=Math.sin(s);return this._x=e.x*i,this._y=e.y*i,this._z=e.z*i,this._w=Math.cos(s),this._onChangeCallback(),this}setFromRotationMatrix(e){const t=e.elements,s=t[0],i=t[4],r=t[8],n=t[1],o=t[5],a=t[9],h=t[2],u=t[6],l=t[10],c=s+o+l;if(c>0){const e=.5/Math.sqrt(c+1);this._w=.25/e,this._x=(u-a)*e,this._y=(r-h)*e,this._z=(n-i)*e}else if(s>o&&s>l){const e=2*Math.sqrt(1+s-o-l);this._w=(u-a)/e,this._x=.25*e,this._y=(i+n)/e,this._z=(r+h)/e}else if(o>l){const e=2*Math.sqrt(1+o-s-l);this._w=(r-h)/e,this._x=(i+n)/e,this._y=.25*e,this._z=(a+u)/e}else{const e=2*Math.sqrt(1+l-s-o);this._w=(n-i)/e,this._x=(r+h)/e,this._y=(a+u)/e,this._z=.25*e}return this._onChangeCallback(),this}setFromUnitVectors(e,t){let s=e.dot(t)+1;return sMath.abs(e.z)?(this._x=-e.y,this._y=e.x,this._z=0,this._w=s):(this._x=0,this._y=-e.z,this._z=e.y,this._w=s)):(this._x=e.y*t.z-e.z*t.y,this._y=e.z*t.x-e.x*t.z,this._z=e.x*t.y-e.y*t.x,this._w=s),this.normalize()}angleTo(e){return 2*Math.acos(Math.abs($s(this.dot(e),-1,1)))}rotateTowards(e,t){const s=this.angleTo(e);if(0===s)return this;const i=Math.min(1,t/s);return this.slerp(e,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(e){return this._x*e._x+this._y*e._y+this._z*e._z+this._w*e._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let e=this.length();return 0===e?(this._x=0,this._y=0,this._z=0,this._w=1):(e=1/e,this._x=this._x*e,this._y=this._y*e,this._z=this._z*e,this._w=this._w*e),this._onChangeCallback(),this}multiply(e){return this.multiplyQuaternions(this,e)}premultiply(e){return this.multiplyQuaternions(e,this)}multiplyQuaternions(e,t){const s=e._x,i=e._y,r=e._z,n=e._w,o=t._x,a=t._y,h=t._z,u=t._w;return this._x=s*u+n*o+i*h-r*a,this._y=i*u+n*a+r*o-s*h,this._z=r*u+n*h+s*a-i*o,this._w=n*u-s*o-i*a-r*h,this._onChangeCallback(),this}slerp(e,t){if(0===t)return this;if(1===t)return this.copy(e);const s=this._x,i=this._y,r=this._z,n=this._w;let o=n*e._w+s*e._x+i*e._y+r*e._z;if(o<0?(this._w=-e._w,this._x=-e._x,this._y=-e._y,this._z=-e._z,o=-o):this.copy(e),o>=1)return this._w=n,this._x=s,this._y=i,this._z=r,this;const a=1-o*o;if(a<=Number.EPSILON){const e=1-t;return this._w=e*n+t*this._w,this._x=e*s+t*this._x,this._y=e*i+t*this._y,this._z=e*r+t*this._z,this.normalize(),this}const h=Math.sqrt(a),u=Math.atan2(h,o),l=Math.sin((1-t)*u)/h,c=Math.sin(t*u)/h;return this._w=n*l+this._w*c,this._x=s*l+this._x*c,this._y=i*l+this._y*c,this._z=r*l+this._z*c,this._onChangeCallback(),this}slerpQuaternions(e,t,s){return this.copy(e).slerp(t,s)}random(){const e=2*Math.PI*Math.random(),t=2*Math.PI*Math.random(),s=Math.random(),i=Math.sqrt(1-s),r=Math.sqrt(s);return this.set(i*Math.sin(e),i*Math.cos(e),r*Math.sin(t),r*Math.cos(t))}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._w===this._w}fromArray(e,t=0){return this._x=e[t],this._y=e[t+1],this._z=e[t+2],this._w=e[t+3],this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._w,e}fromBufferAttribute(e,t){return this._x=e.getX(t),this._y=e.getY(t),this._z=e.getZ(t),this._w=e.getW(t),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}class Ri{constructor(e=0,t=0,s=0){Ri.prototype.isVector3=!0,this.x=e,this.y=t,this.z=s}set(e,t,s){return void 0===s&&(s=this.z),this.x=e,this.y=t,this.z=s,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this}multiplyVectors(e,t){return this.x=e.x*t.x,this.y=e.y*t.y,this.z=e.z*t.z,this}applyEuler(e){return this.applyQuaternion(Bi.setFromEuler(e))}applyAxisAngle(e,t){return this.applyQuaternion(Bi.setFromAxisAngle(e,t))}applyMatrix3(e){const t=this.x,s=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[3]*s+r[6]*i,this.y=r[1]*t+r[4]*s+r[7]*i,this.z=r[2]*t+r[5]*s+r[8]*i,this}applyNormalMatrix(e){return this.applyMatrix3(e).normalize()}applyMatrix4(e){const t=this.x,s=this.y,i=this.z,r=e.elements,n=1/(r[3]*t+r[7]*s+r[11]*i+r[15]);return this.x=(r[0]*t+r[4]*s+r[8]*i+r[12])*n,this.y=(r[1]*t+r[5]*s+r[9]*i+r[13])*n,this.z=(r[2]*t+r[6]*s+r[10]*i+r[14])*n,this}applyQuaternion(e){const t=this.x,s=this.y,i=this.z,r=e.x,n=e.y,o=e.z,a=e.w,h=2*(n*i-o*s),u=2*(o*t-r*i),l=2*(r*s-n*t);return this.x=t+a*h+n*l-o*u,this.y=s+a*u+o*h-r*l,this.z=i+a*l+r*u-n*h,this}project(e){return this.applyMatrix4(e.matrixWorldInverse).applyMatrix4(e.projectionMatrix)}unproject(e){return this.applyMatrix4(e.projectionMatrixInverse).applyMatrix4(e.matrixWorld)}transformDirection(e){const t=this.x,s=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[4]*s+r[8]*i,this.y=r[1]*t+r[5]*s+r[9]*i,this.z=r[2]*t+r[6]*s+r[10]*i,this.normalize()}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this}divideScalar(e){return this.multiplyScalar(1/e)}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this.z=Math.max(e,Math.min(t,this.z)),this}clampLength(e,t){const s=this.length();return this.divideScalar(s||1).multiplyScalar(Math.max(e,Math.min(t,s)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this}lerpVectors(e,t,s){return this.x=e.x+(t.x-e.x)*s,this.y=e.y+(t.y-e.y)*s,this.z=e.z+(t.z-e.z)*s,this}cross(e){return this.crossVectors(this,e)}crossVectors(e,t){const s=e.x,i=e.y,r=e.z,n=t.x,o=t.y,a=t.z;return this.x=i*a-r*o,this.y=r*n-s*a,this.z=s*o-i*n,this}projectOnVector(e){const t=e.lengthSq();if(0===t)return this.set(0,0,0);const s=e.dot(this)/t;return this.copy(e).multiplyScalar(s)}projectOnPlane(e){return Ei.copy(this).projectOnVector(e),this.sub(Ei)}reflect(e){return this.sub(Ei.copy(e).multiplyScalar(2*this.dot(e)))}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(0===t)return Math.PI/2;const s=this.dot(e)/t;return Math.acos($s(s,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,s=this.y-e.y,i=this.z-e.z;return t*t+s*s+i*i}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)+Math.abs(this.z-e.z)}setFromSpherical(e){return this.setFromSphericalCoords(e.radius,e.phi,e.theta)}setFromSphericalCoords(e,t,s){const i=Math.sin(t)*e;return this.x=i*Math.sin(s),this.y=Math.cos(t)*e,this.z=i*Math.cos(s),this}setFromCylindrical(e){return this.setFromCylindricalCoords(e.radius,e.theta,e.y)}setFromCylindricalCoords(e,t,s){return this.x=e*Math.sin(t),this.y=s,this.z=e*Math.cos(t),this}setFromMatrixPosition(e){const t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this}setFromMatrixScale(e){const t=this.setFromMatrixColumn(e,0).length(),s=this.setFromMatrixColumn(e,1).length(),i=this.setFromMatrixColumn(e,2).length();return this.x=t,this.y=s,this.z=i,this}setFromMatrixColumn(e,t){return this.fromArray(e.elements,4*t)}setFromMatrix3Column(e,t){return this.fromArray(e.elements,3*t)}setFromEuler(e){return this.x=e._x,this.y=e._y,this.z=e._z,this}setFromColor(e){return this.x=e.r,this.y=e.g,this.z=e.b,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const e=Math.random()*Math.PI*2,t=2*Math.random()-1,s=Math.sqrt(1-t*t);return this.x=s*Math.cos(e),this.y=t,this.z=s*Math.sin(e),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const Ei=new Ri,Bi=new Ci;class Ii{constructor(e=new Ri(1/0,1/0,1/0),t=new Ri(-1/0,-1/0,-1/0)){this.isBox3=!0,this.min=e,this.max=t}set(e,t){return this.min.copy(e),this.max.copy(t),this}setFromArray(e){this.makeEmpty();for(let t=0,s=e.length;t=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y&&e.z>=this.min.z&&e.z<=this.max.z}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y),(e.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y&&e.max.z>=this.min.z&&e.min.z<=this.max.z}intersectsSphere(e){return this.clampPoint(e.center,Fi),Fi.distanceToSquared(e.center)<=e.radius*e.radius}intersectsPlane(e){let t,s;return e.normal.x>0?(t=e.normal.x*this.min.x,s=e.normal.x*this.max.x):(t=e.normal.x*this.max.x,s=e.normal.x*this.min.x),e.normal.y>0?(t+=e.normal.y*this.min.y,s+=e.normal.y*this.max.y):(t+=e.normal.y*this.max.y,s+=e.normal.y*this.min.y),e.normal.z>0?(t+=e.normal.z*this.min.z,s+=e.normal.z*this.max.z):(t+=e.normal.z*this.max.z,s+=e.normal.z*this.min.z),t<=-e.constant&&s>=-e.constant}intersectsTriangle(e){if(this.isEmpty())return!1;this.getCenter(Gi),Wi.subVectors(this.max,Gi),Ui.subVectors(e.a,Gi),Oi.subVectors(e.b,Gi),Li.subVectors(e.c,Gi),Vi.subVectors(Oi,Ui),Di.subVectors(Li,Oi),ki.subVectors(Ui,Li);let t=[0,-Vi.z,Vi.y,0,-Di.z,Di.y,0,-ki.z,ki.y,Vi.z,0,-Vi.x,Di.z,0,-Di.x,ki.z,0,-ki.x,-Vi.y,Vi.x,0,-Di.y,Di.x,0,-ki.y,ki.x,0];return!!qi(t,Ui,Oi,Li,Wi)&&(t=[1,0,0,0,1,0,0,0,1],!!qi(t,Ui,Oi,Li,Wi)&&(ji.crossVectors(Vi,Di),t=[ji.x,ji.y,ji.z],qi(t,Ui,Oi,Li,Wi)))}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,Fi).distanceTo(e)}getBoundingSphere(e){return this.isEmpty()?e.makeEmpty():(this.getCenter(e.center),e.radius=.5*this.getSize(Fi).length()),e}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}applyMatrix4(e){return this.isEmpty()||(Pi[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(e),Pi[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(e),Pi[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(e),Pi[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(e),Pi[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(e),Pi[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(e),Pi[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(e),Pi[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(e),this.setFromPoints(Pi)),this}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}const Pi=[new Ri,new Ri,new Ri,new Ri,new Ri,new Ri,new Ri,new Ri],Fi=new Ri,zi=new Ii,Ui=new Ri,Oi=new Ri,Li=new Ri,Vi=new Ri,Di=new Ri,ki=new Ri,Gi=new Ri,Wi=new Ri,ji=new Ri,Hi=new Ri;function qi(e,t,s,i,r){for(let n=0,o=e.length-3;n<=o;n+=3){Hi.fromArray(e,n);const o=r.x*Math.abs(Hi.x)+r.y*Math.abs(Hi.y)+r.z*Math.abs(Hi.z),a=t.dot(Hi),h=s.dot(Hi),u=i.dot(Hi);if(Math.max(-Math.max(a,h,u),Math.min(a,h,u))>o)return!1}return!0}const $i=new Ii,Xi=new Ri,Yi=new Ri;class Zi{constructor(e=new Ri,t=-1){this.isSphere=!0,this.center=e,this.radius=t}set(e,t){return this.center.copy(e),this.radius=t,this}setFromPoints(e,t){const s=this.center;void 0!==t?s.copy(t):$i.setFromPoints(e).getCenter(s);let i=0;for(let t=0,r=e.length;tthis.radius*this.radius&&(t.sub(this.center).normalize(),t.multiplyScalar(this.radius).add(this.center)),t}getBoundingBox(e){return this.isEmpty()?(e.makeEmpty(),e):(e.set(this.center,this.center),e.expandByScalar(this.radius),e)}applyMatrix4(e){return this.center.applyMatrix4(e),this.radius=this.radius*e.getMaxScaleOnAxis(),this}translate(e){return this.center.add(e),this}expandByPoint(e){if(this.isEmpty())return this.center.copy(e),this.radius=0,this;Xi.subVectors(e,this.center);const t=Xi.lengthSq();if(t>this.radius*this.radius){const e=Math.sqrt(t),s=.5*(e-this.radius);this.center.addScaledVector(Xi,s/e),this.radius+=s}return this}union(e){return e.isEmpty()?this:this.isEmpty()?(this.copy(e),this):(!0===this.center.equals(e.center)?this.radius=Math.max(this.radius,e.radius):(Yi.subVectors(e.center,this.center).setLength(e.radius),this.expandByPoint(Xi.copy(e.center).add(Yi)),this.expandByPoint(Xi.copy(e.center).sub(Yi))),this)}equals(e){return e.center.equals(this.center)&&e.radius===this.radius}clone(){return(new this.constructor).copy(this)}}const Ji=new Ri,Ki=new Ri,Qi=new Ri,er=new Ri,tr=new Ri,sr=new Ri,ir=new Ri;class rr{constructor(e=new Ri,t=new Ri(0,0,-1)){this.origin=e,this.direction=t}set(e,t){return this.origin.copy(e),this.direction.copy(t),this}copy(e){return this.origin.copy(e.origin),this.direction.copy(e.direction),this}at(e,t){return t.copy(this.origin).addScaledVector(this.direction,e)}lookAt(e){return this.direction.copy(e).sub(this.origin).normalize(),this}recast(e){return this.origin.copy(this.at(e,Ji)),this}closestPointToPoint(e,t){t.subVectors(e,this.origin);const s=t.dot(this.direction);return s<0?t.copy(this.origin):t.copy(this.origin).addScaledVector(this.direction,s)}distanceToPoint(e){return Math.sqrt(this.distanceSqToPoint(e))}distanceSqToPoint(e){const t=Ji.subVectors(e,this.origin).dot(this.direction);return t<0?this.origin.distanceToSquared(e):(Ji.copy(this.origin).addScaledVector(this.direction,t),Ji.distanceToSquared(e))}distanceSqToSegment(e,t,s,i){Ki.copy(e).add(t).multiplyScalar(.5),Qi.copy(t).sub(e).normalize(),er.copy(this.origin).sub(Ki);const r=.5*e.distanceTo(t),n=-this.direction.dot(Qi),o=er.dot(this.direction),a=-er.dot(Qi),h=er.lengthSq(),u=Math.abs(1-n*n);let l,c,d,p;if(u>0)if(l=n*a-o,c=n*o-a,p=r*u,l>=0)if(c>=-p)if(c<=p){const e=1/u;l*=e,c*=e,d=l*(l+n*c+2*o)+c*(n*l+c+2*a)+h}else c=r,l=Math.max(0,-(n*c+o)),d=-l*l+c*(c+2*a)+h;else c=-r,l=Math.max(0,-(n*c+o)),d=-l*l+c*(c+2*a)+h;else c<=-p?(l=Math.max(0,-(-n*r+o)),c=l>0?-r:Math.min(Math.max(-r,-a),r),d=-l*l+c*(c+2*a)+h):c<=p?(l=0,c=Math.min(Math.max(-r,-a),r),d=c*(c+2*a)+h):(l=Math.max(0,-(n*r+o)),c=l>0?r:Math.min(Math.max(-r,-a),r),d=-l*l+c*(c+2*a)+h);else c=n>0?-r:r,l=Math.max(0,-(n*c+o)),d=-l*l+c*(c+2*a)+h;return s&&s.copy(this.origin).addScaledVector(this.direction,l),i&&i.copy(Ki).addScaledVector(Qi,c),d}intersectSphere(e,t){Ji.subVectors(e.center,this.origin);const s=Ji.dot(this.direction),i=Ji.dot(Ji)-s*s,r=e.radius*e.radius;if(i>r)return null;const n=Math.sqrt(r-i),o=s-n,a=s+n;return a<0?null:o<0?this.at(a,t):this.at(o,t)}intersectsSphere(e){return this.distanceSqToPoint(e.center)<=e.radius*e.radius}distanceToPlane(e){const t=e.normal.dot(this.direction);if(0===t)return 0===e.distanceToPoint(this.origin)?0:null;const s=-(this.origin.dot(e.normal)+e.constant)/t;return s>=0?s:null}intersectPlane(e,t){const s=this.distanceToPlane(e);return null===s?null:this.at(s,t)}intersectsPlane(e){const t=e.distanceToPoint(this.origin);if(0===t)return!0;return e.normal.dot(this.direction)*t<0}intersectBox(e,t){let s,i,r,n,o,a;const h=1/this.direction.x,u=1/this.direction.y,l=1/this.direction.z,c=this.origin;return h>=0?(s=(e.min.x-c.x)*h,i=(e.max.x-c.x)*h):(s=(e.max.x-c.x)*h,i=(e.min.x-c.x)*h),u>=0?(r=(e.min.y-c.y)*u,n=(e.max.y-c.y)*u):(r=(e.max.y-c.y)*u,n=(e.min.y-c.y)*u),s>n||r>i?null:((r>s||isNaN(s))&&(s=r),(n=0?(o=(e.min.z-c.z)*l,a=(e.max.z-c.z)*l):(o=(e.max.z-c.z)*l,a=(e.min.z-c.z)*l),s>a||o>i?null:((o>s||s!=s)&&(s=o),(a=0?s:i,t)))}intersectsBox(e){return null!==this.intersectBox(e,Ji)}intersectTriangle(e,t,s,i,r){tr.subVectors(t,e),sr.subVectors(s,e),ir.crossVectors(tr,sr);let n,o=this.direction.dot(ir);if(o>0){if(i)return null;n=1}else{if(!(o<0))return null;n=-1,o=-o}er.subVectors(this.origin,e);const a=n*this.direction.dot(sr.crossVectors(er,sr));if(a<0)return null;const h=n*this.direction.dot(tr.cross(er));if(h<0)return null;if(a+h>o)return null;const u=-n*er.dot(ir);return u<0?null:this.at(u/o,r)}applyMatrix4(e){return this.origin.applyMatrix4(e),this.direction.transformDirection(e),this}equals(e){return e.origin.equals(this.origin)&&e.direction.equals(this.direction)}clone(){return(new this.constructor).copy(this)}}class nr{constructor(e,t,s,i,r,n,o,a,h,u,l,c,d,p,m,g){nr.prototype.isMatrix4=!0,this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],void 0!==e&&this.set(e,t,s,i,r,n,o,a,h,u,l,c,d,p,m,g)}set(e,t,s,i,r,n,o,a,h,u,l,c,d,p,m,g){const f=this.elements;return f[0]=e,f[4]=t,f[8]=s,f[12]=i,f[1]=r,f[5]=n,f[9]=o,f[13]=a,f[2]=h,f[6]=u,f[10]=l,f[14]=c,f[3]=d,f[7]=p,f[11]=m,f[15]=g,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return(new nr).fromArray(this.elements)}copy(e){const t=this.elements,s=e.elements;return t[0]=s[0],t[1]=s[1],t[2]=s[2],t[3]=s[3],t[4]=s[4],t[5]=s[5],t[6]=s[6],t[7]=s[7],t[8]=s[8],t[9]=s[9],t[10]=s[10],t[11]=s[11],t[12]=s[12],t[13]=s[13],t[14]=s[14],t[15]=s[15],this}copyPosition(e){const t=this.elements,s=e.elements;return t[12]=s[12],t[13]=s[13],t[14]=s[14],this}setFromMatrix3(e){const t=e.elements;return this.set(t[0],t[3],t[6],0,t[1],t[4],t[7],0,t[2],t[5],t[8],0,0,0,0,1),this}extractBasis(e,t,s){return e.setFromMatrixColumn(this,0),t.setFromMatrixColumn(this,1),s.setFromMatrixColumn(this,2),this}makeBasis(e,t,s){return this.set(e.x,t.x,s.x,0,e.y,t.y,s.y,0,e.z,t.z,s.z,0,0,0,0,1),this}extractRotation(e){const t=this.elements,s=e.elements,i=1/or.setFromMatrixColumn(e,0).length(),r=1/or.setFromMatrixColumn(e,1).length(),n=1/or.setFromMatrixColumn(e,2).length();return t[0]=s[0]*i,t[1]=s[1]*i,t[2]=s[2]*i,t[3]=0,t[4]=s[4]*r,t[5]=s[5]*r,t[6]=s[6]*r,t[7]=0,t[8]=s[8]*n,t[9]=s[9]*n,t[10]=s[10]*n,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromEuler(e){const t=this.elements,s=e.x,i=e.y,r=e.z,n=Math.cos(s),o=Math.sin(s),a=Math.cos(i),h=Math.sin(i),u=Math.cos(r),l=Math.sin(r);if("XYZ"===e.order){const e=n*u,s=n*l,i=o*u,r=o*l;t[0]=a*u,t[4]=-a*l,t[8]=h,t[1]=s+i*h,t[5]=e-r*h,t[9]=-o*a,t[2]=r-e*h,t[6]=i+s*h,t[10]=n*a}else if("YXZ"===e.order){const e=a*u,s=a*l,i=h*u,r=h*l;t[0]=e+r*o,t[4]=i*o-s,t[8]=n*h,t[1]=n*l,t[5]=n*u,t[9]=-o,t[2]=s*o-i,t[6]=r+e*o,t[10]=n*a}else if("ZXY"===e.order){const e=a*u,s=a*l,i=h*u,r=h*l;t[0]=e-r*o,t[4]=-n*l,t[8]=i+s*o,t[1]=s+i*o,t[5]=n*u,t[9]=r-e*o,t[2]=-n*h,t[6]=o,t[10]=n*a}else if("ZYX"===e.order){const e=n*u,s=n*l,i=o*u,r=o*l;t[0]=a*u,t[4]=i*h-s,t[8]=e*h+r,t[1]=a*l,t[5]=r*h+e,t[9]=s*h-i,t[2]=-h,t[6]=o*a,t[10]=n*a}else if("YZX"===e.order){const e=n*a,s=n*h,i=o*a,r=o*h;t[0]=a*u,t[4]=r-e*l,t[8]=i*l+s,t[1]=l,t[5]=n*u,t[9]=-o*u,t[2]=-h*u,t[6]=s*l+i,t[10]=e-r*l}else if("XZY"===e.order){const e=n*a,s=n*h,i=o*a,r=o*h;t[0]=a*u,t[4]=-l,t[8]=h*u,t[1]=e*l+r,t[5]=n*u,t[9]=s*l-i,t[2]=i*l-s,t[6]=o*u,t[10]=r*l+e}return t[3]=0,t[7]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromQuaternion(e){return this.compose(hr,e,ur)}lookAt(e,t,s){const i=this.elements;return dr.subVectors(e,t),0===dr.lengthSq()&&(dr.z=1),dr.normalize(),lr.crossVectors(s,dr),0===lr.lengthSq()&&(1===Math.abs(s.z)?dr.x+=1e-4:dr.z+=1e-4,dr.normalize(),lr.crossVectors(s,dr)),lr.normalize(),cr.crossVectors(dr,lr),i[0]=lr.x,i[4]=cr.x,i[8]=dr.x,i[1]=lr.y,i[5]=cr.y,i[9]=dr.y,i[2]=lr.z,i[6]=cr.z,i[10]=dr.z,this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const s=e.elements,i=t.elements,r=this.elements,n=s[0],o=s[4],a=s[8],h=s[12],u=s[1],l=s[5],c=s[9],d=s[13],p=s[2],m=s[6],g=s[10],f=s[14],y=s[3],x=s[7],b=s[11],v=s[15],T=i[0],_=i[4],w=i[8],S=i[12],M=i[1],N=i[5],A=i[9],C=i[13],R=i[2],E=i[6],B=i[10],I=i[14],P=i[3],F=i[7],z=i[11],U=i[15];return r[0]=n*T+o*M+a*R+h*P,r[4]=n*_+o*N+a*E+h*F,r[8]=n*w+o*A+a*B+h*z,r[12]=n*S+o*C+a*I+h*U,r[1]=u*T+l*M+c*R+d*P,r[5]=u*_+l*N+c*E+d*F,r[9]=u*w+l*A+c*B+d*z,r[13]=u*S+l*C+c*I+d*U,r[2]=p*T+m*M+g*R+f*P,r[6]=p*_+m*N+g*E+f*F,r[10]=p*w+m*A+g*B+f*z,r[14]=p*S+m*C+g*I+f*U,r[3]=y*T+x*M+b*R+v*P,r[7]=y*_+x*N+b*E+v*F,r[11]=y*w+x*A+b*B+v*z,r[15]=y*S+x*C+b*I+v*U,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[4]*=e,t[8]*=e,t[12]*=e,t[1]*=e,t[5]*=e,t[9]*=e,t[13]*=e,t[2]*=e,t[6]*=e,t[10]*=e,t[14]*=e,t[3]*=e,t[7]*=e,t[11]*=e,t[15]*=e,this}determinant(){const e=this.elements,t=e[0],s=e[4],i=e[8],r=e[12],n=e[1],o=e[5],a=e[9],h=e[13],u=e[2],l=e[6],c=e[10],d=e[14];return e[3]*(+r*a*l-i*h*l-r*o*c+s*h*c+i*o*d-s*a*d)+e[7]*(+t*a*d-t*h*c+r*n*c-i*n*d+i*h*u-r*a*u)+e[11]*(+t*h*l-t*o*d-r*n*l+s*n*d+r*o*u-s*h*u)+e[15]*(-i*o*u-t*a*l+t*o*c+i*n*l-s*n*c+s*a*u)}transpose(){const e=this.elements;let t;return t=e[1],e[1]=e[4],e[4]=t,t=e[2],e[2]=e[8],e[8]=t,t=e[6],e[6]=e[9],e[9]=t,t=e[3],e[3]=e[12],e[12]=t,t=e[7],e[7]=e[13],e[13]=t,t=e[11],e[11]=e[14],e[14]=t,this}setPosition(e,t,s){const i=this.elements;return e.isVector3?(i[12]=e.x,i[13]=e.y,i[14]=e.z):(i[12]=e,i[13]=t,i[14]=s),this}invert(){const e=this.elements,t=e[0],s=e[1],i=e[2],r=e[3],n=e[4],o=e[5],a=e[6],h=e[7],u=e[8],l=e[9],c=e[10],d=e[11],p=e[12],m=e[13],g=e[14],f=e[15],y=l*g*h-m*c*h+m*a*d-o*g*d-l*a*f+o*c*f,x=p*c*h-u*g*h-p*a*d+n*g*d+u*a*f-n*c*f,b=u*m*h-p*l*h+p*o*d-n*m*d-u*o*f+n*l*f,v=p*l*a-u*m*a-p*o*c+n*m*c+u*o*g-n*l*g,T=t*y+s*x+i*b+r*v;if(0===T)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const _=1/T;return e[0]=y*_,e[1]=(m*c*r-l*g*r-m*i*d+s*g*d+l*i*f-s*c*f)*_,e[2]=(o*g*r-m*a*r+m*i*h-s*g*h-o*i*f+s*a*f)*_,e[3]=(l*a*r-o*c*r-l*i*h+s*c*h+o*i*d-s*a*d)*_,e[4]=x*_,e[5]=(u*g*r-p*c*r+p*i*d-t*g*d-u*i*f+t*c*f)*_,e[6]=(p*a*r-n*g*r-p*i*h+t*g*h+n*i*f-t*a*f)*_,e[7]=(n*c*r-u*a*r+u*i*h-t*c*h-n*i*d+t*a*d)*_,e[8]=b*_,e[9]=(p*l*r-u*m*r-p*s*d+t*m*d+u*s*f-t*l*f)*_,e[10]=(n*m*r-p*o*r+p*s*h-t*m*h-n*s*f+t*o*f)*_,e[11]=(u*o*r-n*l*r-u*s*h+t*l*h+n*s*d-t*o*d)*_,e[12]=v*_,e[13]=(u*m*i-p*l*i+p*s*c-t*m*c-u*s*g+t*l*g)*_,e[14]=(p*o*i-n*m*i-p*s*a+t*m*a+n*s*g-t*o*g)*_,e[15]=(n*l*i-u*o*i+u*s*a-t*l*a-n*s*c+t*o*c)*_,this}scale(e){const t=this.elements,s=e.x,i=e.y,r=e.z;return t[0]*=s,t[4]*=i,t[8]*=r,t[1]*=s,t[5]*=i,t[9]*=r,t[2]*=s,t[6]*=i,t[10]*=r,t[3]*=s,t[7]*=i,t[11]*=r,this}getMaxScaleOnAxis(){const e=this.elements,t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2],s=e[4]*e[4]+e[5]*e[5]+e[6]*e[6],i=e[8]*e[8]+e[9]*e[9]+e[10]*e[10];return Math.sqrt(Math.max(t,s,i))}makeTranslation(e,t,s){return e.isVector3?this.set(1,0,0,e.x,0,1,0,e.y,0,0,1,e.z,0,0,0,1):this.set(1,0,0,e,0,1,0,t,0,0,1,s,0,0,0,1),this}makeRotationX(e){const t=Math.cos(e),s=Math.sin(e);return this.set(1,0,0,0,0,t,-s,0,0,s,t,0,0,0,0,1),this}makeRotationY(e){const t=Math.cos(e),s=Math.sin(e);return this.set(t,0,s,0,0,1,0,0,-s,0,t,0,0,0,0,1),this}makeRotationZ(e){const t=Math.cos(e),s=Math.sin(e);return this.set(t,-s,0,0,s,t,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(e,t){const s=Math.cos(t),i=Math.sin(t),r=1-s,n=e.x,o=e.y,a=e.z,h=r*n,u=r*o;return this.set(h*n+s,h*o-i*a,h*a+i*o,0,h*o+i*a,u*o+s,u*a-i*n,0,h*a-i*o,u*a+i*n,r*a*a+s,0,0,0,0,1),this}makeScale(e,t,s){return this.set(e,0,0,0,0,t,0,0,0,0,s,0,0,0,0,1),this}makeShear(e,t,s,i,r,n){return this.set(1,s,r,0,e,1,n,0,t,i,1,0,0,0,0,1),this}compose(e,t,s){const i=this.elements,r=t._x,n=t._y,o=t._z,a=t._w,h=r+r,u=n+n,l=o+o,c=r*h,d=r*u,p=r*l,m=n*u,g=n*l,f=o*l,y=a*h,x=a*u,b=a*l,v=s.x,T=s.y,_=s.z;return i[0]=(1-(m+f))*v,i[1]=(d+b)*v,i[2]=(p-x)*v,i[3]=0,i[4]=(d-b)*T,i[5]=(1-(c+f))*T,i[6]=(g+y)*T,i[7]=0,i[8]=(p+x)*_,i[9]=(g-y)*_,i[10]=(1-(c+m))*_,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,this}decompose(e,t,s){const i=this.elements;let r=or.set(i[0],i[1],i[2]).length();const n=or.set(i[4],i[5],i[6]).length(),o=or.set(i[8],i[9],i[10]).length();this.determinant()<0&&(r=-r),e.x=i[12],e.y=i[13],e.z=i[14],ar.copy(this);const a=1/r,h=1/n,u=1/o;return ar.elements[0]*=a,ar.elements[1]*=a,ar.elements[2]*=a,ar.elements[4]*=h,ar.elements[5]*=h,ar.elements[6]*=h,ar.elements[8]*=u,ar.elements[9]*=u,ar.elements[10]*=u,t.setFromRotationMatrix(ar),s.x=r,s.y=n,s.z=o,this}makePerspective(e,t,s,i,r,n,o=2e3){const a=this.elements,h=2*r/(t-e),u=2*r/(s-i),l=(t+e)/(t-e),c=(s+i)/(s-i);let d,p;if(o===Vs)d=-(n+r)/(n-r),p=-2*n*r/(n-r);else{if(o!==Ds)throw new Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: "+o);d=-n/(n-r),p=-n*r/(n-r)}return a[0]=h,a[4]=0,a[8]=l,a[12]=0,a[1]=0,a[5]=u,a[9]=c,a[13]=0,a[2]=0,a[6]=0,a[10]=d,a[14]=p,a[3]=0,a[7]=0,a[11]=-1,a[15]=0,this}makeOrthographic(e,t,s,i,r,n,o=2e3){const a=this.elements,h=1/(t-e),u=1/(s-i),l=1/(n-r),c=(t+e)*h,d=(s+i)*u;let p,m;if(o===Vs)p=(n+r)*l,m=-2*l;else{if(o!==Ds)throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+o);p=r*l,m=-1*l}return a[0]=2*h,a[4]=0,a[8]=0,a[12]=-c,a[1]=0,a[5]=2*u,a[9]=0,a[13]=-d,a[2]=0,a[6]=0,a[10]=m,a[14]=-p,a[3]=0,a[7]=0,a[11]=0,a[15]=1,this}equals(e){const t=this.elements,s=e.elements;for(let e=0;e<16;e++)if(t[e]!==s[e])return!1;return!0}fromArray(e,t=0){for(let s=0;s<16;s++)this.elements[s]=e[s+t];return this}toArray(e=[],t=0){const s=this.elements;return e[t]=s[0],e[t+1]=s[1],e[t+2]=s[2],e[t+3]=s[3],e[t+4]=s[4],e[t+5]=s[5],e[t+6]=s[6],e[t+7]=s[7],e[t+8]=s[8],e[t+9]=s[9],e[t+10]=s[10],e[t+11]=s[11],e[t+12]=s[12],e[t+13]=s[13],e[t+14]=s[14],e[t+15]=s[15],e}}const or=new Ri,ar=new nr,hr=new Ri(0,0,0),ur=new Ri(1,1,1),lr=new Ri,cr=new Ri,dr=new Ri,pr=new nr,mr=new Ci;class gr{constructor(e=0,t=0,s=0,i=gr.DEFAULT_ORDER){this.isEuler=!0,this._x=e,this._y=t,this._z=s,this._order=i}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get order(){return this._order}set order(e){this._order=e,this._onChangeCallback()}set(e,t,s,i=this._order){return this._x=e,this._y=t,this._z=s,this._order=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(e){return this._x=e._x,this._y=e._y,this._z=e._z,this._order=e._order,this._onChangeCallback(),this}setFromRotationMatrix(e,t=this._order,s=!0){const i=e.elements,r=i[0],n=i[4],o=i[8],a=i[1],h=i[5],u=i[9],l=i[2],c=i[6],d=i[10];switch(t){case"XYZ":this._y=Math.asin($s(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-u,d),this._z=Math.atan2(-n,r)):(this._x=Math.atan2(c,h),this._z=0);break;case"YXZ":this._x=Math.asin(-$s(u,-1,1)),Math.abs(u)<.9999999?(this._y=Math.atan2(o,d),this._z=Math.atan2(a,h)):(this._y=Math.atan2(-l,r),this._z=0);break;case"ZXY":this._x=Math.asin($s(c,-1,1)),Math.abs(c)<.9999999?(this._y=Math.atan2(-l,d),this._z=Math.atan2(-n,h)):(this._y=0,this._z=Math.atan2(a,r));break;case"ZYX":this._y=Math.asin(-$s(l,-1,1)),Math.abs(l)<.9999999?(this._x=Math.atan2(c,d),this._z=Math.atan2(a,r)):(this._x=0,this._z=Math.atan2(-n,h));break;case"YZX":this._z=Math.asin($s(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(-u,h),this._y=Math.atan2(-l,r)):(this._x=0,this._y=Math.atan2(o,d));break;case"XZY":this._z=Math.asin(-$s(n,-1,1)),Math.abs(n)<.9999999?(this._x=Math.atan2(c,h),this._y=Math.atan2(o,r)):(this._x=Math.atan2(-u,d),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+t)}return this._order=t,!0===s&&this._onChangeCallback(),this}setFromQuaternion(e,t,s){return pr.makeRotationFromQuaternion(e),this.setFromRotationMatrix(pr,t,s)}setFromVector3(e,t=this._order){return this.set(e.x,e.y,e.z,t)}reorder(e){return mr.setFromEuler(this),this.setFromQuaternion(mr,e)}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._order===this._order}fromArray(e){return this._x=e[0],this._y=e[1],this._z=e[2],void 0!==e[3]&&(this._order=e[3]),this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._order,e}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._order}}gr.DEFAULT_ORDER="XYZ";class fr{constructor(){this.mask=1}set(e){this.mask=(1<>>0}enable(e){this.mask|=1<1){for(let e=0;e1){for(let e=0;e0&&(i.userData=this.userData),i.layers=this.layers.mask,i.matrix=this.matrix.toArray(),i.up=this.up.toArray(),!1===this.matrixAutoUpdate&&(i.matrixAutoUpdate=!1),this.isInstancedMesh&&(i.type="InstancedMesh",i.count=this.count,i.instanceMatrix=this.instanceMatrix.toJSON(),null!==this.instanceColor&&(i.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(i.type="BatchedMesh",i.perObjectFrustumCulled=this.perObjectFrustumCulled,i.sortObjects=this.sortObjects,i.drawRanges=this._drawRanges,i.reservedRanges=this._reservedRanges,i.visibility=this._visibility,i.active=this._active,i.bounds=this._bounds.map((e=>({boxInitialized:e.boxInitialized,boxMin:e.box.min.toArray(),boxMax:e.box.max.toArray(),sphereInitialized:e.sphereInitialized,sphereRadius:e.sphere.radius,sphereCenter:e.sphere.center.toArray()}))),i.maxInstanceCount=this._maxInstanceCount,i.maxVertexCount=this._maxVertexCount,i.maxIndexCount=this._maxIndexCount,i.geometryInitialized=this._geometryInitialized,i.geometryCount=this._geometryCount,i.matricesTexture=this._matricesTexture.toJSON(e),null!==this._colorsTexture&&(i.colorsTexture=this._colorsTexture.toJSON(e)),null!==this.boundingSphere&&(i.boundingSphere={center:i.boundingSphere.center.toArray(),radius:i.boundingSphere.radius}),null!==this.boundingBox&&(i.boundingBox={min:i.boundingBox.min.toArray(),max:i.boundingBox.max.toArray()})),this.isScene)this.background&&(this.background.isColor?i.background=this.background.toJSON():this.background.isTexture&&(i.background=this.background.toJSON(e).uuid)),this.environment&&this.environment.isTexture&&!0!==this.environment.isRenderTargetTexture&&(i.environment=this.environment.toJSON(e).uuid);else if(this.isMesh||this.isLine||this.isPoints){i.geometry=r(e.geometries,this.geometry);const t=this.geometry.parameters;if(void 0!==t&&void 0!==t.shapes){const s=t.shapes;if(Array.isArray(s))for(let t=0,i=s.length;t0){i.children=[];for(let t=0;t0){i.animations=[];for(let t=0;t0&&(s.geometries=t),i.length>0&&(s.materials=i),r.length>0&&(s.textures=r),o.length>0&&(s.images=o),a.length>0&&(s.shapes=a),h.length>0&&(s.skeletons=h),u.length>0&&(s.animations=u),l.length>0&&(s.nodes=l)}return s.object=i,s;function n(e){const t=[];for(const s in e){const i=e[s];delete i.metadata,t.push(i)}return t}}clone(e){return(new this.constructor).copy(this,e)}copy(e,t=!0){if(this.name=e.name,this.up.copy(e.up),this.position.copy(e.position),this.rotation.order=e.rotation.order,this.quaternion.copy(e.quaternion),this.scale.copy(e.scale),this.matrix.copy(e.matrix),this.matrixWorld.copy(e.matrixWorld),this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrixWorldAutoUpdate=e.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=e.matrixWorldNeedsUpdate,this.layers.mask=e.layers.mask,this.visible=e.visible,this.castShadow=e.castShadow,this.receiveShadow=e.receiveShadow,this.frustumCulled=e.frustumCulled,this.renderOrder=e.renderOrder,this.animations=e.animations.slice(),this.userData=JSON.parse(JSON.stringify(e.userData)),!0===t)for(let t=0;t0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(e,t,s,i,r){Pr.subVectors(i,t),Fr.subVectors(s,t),zr.subVectors(e,t);const n=Pr.dot(Pr),o=Pr.dot(Fr),a=Pr.dot(zr),h=Fr.dot(Fr),u=Fr.dot(zr),l=n*h-o*o;if(0===l)return r.set(0,0,0),null;const c=1/l,d=(h*a-o*u)*c,p=(n*u-o*a)*c;return r.set(1-d-p,p,d)}static containsPoint(e,t,s,i){return null!==this.getBarycoord(e,t,s,i,Ur)&&(Ur.x>=0&&Ur.y>=0&&Ur.x+Ur.y<=1)}static getInterpolation(e,t,s,i,r,n,o,a){return null===this.getBarycoord(e,t,s,i,Ur)?(a.x=0,a.y=0,"z"in a&&(a.z=0),"w"in a&&(a.w=0),null):(a.setScalar(0),a.addScaledVector(r,Ur.x),a.addScaledVector(n,Ur.y),a.addScaledVector(o,Ur.z),a)}static getInterpolatedAttribute(e,t,s,i,r,n){return Wr.setScalar(0),jr.setScalar(0),Hr.setScalar(0),Wr.fromBufferAttribute(e,t),jr.fromBufferAttribute(e,s),Hr.fromBufferAttribute(e,i),n.setScalar(0),n.addScaledVector(Wr,r.x),n.addScaledVector(jr,r.y),n.addScaledVector(Hr,r.z),n}static isFrontFacing(e,t,s,i){return Pr.subVectors(s,t),Fr.subVectors(e,t),Pr.cross(Fr).dot(i)<0}set(e,t,s){return this.a.copy(e),this.b.copy(t),this.c.copy(s),this}setFromPointsAndIndices(e,t,s,i){return this.a.copy(e[t]),this.b.copy(e[s]),this.c.copy(e[i]),this}setFromAttributeAndIndices(e,t,s,i){return this.a.fromBufferAttribute(e,t),this.b.fromBufferAttribute(e,s),this.c.fromBufferAttribute(e,i),this}clone(){return(new this.constructor).copy(this)}copy(e){return this.a.copy(e.a),this.b.copy(e.b),this.c.copy(e.c),this}getArea(){return Pr.subVectors(this.c,this.b),Fr.subVectors(this.a,this.b),.5*Pr.cross(Fr).length()}getMidpoint(e){return e.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(e){return qr.getNormal(this.a,this.b,this.c,e)}getPlane(e){return e.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(e,t){return qr.getBarycoord(e,this.a,this.b,this.c,t)}getInterpolation(e,t,s,i,r){return qr.getInterpolation(e,this.a,this.b,this.c,t,s,i,r)}containsPoint(e){return qr.containsPoint(e,this.a,this.b,this.c)}isFrontFacing(e){return qr.isFrontFacing(this.a,this.b,this.c,e)}intersectsBox(e){return e.intersectsTriangle(this)}closestPointToPoint(e,t){const s=this.a,i=this.b,r=this.c;let n,o;Or.subVectors(i,s),Lr.subVectors(r,s),Dr.subVectors(e,s);const a=Or.dot(Dr),h=Lr.dot(Dr);if(a<=0&&h<=0)return t.copy(s);kr.subVectors(e,i);const u=Or.dot(kr),l=Lr.dot(kr);if(u>=0&&l<=u)return t.copy(i);const c=a*l-u*h;if(c<=0&&a>=0&&u<=0)return n=a/(a-u),t.copy(s).addScaledVector(Or,n);Gr.subVectors(e,r);const d=Or.dot(Gr),p=Lr.dot(Gr);if(p>=0&&d<=p)return t.copy(r);const m=d*h-a*p;if(m<=0&&h>=0&&p<=0)return o=h/(h-p),t.copy(s).addScaledVector(Lr,o);const g=u*p-d*l;if(g<=0&&l-u>=0&&d-p>=0)return Vr.subVectors(r,i),o=(l-u)/(l-u+(d-p)),t.copy(i).addScaledVector(Vr,o);const f=1/(g+m+c);return n=m*f,o=c*f,t.copy(s).addScaledVector(Or,n).addScaledVector(Lr,o)}equals(e){return e.a.equals(this.a)&&e.b.equals(this.b)&&e.c.equals(this.c)}}const $r={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},Xr={h:0,s:0,l:0},Yr={h:0,s:0,l:0};function Zr(e,t,s){return s<0&&(s+=1),s>1&&(s-=1),s<1/6?e+6*(t-e)*s:s<.5?t:s<2/3?e+6*(t-e)*(2/3-s):e}class Jr{constructor(e,t,s){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(e,t,s)}set(e,t,s){if(void 0===t&&void 0===s){const t=e;t&&t.isColor?this.copy(t):"number"==typeof t?this.setHex(t):"string"==typeof t&&this.setStyle(t)}else this.setRGB(e,t,s);return this}setScalar(e){return this.r=e,this.g=e,this.b=e,this}setHex(e,t=Zt){return e=Math.floor(e),this.r=(e>>16&255)/255,this.g=(e>>8&255)/255,this.b=(255&e)/255,ci.toWorkingColorSpace(this,t),this}setRGB(e,t,s,i=ci.workingColorSpace){return this.r=e,this.g=t,this.b=s,ci.toWorkingColorSpace(this,i),this}setHSL(e,t,s,i=ci.workingColorSpace){if(e=Xs(e,1),t=$s(t,0,1),s=$s(s,0,1),0===t)this.r=this.g=this.b=s;else{const i=s<=.5?s*(1+t):s+t-s*t,r=2*s-i;this.r=Zr(r,i,e+1/3),this.g=Zr(r,i,e),this.b=Zr(r,i,e-1/3)}return ci.toWorkingColorSpace(this,i),this}setStyle(e,t=Zt){function s(t){void 0!==t&&parseFloat(t)<1&&console.warn("THREE.Color: Alpha component of "+e+" will be ignored.")}let i;if(i=/^(\w+)\(([^\)]*)\)/.exec(e)){let r;const n=i[1],o=i[2];switch(n){case"rgb":case"rgba":if(r=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return s(r[4]),this.setRGB(Math.min(255,parseInt(r[1],10))/255,Math.min(255,parseInt(r[2],10))/255,Math.min(255,parseInt(r[3],10))/255,t);if(r=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return s(r[4]),this.setRGB(Math.min(100,parseInt(r[1],10))/100,Math.min(100,parseInt(r[2],10))/100,Math.min(100,parseInt(r[3],10))/100,t);break;case"hsl":case"hsla":if(r=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return s(r[4]),this.setHSL(parseFloat(r[1])/360,parseFloat(r[2])/100,parseFloat(r[3])/100,t);break;default:console.warn("THREE.Color: Unknown color model "+e)}}else if(i=/^\#([A-Fa-f\d]+)$/.exec(e)){const s=i[1],r=s.length;if(3===r)return this.setRGB(parseInt(s.charAt(0),16)/15,parseInt(s.charAt(1),16)/15,parseInt(s.charAt(2),16)/15,t);if(6===r)return this.setHex(parseInt(s,16),t);console.warn("THREE.Color: Invalid hex color "+e)}else if(e&&e.length>0)return this.setColorName(e,t);return this}setColorName(e,t=Zt){const s=$r[e.toLowerCase()];return void 0!==s?this.setHex(s,t):console.warn("THREE.Color: Unknown color "+e),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(e){return this.r=e.r,this.g=e.g,this.b=e.b,this}copySRGBToLinear(e){return this.r=di(e.r),this.g=di(e.g),this.b=di(e.b),this}copyLinearToSRGB(e){return this.r=pi(e.r),this.g=pi(e.g),this.b=pi(e.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(e=Zt){return ci.fromWorkingColorSpace(Kr.copy(this),e),65536*Math.round($s(255*Kr.r,0,255))+256*Math.round($s(255*Kr.g,0,255))+Math.round($s(255*Kr.b,0,255))}getHexString(e=Zt){return("000000"+this.getHex(e).toString(16)).slice(-6)}getHSL(e,t=ci.workingColorSpace){ci.fromWorkingColorSpace(Kr.copy(this),t);const s=Kr.r,i=Kr.g,r=Kr.b,n=Math.max(s,i,r),o=Math.min(s,i,r);let a,h;const u=(o+n)/2;if(o===n)a=0,h=0;else{const e=n-o;switch(h=u<=.5?e/(n+o):e/(2-n-o),n){case s:a=(i-r)/e+(i0!=e>0&&this.version++,this._alphaTest=e}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(e){if(void 0!==e)for(const t in e){const s=e[t];if(void 0===s){console.warn(`THREE.Material: parameter '${t}' has value of undefined.`);continue}const i=this[t];void 0!==i?i&&i.isColor?i.set(s):i&&i.isVector3&&s&&s.isVector3?i.copy(s):this[t]=s:console.warn(`THREE.Material: '${t}' is not a property of THREE.${this.type}.`)}}toJSON(e){const t=void 0===e||"string"==typeof e;t&&(e={textures:{},images:{}});const s={metadata:{version:4.6,type:"Material",generator:"Material.toJSON"}};function i(e){const t=[];for(const s in e){const i=e[s];delete i.metadata,t.push(i)}return t}if(s.uuid=this.uuid,s.type=this.type,""!==this.name&&(s.name=this.name),this.color&&this.color.isColor&&(s.color=this.color.getHex()),void 0!==this.roughness&&(s.roughness=this.roughness),void 0!==this.metalness&&(s.metalness=this.metalness),void 0!==this.sheen&&(s.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(s.sheenColor=this.sheenColor.getHex()),void 0!==this.sheenRoughness&&(s.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(s.emissive=this.emissive.getHex()),void 0!==this.emissiveIntensity&&1!==this.emissiveIntensity&&(s.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(s.specular=this.specular.getHex()),void 0!==this.specularIntensity&&(s.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(s.specularColor=this.specularColor.getHex()),void 0!==this.shininess&&(s.shininess=this.shininess),void 0!==this.clearcoat&&(s.clearcoat=this.clearcoat),void 0!==this.clearcoatRoughness&&(s.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(s.clearcoatMap=this.clearcoatMap.toJSON(e).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(s.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(e).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(s.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(e).uuid,s.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),void 0!==this.dispersion&&(s.dispersion=this.dispersion),void 0!==this.iridescence&&(s.iridescence=this.iridescence),void 0!==this.iridescenceIOR&&(s.iridescenceIOR=this.iridescenceIOR),void 0!==this.iridescenceThicknessRange&&(s.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(s.iridescenceMap=this.iridescenceMap.toJSON(e).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(s.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(e).uuid),void 0!==this.anisotropy&&(s.anisotropy=this.anisotropy),void 0!==this.anisotropyRotation&&(s.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(s.anisotropyMap=this.anisotropyMap.toJSON(e).uuid),this.map&&this.map.isTexture&&(s.map=this.map.toJSON(e).uuid),this.matcap&&this.matcap.isTexture&&(s.matcap=this.matcap.toJSON(e).uuid),this.alphaMap&&this.alphaMap.isTexture&&(s.alphaMap=this.alphaMap.toJSON(e).uuid),this.lightMap&&this.lightMap.isTexture&&(s.lightMap=this.lightMap.toJSON(e).uuid,s.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(s.aoMap=this.aoMap.toJSON(e).uuid,s.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(s.bumpMap=this.bumpMap.toJSON(e).uuid,s.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(s.normalMap=this.normalMap.toJSON(e).uuid,s.normalMapType=this.normalMapType,s.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(s.displacementMap=this.displacementMap.toJSON(e).uuid,s.displacementScale=this.displacementScale,s.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(s.roughnessMap=this.roughnessMap.toJSON(e).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(s.metalnessMap=this.metalnessMap.toJSON(e).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(s.emissiveMap=this.emissiveMap.toJSON(e).uuid),this.specularMap&&this.specularMap.isTexture&&(s.specularMap=this.specularMap.toJSON(e).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(s.specularIntensityMap=this.specularIntensityMap.toJSON(e).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(s.specularColorMap=this.specularColorMap.toJSON(e).uuid),this.envMap&&this.envMap.isTexture&&(s.envMap=this.envMap.toJSON(e).uuid,void 0!==this.combine&&(s.combine=this.combine)),void 0!==this.envMapRotation&&(s.envMapRotation=this.envMapRotation.toArray()),void 0!==this.envMapIntensity&&(s.envMapIntensity=this.envMapIntensity),void 0!==this.reflectivity&&(s.reflectivity=this.reflectivity),void 0!==this.refractionRatio&&(s.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(s.gradientMap=this.gradientMap.toJSON(e).uuid),void 0!==this.transmission&&(s.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(s.transmissionMap=this.transmissionMap.toJSON(e).uuid),void 0!==this.thickness&&(s.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(s.thicknessMap=this.thicknessMap.toJSON(e).uuid),void 0!==this.attenuationDistance&&this.attenuationDistance!==1/0&&(s.attenuationDistance=this.attenuationDistance),void 0!==this.attenuationColor&&(s.attenuationColor=this.attenuationColor.getHex()),void 0!==this.size&&(s.size=this.size),null!==this.shadowSide&&(s.shadowSide=this.shadowSide),void 0!==this.sizeAttenuation&&(s.sizeAttenuation=this.sizeAttenuation),1!==this.blending&&(s.blending=this.blending),this.side!==c&&(s.side=this.side),!0===this.vertexColors&&(s.vertexColors=!0),this.opacity<1&&(s.opacity=this.opacity),!0===this.transparent&&(s.transparent=!0),this.blendSrc!==R&&(s.blendSrc=this.blendSrc),this.blendDst!==E&&(s.blendDst=this.blendDst),this.blendEquation!==v&&(s.blendEquation=this.blendEquation),null!==this.blendSrcAlpha&&(s.blendSrcAlpha=this.blendSrcAlpha),null!==this.blendDstAlpha&&(s.blendDstAlpha=this.blendDstAlpha),null!==this.blendEquationAlpha&&(s.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(s.blendColor=this.blendColor.getHex()),0!==this.blendAlpha&&(s.blendAlpha=this.blendAlpha),3!==this.depthFunc&&(s.depthFunc=this.depthFunc),!1===this.depthTest&&(s.depthTest=this.depthTest),!1===this.depthWrite&&(s.depthWrite=this.depthWrite),!1===this.colorWrite&&(s.colorWrite=this.colorWrite),255!==this.stencilWriteMask&&(s.stencilWriteMask=this.stencilWriteMask),this.stencilFunc!==bs&&(s.stencilFunc=this.stencilFunc),0!==this.stencilRef&&(s.stencilRef=this.stencilRef),255!==this.stencilFuncMask&&(s.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==ns&&(s.stencilFail=this.stencilFail),this.stencilZFail!==ns&&(s.stencilZFail=this.stencilZFail),this.stencilZPass!==ns&&(s.stencilZPass=this.stencilZPass),!0===this.stencilWrite&&(s.stencilWrite=this.stencilWrite),void 0!==this.rotation&&0!==this.rotation&&(s.rotation=this.rotation),!0===this.polygonOffset&&(s.polygonOffset=!0),0!==this.polygonOffsetFactor&&(s.polygonOffsetFactor=this.polygonOffsetFactor),0!==this.polygonOffsetUnits&&(s.polygonOffsetUnits=this.polygonOffsetUnits),void 0!==this.linewidth&&1!==this.linewidth&&(s.linewidth=this.linewidth),void 0!==this.dashSize&&(s.dashSize=this.dashSize),void 0!==this.gapSize&&(s.gapSize=this.gapSize),void 0!==this.scale&&(s.scale=this.scale),!0===this.dithering&&(s.dithering=!0),this.alphaTest>0&&(s.alphaTest=this.alphaTest),!0===this.alphaHash&&(s.alphaHash=!0),!0===this.alphaToCoverage&&(s.alphaToCoverage=!0),!0===this.premultipliedAlpha&&(s.premultipliedAlpha=!0),!0===this.forceSinglePass&&(s.forceSinglePass=!0),!0===this.wireframe&&(s.wireframe=!0),this.wireframeLinewidth>1&&(s.wireframeLinewidth=this.wireframeLinewidth),"round"!==this.wireframeLinecap&&(s.wireframeLinecap=this.wireframeLinecap),"round"!==this.wireframeLinejoin&&(s.wireframeLinejoin=this.wireframeLinejoin),!0===this.flatShading&&(s.flatShading=!0),!1===this.visible&&(s.visible=!1),!1===this.toneMapped&&(s.toneMapped=!1),!1===this.fog&&(s.fog=!1),Object.keys(this.userData).length>0&&(s.userData=this.userData),t){const t=i(e.textures),r=i(e.images);t.length>0&&(s.textures=t),r.length>0&&(s.images=r)}return s}clone(){return(new this.constructor).copy(this)}copy(e){this.name=e.name,this.blending=e.blending,this.side=e.side,this.vertexColors=e.vertexColors,this.opacity=e.opacity,this.transparent=e.transparent,this.blendSrc=e.blendSrc,this.blendDst=e.blendDst,this.blendEquation=e.blendEquation,this.blendSrcAlpha=e.blendSrcAlpha,this.blendDstAlpha=e.blendDstAlpha,this.blendEquationAlpha=e.blendEquationAlpha,this.blendColor.copy(e.blendColor),this.blendAlpha=e.blendAlpha,this.depthFunc=e.depthFunc,this.depthTest=e.depthTest,this.depthWrite=e.depthWrite,this.stencilWriteMask=e.stencilWriteMask,this.stencilFunc=e.stencilFunc,this.stencilRef=e.stencilRef,this.stencilFuncMask=e.stencilFuncMask,this.stencilFail=e.stencilFail,this.stencilZFail=e.stencilZFail,this.stencilZPass=e.stencilZPass,this.stencilWrite=e.stencilWrite;const t=e.clippingPlanes;let s=null;if(null!==t){const e=t.length;s=new Array(e);for(let i=0;i!==e;++i)s[i]=t[i].clone()}return this.clippingPlanes=s,this.clipIntersection=e.clipIntersection,this.clipShadows=e.clipShadows,this.shadowSide=e.shadowSide,this.colorWrite=e.colorWrite,this.precision=e.precision,this.polygonOffset=e.polygonOffset,this.polygonOffsetFactor=e.polygonOffsetFactor,this.polygonOffsetUnits=e.polygonOffsetUnits,this.dithering=e.dithering,this.alphaTest=e.alphaTest,this.alphaHash=e.alphaHash,this.alphaToCoverage=e.alphaToCoverage,this.premultipliedAlpha=e.premultipliedAlpha,this.forceSinglePass=e.forceSinglePass,this.visible=e.visible,this.toneMapped=e.toneMapped,this.userData=JSON.parse(JSON.stringify(e.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){!0===e&&this.version++}onBuild(){console.warn("Material: onBuild() has been removed.")}}class tn extends en{constructor(e){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new Jr(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new gr,this.combine=0,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}}const sn=rn();function rn(){const e=new ArrayBuffer(4),t=new Float32Array(e),s=new Uint32Array(e),i=new Uint32Array(512),r=new Uint32Array(512);for(let e=0;e<256;++e){const t=e-127;t<-27?(i[e]=0,i[256|e]=32768,r[e]=24,r[256|e]=24):t<-14?(i[e]=1024>>-t-14,i[256|e]=1024>>-t-14|32768,r[e]=-t-1,r[256|e]=-t-1):t<=15?(i[e]=t+15<<10,i[256|e]=t+15<<10|32768,r[e]=13,r[256|e]=13):t<128?(i[e]=31744,i[256|e]=64512,r[e]=24,r[256|e]=24):(i[e]=31744,i[256|e]=64512,r[e]=13,r[256|e]=13)}const n=new Uint32Array(2048),o=new Uint32Array(64),a=new Uint32Array(64);for(let e=1;e<1024;++e){let t=e<<13,s=0;for(;0==(8388608&t);)t<<=1,s-=8388608;t&=-8388609,s+=947912704,n[e]=t|s}for(let e=1024;e<2048;++e)n[e]=939524096+(e-1024<<13);for(let e=1;e<31;++e)o[e]=e<<23;o[31]=1199570944,o[32]=2147483648;for(let e=33;e<63;++e)o[e]=2147483648+(e-32<<23);o[63]=3347054592;for(let e=1;e<64;++e)32!==e&&(a[e]=1024);return{floatView:t,uint32View:s,baseTable:i,shiftTable:r,mantissaTable:n,exponentTable:o,offsetTable:a}}function nn(e){Math.abs(e)>65504&&console.warn("THREE.DataUtils.toHalfFloat(): Value out of range."),e=$s(e,-65504,65504),sn.floatView[0]=e;const t=sn.uint32View[0],s=t>>23&511;return sn.baseTable[s]+((8388607&t)>>sn.shiftTable[s])}function on(e){const t=e>>10;return sn.uint32View[0]=sn.mantissaTable[sn.offsetTable[t]+(1023&e)]+sn.exponentTable[t],sn.floatView[0]}const an={toHalfFloat:nn,fromHalfFloat:on},hn=new Ri,un=new Qs;class ln{constructor(e,t,s=!1){if(Array.isArray(e))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,this.name="",this.array=e,this.itemSize=t,this.count=void 0!==e?e.length/t:0,this.normalized=s,this.usage=Cs,this.updateRanges=[],this.gpuType=Ie,this.version=0}onUploadCallback(){}set needsUpdate(e){!0===e&&this.version++}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.name=e.name,this.array=new e.array.constructor(e.array),this.itemSize=e.itemSize,this.count=e.count,this.normalized=e.normalized,this.usage=e.usage,this.gpuType=e.gpuType,this}copyAt(e,t,s){e*=this.itemSize,s*=t.itemSize;for(let i=0,r=this.itemSize;i=0;--t)if(e[t]>=65535)return!0;return!1}(e)?yn:gn)(e,1):this.index=e,this}getAttribute(e){return this.attributes[e]}setAttribute(e,t){return this.attributes[e]=t,this}deleteAttribute(e){return delete this.attributes[e],this}hasAttribute(e){return void 0!==this.attributes[e]}addGroup(e,t,s=0){this.groups.push({start:e,count:t,materialIndex:s})}clearGroups(){this.groups=[]}setDrawRange(e,t){this.drawRange.start=e,this.drawRange.count=t}applyMatrix4(e){const t=this.attributes.position;void 0!==t&&(t.applyMatrix4(e),t.needsUpdate=!0);const s=this.attributes.normal;if(void 0!==s){const t=(new ei).getNormalMatrix(e);s.applyNormalMatrix(t),s.needsUpdate=!0}const i=this.attributes.tangent;return void 0!==i&&(i.transformDirection(e),i.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this}applyQuaternion(e){return Tn.makeRotationFromQuaternion(e),this.applyMatrix4(Tn),this}rotateX(e){return Tn.makeRotationX(e),this.applyMatrix4(Tn),this}rotateY(e){return Tn.makeRotationY(e),this.applyMatrix4(Tn),this}rotateZ(e){return Tn.makeRotationZ(e),this.applyMatrix4(Tn),this}translate(e,t,s){return Tn.makeTranslation(e,t,s),this.applyMatrix4(Tn),this}scale(e,t,s){return Tn.makeScale(e,t,s),this.applyMatrix4(Tn),this}lookAt(e){return _n.lookAt(e),_n.updateMatrix(),this.applyMatrix4(_n.matrix),this}center(){return this.computeBoundingBox(),this.boundingBox.getCenter(wn).negate(),this.translate(wn.x,wn.y,wn.z),this}setFromPoints(e){const t=[];for(let s=0,i=e.length;s0&&(e.userData=this.userData),void 0!==this.parameters){const t=this.parameters;for(const s in t)void 0!==t[s]&&(e[s]=t[s]);return e}e.data={attributes:{}};const t=this.index;null!==t&&(e.data.index={type:t.array.constructor.name,array:Array.prototype.slice.call(t.array)});const s=this.attributes;for(const t in s){const i=s[t];e.data.attributes[t]=i.toJSON(e.data)}const i={};let r=!1;for(const t in this.morphAttributes){const s=this.morphAttributes[t],n=[];for(let t=0,i=s.length;t0&&(i[t]=n,r=!0)}r&&(e.data.morphAttributes=i,e.data.morphTargetsRelative=this.morphTargetsRelative);const n=this.groups;n.length>0&&(e.data.groups=JSON.parse(JSON.stringify(n)));const o=this.boundingSphere;return null!==o&&(e.data.boundingSphere={center:o.center.toArray(),radius:o.radius}),e}clone(){return(new this.constructor).copy(this)}copy(e){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const t={};this.name=e.name;const s=e.index;null!==s&&this.setIndex(s.clone(t));const i=e.attributes;for(const e in i){const s=i[e];this.setAttribute(e,s.clone(t))}const r=e.morphAttributes;for(const e in r){const s=[],i=r[e];for(let e=0,r=i.length;e0){const s=e[t[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,t=s.length;e(e.far-e.near)**2)return}Cn.copy(r).invert(),Rn.copy(e.ray).applyMatrix4(Cn),null!==s.boundingBox&&!1===Rn.intersectsBox(s.boundingBox)||this._computeIntersections(e,t,Rn)}}_computeIntersections(e,t,s){let i;const r=this.geometry,n=this.material,o=r.index,a=r.attributes.position,h=r.attributes.uv,u=r.attributes.uv1,l=r.attributes.normal,c=r.groups,d=r.drawRange;if(null!==o)if(Array.isArray(n))for(let r=0,a=c.length;rs.far?null:{distance:u,point:Ln.clone(),object:e}}(e,t,s,i,In,Pn,Fn,On);if(l){const e=new Ri;qr.getBarycoord(On,In,Pn,Fn,e),r&&(l.uv=qr.getInterpolatedAttribute(r,a,h,u,e,new Qs)),n&&(l.uv1=qr.getInterpolatedAttribute(n,a,h,u,e,new Qs)),o&&(l.normal=qr.getInterpolatedAttribute(o,a,h,u,e,new Ri),l.normal.dot(i.direction)>0&&l.normal.multiplyScalar(-1));const t={a:a,b:h,c:u,normal:new Ri,materialIndex:0};qr.getNormal(In,Pn,Fn,t.normal),l.face=t,l.barycoord=e}return l}class kn extends An{constructor(e=1,t=1,s=1,i=1,r=1,n=1){super(),this.type="BoxGeometry",this.parameters={width:e,height:t,depth:s,widthSegments:i,heightSegments:r,depthSegments:n};const o=this;i=Math.floor(i),r=Math.floor(r),n=Math.floor(n);const a=[],h=[],u=[],l=[];let c=0,d=0;function p(e,t,s,i,r,n,p,m,g,f,y){const x=n/g,b=p/f,v=n/2,T=p/2,_=m/2,w=g+1,S=f+1;let M=0,N=0;const A=new Ri;for(let n=0;n0?1:-1,u.push(A.x,A.y,A.z),l.push(a/g),l.push(1-n/f),M+=1}}for(let e=0;e0&&(t.defines=this.defines),t.vertexShader=this.vertexShader,t.fragmentShader=this.fragmentShader,t.lights=this.lights,t.clipping=this.clipping;const s={};for(const e in this.extensions)!0===this.extensions[e]&&(s[e]=!0);return Object.keys(s).length>0&&(t.extensions=s),t}}class jn extends Ir{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new nr,this.projectionMatrix=new nr,this.projectionMatrixInverse=new nr,this.coordinateSystem=Vs}copy(e,t){return super.copy(e,t),this.matrixWorldInverse.copy(e.matrixWorldInverse),this.projectionMatrix.copy(e.projectionMatrix),this.projectionMatrixInverse.copy(e.projectionMatrixInverse),this.coordinateSystem=e.coordinateSystem,this}getWorldDirection(e){return super.getWorldDirection(e).negate()}updateMatrixWorld(e){super.updateMatrixWorld(e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(e,t){super.updateWorldMatrix(e,t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return(new this.constructor).copy(this)}}const Hn=new Ri,qn=new Qs,$n=new Qs;class Xn extends jn{constructor(e=50,t=1,s=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=e,this.zoom=1,this.near=s,this.far=i,this.focus=10,this.aspect=t,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(e,t){return super.copy(e,t),this.fov=e.fov,this.zoom=e.zoom,this.near=e.near,this.far=e.far,this.focus=e.focus,this.aspect=e.aspect,this.view=null===e.view?null:Object.assign({},e.view),this.filmGauge=e.filmGauge,this.filmOffset=e.filmOffset,this}setFocalLength(e){const t=.5*this.getFilmHeight()/e;this.fov=2*Hs*Math.atan(t),this.updateProjectionMatrix()}getFocalLength(){const e=Math.tan(.5*js*this.fov);return.5*this.getFilmHeight()/e}getEffectiveFOV(){return 2*Hs*Math.atan(Math.tan(.5*js*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(e,t,s){Hn.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),t.set(Hn.x,Hn.y).multiplyScalar(-e/Hn.z),Hn.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),s.set(Hn.x,Hn.y).multiplyScalar(-e/Hn.z)}getViewSize(e,t){return this.getViewBounds(e,qn,$n),t.subVectors($n,qn)}setViewOffset(e,t,s,i,r,n){this.aspect=e/t,null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=s,this.view.offsetY=i,this.view.width=r,this.view.height=n,this.updateProjectionMatrix()}clearViewOffset(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const e=this.near;let t=e*Math.tan(.5*js*this.fov)/this.zoom,s=2*t,i=this.aspect*s,r=-.5*i;const n=this.view;if(null!==this.view&&this.view.enabled){const e=n.fullWidth,o=n.fullHeight;r+=n.offsetX*i/e,t-=n.offsetY*s/o,i*=n.width/e,s*=n.height/o}const o=this.filmOffset;0!==o&&(r+=e*o/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,t,t-s,e,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(e){const t=super.toJSON(e);return t.object.fov=this.fov,t.object.zoom=this.zoom,t.object.near=this.near,t.object.far=this.far,t.object.focus=this.focus,t.object.aspect=this.aspect,null!==this.view&&(t.object.view=Object.assign({},this.view)),t.object.filmGauge=this.filmGauge,t.object.filmOffset=this.filmOffset,t}}const Yn=-90;class Zn extends Ir{constructor(e,t,s){super(),this.type="CubeCamera",this.renderTarget=s,this.coordinateSystem=null,this.activeMipmapLevel=0;const i=new Xn(Yn,1,e,t);i.layers=this.layers,this.add(i);const r=new Xn(Yn,1,e,t);r.layers=this.layers,this.add(r);const n=new Xn(Yn,1,e,t);n.layers=this.layers,this.add(n);const o=new Xn(Yn,1,e,t);o.layers=this.layers,this.add(o);const a=new Xn(Yn,1,e,t);a.layers=this.layers,this.add(a);const h=new Xn(Yn,1,e,t);h.layers=this.layers,this.add(h)}updateCoordinateSystem(){const e=this.coordinateSystem,t=this.children.concat(),[s,i,r,n,o,a]=t;for(const e of t)this.remove(e);if(e===Vs)s.up.set(0,1,0),s.lookAt(1,0,0),i.up.set(0,1,0),i.lookAt(-1,0,0),r.up.set(0,0,-1),r.lookAt(0,1,0),n.up.set(0,0,1),n.lookAt(0,-1,0),o.up.set(0,1,0),o.lookAt(0,0,1),a.up.set(0,1,0),a.lookAt(0,0,-1);else{if(e!==Ds)throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+e);s.up.set(0,-1,0),s.lookAt(-1,0,0),i.up.set(0,-1,0),i.lookAt(1,0,0),r.up.set(0,0,1),r.lookAt(0,1,0),n.up.set(0,0,-1),n.lookAt(0,-1,0),o.up.set(0,-1,0),o.lookAt(0,0,1),a.up.set(0,-1,0),a.lookAt(0,0,-1)}for(const e of t)this.add(e),e.updateMatrixWorld()}update(e,t){null===this.parent&&this.updateMatrixWorld();const{renderTarget:s,activeMipmapLevel:i}=this;this.coordinateSystem!==e.coordinateSystem&&(this.coordinateSystem=e.coordinateSystem,this.updateCoordinateSystem());const[r,n,o,a,h,u]=this.children,l=e.getRenderTarget(),c=e.getActiveCubeFace(),d=e.getActiveMipmapLevel(),p=e.xr.enabled;e.xr.enabled=!1;const m=s.texture.generateMipmaps;s.texture.generateMipmaps=!1,e.setRenderTarget(s,0,i),e.render(t,r),e.setRenderTarget(s,1,i),e.render(t,n),e.setRenderTarget(s,2,i),e.render(t,o),e.setRenderTarget(s,3,i),e.render(t,a),e.setRenderTarget(s,4,i),e.render(t,h),s.texture.generateMipmaps=m,e.setRenderTarget(s,5,i),e.render(t,u),e.setRenderTarget(l,c,d),e.xr.enabled=p,s.texture.needsPMREMUpdate=!0}}class Jn extends vi{constructor(e,t,s,i,r,n,o,a,h,u){super(e=void 0!==e?e:[],t=void 0!==t?t:he,s,i,r,n,o,a,h,u),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(e){this.image=e}}class Kn extends wi{constructor(e=1,t={}){super(e,e,t),this.isWebGLCubeRenderTarget=!0;const s={width:e,height:e,depth:1},i=[s,s,s,s,s,s];this.texture=new Jn(i,t.mapping,t.wrapS,t.wrapT,t.magFilter,t.minFilter,t.format,t.type,t.anisotropy,t.colorSpace),this.texture.isRenderTargetTexture=!0,this.texture.generateMipmaps=void 0!==t.generateMipmaps&&t.generateMipmaps,this.texture.minFilter=void 0!==t.minFilter?t.minFilter:Te}fromEquirectangularTexture(e,t){this.texture.type=t.type,this.texture.colorSpace=t.colorSpace,this.texture.generateMipmaps=t.generateMipmaps,this.texture.minFilter=t.minFilter,this.texture.magFilter=t.magFilter;const s={uniforms:{tEquirect:{value:null}},vertexShader:"\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\tvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\n\t\t\t\t\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvWorldDirection = transformDirection( position, modelMatrix );\n\n\t\t\t\t\t#include \n\t\t\t\t\t#include \n\n\t\t\t\t}\n\t\t\t",fragmentShader:"\n\n\t\t\t\tuniform sampler2D tEquirect;\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\t#include \n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvec3 direction = normalize( vWorldDirection );\n\n\t\t\t\t\tvec2 sampleUV = equirectUv( direction );\n\n\t\t\t\t\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\n\t\t\t\t}\n\t\t\t"},i=new kn(5,5,5),r=new Wn({name:"CubemapFromEquirect",uniforms:Gn(s.uniforms),vertexShader:s.vertexShader,fragmentShader:s.fragmentShader,side:d,blending:m});r.uniforms.tEquirect.value=t;const n=new Vn(i,r),o=t.minFilter;t.minFilter===Se&&(t.minFilter=Te);return new Zn(1,10,this).update(e,n),t.minFilter=o,n.geometry.dispose(),n.material.dispose(),this}clear(e,t,s,i){const r=e.getRenderTarget();for(let r=0;r<6;r++)e.setRenderTarget(this,r),e.clear(t,s,i);e.setRenderTarget(r)}}class Qn{constructor(e,t=25e-5){this.isFogExp2=!0,this.name="",this.color=new Jr(e),this.density=t}clone(){return new Qn(this.color,this.density)}toJSON(){return{type:"FogExp2",name:this.name,color:this.color.getHex(),density:this.density}}}class eo{constructor(e,t=1,s=1e3){this.isFog=!0,this.name="",this.color=new Jr(e),this.near=t,this.far=s}clone(){return new eo(this.color,this.near,this.far)}toJSON(){return{type:"Fog",name:this.name,color:this.color.getHex(),near:this.near,far:this.far}}}class to extends Ir{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.backgroundRotation=new gr,this.environmentIntensity=1,this.environmentRotation=new gr,this.overrideMaterial=null,"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(e,t){return super.copy(e,t),null!==e.background&&(this.background=e.background.clone()),null!==e.environment&&(this.environment=e.environment.clone()),null!==e.fog&&(this.fog=e.fog.clone()),this.backgroundBlurriness=e.backgroundBlurriness,this.backgroundIntensity=e.backgroundIntensity,this.backgroundRotation.copy(e.backgroundRotation),this.environmentIntensity=e.environmentIntensity,this.environmentRotation.copy(e.environmentRotation),null!==e.overrideMaterial&&(this.overrideMaterial=e.overrideMaterial.clone()),this.matrixAutoUpdate=e.matrixAutoUpdate,this}toJSON(e){const t=super.toJSON(e);return null!==this.fog&&(t.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(t.object.backgroundBlurriness=this.backgroundBlurriness),1!==this.backgroundIntensity&&(t.object.backgroundIntensity=this.backgroundIntensity),t.object.backgroundRotation=this.backgroundRotation.toArray(),1!==this.environmentIntensity&&(t.object.environmentIntensity=this.environmentIntensity),t.object.environmentRotation=this.environmentRotation.toArray(),t}}class so{constructor(e,t){this.isInterleavedBuffer=!0,this.array=e,this.stride=t,this.count=void 0!==e?e.length/t:0,this.usage=Cs,this.updateRanges=[],this.version=0,this.uuid=qs()}onUploadCallback(){}set needsUpdate(e){!0===e&&this.version++}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.array=new e.array.constructor(e.array),this.count=e.count,this.stride=e.stride,this.usage=e.usage,this}copyAt(e,t,s){e*=this.stride,s*=t.stride;for(let i=0,r=this.stride;ie.far||t.push({distance:a,point:ao.clone(),uv:qr.getInterpolation(ao,mo,go,fo,yo,xo,bo,new Qs),face:null,object:this})}copy(e,t){return super.copy(e,t),void 0!==e.center&&this.center.copy(e.center),this.material=e.material,this}}function To(e,t,s,i,r,n){lo.subVectors(e,s).addScalar(.5).multiply(i),void 0!==r?(co.x=n*lo.x-r*lo.y,co.y=r*lo.x+n*lo.y):co.copy(lo),e.copy(t),e.x+=co.x,e.y+=co.y,e.applyMatrix4(po)}const _o=new Ri,wo=new Ri;class So extends Ir{constructor(){super(),this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]},isLOD:{value:!0}}),this.autoUpdate=!0}copy(e){super.copy(e,!1);const t=e.levels;for(let e=0,s=t.length;e0){let s,i;for(s=1,i=t.length;s0){_o.setFromMatrixPosition(this.matrixWorld);const s=e.ray.origin.distanceTo(_o);this.getObjectForDistance(s).raycast(e,t)}}update(e){const t=this.levels;if(t.length>1){_o.setFromMatrixPosition(e.matrixWorld),wo.setFromMatrixPosition(this.matrixWorld);const s=_o.distanceTo(wo)/e.zoom;let i,r;for(t[0].object.visible=!0,i=1,r=t.length;i=e))break;t[i-1].object.visible=!1,t[i].object.visible=!0}for(this._currentLevel=i-1;i1?null:t.copy(e.start).addScaledVector(s,r)}intersectsLine(e){const t=this.distanceToPoint(e.start),s=this.distanceToPoint(e.end);return t<0&&s>0||s<0&&t>0}intersectsBox(e){return e.intersectsPlane(this)}intersectsSphere(e){return e.intersectsPlane(this)}coplanarPoint(e){return e.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(e,t){const s=t||Jo.getNormalMatrix(e),i=this.coplanarPoint(Yo).applyMatrix4(e),r=this.normal.applyMatrix3(s).normalize();return this.constant=-i.dot(r),this}translate(e){return this.constant-=e.dot(this.normal),this}equals(e){return e.normal.equals(this.normal)&&e.constant===this.constant}clone(){return(new this.constructor).copy(this)}}const Qo=new Zi,ea=new Ri;class ta{constructor(e=new Ko,t=new Ko,s=new Ko,i=new Ko,r=new Ko,n=new Ko){this.planes=[e,t,s,i,r,n]}set(e,t,s,i,r,n){const o=this.planes;return o[0].copy(e),o[1].copy(t),o[2].copy(s),o[3].copy(i),o[4].copy(r),o[5].copy(n),this}copy(e){const t=this.planes;for(let s=0;s<6;s++)t[s].copy(e.planes[s]);return this}setFromProjectionMatrix(e,t=2e3){const s=this.planes,i=e.elements,r=i[0],n=i[1],o=i[2],a=i[3],h=i[4],u=i[5],l=i[6],c=i[7],d=i[8],p=i[9],m=i[10],g=i[11],f=i[12],y=i[13],x=i[14],b=i[15];if(s[0].setComponents(a-r,c-h,g-d,b-f).normalize(),s[1].setComponents(a+r,c+h,g+d,b+f).normalize(),s[2].setComponents(a+n,c+u,g+p,b+y).normalize(),s[3].setComponents(a-n,c-u,g-p,b-y).normalize(),s[4].setComponents(a-o,c-l,g-m,b-x).normalize(),t===Vs)s[5].setComponents(a+o,c+l,g+m,b+x).normalize();else{if(t!==Ds)throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+t);s[5].setComponents(o,l,m,x).normalize()}return this}intersectsObject(e){if(void 0!==e.boundingSphere)null===e.boundingSphere&&e.computeBoundingSphere(),Qo.copy(e.boundingSphere).applyMatrix4(e.matrixWorld);else{const t=e.geometry;null===t.boundingSphere&&t.computeBoundingSphere(),Qo.copy(t.boundingSphere).applyMatrix4(e.matrixWorld)}return this.intersectsSphere(Qo)}intersectsSprite(e){return Qo.center.set(0,0,0),Qo.radius=.7071067811865476,Qo.applyMatrix4(e.matrixWorld),this.intersectsSphere(Qo)}intersectsSphere(e){const t=this.planes,s=e.center,i=-e.radius;for(let e=0;e<6;e++){if(t[e].distanceToPoint(s)0?e.max.x:e.min.x,ea.y=i.normal.y>0?e.max.y:e.min.y,ea.z=i.normal.z>0?e.max.z:e.min.z,i.distanceToPoint(ea)<0)return!1}return!0}containsPoint(e){const t=this.planes;for(let s=0;s<6;s++)if(t[s].distanceToPoint(e)<0)return!1;return!0}clone(){return(new this.constructor).copy(this)}}function sa(e,t){return e.z-t.z}function ia(e,t){return t.z-e.z}class ra{constructor(){this.index=0,this.pool=[],this.list=[]}push(e,t,s){const i=this.pool,r=this.list;this.index>=i.length&&i.push({start:-1,count:-1,z:-1,index:-1});const n=i[this.index];r.push(n),this.index++,n.start=e.start,n.count=e.count,n.z=t,n.index=s}reset(){this.list.length=0,this.index=0}}const na=new nr,oa=new nr,aa=new nr,ha=new Jr(1,1,1),ua=new nr,la=new ta,ca=new Ii,da=new Zi,pa=new Ri,ma=new Ri,ga=new Ri,fa=new ra,ya=new Vn,xa=[];function ba(e,t,s=0){const i=t.itemSize;if(e.isInterleavedBufferAttribute||e.array.constructor!==t.array.constructor){const r=e.count;for(let n=0;n65535?new Uint32Array(i):new Uint16Array(i);t.setIndex(new ln(e,1))}this._geometryInitialized=!0}}_validateGeometry(e){const t=this.geometry;if(Boolean(e.getIndex())!==Boolean(t.getIndex()))throw new Error('BatchedMesh: All geometries must consistently have "index".');for(const s in t.attributes){if(!e.hasAttribute(s))throw new Error(`BatchedMesh: Added geometry missing "${s}". All geometries must have consistent attributes.`);const i=e.getAttribute(s),r=t.getAttribute(s);if(i.itemSize!==r.itemSize||i.normalized!==r.normalized)throw new Error("BatchedMesh: All attributes must have a consistent itemSize and normalized value.")}}setCustomSort(e){return this.customSort=e,this}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new Ii);const e=this.boundingBox,t=this._drawInfo;e.makeEmpty();for(let s=0,i=t.length;s=this.maxInstanceCount&&0===this._availableInstanceIds.length)throw new Error("BatchedMesh: Maximum item count reached.");const t={visible:!0,active:!0,geometryIndex:e};let s=null;this._availableInstanceIds.length>0?(s=this._availableInstanceIds.pop(),this._drawInfo[s]=t):(s=this._drawInfo.length,this._drawInfo.push(t));const i=this._matricesTexture,r=i.image.data;aa.toArray(r,16*s),i.needsUpdate=!0;const n=this._colorsTexture;return n&&(ha.toArray(n.image.data,4*s),n.needsUpdate=!0),s}addGeometry(e,t=-1,s=-1){if(this._initializeGeometry(e),this._validateGeometry(e),this._drawInfo.length>=this._maxInstanceCount)throw new Error("BatchedMesh: Maximum item count reached.");const i={vertexStart:-1,vertexCount:-1,indexStart:-1,indexCount:-1};let r=null;const n=this._reservedRanges,o=this._drawRanges,a=this._bounds;0!==this._geometryCount&&(r=n[n.length-1]),i.vertexCount=-1===t?e.getAttribute("position").count:t,i.vertexStart=null===r?0:r.vertexStart+r.vertexCount;const h=e.getIndex(),u=null!==h;if(u&&(i.indexCount=-1===s?h.count:s,i.indexStart=null===r?0:r.indexStart+r.indexCount),-1!==i.indexStart&&i.indexStart+i.indexCount>this._maxIndexCount||i.vertexStart+i.vertexCount>this._maxVertexCount)throw new Error("BatchedMesh: Reserved space request exceeds the maximum buffer size.");const l=this._geometryCount;return this._geometryCount++,n.push(i),o.push({start:u?i.indexStart:i.vertexStart,count:-1}),a.push({boxInitialized:!1,box:new Ii,sphereInitialized:!1,sphere:new Zi}),this.setGeometryAt(l,e),l}setGeometryAt(e,t){if(e>=this._geometryCount)throw new Error("BatchedMesh: Maximum geometry count reached.");this._validateGeometry(t);const s=this.geometry,i=null!==s.getIndex(),r=s.getIndex(),n=t.getIndex(),o=this._reservedRanges[e];if(i&&n.count>o.indexCount||t.attributes.position.count>o.vertexCount)throw new Error("BatchedMesh: Reserved space not large enough for provided geometry.");const a=o.vertexStart,h=o.vertexCount;for(const e in s.attributes){const i=t.getAttribute(e),r=s.getAttribute(e);ba(i,r,a);const n=i.itemSize;for(let e=i.count,t=h;e=t.length||!1===t[e].active||(t[e].active=!1,this._availableInstanceIds.push(e),this._visibilityChanged=!0),this}getBoundingBoxAt(e,t){if(e>=this._geometryCount)return null;const s=this._bounds[e],i=s.box,r=this.geometry;if(!1===s.boxInitialized){i.makeEmpty();const t=r.index,n=r.attributes.position,o=this._drawRanges[e];for(let e=o.start,s=o.start+o.count;e=this._geometryCount)return null;const s=this._bounds[e],i=s.sphere,r=this.geometry;if(!1===s.sphereInitialized){i.makeEmpty(),this.getBoundingBoxAt(e,ca),ca.getCenter(i.center);const t=r.index,n=r.attributes.position,o=this._drawRanges[e];let a=0;for(let e=o.start,s=o.start+o.count;e=s.length||!1===s[e].active||(t.toArray(r,16*e),i.needsUpdate=!0),this}getMatrixAt(e,t){const s=this._drawInfo,i=this._matricesTexture.image.data;return e>=s.length||!1===s[e].active?null:t.fromArray(i,16*e)}setColorAt(e,t){null===this._colorsTexture&&this._initColorsTexture();const s=this._colorsTexture,i=this._colorsTexture.image.data,r=this._drawInfo;return e>=r.length||!1===r[e].active||(t.toArray(i,4*e),s.needsUpdate=!0),this}getColorAt(e,t){const s=this._colorsTexture.image.data,i=this._drawInfo;return e>=i.length||!1===i[e].active?null:t.fromArray(s,4*e)}setVisibleAt(e,t){const s=this._drawInfo;return e>=s.length||!1===s[e].active||s[e].visible===t||(s[e].visible=t,this._visibilityChanged=!0),this}getVisibleAt(e){const t=this._drawInfo;return!(e>=t.length||!1===t[e].active)&&t[e].visible}setGeometryIdAt(e,t){const s=this._drawInfo;return e>=s.length||!1===s[e].active||t<0||t>=this._geometryCount?null:(s[e].geometryIndex=t,this)}getGeometryIdAt(e){const t=this._drawInfo;return e>=t.length||!1===t[e].active?-1:t[e].geometryIndex}getGeometryRangeAt(e,t={}){if(e<0||e>=this._geometryCount)return null;const s=this._drawRanges[e];return t.start=s.start,t.count=s.count,t}raycast(e,t){const s=this._drawInfo,i=this._drawRanges,r=this.matrixWorld,n=this.geometry;ya.material=this.material,ya.geometry.index=n.index,ya.geometry.attributes=n.attributes,null===ya.geometry.boundingBox&&(ya.geometry.boundingBox=new Ii),null===ya.geometry.boundingSphere&&(ya.geometry.boundingSphere=new Zi);for(let n=0,o=s.length;n({...e}))),this._reservedRanges=e._reservedRanges.map((e=>({...e}))),this._drawInfo=e._drawInfo.map((e=>({...e}))),this._bounds=e._bounds.map((e=>({boxInitialized:e.boxInitialized,box:e.box.clone(),sphereInitialized:e.sphereInitialized,sphere:e.sphere.clone()}))),this._maxInstanceCount=e._maxInstanceCount,this._maxVertexCount=e._maxVertexCount,this._maxIndexCount=e._maxIndexCount,this._geometryInitialized=e._geometryInitialized,this._geometryCount=e._geometryCount,this._multiDrawCounts=e._multiDrawCounts.slice(),this._multiDrawStarts=e._multiDrawStarts.slice(),this._matricesTexture=e._matricesTexture.clone(),this._matricesTexture.image.data=this._matricesTexture.image.data.slice(),null!==this._colorsTexture&&(this._colorsTexture=e._colorsTexture.clone(),this._colorsTexture.image.data=this._colorsTexture.image.data.slice()),this}dispose(){return this.geometry.dispose(),this._matricesTexture.dispose(),this._matricesTexture=null,this._indirectTexture.dispose(),this._indirectTexture=null,null!==this._colorsTexture&&(this._colorsTexture.dispose(),this._colorsTexture=null),this}onBeforeRender(e,t,s,i,r){if(!this._visibilityChanged&&!this.perObjectFrustumCulled&&!this.sortObjects)return;const n=i.getIndex(),o=null===n?1:n.array.BYTES_PER_ELEMENT,a=this._drawInfo,h=this._multiDrawStarts,u=this._multiDrawCounts,l=this._drawRanges,c=this.perObjectFrustumCulled,d=this._indirectTexture,p=d.image.data;c&&(ua.multiplyMatrices(s.projectionMatrix,s.matrixWorldInverse).multiply(this.matrixWorld),la.setFromProjectionMatrix(ua,e.coordinateSystem));let m=0;if(this.sortObjects){oa.copy(this.matrixWorld).invert(),pa.setFromMatrixPosition(s.matrixWorld).applyMatrix4(oa),ma.set(0,0,-1).transformDirection(s.matrixWorld).transformDirection(oa);for(let e=0,t=a.length;e0){const s=e[t[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,t=s.length;ei)return;Aa.applyMatrix4(e.matrixWorld);const a=t.ray.origin.distanceTo(Aa);return at.far?void 0:{distance:a,point:Ca.clone().applyMatrix4(e.matrixWorld),index:r,face:null,faceIndex:null,barycoord:null,object:e}}const Ba=new Ri,Ia=new Ri;class Pa extends Ra{constructor(e,t){super(e,t),this.isLineSegments=!0,this.type="LineSegments"}computeLineDistances(){const e=this.geometry;if(null===e.index){const t=e.attributes.position,s=[];for(let e=0,i=t.count;e0){const s=e[t[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,t=s.length;er.far)return;n.push({distance:h,distanceToRay:Math.sqrt(a),point:s,index:t,face:null,faceIndex:null,barycoord:null,object:o})}}class Ga extends Ir{constructor(){super(),this.isGroup=!0,this.type="Group"}}class Wa extends vi{constructor(e,t,s,i,r,n,o,a,h){super(e,t,s,i,r,n,o,a,h),this.isVideoTexture=!0,this.minFilter=void 0!==n?n:Te,this.magFilter=void 0!==r?r:Te,this.generateMipmaps=!1;const u=this;"requestVideoFrameCallback"in e&&e.requestVideoFrameCallback((function t(){u.needsUpdate=!0,e.requestVideoFrameCallback(t)}))}clone(){return new this.constructor(this.image).copy(this)}update(){const e=this.image;!1==="requestVideoFrameCallback"in e&&e.readyState>=e.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}}class ja extends vi{constructor(e,t){super({width:e,height:t}),this.isFramebufferTexture=!0,this.magFilter=fe,this.minFilter=fe,this.generateMipmaps=!1,this.needsUpdate=!0}}class Ha extends vi{constructor(e,t,s,i,r,n,o,a,h,u,l,c){super(null,n,o,a,h,u,i,r,l,c),this.isCompressedTexture=!0,this.image={width:t,height:s},this.mipmaps=e,this.flipY=!1,this.generateMipmaps=!1}}class qa extends Ha{constructor(e,t,s,i,r,n){super(e,t,s,r,n),this.isCompressedArrayTexture=!0,this.image.depth=i,this.wrapR=me,this.layerUpdates=new Set}addLayerUpdate(e){this.layerUpdates.add(e)}clearLayerUpdates(){this.layerUpdates.clear()}}class $a extends Ha{constructor(e,t,s){super(void 0,e[0].width,e[0].height,t,s,he),this.isCompressedCubeTexture=!0,this.isCubeTexture=!0,this.image=e}}class Xa extends vi{constructor(e,t,s,i,r,n,o,a,h){super(e,t,s,i,r,n,o,a,h),this.isCanvasTexture=!0,this.needsUpdate=!0}}class Ya extends vi{constructor(e,t,s,i,r,n,o,a,h,u=1026){if(u!==We&&u!==je)throw new Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");void 0===s&&u===We&&(s=Be),void 0===s&&u===je&&(s=Ue),super(null,i,r,n,o,a,u,s,h),this.isDepthTexture=!0,this.image={width:e,height:t},this.magFilter=void 0!==o?o:fe,this.minFilter=void 0!==a?a:fe,this.flipY=!1,this.generateMipmaps=!1,this.compareFunction=null}copy(e){return super.copy(e),this.compareFunction=e.compareFunction,this}toJSON(e){const t=super.toJSON(e);return null!==this.compareFunction&&(t.compareFunction=this.compareFunction),t}}class Za{constructor(){this.type="Curve",this.arcLengthDivisions=200}getPoint(){return console.warn("THREE.Curve: .getPoint() not implemented."),null}getPointAt(e,t){const s=this.getUtoTmapping(e);return this.getPoint(s,t)}getPoints(e=5){const t=[];for(let s=0;s<=e;s++)t.push(this.getPoint(s/e));return t}getSpacedPoints(e=5){const t=[];for(let s=0;s<=e;s++)t.push(this.getPointAt(s/e));return t}getLength(){const e=this.getLengths();return e[e.length-1]}getLengths(e=this.arcLengthDivisions){if(this.cacheArcLengths&&this.cacheArcLengths.length===e+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;const t=[];let s,i=this.getPoint(0),r=0;t.push(0);for(let n=1;n<=e;n++)s=this.getPoint(n/e),r+=s.distanceTo(i),t.push(r),i=s;return this.cacheArcLengths=t,t}updateArcLengths(){this.needsUpdate=!0,this.getLengths()}getUtoTmapping(e,t){const s=this.getLengths();let i=0;const r=s.length;let n;n=t||e*s[r-1];let o,a=0,h=r-1;for(;a<=h;)if(i=Math.floor(a+(h-a)/2),o=s[i]-n,o<0)a=i+1;else{if(!(o>0)){h=i;break}h=i-1}if(i=h,s[i]===n)return i/(r-1);const u=s[i];return(i+(n-u)/(s[i+1]-u))/(r-1)}getTangent(e,t){const s=1e-4;let i=e-s,r=e+s;i<0&&(i=0),r>1&&(r=1);const n=this.getPoint(i),o=this.getPoint(r),a=t||(n.isVector2?new Qs:new Ri);return a.copy(o).sub(n).normalize(),a}getTangentAt(e,t){const s=this.getUtoTmapping(e);return this.getTangent(s,t)}computeFrenetFrames(e,t){const s=new Ri,i=[],r=[],n=[],o=new Ri,a=new nr;for(let t=0;t<=e;t++){const s=t/e;i[t]=this.getTangentAt(s,new Ri)}r[0]=new Ri,n[0]=new Ri;let h=Number.MAX_VALUE;const u=Math.abs(i[0].x),l=Math.abs(i[0].y),c=Math.abs(i[0].z);u<=h&&(h=u,s.set(1,0,0)),l<=h&&(h=l,s.set(0,1,0)),c<=h&&s.set(0,0,1),o.crossVectors(i[0],s).normalize(),r[0].crossVectors(i[0],o),n[0].crossVectors(i[0],r[0]);for(let t=1;t<=e;t++){if(r[t]=r[t-1].clone(),n[t]=n[t-1].clone(),o.crossVectors(i[t-1],i[t]),o.length()>Number.EPSILON){o.normalize();const e=Math.acos($s(i[t-1].dot(i[t]),-1,1));r[t].applyMatrix4(a.makeRotationAxis(o,e))}n[t].crossVectors(i[t],r[t])}if(!0===t){let t=Math.acos($s(r[0].dot(r[e]),-1,1));t/=e,i[0].dot(o.crossVectors(r[0],r[e]))>0&&(t=-t);for(let s=1;s<=e;s++)r[s].applyMatrix4(a.makeRotationAxis(i[s],t*s)),n[s].crossVectors(i[s],r[s])}return{tangents:i,normals:r,binormals:n}}clone(){return(new this.constructor).copy(this)}copy(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}toJSON(){const e={metadata:{version:4.6,type:"Curve",generator:"Curve.toJSON"}};return e.arcLengthDivisions=this.arcLengthDivisions,e.type=this.type,e}fromJSON(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}}class Ja extends Za{constructor(e=0,t=0,s=1,i=1,r=0,n=2*Math.PI,o=!1,a=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=e,this.aY=t,this.xRadius=s,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=n,this.aClockwise=o,this.aRotation=a}getPoint(e,t=new Qs){const s=t,i=2*Math.PI;let r=this.aEndAngle-this.aStartAngle;const n=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(h)/r)+1)*r:0===u&&h===r-1&&(h=r-2,u=1),this.closed||h>0?o=i[(h-1)%r]:(eh.subVectors(i[0],i[1]).add(i[0]),o=eh);const l=i[h%r],c=i[(h+1)%r];if(this.closed||h+2i.length-2?i.length-1:n+1],l=i[n>i.length-3?i.length-1:n+2];return s.set(nh(o,a.x,h.x,u.x,l.x),nh(o,a.y,h.y,u.y,l.y)),s}copy(e){super.copy(e),this.points=[];for(let t=0,s=e.points.length;t=s){const e=i[r]-s,n=this.curves[r],o=n.getLength(),a=0===o?0:1-e/o;return n.getPointAt(a,t)}r++}return null}getLength(){const e=this.getCurveLengths();return e[e.length-1]}updateArcLengths(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()}getCurveLengths(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;const e=[];let t=0;for(let s=0,i=this.curves.length;s1&&!t[t.length-1].equals(t[0])&&t.push(t[0]),t}copy(e){super.copy(e),this.curves=[];for(let t=0,s=e.curves.length;t0){const e=h.getPoint(0);e.equals(this.currentPoint)||this.lineTo(e.x,e.y)}this.curves.push(h);const u=h.getPoint(1);return this.currentPoint.copy(u),this}copy(e){return super.copy(e),this.currentPoint.copy(e.currentPoint),this}toJSON(){const e=super.toJSON();return e.currentPoint=this.currentPoint.toArray(),e}fromJSON(e){return super.fromJSON(e),this.currentPoint.fromArray(e.currentPoint),this}}class xh extends An{constructor(e=[new Qs(0,-.5),new Qs(.5,0),new Qs(0,.5)],t=12,s=0,i=2*Math.PI){super(),this.type="LatheGeometry",this.parameters={points:e,segments:t,phiStart:s,phiLength:i},t=Math.floor(t),i=$s(i,0,2*Math.PI);const r=[],n=[],o=[],a=[],h=[],u=1/t,l=new Ri,c=new Qs,d=new Ri,p=new Ri,m=new Ri;let g=0,f=0;for(let t=0;t<=e.length-1;t++)switch(t){case 0:g=e[t+1].x-e[t].x,f=e[t+1].y-e[t].y,d.x=1*f,d.y=-g,d.z=0*f,m.copy(d),d.normalize(),a.push(d.x,d.y,d.z);break;case e.length-1:a.push(m.x,m.y,m.z);break;default:g=e[t+1].x-e[t].x,f=e[t+1].y-e[t].y,d.x=1*f,d.y=-g,d.z=0*f,p.copy(d),d.x+=m.x,d.y+=m.y,d.z+=m.z,d.normalize(),a.push(d.x,d.y,d.z),m.copy(p)}for(let r=0;r<=t;r++){const d=s+r*u*i,p=Math.sin(d),m=Math.cos(d);for(let s=0;s<=e.length-1;s++){l.x=e[s].x*p,l.y=e[s].y,l.z=e[s].x*m,n.push(l.x,l.y,l.z),c.x=r/t,c.y=s/(e.length-1),o.push(c.x,c.y);const i=a[3*s+0]*p,u=a[3*s+1],d=a[3*s+0]*m;h.push(i,u,d)}}for(let s=0;s0&&(u.push(r,n,a),x+=3),t>0&&(u.push(n,o,a),x+=3)}h.addGroup(f,x,0),f+=x}(),!1===n&&(e>0&&y(!0),t>0&&y(!1)),this.setIndex(u),this.setAttribute("position",new bn(l,3)),this.setAttribute("normal",new bn(c,3)),this.setAttribute("uv",new bn(d,2))}copy(e){return super.copy(e),this.parameters=Object.assign({},e.parameters),this}static fromJSON(e){return new Th(e.radiusTop,e.radiusBottom,e.height,e.radialSegments,e.heightSegments,e.openEnded,e.thetaStart,e.thetaLength)}}class _h extends Th{constructor(e=1,t=1,s=32,i=1,r=!1,n=0,o=2*Math.PI){super(0,e,t,s,i,r,n,o),this.type="ConeGeometry",this.parameters={radius:e,height:t,radialSegments:s,heightSegments:i,openEnded:r,thetaStart:n,thetaLength:o}}static fromJSON(e){return new _h(e.radius,e.height,e.radialSegments,e.heightSegments,e.openEnded,e.thetaStart,e.thetaLength)}}class wh extends An{constructor(e=[],t=[],s=1,i=0){super(),this.type="PolyhedronGeometry",this.parameters={vertices:e,indices:t,radius:s,detail:i};const r=[],n=[];function o(e,t,s,i){const r=i+1,n=[];for(let i=0;i<=r;i++){n[i]=[];const o=e.clone().lerp(s,i/r),a=t.clone().lerp(s,i/r),h=r-i;for(let e=0;e<=h;e++)n[i][e]=0===e&&i===r?o:o.clone().lerp(a,e/h)}for(let e=0;e.9&&o<.1&&(t<.2&&(n[e+0]+=1),s<.2&&(n[e+2]+=1),i<.2&&(n[e+4]+=1))}}()}(),this.setAttribute("position",new bn(r,3)),this.setAttribute("normal",new bn(r.slice(),3)),this.setAttribute("uv",new bn(n,2)),0===i?this.computeVertexNormals():this.normalizeNormals()}copy(e){return super.copy(e),this.parameters=Object.assign({},e.parameters),this}static fromJSON(e){return new wh(e.vertices,e.indices,e.radius,e.details)}}class Sh extends wh{constructor(e=1,t=0){const s=(1+Math.sqrt(5))/2,i=1/s;super([-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-i,-s,0,-i,s,0,i,-s,0,i,s,-i,-s,0,-i,s,0,i,-s,0,i,s,0,-s,0,-i,s,0,-i,-s,0,i,s,0,i],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],e,t),this.type="DodecahedronGeometry",this.parameters={radius:e,detail:t}}static fromJSON(e){return new Sh(e.radius,e.detail)}}const Mh=new Ri,Nh=new Ri,Ah=new Ri,Ch=new qr;class Rh extends An{constructor(e=null,t=1){if(super(),this.type="EdgesGeometry",this.parameters={geometry:e,thresholdAngle:t},null!==e){const s=4,i=Math.pow(10,s),r=Math.cos(js*t),n=e.getIndex(),o=e.getAttribute("position"),a=n?n.count:o.count,h=[0,0,0],u=["a","b","c"],l=new Array(3),c={},d=[];for(let e=0;e80*s){a=u=e[0],h=l=e[1];for(let t=s;tu&&(u=c),d>l&&(l=d);p=Math.max(u-a,l-h),p=0!==p?32767/p:0}return Fh(n,o,s,a,h,p,0),o};function Ih(e,t,s,i,r){let n,o;if(r===function(e,t,s,i){let r=0;for(let n=t,o=s-i;n0)for(n=t;n=t;n-=i)o=Qh(n,e[n],e[n+1],o);return o&&$h(o,o.next)&&(eu(o),o=o.next),o}function Ph(e,t){if(!e)return e;t||(t=e);let s,i=e;do{if(s=!1,i.steiner||!$h(i,i.next)&&0!==qh(i.prev,i,i.next))i=i.next;else{if(eu(i),i=t=i.prev,i===i.next)break;s=!0}}while(s||i!==t);return t}function Fh(e,t,s,i,r,n,o){if(!e)return;!o&&n&&function(e,t,s,i){let r=e;do{0===r.z&&(r.z=Gh(r.x,r.y,t,s,i)),r.prevZ=r.prev,r.nextZ=r.next,r=r.next}while(r!==e);r.prevZ.nextZ=null,r.prevZ=null,function(e){let t,s,i,r,n,o,a,h,u=1;do{for(s=e,e=null,n=null,o=0;s;){for(o++,i=s,a=0,t=0;t0||h>0&&i;)0!==a&&(0===h||!i||s.z<=i.z)?(r=s,s=s.nextZ,a--):(r=i,i=i.nextZ,h--),n?n.nextZ=r:e=r,r.prevZ=n,n=r;s=i}n.nextZ=null,u*=2}while(o>1)}(r)}(e,i,r,n);let a,h,u=e;for(;e.prev!==e.next;)if(a=e.prev,h=e.next,n?Uh(e,i,r,n):zh(e))t.push(a.i/s|0),t.push(e.i/s|0),t.push(h.i/s|0),eu(e),e=h.next,u=h.next;else if((e=h)===u){o?1===o?Fh(e=Oh(Ph(e),t,s),t,s,i,r,n,2):2===o&&Lh(e,t,s,i,r,n):Fh(Ph(e),t,s,i,r,n,1);break}}function zh(e){const t=e.prev,s=e,i=e.next;if(qh(t,s,i)>=0)return!1;const r=t.x,n=s.x,o=i.x,a=t.y,h=s.y,u=i.y,l=rn?r>o?r:o:n>o?n:o,p=a>h?a>u?a:u:h>u?h:u;let m=i.next;for(;m!==t;){if(m.x>=l&&m.x<=d&&m.y>=c&&m.y<=p&&jh(r,a,n,h,o,u,m.x,m.y)&&qh(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function Uh(e,t,s,i){const r=e.prev,n=e,o=e.next;if(qh(r,n,o)>=0)return!1;const a=r.x,h=n.x,u=o.x,l=r.y,c=n.y,d=o.y,p=ah?a>u?a:u:h>u?h:u,f=l>c?l>d?l:d:c>d?c:d,y=Gh(p,m,t,s,i),x=Gh(g,f,t,s,i);let b=e.prevZ,v=e.nextZ;for(;b&&b.z>=y&&v&&v.z<=x;){if(b.x>=p&&b.x<=g&&b.y>=m&&b.y<=f&&b!==r&&b!==o&&jh(a,l,h,c,u,d,b.x,b.y)&&qh(b.prev,b,b.next)>=0)return!1;if(b=b.prevZ,v.x>=p&&v.x<=g&&v.y>=m&&v.y<=f&&v!==r&&v!==o&&jh(a,l,h,c,u,d,v.x,v.y)&&qh(v.prev,v,v.next)>=0)return!1;v=v.nextZ}for(;b&&b.z>=y;){if(b.x>=p&&b.x<=g&&b.y>=m&&b.y<=f&&b!==r&&b!==o&&jh(a,l,h,c,u,d,b.x,b.y)&&qh(b.prev,b,b.next)>=0)return!1;b=b.prevZ}for(;v&&v.z<=x;){if(v.x>=p&&v.x<=g&&v.y>=m&&v.y<=f&&v!==r&&v!==o&&jh(a,l,h,c,u,d,v.x,v.y)&&qh(v.prev,v,v.next)>=0)return!1;v=v.nextZ}return!0}function Oh(e,t,s){let i=e;do{const r=i.prev,n=i.next.next;!$h(r,n)&&Xh(r,i,i.next,n)&&Jh(r,n)&&Jh(n,r)&&(t.push(r.i/s|0),t.push(i.i/s|0),t.push(n.i/s|0),eu(i),eu(i.next),i=e=n),i=i.next}while(i!==e);return Ph(i)}function Lh(e,t,s,i,r,n){let o=e;do{let e=o.next.next;for(;e!==o.prev;){if(o.i!==e.i&&Hh(o,e)){let a=Kh(o,e);return o=Ph(o,o.next),a=Ph(a,a.next),Fh(o,t,s,i,r,n,0),void Fh(a,t,s,i,r,n,0)}e=e.next}o=o.next}while(o!==e)}function Vh(e,t){return e.x-t.x}function Dh(e,t){const s=function(e,t){let s,i=t,r=-1/0;const n=e.x,o=e.y;do{if(o<=i.y&&o>=i.next.y&&i.next.y!==i.y){const e=i.x+(o-i.y)*(i.next.x-i.x)/(i.next.y-i.y);if(e<=n&&e>r&&(r=e,s=i.x=i.x&&i.x>=h&&n!==i.x&&jh(os.x||i.x===s.x&&kh(s,i)))&&(s=i,c=l)),i=i.next}while(i!==a);return s}(e,t);if(!s)return t;const i=Kh(s,e);return Ph(i,i.next),Ph(s,s.next)}function kh(e,t){return qh(e.prev,e,t.prev)<0&&qh(t.next,e,e.next)<0}function Gh(e,t,s,i,r){return(e=1431655765&((e=858993459&((e=252645135&((e=16711935&((e=(e-s)*r|0)|e<<8))|e<<4))|e<<2))|e<<1))|(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=(t-i)*r|0)|t<<8))|t<<4))|t<<2))|t<<1))<<1}function Wh(e){let t=e,s=e;do{(t.x=(e-o)*(n-a)&&(e-o)*(i-a)>=(s-o)*(t-a)&&(s-o)*(n-a)>=(r-o)*(i-a)}function Hh(e,t){return e.next.i!==t.i&&e.prev.i!==t.i&&!function(e,t){let s=e;do{if(s.i!==e.i&&s.next.i!==e.i&&s.i!==t.i&&s.next.i!==t.i&&Xh(s,s.next,e,t))return!0;s=s.next}while(s!==e);return!1}(e,t)&&(Jh(e,t)&&Jh(t,e)&&function(e,t){let s=e,i=!1;const r=(e.x+t.x)/2,n=(e.y+t.y)/2;do{s.y>n!=s.next.y>n&&s.next.y!==s.y&&r<(s.next.x-s.x)*(n-s.y)/(s.next.y-s.y)+s.x&&(i=!i),s=s.next}while(s!==e);return i}(e,t)&&(qh(e.prev,e,t.prev)||qh(e,t.prev,t))||$h(e,t)&&qh(e.prev,e,e.next)>0&&qh(t.prev,t,t.next)>0)}function qh(e,t,s){return(t.y-e.y)*(s.x-t.x)-(t.x-e.x)*(s.y-t.y)}function $h(e,t){return e.x===t.x&&e.y===t.y}function Xh(e,t,s,i){const r=Zh(qh(e,t,s)),n=Zh(qh(e,t,i)),o=Zh(qh(s,i,e)),a=Zh(qh(s,i,t));return r!==n&&o!==a||(!(0!==r||!Yh(e,s,t))||(!(0!==n||!Yh(e,i,t))||(!(0!==o||!Yh(s,e,i))||!(0!==a||!Yh(s,t,i)))))}function Yh(e,t,s){return t.x<=Math.max(e.x,s.x)&&t.x>=Math.min(e.x,s.x)&&t.y<=Math.max(e.y,s.y)&&t.y>=Math.min(e.y,s.y)}function Zh(e){return e>0?1:e<0?-1:0}function Jh(e,t){return qh(e.prev,e,e.next)<0?qh(e,t,e.next)>=0&&qh(e,e.prev,t)>=0:qh(e,t,e.prev)<0||qh(e,e.next,t)<0}function Kh(e,t){const s=new tu(e.i,e.x,e.y),i=new tu(t.i,t.x,t.y),r=e.next,n=t.prev;return e.next=t,t.prev=e,s.next=r,r.prev=s,i.next=s,s.prev=i,n.next=i,i.prev=n,i}function Qh(e,t,s,i){const r=new tu(e,t,s);return i?(r.next=i.next,r.prev=i,i.next.prev=r,i.next=r):(r.prev=r,r.next=r),r}function eu(e){e.next.prev=e.prev,e.prev.next=e.next,e.prevZ&&(e.prevZ.nextZ=e.nextZ),e.nextZ&&(e.nextZ.prevZ=e.prevZ)}function tu(e,t,s){this.i=e,this.x=t,this.y=s,this.prev=null,this.next=null,this.z=0,this.prevZ=null,this.nextZ=null,this.steiner=!1}class su{static area(e){const t=e.length;let s=0;for(let i=t-1,r=0;r2&&e[t-1].equals(e[0])&&e.pop()}function ru(e,t){for(let s=0;sNumber.EPSILON){const c=Math.sqrt(l),d=Math.sqrt(h*h+u*u),p=t.x-a/c,m=t.y+o/c,g=((s.x-u/d-p)*u-(s.y+h/d-m)*h)/(o*u-a*h);i=p+o*g-e.x,r=m+a*g-e.y;const f=i*i+r*r;if(f<=2)return new Qs(i,r);n=Math.sqrt(f/2)}else{let e=!1;o>Number.EPSILON?h>Number.EPSILON&&(e=!0):o<-Number.EPSILON?h<-Number.EPSILON&&(e=!0):Math.sign(a)===Math.sign(u)&&(e=!0),e?(i=-a,r=o,n=Math.sqrt(l)):(i=o,r=a,n=Math.sqrt(l/2))}return new Qs(i/n,r/n)}const B=[];for(let e=0,t=N.length,s=t-1,i=e+1;e=0;e--){const t=e/p,s=l*Math.cos(t*Math.PI/2),i=c*Math.sin(t*Math.PI/2)+d;for(let e=0,t=N.length;e=0;){const i=s;let r=s-1;r<0&&(r=e.length-1);for(let e=0,s=a+2*p;e0)&&d.push(t,r,h),(e!==s-1||a0!=e>0&&this.version++,this._anisotropy=e}get clearcoat(){return this._clearcoat}set clearcoat(e){this._clearcoat>0!=e>0&&this.version++,this._clearcoat=e}get iridescence(){return this._iridescence}set iridescence(e){this._iridescence>0!=e>0&&this.version++,this._iridescence=e}get dispersion(){return this._dispersion}set dispersion(e){this._dispersion>0!=e>0&&this.version++,this._dispersion=e}get sheen(){return this._sheen}set sheen(e){this._sheen>0!=e>0&&this.version++,this._sheen=e}get transmission(){return this._transmission}set transmission(e){this._transmission>0!=e>0&&this.version++,this._transmission=e}copy(e){return super.copy(e),this.defines={STANDARD:"",PHYSICAL:""},this.anisotropy=e.anisotropy,this.anisotropyRotation=e.anisotropyRotation,this.anisotropyMap=e.anisotropyMap,this.clearcoat=e.clearcoat,this.clearcoatMap=e.clearcoatMap,this.clearcoatRoughness=e.clearcoatRoughness,this.clearcoatRoughnessMap=e.clearcoatRoughnessMap,this.clearcoatNormalMap=e.clearcoatNormalMap,this.clearcoatNormalScale.copy(e.clearcoatNormalScale),this.dispersion=e.dispersion,this.ior=e.ior,this.iridescence=e.iridescence,this.iridescenceMap=e.iridescenceMap,this.iridescenceIOR=e.iridescenceIOR,this.iridescenceThicknessRange=[...e.iridescenceThicknessRange],this.iridescenceThicknessMap=e.iridescenceThicknessMap,this.sheen=e.sheen,this.sheenColor.copy(e.sheenColor),this.sheenColorMap=e.sheenColorMap,this.sheenRoughness=e.sheenRoughness,this.sheenRoughnessMap=e.sheenRoughnessMap,this.transmission=e.transmission,this.transmissionMap=e.transmissionMap,this.thickness=e.thickness,this.thicknessMap=e.thicknessMap,this.attenuationDistance=e.attenuationDistance,this.attenuationColor.copy(e.attenuationColor),this.specularIntensity=e.specularIntensity,this.specularIntensityMap=e.specularIntensityMap,this.specularColor.copy(e.specularColor),this.specularColorMap=e.specularColorMap,this}}class Su extends en{constructor(e){super(),this.isMeshPhongMaterial=!0,this.type="MeshPhongMaterial",this.color=new Jr(16777215),this.specular=new Jr(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Jr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new gr,this.combine=0,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.specular.copy(e.specular),this.shininess=e.shininess,this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.flatShading=e.flatShading,this.fog=e.fog,this}}class Mu extends en{constructor(e){super(),this.isMeshToonMaterial=!0,this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new Jr(16777215),this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Jr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.gradientMap=e.gradientMap,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}}class Nu extends en{constructor(e){super(),this.isMeshNormalMaterial=!0,this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.flatShading=!1,this.setValues(e)}copy(e){return super.copy(e),this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.flatShading=e.flatShading,this}}class Au extends en{constructor(e){super(),this.isMeshLambertMaterial=!0,this.type="MeshLambertMaterial",this.color=new Jr(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Jr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new gr,this.combine=0,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.flatShading=e.flatShading,this.fog=e.fog,this}}class Cu extends en{constructor(e){super(),this.isMeshDepthMaterial=!0,this.type="MeshDepthMaterial",this.depthPacking=3200,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.setValues(e)}copy(e){return super.copy(e),this.depthPacking=e.depthPacking,this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this}}class Ru extends en{constructor(e){super(),this.isMeshDistanceMaterial=!0,this.type="MeshDistanceMaterial",this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.setValues(e)}copy(e){return super.copy(e),this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this}}class Eu extends en{constructor(e){super(),this.isMeshMatcapMaterial=!0,this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new Jr(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.defines={MATCAP:""},this.color.copy(e.color),this.matcap=e.matcap,this.map=e.map,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.flatShading=e.flatShading,this.fog=e.fog,this}}class Bu extends Ta{constructor(e){super(),this.isLineDashedMaterial=!0,this.type="LineDashedMaterial",this.scale=1,this.dashSize=3,this.gapSize=1,this.setValues(e)}copy(e){return super.copy(e),this.scale=e.scale,this.dashSize=e.dashSize,this.gapSize=e.gapSize,this}}function Iu(e,t,s){return!e||!s&&e.constructor===t?e:"number"==typeof t.BYTES_PER_ELEMENT?new t(e):Array.prototype.slice.call(e)}function Pu(e){return ArrayBuffer.isView(e)&&!(e instanceof DataView)}function Fu(e){const t=e.length,s=new Array(t);for(let e=0;e!==t;++e)s[e]=e;return s.sort((function(t,s){return e[t]-e[s]})),s}function zu(e,t,s){const i=e.length,r=new e.constructor(i);for(let n=0,o=0;o!==i;++n){const i=s[n]*t;for(let s=0;s!==t;++s)r[o++]=e[i+s]}return r}function Uu(e,t,s,i){let r=1,n=e[0];for(;void 0!==n&&void 0===n[i];)n=e[r++];if(void 0===n)return;let o=n[i];if(void 0!==o)if(Array.isArray(o))do{o=n[i],void 0!==o&&(t.push(n.time),s.push.apply(s,o)),n=e[r++]}while(void 0!==n);else if(void 0!==o.toArray)do{o=n[i],void 0!==o&&(t.push(n.time),o.toArray(s,s.length)),n=e[r++]}while(void 0!==n);else do{o=n[i],void 0!==o&&(t.push(n.time),s.push(o)),n=e[r++]}while(void 0!==n)}const Ou={convertArray:Iu,isTypedArray:Pu,getKeyframeOrder:Fu,sortedArray:zu,flattenJSON:Uu,subclip:function(e,t,s,i,r=30){const n=e.clone();n.name=t;const o=[];for(let e=0;e=i)){h.push(t.times[e]);for(let s=0;sn.tracks[e].times[0]&&(a=n.tracks[e].times[0]);for(let e=0;e=i.times[c]){const e=c*h+a,t=e+h-a;d=i.values.slice(e,t)}else{const e=i.createInterpolant(),t=a,s=h-a;e.evaluate(n),d=e.resultBuffer.slice(t,s)}if("quaternion"===r){(new Ci).fromArray(d).normalize().conjugate().toArray(d)}const p=o.times.length;for(let e=0;e=r)break e;{const o=t[1];e=r)break t}n=s,s=0}}for(;s>>1;et;)--n;if(++n,0!==r||n!==i){r>=n&&(n=Math.max(n,1),r=n-1);const e=this.getValueSize();this.times=s.slice(r,n),this.values=this.values.slice(r*e,n*e)}return this}validate(){let e=!0;const t=this.getValueSize();t-Math.floor(t)!=0&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),e=!1);const s=this.times,i=this.values,r=s.length;0===r&&(console.error("THREE.KeyframeTrack: Track is empty.",this),e=!1);let n=null;for(let t=0;t!==r;t++){const i=s[t];if("number"==typeof i&&isNaN(i)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,t,i),e=!1;break}if(null!==n&&n>i){console.error("THREE.KeyframeTrack: Out of order keys.",this,t,i,n),e=!1;break}n=i}if(void 0!==i&&Pu(i))for(let t=0,s=i.length;t!==s;++t){const s=i[t];if(isNaN(s)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,t,s),e=!1;break}}return e}optimize(){const e=this.times.slice(),t=this.values.slice(),s=this.getValueSize(),i=this.getInterpolation()===Ft,r=e.length-1;let n=1;for(let o=1;o0){e[n]=e[r];for(let e=r*s,i=n*s,o=0;o!==s;++o)t[i+o]=t[e+o];++n}return n!==e.length?(this.times=e.slice(0,n),this.values=t.slice(0,n*s)):(this.times=e,this.values=t),this}clone(){const e=this.times.slice(),t=this.values.slice(),s=new(0,this.constructor)(this.name,e,t);return s.createInterpolant=this.createInterpolant,s}}Gu.prototype.TimeBufferType=Float32Array,Gu.prototype.ValueBufferType=Float32Array,Gu.prototype.DefaultInterpolation=Pt;class Wu extends Gu{constructor(e,t,s){super(e,t,s)}}Wu.prototype.ValueTypeName="bool",Wu.prototype.ValueBufferType=Array,Wu.prototype.DefaultInterpolation=It,Wu.prototype.InterpolantFactoryMethodLinear=void 0,Wu.prototype.InterpolantFactoryMethodSmooth=void 0;class ju extends Gu{}ju.prototype.ValueTypeName="color";class Hu extends Gu{}Hu.prototype.ValueTypeName="number";class qu extends Lu{constructor(e,t,s,i){super(e,t,s,i)}interpolate_(e,t,s,i){const r=this.resultBuffer,n=this.sampleValues,o=this.valueSize,a=(s-t)/(i-t);let h=e*o;for(let e=h+o;h!==e;h+=4)Ci.slerpFlat(r,0,n,h-o,n,h,a);return r}}class $u extends Gu{InterpolantFactoryMethodLinear(e){return new qu(this.times,this.values,this.getValueSize(),e)}}$u.prototype.ValueTypeName="quaternion",$u.prototype.InterpolantFactoryMethodSmooth=void 0;class Xu extends Gu{constructor(e,t,s){super(e,t,s)}}Xu.prototype.ValueTypeName="string",Xu.prototype.ValueBufferType=Array,Xu.prototype.DefaultInterpolation=It,Xu.prototype.InterpolantFactoryMethodLinear=void 0,Xu.prototype.InterpolantFactoryMethodSmooth=void 0;class Yu extends Gu{}Yu.prototype.ValueTypeName="vector";class Zu{constructor(e="",t=-1,s=[],i=2500){this.name=e,this.tracks=s,this.duration=t,this.blendMode=i,this.uuid=qs(),this.duration<0&&this.resetDuration()}static parse(e){const t=[],s=e.tracks,i=1/(e.fps||1);for(let e=0,r=s.length;e!==r;++e)t.push(Ju(s[e]).scale(i));const r=new this(e.name,e.duration,t,e.blendMode);return r.uuid=e.uuid,r}static toJSON(e){const t=[],s=e.tracks,i={name:e.name,duration:e.duration,tracks:t,uuid:e.uuid,blendMode:e.blendMode};for(let e=0,i=s.length;e!==i;++e)t.push(Gu.toJSON(s[e]));return i}static CreateFromMorphTargetSequence(e,t,s,i){const r=t.length,n=[];for(let e=0;e1){const e=n[1];let t=i[e];t||(i[e]=t=[]),t.push(s)}}const n=[];for(const e in i)n.push(this.CreateFromMorphTargetSequence(e,i[e],t,s));return n}static parseAnimation(e,t){if(!e)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;const s=function(e,t,s,i,r){if(0!==s.length){const n=[],o=[];Uu(s,n,o,i),0!==n.length&&r.push(new e(t,n,o))}},i=[],r=e.name||"default",n=e.fps||30,o=e.blendMode;let a=e.length||-1;const h=e.hierarchy||[];for(let e=0;e{t&&t(r),this.manager.itemEnd(e)}),0),r;if(void 0!==sl[e])return void sl[e].push({onLoad:t,onProgress:s,onError:i});sl[e]=[],sl[e].push({onLoad:t,onProgress:s,onError:i});const n=new Request(e,{headers:new Headers(this.requestHeader),credentials:this.withCredentials?"include":"same-origin"}),o=this.mimeType,a=this.responseType;fetch(n).then((t=>{if(200===t.status||0===t.status){if(0===t.status&&console.warn("THREE.FileLoader: HTTP Status 0 received."),"undefined"==typeof ReadableStream||void 0===t.body||void 0===t.body.getReader)return t;const s=sl[e],i=t.body.getReader(),r=t.headers.get("X-File-Size")||t.headers.get("Content-Length"),n=r?parseInt(r):0,o=0!==n;let a=0;const h=new ReadableStream({start(e){!function t(){i.read().then((({done:i,value:r})=>{if(i)e.close();else{a+=r.byteLength;const i=new ProgressEvent("progress",{lengthComputable:o,loaded:a,total:n});for(let e=0,t=s.length;e{e.error(t)}))}()}});return new Response(h)}throw new il(`fetch for "${t.url}" responded with ${t.status}: ${t.statusText}`,t)})).then((e=>{switch(a){case"arraybuffer":return e.arrayBuffer();case"blob":return e.blob();case"document":return e.text().then((e=>(new DOMParser).parseFromString(e,o)));case"json":return e.json();default:if(void 0===o)return e.text();{const t=/charset="?([^;"\s]*)"?/i.exec(o),s=t&&t[1]?t[1].toLowerCase():void 0,i=new TextDecoder(s);return e.arrayBuffer().then((e=>i.decode(e)))}}})).then((t=>{Ku.add(e,t);const s=sl[e];delete sl[e];for(let e=0,i=s.length;e{const s=sl[e];if(void 0===s)throw this.manager.itemError(e),t;delete sl[e];for(let e=0,i=s.length;e{this.manager.itemEnd(e)})),this.manager.itemStart(e)}setResponseType(e){return this.responseType=e,this}setMimeType(e){return this.mimeType=e,this}}class nl extends tl{constructor(e){super(e)}load(e,t,s,i){const r=this,n=new rl(this.manager);n.setPath(this.path),n.setRequestHeader(this.requestHeader),n.setWithCredentials(this.withCredentials),n.load(e,(function(s){try{t(r.parse(JSON.parse(s)))}catch(t){i?i(t):console.error(t),r.manager.itemError(e)}}),s,i)}parse(e){const t=[];for(let s=0;s0:i.vertexColors=e.vertexColors),void 0!==e.uniforms)for(const t in e.uniforms){const r=e.uniforms[t];switch(i.uniforms[t]={},r.type){case"t":i.uniforms[t].value=s(r.value);break;case"c":i.uniforms[t].value=(new Jr).setHex(r.value);break;case"v2":i.uniforms[t].value=(new Qs).fromArray(r.value);break;case"v3":i.uniforms[t].value=(new Ri).fromArray(r.value);break;case"v4":i.uniforms[t].value=(new Ti).fromArray(r.value);break;case"m3":i.uniforms[t].value=(new ei).fromArray(r.value);break;case"m4":i.uniforms[t].value=(new nr).fromArray(r.value);break;default:i.uniforms[t].value=r.value}}if(void 0!==e.defines&&(i.defines=e.defines),void 0!==e.vertexShader&&(i.vertexShader=e.vertexShader),void 0!==e.fragmentShader&&(i.fragmentShader=e.fragmentShader),void 0!==e.glslVersion&&(i.glslVersion=e.glslVersion),void 0!==e.extensions)for(const t in e.extensions)i.extensions[t]=e.extensions[t];if(void 0!==e.lights&&(i.lights=e.lights),void 0!==e.clipping&&(i.clipping=e.clipping),void 0!==e.size&&(i.size=e.size),void 0!==e.sizeAttenuation&&(i.sizeAttenuation=e.sizeAttenuation),void 0!==e.map&&(i.map=s(e.map)),void 0!==e.matcap&&(i.matcap=s(e.matcap)),void 0!==e.alphaMap&&(i.alphaMap=s(e.alphaMap)),void 0!==e.bumpMap&&(i.bumpMap=s(e.bumpMap)),void 0!==e.bumpScale&&(i.bumpScale=e.bumpScale),void 0!==e.normalMap&&(i.normalMap=s(e.normalMap)),void 0!==e.normalMapType&&(i.normalMapType=e.normalMapType),void 0!==e.normalScale){let t=e.normalScale;!1===Array.isArray(t)&&(t=[t,t]),i.normalScale=(new Qs).fromArray(t)}return void 0!==e.displacementMap&&(i.displacementMap=s(e.displacementMap)),void 0!==e.displacementScale&&(i.displacementScale=e.displacementScale),void 0!==e.displacementBias&&(i.displacementBias=e.displacementBias),void 0!==e.roughnessMap&&(i.roughnessMap=s(e.roughnessMap)),void 0!==e.metalnessMap&&(i.metalnessMap=s(e.metalnessMap)),void 0!==e.emissiveMap&&(i.emissiveMap=s(e.emissiveMap)),void 0!==e.emissiveIntensity&&(i.emissiveIntensity=e.emissiveIntensity),void 0!==e.specularMap&&(i.specularMap=s(e.specularMap)),void 0!==e.specularIntensityMap&&(i.specularIntensityMap=s(e.specularIntensityMap)),void 0!==e.specularColorMap&&(i.specularColorMap=s(e.specularColorMap)),void 0!==e.envMap&&(i.envMap=s(e.envMap)),void 0!==e.envMapRotation&&i.envMapRotation.fromArray(e.envMapRotation),void 0!==e.envMapIntensity&&(i.envMapIntensity=e.envMapIntensity),void 0!==e.reflectivity&&(i.reflectivity=e.reflectivity),void 0!==e.refractionRatio&&(i.refractionRatio=e.refractionRatio),void 0!==e.lightMap&&(i.lightMap=s(e.lightMap)),void 0!==e.lightMapIntensity&&(i.lightMapIntensity=e.lightMapIntensity),void 0!==e.aoMap&&(i.aoMap=s(e.aoMap)),void 0!==e.aoMapIntensity&&(i.aoMapIntensity=e.aoMapIntensity),void 0!==e.gradientMap&&(i.gradientMap=s(e.gradientMap)),void 0!==e.clearcoatMap&&(i.clearcoatMap=s(e.clearcoatMap)),void 0!==e.clearcoatRoughnessMap&&(i.clearcoatRoughnessMap=s(e.clearcoatRoughnessMap)),void 0!==e.clearcoatNormalMap&&(i.clearcoatNormalMap=s(e.clearcoatNormalMap)),void 0!==e.clearcoatNormalScale&&(i.clearcoatNormalScale=(new Qs).fromArray(e.clearcoatNormalScale)),void 0!==e.iridescenceMap&&(i.iridescenceMap=s(e.iridescenceMap)),void 0!==e.iridescenceThicknessMap&&(i.iridescenceThicknessMap=s(e.iridescenceThicknessMap)),void 0!==e.transmissionMap&&(i.transmissionMap=s(e.transmissionMap)),void 0!==e.thicknessMap&&(i.thicknessMap=s(e.thicknessMap)),void 0!==e.anisotropyMap&&(i.anisotropyMap=s(e.anisotropyMap)),void 0!==e.sheenColorMap&&(i.sheenColorMap=s(e.sheenColorMap)),void 0!==e.sheenRoughnessMap&&(i.sheenRoughnessMap=s(e.sheenRoughnessMap)),i}setTextures(e){return this.textures=e,this}createMaterialFromType(e){return Bl.createMaterialFromType(e)}static createMaterialFromType(e){return new{ShadowMaterial:vu,SpriteMaterial:no,RawShaderMaterial:Tu,ShaderMaterial:Wn,PointsMaterial:za,MeshPhysicalMaterial:wu,MeshStandardMaterial:_u,MeshPhongMaterial:Su,MeshToonMaterial:Mu,MeshNormalMaterial:Nu,MeshLambertMaterial:Au,MeshDepthMaterial:Cu,MeshDistanceMaterial:Ru,MeshBasicMaterial:tn,MeshMatcapMaterial:Eu,LineDashedMaterial:Bu,LineBasicMaterial:Ta,Material:en}[e]}}class Il{static decodeText(e){if(console.warn("THREE.LoaderUtils: decodeText() has been deprecated with r165 and will be removed with r175. Use TextDecoder instead."),"undefined"!=typeof TextDecoder)return(new TextDecoder).decode(e);let t="";for(let s=0,i=e.length;s0){const s=new Qu(t);r=new al(s),r.setCrossOrigin(this.crossOrigin);for(let t=0,s=e.length;t0){i=new al(this.manager),i.setCrossOrigin(this.crossOrigin);for(let t=0,i=e.length;t{const t=new Ii;t.min.fromArray(e.boxMin),t.max.fromArray(e.boxMax);const s=new Zi;return s.radius=e.sphereRadius,s.center.fromArray(e.sphereCenter),{boxInitialized:e.boxInitialized,box:t,sphereInitialized:e.sphereInitialized,sphere:s}})),n._maxInstanceCount=e.maxInstanceCount,n._maxVertexCount=e.maxVertexCount,n._maxIndexCount=e.maxIndexCount,n._geometryInitialized=e.geometryInitialized,n._geometryCount=e.geometryCount,n._matricesTexture=l(e.matricesTexture.uuid),void 0!==e.colorsTexture&&(n._colorsTexture=l(e.colorsTexture.uuid));break;case"LOD":n=new So;break;case"Line":n=new Ra(h(e.geometry),u(e.material));break;case"LineLoop":n=new Fa(h(e.geometry),u(e.material));break;case"LineSegments":n=new Pa(h(e.geometry),u(e.material));break;case"PointCloud":case"Points":n=new Da(h(e.geometry),u(e.material));break;case"Sprite":n=new vo(u(e.material));break;case"Group":n=new Ga;break;case"Bone":n=new zo;break;default:n=new Ir}if(n.uuid=e.uuid,void 0!==e.name&&(n.name=e.name),void 0!==e.matrix?(n.matrix.fromArray(e.matrix),void 0!==e.matrixAutoUpdate&&(n.matrixAutoUpdate=e.matrixAutoUpdate),n.matrixAutoUpdate&&n.matrix.decompose(n.position,n.quaternion,n.scale)):(void 0!==e.position&&n.position.fromArray(e.position),void 0!==e.rotation&&n.rotation.fromArray(e.rotation),void 0!==e.quaternion&&n.quaternion.fromArray(e.quaternion),void 0!==e.scale&&n.scale.fromArray(e.scale)),void 0!==e.up&&n.up.fromArray(e.up),void 0!==e.castShadow&&(n.castShadow=e.castShadow),void 0!==e.receiveShadow&&(n.receiveShadow=e.receiveShadow),e.shadow&&(void 0!==e.shadow.intensity&&(n.shadow.intensity=e.shadow.intensity),void 0!==e.shadow.bias&&(n.shadow.bias=e.shadow.bias),void 0!==e.shadow.normalBias&&(n.shadow.normalBias=e.shadow.normalBias),void 0!==e.shadow.radius&&(n.shadow.radius=e.shadow.radius),void 0!==e.shadow.mapSize&&n.shadow.mapSize.fromArray(e.shadow.mapSize),void 0!==e.shadow.camera&&(n.shadow.camera=this.parseObject(e.shadow.camera))),void 0!==e.visible&&(n.visible=e.visible),void 0!==e.frustumCulled&&(n.frustumCulled=e.frustumCulled),void 0!==e.renderOrder&&(n.renderOrder=e.renderOrder),void 0!==e.userData&&(n.userData=e.userData),void 0!==e.layers&&(n.layers.mask=e.layers),void 0!==e.children){const o=e.children;for(let e=0;e{t&&t(s),r.manager.itemEnd(e)})).catch((e=>{i&&i(e)})):(setTimeout((function(){t&&t(n),r.manager.itemEnd(e)}),0),n);const o={};o.credentials="anonymous"===this.crossOrigin?"same-origin":"include",o.headers=this.requestHeader;const a=fetch(e,o).then((function(e){return e.blob()})).then((function(e){return createImageBitmap(e,Object.assign(r.options,{colorSpaceConversion:"none"}))})).then((function(s){return Ku.add(e,s),t&&t(s),r.manager.itemEnd(e),s})).catch((function(t){i&&i(t),Ku.remove(e),r.manager.itemError(e),r.manager.itemEnd(e)}));Ku.add(e,a),r.manager.itemStart(e)}}let Dl;class kl{static getContext(){return void 0===Dl&&(Dl=new(window.AudioContext||window.webkitAudioContext)),Dl}static setContext(e){Dl=e}}class Gl extends tl{constructor(e){super(e)}load(e,t,s,i){const r=this,n=new rl(this.manager);function o(t){i?i(t):console.error(t),r.manager.itemError(e)}n.setResponseType("arraybuffer"),n.setPath(this.path),n.setRequestHeader(this.requestHeader),n.setWithCredentials(this.withCredentials),n.load(e,(function(e){try{const s=e.slice(0);kl.getContext().decodeAudioData(s,(function(e){t(e)})).catch(o)}catch(e){o(e)}}),s,i)}}const Wl=new nr,jl=new nr,Hl=new nr;class ql{constructor(){this.type="StereoCamera",this.aspect=1,this.eyeSep=.064,this.cameraL=new Xn,this.cameraL.layers.enable(1),this.cameraL.matrixAutoUpdate=!1,this.cameraR=new Xn,this.cameraR.layers.enable(2),this.cameraR.matrixAutoUpdate=!1,this._cache={focus:null,fov:null,aspect:null,near:null,far:null,zoom:null,eyeSep:null}}update(e){const t=this._cache;if(t.focus!==e.focus||t.fov!==e.fov||t.aspect!==e.aspect*this.aspect||t.near!==e.near||t.far!==e.far||t.zoom!==e.zoom||t.eyeSep!==this.eyeSep){t.focus=e.focus,t.fov=e.fov,t.aspect=e.aspect*this.aspect,t.near=e.near,t.far=e.far,t.zoom=e.zoom,t.eyeSep=this.eyeSep,Hl.copy(e.projectionMatrix);const s=t.eyeSep/2,i=s*t.near/t.focus,r=t.near*Math.tan(js*t.fov*.5)/t.zoom;let n,o;jl.elements[12]=-s,Wl.elements[12]=s,n=-r*t.aspect+i,o=r*t.aspect+i,Hl.elements[0]=2*t.near/(o-n),Hl.elements[8]=(o+n)/(o-n),this.cameraL.projectionMatrix.copy(Hl),n=-r*t.aspect-i,o=r*t.aspect-i,Hl.elements[0]=2*t.near/(o-n),Hl.elements[8]=(o+n)/(o-n),this.cameraR.projectionMatrix.copy(Hl)}this.cameraL.matrixWorld.copy(e.matrixWorld).multiply(jl),this.cameraR.matrixWorld.copy(e.matrixWorld).multiply(Wl)}}class $l extends Xn{constructor(e=[]){super(),this.isArrayCamera=!0,this.cameras=e}}class Xl{constructor(e=!0){this.autoStart=e,this.startTime=0,this.oldTime=0,this.elapsedTime=0,this.running=!1}start(){this.startTime=Yl(),this.oldTime=this.startTime,this.elapsedTime=0,this.running=!0}stop(){this.getElapsedTime(),this.running=!1,this.autoStart=!1}getElapsedTime(){return this.getDelta(),this.elapsedTime}getDelta(){let e=0;if(this.autoStart&&!this.running)return this.start(),0;if(this.running){const t=Yl();e=(t-this.oldTime)/1e3,this.oldTime=t,this.elapsedTime+=e}return e}}function Yl(){return performance.now()}const Zl=new Ri,Jl=new Ci,Kl=new Ri,Ql=new Ri;class ec extends Ir{constructor(){super(),this.type="AudioListener",this.context=kl.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._clock=new Xl}getInput(){return this.gain}removeFilter(){return null!==this.filter&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null),this}getFilter(){return this.filter}setFilter(e){return null!==this.filter?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination),this.filter=e,this.gain.connect(this.filter),this.filter.connect(this.context.destination),this}getMasterVolume(){return this.gain.gain.value}setMasterVolume(e){return this.gain.gain.setTargetAtTime(e,this.context.currentTime,.01),this}updateMatrixWorld(e){super.updateMatrixWorld(e);const t=this.context.listener,s=this.up;if(this.timeDelta=this._clock.getDelta(),this.matrixWorld.decompose(Zl,Jl,Kl),Ql.set(0,0,-1).applyQuaternion(Jl),t.positionX){const e=this.context.currentTime+this.timeDelta;t.positionX.linearRampToValueAtTime(Zl.x,e),t.positionY.linearRampToValueAtTime(Zl.y,e),t.positionZ.linearRampToValueAtTime(Zl.z,e),t.forwardX.linearRampToValueAtTime(Ql.x,e),t.forwardY.linearRampToValueAtTime(Ql.y,e),t.forwardZ.linearRampToValueAtTime(Ql.z,e),t.upX.linearRampToValueAtTime(s.x,e),t.upY.linearRampToValueAtTime(s.y,e),t.upZ.linearRampToValueAtTime(s.z,e)}else t.setPosition(Zl.x,Zl.y,Zl.z),t.setOrientation(Ql.x,Ql.y,Ql.z,s.x,s.y,s.z)}}class tc extends Ir{constructor(e){super(),this.type="Audio",this.listener=e,this.context=e.context,this.gain=this.context.createGain(),this.gain.connect(e.getInput()),this.autoplay=!1,this.buffer=null,this.detune=0,this.loop=!1,this.loopStart=0,this.loopEnd=0,this.offset=0,this.duration=void 0,this.playbackRate=1,this.isPlaying=!1,this.hasPlaybackControl=!0,this.source=null,this.sourceType="empty",this._startedAt=0,this._progress=0,this._connected=!1,this.filters=[]}getOutput(){return this.gain}setNodeSource(e){return this.hasPlaybackControl=!1,this.sourceType="audioNode",this.source=e,this.connect(),this}setMediaElementSource(e){return this.hasPlaybackControl=!1,this.sourceType="mediaNode",this.source=this.context.createMediaElementSource(e),this.connect(),this}setMediaStreamSource(e){return this.hasPlaybackControl=!1,this.sourceType="mediaStreamNode",this.source=this.context.createMediaStreamSource(e),this.connect(),this}setBuffer(e){return this.buffer=e,this.sourceType="buffer",this.autoplay&&this.play(),this}play(e=0){if(!0===this.isPlaying)return void console.warn("THREE.Audio: Audio is already playing.");if(!1===this.hasPlaybackControl)return void console.warn("THREE.Audio: this Audio has no playback control.");this._startedAt=this.context.currentTime+e;const t=this.context.createBufferSource();return t.buffer=this.buffer,t.loop=this.loop,t.loopStart=this.loopStart,t.loopEnd=this.loopEnd,t.onended=this.onEnded.bind(this),t.start(this._startedAt,this._progress+this.offset,this.duration),this.isPlaying=!0,this.source=t,this.setDetune(this.detune),this.setPlaybackRate(this.playbackRate),this.connect()}pause(){if(!1!==this.hasPlaybackControl)return!0===this.isPlaying&&(this._progress+=Math.max(this.context.currentTime-this._startedAt,0)*this.playbackRate,!0===this.loop&&(this._progress=this._progress%(this.duration||this.buffer.duration)),this.source.stop(),this.source.onended=null,this.isPlaying=!1),this;console.warn("THREE.Audio: this Audio has no playback control.")}stop(e=0){if(!1!==this.hasPlaybackControl)return this._progress=0,null!==this.source&&(this.source.stop(this.context.currentTime+e),this.source.onended=null),this.isPlaying=!1,this;console.warn("THREE.Audio: this Audio has no playback control.")}connect(){if(this.filters.length>0){this.source.connect(this.filters[0]);for(let e=1,t=this.filters.length;e0){this.source.disconnect(this.filters[0]);for(let e=1,t=this.filters.length;e0&&this._mixBufferRegionAdditive(s,i,this._addIndex*t,1,t);for(let e=t,r=t+t;e!==r;++e)if(s[e]!==s[e+t]){o.setValue(s,i);break}}saveOriginalState(){const e=this.binding,t=this.buffer,s=this.valueSize,i=s*this._origIndex;e.getValue(t,i);for(let e=s,r=i;e!==r;++e)t[e]=t[i+e%s];this._setIdentity(),this.cumulativeWeight=0,this.cumulativeWeightAdditive=0}restoreOriginalState(){const e=3*this.valueSize;this.binding.setValue(this.buffer,e)}_setAdditiveIdentityNumeric(){const e=this._addIndex*this.valueSize,t=e+this.valueSize;for(let s=e;s=.5)for(let i=0;i!==r;++i)e[t+i]=e[s+i]}_slerp(e,t,s,i){Ci.slerpFlat(e,t,e,t,e,s,i)}_slerpAdditive(e,t,s,i,r){const n=this._workIndex*r;Ci.multiplyQuaternionsFlat(e,n,e,t,e,s),Ci.slerpFlat(e,t,e,t,e,n,i)}_lerp(e,t,s,i,r){const n=1-i;for(let o=0;o!==r;++o){const r=t+o;e[r]=e[r]*n+e[s+o]*i}}_lerpAdditive(e,t,s,i,r){for(let n=0;n!==r;++n){const r=t+n;e[r]=e[r]+e[s+n]*i}}}const uc="\\[\\]\\.:\\/",lc=new RegExp("["+uc+"]","g"),cc="[^"+uc+"]",dc="[^"+uc.replace("\\.","")+"]",pc=new RegExp("^"+/((?:WC+[\/:])*)/.source.replace("WC",cc)+/(WCOD+)?/.source.replace("WCOD",dc)+/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",cc)+/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",cc)+"$"),mc=["material","materials","bones","map"];class gc{constructor(e,t,s){this.path=t,this.parsedPath=s||gc.parseTrackName(t),this.node=gc.findNode(e,this.parsedPath.nodeName),this.rootNode=e,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(e,t,s){return e&&e.isAnimationObjectGroup?new gc.Composite(e,t,s):new gc(e,t,s)}static sanitizeNodeName(e){return e.replace(/\s/g,"_").replace(lc,"")}static parseTrackName(e){const t=pc.exec(e);if(null===t)throw new Error("PropertyBinding: Cannot parse trackName: "+e);const s={nodeName:t[2],objectName:t[3],objectIndex:t[4],propertyName:t[5],propertyIndex:t[6]},i=s.nodeName&&s.nodeName.lastIndexOf(".");if(void 0!==i&&-1!==i){const e=s.nodeName.substring(i+1);-1!==mc.indexOf(e)&&(s.nodeName=s.nodeName.substring(0,i),s.objectName=e)}if(null===s.propertyName||0===s.propertyName.length)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+e);return s}static findNode(e,t){if(void 0===t||""===t||"."===t||-1===t||t===e.name||t===e.uuid)return e;if(e.skeleton){const s=e.skeleton.getBoneByName(t);if(void 0!==s)return s}if(e.children){const s=function(e){for(let i=0;i=r){const n=r++,u=e[n];t[u.uuid]=h,e[h]=u,t[a]=n,e[n]=o;for(let e=0,t=i;e!==t;++e){const t=s[e],i=t[n],r=t[h];t[h]=i,t[n]=r}}}this.nCachedObjects_=r}uncache(){const e=this._objects,t=this._indicesByUUID,s=this._bindings,i=s.length;let r=this.nCachedObjects_,n=e.length;for(let o=0,a=arguments.length;o!==a;++o){const a=arguments[o].uuid,h=t[a];if(void 0!==h)if(delete t[a],h0&&(t[o.uuid]=h),e[h]=o,e.pop();for(let e=0,t=i;e!==t;++e){const t=s[e];t[h]=t[r],t.pop()}}}this.nCachedObjects_=r}subscribe_(e,t){const s=this._bindingsIndicesByPath;let i=s[e];const r=this._bindings;if(void 0!==i)return r[i];const n=this._paths,o=this._parsedPaths,a=this._objects,h=a.length,u=this.nCachedObjects_,l=new Array(h);i=r.length,s[e]=i,n.push(e),o.push(t),r.push(l);for(let s=u,i=a.length;s!==i;++s){const i=a[s];l[s]=new gc(i,e,t)}return l}unsubscribe_(e){const t=this._bindingsIndicesByPath,s=t[e];if(void 0!==s){const i=this._paths,r=this._parsedPaths,n=this._bindings,o=n.length-1,a=n[o];t[e[o]]=s,n[s]=a,n.pop(),r[s]=r[o],r.pop(),i[s]=i[o],i.pop()}}}class yc{constructor(e,t,s=null,i=t.blendMode){this._mixer=e,this._clip=t,this._localRoot=s,this.blendMode=i;const r=t.tracks,n=r.length,o=new Array(n),a={endingStart:zt,endingEnd:zt};for(let e=0;e!==n;++e){const t=r[e].createInterpolant(null);o[e]=t,t.settings=a}this._interpolantSettings=a,this._interpolants=o,this._propertyBindings=new Array(n),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=2201,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}play(){return this._mixer._activateAction(this),this}stop(){return this._mixer._deactivateAction(this),this.reset()}reset(){return this.paused=!1,this.enabled=!0,this.time=0,this._loopCount=-1,this._startTime=null,this.stopFading().stopWarping()}isRunning(){return this.enabled&&!this.paused&&0!==this.timeScale&&null===this._startTime&&this._mixer._isActiveAction(this)}isScheduled(){return this._mixer._isActiveAction(this)}startAt(e){return this._startTime=e,this}setLoop(e,t){return this.loop=e,this.repetitions=t,this}setEffectiveWeight(e){return this.weight=e,this._effectiveWeight=this.enabled?e:0,this.stopFading()}getEffectiveWeight(){return this._effectiveWeight}fadeIn(e){return this._scheduleFading(e,0,1)}fadeOut(e){return this._scheduleFading(e,1,0)}crossFadeFrom(e,t,s){if(e.fadeOut(t),this.fadeIn(t),s){const s=this._clip.duration,i=e._clip.duration,r=i/s,n=s/i;e.warp(1,r,t),this.warp(n,1,t)}return this}crossFadeTo(e,t,s){return e.crossFadeFrom(this,t,s)}stopFading(){const e=this._weightInterpolant;return null!==e&&(this._weightInterpolant=null,this._mixer._takeBackControlInterpolant(e)),this}setEffectiveTimeScale(e){return this.timeScale=e,this._effectiveTimeScale=this.paused?0:e,this.stopWarping()}getEffectiveTimeScale(){return this._effectiveTimeScale}setDuration(e){return this.timeScale=this._clip.duration/e,this.stopWarping()}syncWith(e){return this.time=e.time,this.timeScale=e.timeScale,this.stopWarping()}halt(e){return this.warp(this._effectiveTimeScale,0,e)}warp(e,t,s){const i=this._mixer,r=i.time,n=this.timeScale;let o=this._timeScaleInterpolant;null===o&&(o=i._lendControlInterpolant(),this._timeScaleInterpolant=o);const a=o.parameterPositions,h=o.sampleValues;return a[0]=r,a[1]=r+s,h[0]=e/n,h[1]=t/n,this}stopWarping(){const e=this._timeScaleInterpolant;return null!==e&&(this._timeScaleInterpolant=null,this._mixer._takeBackControlInterpolant(e)),this}getMixer(){return this._mixer}getClip(){return this._clip}getRoot(){return this._localRoot||this._mixer._root}_update(e,t,s,i){if(!this.enabled)return void this._updateWeight(e);const r=this._startTime;if(null!==r){const i=(e-r)*s;i<0||0===s?t=0:(this._startTime=null,t=s*i)}t*=this._updateTimeScale(e);const n=this._updateTime(t),o=this._updateWeight(e);if(o>0){const e=this._interpolants,t=this._propertyBindings;if(this.blendMode===Vt)for(let s=0,i=e.length;s!==i;++s)e[s].evaluate(n),t[s].accumulateAdditive(o);else for(let s=0,r=e.length;s!==r;++s)e[s].evaluate(n),t[s].accumulate(i,o)}}_updateWeight(e){let t=0;if(this.enabled){t=this.weight;const s=this._weightInterpolant;if(null!==s){const i=s.evaluate(e)[0];t*=i,e>s.parameterPositions[1]&&(this.stopFading(),0===i&&(this.enabled=!1))}}return this._effectiveWeight=t,t}_updateTimeScale(e){let t=0;if(!this.paused){t=this.timeScale;const s=this._timeScaleInterpolant;if(null!==s){t*=s.evaluate(e)[0],e>s.parameterPositions[1]&&(this.stopWarping(),0===t?this.paused=!0:this.timeScale=t)}}return this._effectiveTimeScale=t,t}_updateTime(e){const t=this._clip.duration,s=this.loop;let i=this.time+e,r=this._loopCount;const n=2202===s;if(0===e)return-1===r?i:n&&1==(1&r)?t-i:i;if(2200===s){-1===r&&(this._loopCount=0,this._setEndings(!0,!0,!1));e:{if(i>=t)i=t;else{if(!(i<0)){this.time=i;break e}i=0}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:e<0?-1:1})}}else{if(-1===r&&(e>=0?(r=0,this._setEndings(!0,0===this.repetitions,n)):this._setEndings(0===this.repetitions,!0,n)),i>=t||i<0){const s=Math.floor(i/t);i-=t*s,r+=Math.abs(s);const o=this.repetitions-r;if(o<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,i=e>0?t:0,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:e>0?1:-1});else{if(1===o){const t=e<0;this._setEndings(t,!t,n)}else this._setEndings(!1,!1,n);this._loopCount=r,this.time=i,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:s})}}else this.time=i;if(n&&1==(1&r))return t-i}return i}_setEndings(e,t,s){const i=this._interpolantSettings;s?(i.endingStart=Ut,i.endingEnd=Ut):(i.endingStart=e?this.zeroSlopeAtStart?Ut:zt:Ot,i.endingEnd=t?this.zeroSlopeAtEnd?Ut:zt:Ot)}_scheduleFading(e,t,s){const i=this._mixer,r=i.time;let n=this._weightInterpolant;null===n&&(n=i._lendControlInterpolant(),this._weightInterpolant=n);const o=n.parameterPositions,a=n.sampleValues;return o[0]=r,a[0]=t,o[1]=r+e,a[1]=s,this}}const xc=new Float32Array(1);class bc extends ks{constructor(e){super(),this._root=e,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}_bindAction(e,t){const s=e._localRoot||this._root,i=e._clip.tracks,r=i.length,n=e._propertyBindings,o=e._interpolants,a=s.uuid,h=this._bindingsByRootAndName;let u=h[a];void 0===u&&(u={},h[a]=u);for(let e=0;e!==r;++e){const r=i[e],h=r.name;let l=u[h];if(void 0!==l)++l.referenceCount,n[e]=l;else{if(l=n[e],void 0!==l){null===l._cacheIndex&&(++l.referenceCount,this._addInactiveBinding(l,a,h));continue}const i=t&&t._propertyBindings[e].binding.parsedPath;l=new hc(gc.create(s,h,i),r.ValueTypeName,r.getValueSize()),++l.referenceCount,this._addInactiveBinding(l,a,h),n[e]=l}o[e].resultBuffer=l.buffer}}_activateAction(e){if(!this._isActiveAction(e)){if(null===e._cacheIndex){const t=(e._localRoot||this._root).uuid,s=e._clip.uuid,i=this._actionsByClip[s];this._bindAction(e,i&&i.knownActions[0]),this._addInactiveAction(e,s,t)}const t=e._propertyBindings;for(let e=0,s=t.length;e!==s;++e){const s=t[e];0==s.useCount++&&(this._lendBinding(s),s.saveOriginalState())}this._lendAction(e)}}_deactivateAction(e){if(this._isActiveAction(e)){const t=e._propertyBindings;for(let e=0,s=t.length;e!==s;++e){const s=t[e];0==--s.useCount&&(s.restoreOriginalState(),this._takeBackBinding(s))}this._takeBackAction(e)}}_initMemoryManager(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;const e=this;this.stats={actions:{get total(){return e._actions.length},get inUse(){return e._nActiveActions}},bindings:{get total(){return e._bindings.length},get inUse(){return e._nActiveBindings}},controlInterpolants:{get total(){return e._controlInterpolants.length},get inUse(){return e._nActiveControlInterpolants}}}}_isActiveAction(e){const t=e._cacheIndex;return null!==t&&t=0;--t)e[t].stop();return this}update(e){e*=this.timeScale;const t=this._actions,s=this._nActiveActions,i=this.time+=e,r=Math.sign(e),n=this._accuIndex^=1;for(let o=0;o!==s;++o){t[o]._update(i,e,r,n)}const o=this._bindings,a=this._nActiveBindings;for(let e=0;e!==a;++e)o[e].apply(n);return this}setTime(e){this.time=0;for(let e=0;e=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y))}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,Ic).distanceTo(e)}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}const Fc=new Ri,zc=new Ri;class Uc{constructor(e=new Ri,t=new Ri){this.start=e,this.end=t}set(e,t){return this.start.copy(e),this.end.copy(t),this}copy(e){return this.start.copy(e.start),this.end.copy(e.end),this}getCenter(e){return e.addVectors(this.start,this.end).multiplyScalar(.5)}delta(e){return e.subVectors(this.end,this.start)}distanceSq(){return this.start.distanceToSquared(this.end)}distance(){return this.start.distanceTo(this.end)}at(e,t){return this.delta(t).multiplyScalar(e).add(this.start)}closestPointToPointParameter(e,t){Fc.subVectors(e,this.start),zc.subVectors(this.end,this.start);const s=zc.dot(zc);let i=zc.dot(Fc)/s;return t&&(i=$s(i,0,1)),i}closestPointToPoint(e,t,s){const i=this.closestPointToPointParameter(e,t);return this.delta(s).multiplyScalar(i).add(this.start)}applyMatrix4(e){return this.start.applyMatrix4(e),this.end.applyMatrix4(e),this}equals(e){return e.start.equals(this.start)&&e.end.equals(this.end)}clone(){return(new this.constructor).copy(this)}}const Oc=new Ri;class Lc extends Ir{constructor(e,t){super(),this.light=e,this.matrixAutoUpdate=!1,this.color=t,this.type="SpotLightHelper";const s=new An,i=[0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,-1,0,1,0,0,0,0,1,1,0,0,0,0,-1,1];for(let e=0,t=1,s=32;e1)for(let s=0;s.99999)this.quaternion.set(0,0,0,1);else if(e.y<-.99999)this.quaternion.set(1,0,0,0);else{ud.set(e.z,0,-e.x).normalize();const t=Math.acos(e.y);this.quaternion.setFromAxisAngle(ud,t)}}setLength(e,t=.2*e,s=.2*t){this.line.scale.set(1,Math.max(1e-4,e-t),1),this.line.updateMatrix(),this.cone.scale.set(s,t,s),this.cone.position.y=e,this.cone.updateMatrix()}setColor(e){this.line.material.color.set(e),this.cone.material.color.set(e)}copy(e){return super.copy(e,!1),this.line.copy(e.line),this.cone.copy(e.cone),this}dispose(){this.line.geometry.dispose(),this.line.material.dispose(),this.cone.geometry.dispose(),this.cone.material.dispose()}}class pd extends Pa{constructor(e=1){const t=[0,0,0,e,0,0,0,0,0,0,e,0,0,0,0,0,0,e],s=new An;s.setAttribute("position",new bn(t,3)),s.setAttribute("color",new bn([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1],3));super(s,new Ta({vertexColors:!0,toneMapped:!1})),this.type="AxesHelper"}setColors(e,t,s){const i=new Jr,r=this.geometry.attributes.color.array;return i.set(e),i.toArray(r,0),i.toArray(r,3),i.set(t),i.toArray(r,6),i.toArray(r,9),i.set(s),i.toArray(r,12),i.toArray(r,15),this.geometry.attributes.color.needsUpdate=!0,this}dispose(){this.geometry.dispose(),this.material.dispose()}}class md{constructor(){this.type="ShapePath",this.color=new Jr,this.subPaths=[],this.currentPath=null}moveTo(e,t){return this.currentPath=new yh,this.subPaths.push(this.currentPath),this.currentPath.moveTo(e,t),this}lineTo(e,t){return this.currentPath.lineTo(e,t),this}quadraticCurveTo(e,t,s,i){return this.currentPath.quadraticCurveTo(e,t,s,i),this}bezierCurveTo(e,t,s,i,r,n){return this.currentPath.bezierCurveTo(e,t,s,i,r,n),this}splineThru(e){return this.currentPath.splineThru(e),this}toShapes(e){function t(e,t){const s=t.length;let i=!1;for(let r=s-1,n=0;nNumber.EPSILON){if(h<0&&(s=t[n],a=-a,o=t[r],h=-h),e.yo.y)continue;if(e.y===s.y){if(e.x===s.x)return!0}else{const t=h*(e.x-s.x)-a*(e.y-s.y);if(0===t)return!0;if(t<0)continue;i=!i}}else{if(e.y!==s.y)continue;if(o.x<=e.x&&e.x<=s.x||s.x<=e.x&&e.x<=o.x)return!0}}return i}const s=su.isClockWise,i=this.subPaths;if(0===i.length)return[];let r,n,o;const a=[];if(1===i.length)return n=i[0],o=new Eh,o.curves=n.curves,a.push(o),a;let h=!s(i[0].getPoints());h=e?!h:h;const u=[],l=[];let c,d,p=[],m=0;l[m]=void 0,p[m]=[];for(let t=0,o=i.length;t1){let e=!1,s=0;for(let e=0,t=l.length;e0&&!1===e&&(p=u)}for(let e=0,t=l.length;e>>16,2246822507),s^=Math.imul(i^i>>>13,3266489909),i=Math.imul(i^i>>>16,2246822507),i^=Math.imul(s^s>>>13,3266489909),4294967296*(2097151&i)+(s>>>0)}const vd=e=>bd(e),Td=e=>bd(e),_d=(...e)=>bd(e);function wd(e,t=!1){const s=[];!0===e.isNode&&(s.push(e.id),e=e.getSelf());for(const{property:i,childNode:r}of Sd(e))s.push(s,bd(i.slice(0,-4)),r.getCacheKey(t));return bd(s)}function*Sd(e,t=!1){for(const s in e){if(!0===s.startsWith("_"))continue;const i=e[s];if(!0===Array.isArray(i))for(let e=0;ee.charCodeAt(0))).buffer}var Rd=Object.freeze({__proto__:null,arrayBufferToBase64:Ad,base64ToArrayBuffer:Cd,getCacheKey:wd,getNodeChildren:Sd,getValueFromType:Nd,getValueType:Md,hash:_d,hashArray:Td,hashString:vd});const Ed={VERTEX:"vertex",FRAGMENT:"fragment"},Bd={NONE:"none",FRAME:"frame",RENDER:"render",OBJECT:"object"},Id={BOOLEAN:"bool",INTEGER:"int",FLOAT:"float",VECTOR2:"vec2",VECTOR3:"vec3",VECTOR4:"vec4",MATRIX2:"mat2",MATRIX3:"mat3",MATRIX4:"mat4"},Pd=["fragment","vertex"],Fd=["setup","analyze","generate"],zd=[...Pd,"compute"],Ud=["x","y","z","w"];let Od=0;class Ld extends ks{static get type(){return"Node"}constructor(e=null){super(),this.nodeType=e,this.updateType=Bd.NONE,this.updateBeforeType=Bd.NONE,this.updateAfterType=Bd.NONE,this.uuid=Ks.generateUUID(),this.version=0,this._cacheKey=null,this._cacheKeyVersion=0,this.global=!1,this.isNode=!0,Object.defineProperty(this,"id",{value:Od++})}set needsUpdate(e){!0===e&&this.version++}get type(){return this.constructor.type}onUpdate(e,t){return this.updateType=t,this.update=e.bind(this.getSelf()),this}onFrameUpdate(e){return this.onUpdate(e,Bd.FRAME)}onRenderUpdate(e){return this.onUpdate(e,Bd.RENDER)}onObjectUpdate(e){return this.onUpdate(e,Bd.OBJECT)}onReference(e){return this.updateReference=e.bind(this.getSelf()),this}getSelf(){return this.self||this}updateReference(){return this}isGlobal(){return this.global}*getChildren(){for(const{childNode:e}of Sd(this))yield e}dispose(){this.dispatchEvent({type:"dispose"})}traverse(e){e(this);for(const t of this.getChildren())t.traverse(e)}getCacheKey(e=!1){return!0!==(e=e||this.version!==this._cacheKeyVersion)&&null!==this._cacheKey||(this._cacheKey=wd(this,e),this._cacheKeyVersion=this.version),this._cacheKey}getScope(){return this}getHash(){return this.uuid}getUpdateType(){return this.updateType}getUpdateBeforeType(){return this.updateBeforeType}getUpdateAfterType(){return this.updateAfterType}getElementType(e){const t=this.getNodeType(e);return e.getElementType(t)}getNodeType(e){const t=e.getNodeProperties(this);return t.outputNode?t.outputNode.getNodeType(e):this.nodeType}getShared(e){const t=this.getHash(e);return e.getNodeFromHash(t)||this}setup(e){const t=e.getNodeProperties(this);let s=0;for(const e of this.getChildren())t["node"+s++]=e;return null}analyze(e){if(1===e.increaseUsage(this)){const t=e.getNodeProperties(this);for(const s of Object.values(t))s&&!0===s.isNode&&s.build(e)}}generate(e,t){const{outputNode:s}=e.getNodeProperties(this);if(s&&!0===s.isNode)return s.build(e,t)}updateBefore(){console.warn("Abstract function.")}updateAfter(){console.warn("Abstract function.")}update(){console.warn("Abstract function.")}build(e,t=null){const s=this.getShared(e);if(this!==s)return s.build(e,t);e.addNode(this),e.addChain(this);let i=null;const r=e.getBuildStage();if("setup"===r){this.updateReference(e);const t=e.getNodeProperties(this);if(!0!==t.initialized){e.stack.nodes.length;t.initialized=!0,t.outputNode=this.setup(e),null!==t.outputNode&&e.stack.nodes.length;for(const s of Object.values(t))s&&!0===s.isNode&&s.build(e)}}else if("analyze"===r)this.analyze(e);else if("generate"===r){if(1===this.generate.length){const s=this.getNodeType(e),r=e.getDataFromNode(this);i=r.snippet,void 0===i?(i=this.generate(e)||"",r.snippet=i):void 0!==r.flowCodes&&void 0!==e.context.nodeBlock&&e.addFlowCodeHierarchy(this,e.context.nodeBlock),i=e.format(i,s,t)}else i=this.generate(e,t)||""}return e.removeChain(this),i}getSerializeChildren(){return Sd(this)}serialize(e){const t=this.getSerializeChildren(),s={};for(const{property:i,index:r,childNode:n}of t)void 0!==r?(void 0===s[i]&&(s[i]=Number.isInteger(r)?[]:{}),s[i][r]=n.toJSON(e.meta).uuid):s[i]=n.toJSON(e.meta).uuid;Object.keys(s).length>0&&(e.inputNodes=s)}deserialize(e){if(void 0!==e.inputNodes){const t=e.meta.nodes;for(const s in e.inputNodes)if(Array.isArray(e.inputNodes[s])){const i=[];for(const r of e.inputNodes[s])i.push(t[r]);this[s]=i}else if("object"==typeof e.inputNodes[s]){const i={};for(const r in e.inputNodes[s]){const n=e.inputNodes[s][r];i[r]=t[n]}this[s]=i}else{const i=e.inputNodes[s];this[s]=t[i]}}}toJSON(e){const{uuid:t,type:s}=this,i=void 0===e||"string"==typeof e;i&&(e={textures:{},images:{},nodes:{}});let r=e.nodes[t];function n(e){const t=[];for(const s in e){const i=e[s];delete i.metadata,t.push(i)}return t}if(void 0===r&&(r={uuid:t,type:s,meta:e,metadata:{version:4.6,type:"Node",generator:"Node.toJSON"}},!0!==i&&(e.nodes[r.uuid]=r),this.serialize(r),delete r.meta),i){const t=n(e.textures),s=n(e.images),i=n(e.nodes);t.length>0&&(r.textures=t),s.length>0&&(r.images=s),i.length>0&&(r.nodes=i)}return r}}class Vd extends Ld{static get type(){return"ArrayElementNode"}constructor(e,t){super(),this.node=e,this.indexNode=t,this.isArrayElementNode=!0}getNodeType(e){return this.node.getElementType(e)}generate(e){return`${this.node.build(e)}[ ${this.indexNode.build(e,"uint")} ]`}}class Dd extends Ld{static get type(){return"ConvertNode"}constructor(e,t){super(),this.node=e,this.convertTo=t}getNodeType(e){const t=this.node.getNodeType(e);let s=null;for(const i of this.convertTo.split("|"))null!==s&&e.getTypeLength(t)!==e.getTypeLength(i)||(s=i);return s}serialize(e){super.serialize(e),e.convertTo=this.convertTo}deserialize(e){super.deserialize(e),this.convertTo=e.convertTo}generate(e,t){const s=this.node,i=this.getNodeType(e),r=s.build(e,i);return e.format(r,i,t)}}class kd extends Ld{static get type(){return"TempNode"}constructor(e){super(e),this.isTempNode=!0}hasDependencies(e){return e.getDataFromNode(this).usageCount>1}build(e,t){if("generate"===e.getBuildStage()){const s=e.getVectorType(this.getNodeType(e,t)),i=e.getDataFromNode(this);if(void 0!==i.propertyName)return e.format(i.propertyName,s,t);if("void"!==s&&"void"!==t&&this.hasDependencies(e)){const r=super.build(e,s),n=e.getVarFromNode(this,null,s),o=e.getPropertyName(n);return e.addLineFlowCode(`${o} = ${r}`,this),i.snippet=r,i.propertyName=o,e.format(i.propertyName,s,t)}}return super.build(e,t)}}class Gd extends kd{static get type(){return"JoinNode"}constructor(e=[],t=null){super(t),this.nodes=e}getNodeType(e){return null!==this.nodeType?e.getVectorType(this.nodeType):e.getTypeFromLength(this.nodes.reduce(((t,s)=>t+e.getTypeLength(s.getNodeType(e))),0))}generate(e,t){const s=this.getNodeType(e),i=this.nodes,r=e.getComponentType(s),n=[];for(const t of i){let s=t.build(e);const i=e.getComponentType(t.getNodeType(e));i!==r&&(s=e.format(s,i,r)),n.push(s)}const o=`${e.getType(s)}( ${n.join(", ")} )`;return e.format(o,s,t)}}const Wd=Ud.join("");class jd extends Ld{static get type(){return"SplitNode"}constructor(e,t="x"){super(),this.node=e,this.components=t,this.isSplitNode=!0}getVectorLength(){let e=this.components.length;for(const t of this.components)e=Math.max(Ud.indexOf(t)+1,e);return e}getComponentType(e){return e.getComponentType(this.node.getNodeType(e))}getNodeType(e){return e.getTypeFromLength(this.components.length,this.getComponentType(e))}generate(e,t){const s=this.node,i=e.getTypeLength(s.getNodeType(e));let r=null;if(i>1){let n=null;this.getVectorLength()>=i&&(n=e.getTypeFromLength(this.getVectorLength(),this.getComponentType(e)));const o=s.build(e,n);r=this.components.length===i&&this.components===Wd.slice(0,this.components.length)?e.format(o,n,t):e.format(`${o}.${this.components}`,this.getNodeType(e),t)}else r=s.build(e,t);return r}serialize(e){super.serialize(e),e.components=this.components}deserialize(e){super.deserialize(e),this.components=e.components}}class Hd extends kd{static get type(){return"SetNode"}constructor(e,t,s){super(),this.sourceNode=e,this.components=t,this.targetNode=s}getNodeType(e){return this.sourceNode.getNodeType(e)}generate(e){const{sourceNode:t,components:s,targetNode:i}=this,r=this.getNodeType(e),n=e.getTypeFromLength(s.length,i.getNodeType(e)),o=i.build(e,n),a=t.build(e,r),h=e.getTypeLength(r),u=[];for(let e=0;ee.replace(/r|s/g,"x").replace(/g|t/g,"y").replace(/b|p/g,"z").replace(/a|q/g,"w"),Qd=e=>Kd(e).split("").sort().join(""),ep={setup(e,t){const s=t.shift();return e(Mp(s),...t)},get(e,t,s){if("string"==typeof t&&void 0===e[t]){if(!0!==e.isStackNode&&"assign"===t)return(...e)=>(Yd.assign(s,...e),s);if(Zd.has(t)){const i=Zd.get(t);return e.isStackNode?(...e)=>s.add(i(...e)):(...e)=>i(s,...e)}if("self"===t)return e;if(t.endsWith("Assign")&&Zd.has(t.slice(0,t.length-6))){const i=Zd.get(t.slice(0,t.length-6));return e.isStackNode?(...e)=>s.assign(e[0],i(...e)):(...e)=>s.assign(i(s,...e))}if(!0===/^[xyzwrgbastpq]{1,4}$/.test(t))return t=Kd(t),Sp(new jd(s,t));if(!0===/^set[XYZWRGBASTPQ]{1,4}$/.test(t))return t=Qd(t.slice(3).toLowerCase()),s=>Sp(new Hd(e,t,s));if(!0===/^flip[XYZWRGBASTPQ]{1,4}$/.test(t))return t=Qd(t.slice(4).toLowerCase()),()=>Sp(new qd(Sp(e),t));if("width"===t||"height"===t||"depth"===t)return"width"===t?t="x":"height"===t?t="y":"depth"===t&&(t="z"),Sp(new jd(e,t));if(!0===/^\d+$/.test(t))return Sp(new Vd(s,new Xd(Number(t),"uint")))}return Reflect.get(e,t,s)},set:(e,t,s,i)=>"string"!=typeof t||void 0!==e[t]||!0!==/^[xyzwrgbastpq]{1,4}$/.test(t)&&"width"!==t&&"height"!==t&&"depth"!==t&&!0!==/^\d+$/.test(t)?Reflect.set(e,t,s,i):(i[t].assign(s),!0)},tp=new WeakMap,sp=new WeakMap,ip=function(e,t=null){for(const s in e)e[s]=Sp(e[s],t);return e},rp=function(e,t=null){const s=e.length;for(let i=0;iSp(null!==i?Object.assign(e,i):e);return null===t?(...t)=>r(new e(...Np(t))):null!==s?(s=Sp(s),(...i)=>r(new e(t,...Np(i),s))):(...s)=>r(new e(t,...Np(s)))},op=function(e,...t){return Sp(new e(...Np(t)))};class ap extends Ld{constructor(e,t){super(),this.shaderNode=e,this.inputNodes=t}getNodeType(e){return this.shaderNode.nodeType||this.getOutputNode(e).getNodeType(e)}call(e){const{shaderNode:t,inputNodes:s}=this,i=e.getNodeProperties(t);if(i.onceOutput)return i.onceOutput;let r=null;if(t.layout){let i=sp.get(e.constructor);void 0===i&&(i=new WeakMap,sp.set(e.constructor,i));let n=i.get(t);void 0===n&&(n=Sp(e.buildFunctionNode(t)),i.set(t,n)),null!==e.currentFunctionNode&&e.currentFunctionNode.includes.push(n),r=Sp(n.call(s))}else{const i=t.jsFunc,n=null!==s?i(s,e):i(e);r=Sp(n)}return t.once&&(i.onceOutput=r),r}getOutputNode(e){const t=e.getNodeProperties(this);return null===t.outputNode&&(t.outputNode=this.setupOutput(e)),t.outputNode}setup(e){return this.getOutputNode(e)}setupOutput(e){return e.addStack(),e.stack.outputNode=this.call(e),e.removeStack()}generate(e,t){return this.getOutputNode(e).build(e,t)}}class hp extends Ld{constructor(e,t){super(t),this.jsFunc=e,this.layout=null,this.global=!0,this.once=!1}setLayout(e){return this.layout=e,this}call(e=null){return Mp(e),Sp(new ap(this,e))}setup(){return this.call()}}const up=[!1,!0],lp=[0,1,2,3],cp=[-1,-2],dp=[.5,1.5,1/3,1e-6,1e6,Math.PI,2*Math.PI,1/Math.PI,2/Math.PI,1/(2*Math.PI),Math.PI/2],pp=new Map;for(const e of up)pp.set(e,new Xd(e));const mp=new Map;for(const e of lp)mp.set(e,new Xd(e,"uint"));const gp=new Map([...mp].map((e=>new Xd(e.value,"int"))));for(const e of cp)gp.set(e,new Xd(e,"int"));const fp=new Map([...gp].map((e=>new Xd(e.value))));for(const e of dp)fp.set(e,new Xd(e));for(const e of dp)fp.set(-e,new Xd(-e));const yp={bool:pp,uint:mp,ints:gp,float:fp},xp=new Map([...pp,...fp]),bp=(e,t)=>xp.has(e)?xp.get(e):!0===e.isNode?e:new Xd(e,t),vp=function(e,t=null){return(...s)=>{if((0===s.length||!["bool","float","int","uint"].includes(e)&&s.every((e=>"object"!=typeof e)))&&(s=[Nd(e,...s)]),1===s.length&&null!==t&&t.has(s[0]))return Sp(t.get(s[0]));if(1===s.length){const t=bp(s[0],e);return(e=>{try{return e.getNodeType()}catch(e){return}})(t)===e?Sp(t):Sp(new Dd(t,e))}const i=s.map((e=>bp(e)));return Sp(new Gd(i,e))}},Tp=e=>"object"==typeof e&&null!==e?e.value:e,_p=e=>null!=e?e.nodeType||e.convertTo||("string"==typeof e?e:null):null;function wp(e,t){return new Proxy(new hp(e,t),ep)}const Sp=(e,t=null)=>function(e,t=null){const s=Md(e);if("node"===s){let t=tp.get(e);return void 0===t&&(t=new Proxy(e,ep),tp.set(e,t),tp.set(t,t)),t}return null===t&&("float"===s||"boolean"===s)||s&&"shader"!==s&&"string"!==s?Sp(bp(e,t)):"shader"===s?Rp(e):e}(e,t),Mp=(e,t=null)=>new ip(e,t),Np=(e,t=null)=>new rp(e,t),Ap=(...e)=>new np(...e),Cp=(...e)=>new op(...e),Rp=(e,t)=>{const s=new wp(e,t),i=(...e)=>{let t;return Mp(e),t=e[0]&&e[0].isNode?[...e]:e[0],s.call(t)};return i.shaderNode=s,i.setLayout=e=>(s.setLayout(e),i),i.once=()=>(s.once=!0,i),i},Ep=(...e)=>(console.warn("TSL.ShaderNode: tslFn() has been renamed to Fn()."),Rp(...e));Jd("toGlobal",(e=>(e.global=!0,e)));const Bp=e=>{Yd=e},Ip=()=>Yd,Pp=(...e)=>Yd.If(...e);function Fp(e){return Yd&&Yd.add(e),e}Jd("append",Fp);const zp=new vp("color"),Up=new vp("float",yp.float),Op=new vp("int",yp.ints),Lp=new vp("uint",yp.uint),Vp=new vp("bool",yp.bool),Dp=new vp("vec2"),kp=new vp("ivec2"),Gp=new vp("uvec2"),Wp=new vp("bvec2"),jp=new vp("vec3"),Hp=new vp("ivec3"),qp=new vp("uvec3"),$p=new vp("bvec3"),Xp=new vp("vec4"),Yp=new vp("ivec4"),Zp=new vp("uvec4"),Jp=new vp("bvec4"),Kp=new vp("mat2"),Qp=new vp("mat3"),em=new vp("mat4"),tm=(e="")=>Sp(new Xd(e,"string")),sm=e=>Sp(new Xd(e,"ArrayBuffer"));Jd("toColor",zp),Jd("toFloat",Up),Jd("toInt",Op),Jd("toUint",Lp),Jd("toBool",Vp),Jd("toVec2",Dp),Jd("toIVec2",kp),Jd("toUVec2",Gp),Jd("toBVec2",Wp),Jd("toVec3",jp),Jd("toIVec3",Hp),Jd("toUVec3",qp),Jd("toBVec3",$p),Jd("toVec4",Xp),Jd("toIVec4",Yp),Jd("toUVec4",Zp),Jd("toBVec4",Jp),Jd("toMat2",Kp),Jd("toMat3",Qp),Jd("toMat4",em);const im=Ap(Vd),rm=(e,t)=>Sp(new Dd(Sp(e),t)),nm=(e,t)=>Sp(new jd(Sp(e),t));Jd("element",im),Jd("convert",rm);class om extends Ld{static get type(){return"UniformGroupNode"}constructor(e,t=!1,s=1){super("string"),this.name=e,this.version=0,this.shared=t,this.order=s,this.isUniformGroup=!0}set needsUpdate(e){!0===e&&this.version++}serialize(e){super.serialize(e),e.name=this.name,e.version=this.version,e.shared=this.shared}deserialize(e){super.deserialize(e),this.name=e.name,this.version=e.version,this.shared=e.shared}}const am=e=>new om(e),hm=(e,t=0)=>new om(e,!0,t),um=hm("frame"),lm=hm("render"),cm=am("object");class dm extends $d{static get type(){return"UniformNode"}constructor(e,t=null){super(e,t),this.isUniformNode=!0,this.name="",this.groupNode=cm}label(e){return this.name=e,this}setGroup(e){return this.groupNode=e,this}getGroup(){return this.groupNode}getUniformHash(e){return this.getHash(e)}onUpdate(e,t){const s=this.getSelf();return e=e.bind(s),super.onUpdate((t=>{const i=e(t,s);void 0!==i&&(this.value=i)}),t)}generate(e,t){const s=this.getNodeType(e),i=this.getUniformHash(e);let r=e.getNodeFromHash(i);void 0===r&&(e.setHashNode(this,i),r=this);const n=r.getInputType(e),o=e.getUniformFromNode(r,n,e.shaderStage,this.name||e.context.label),a=e.getPropertyName(o);return void 0!==e.context.label&&delete e.context.label,e.format(a,s,t)}}const pm=(e,t)=>{const s=_p(t||e),i=e&&!0===e.isNode?e.node&&e.node.value||e.value:e;return Sp(new dm(i,s))};class mm extends Ld{static get type(){return"PropertyNode"}constructor(e,t=null,s=!1){super(e),this.name=t,this.varying=s,this.isPropertyNode=!0}getHash(e){return this.name||super.getHash(e)}isGlobal(){return!0}generate(e){let t;return!0===this.varying?(t=e.getVaryingFromNode(this,this.name),t.needsInterpolation=!0):t=e.getVarFromNode(this,this.name),e.getPropertyName(t)}}const gm=(e,t)=>Sp(new mm(e,t)),fm=(e,t)=>Sp(new mm(e,t,!0)),ym=Cp(mm,"vec4","DiffuseColor"),xm=Cp(mm,"vec3","EmissiveColor"),bm=Cp(mm,"float","Roughness"),vm=Cp(mm,"float","Metalness"),Tm=Cp(mm,"float","Clearcoat"),_m=Cp(mm,"float","ClearcoatRoughness"),wm=Cp(mm,"vec3","Sheen"),Sm=Cp(mm,"float","SheenRoughness"),Mm=Cp(mm,"float","Iridescence"),Nm=Cp(mm,"float","IridescenceIOR"),Am=Cp(mm,"float","IridescenceThickness"),Cm=Cp(mm,"float","AlphaT"),Rm=Cp(mm,"float","Anisotropy"),Em=Cp(mm,"vec3","AnisotropyT"),Bm=Cp(mm,"vec3","AnisotropyB"),Im=Cp(mm,"color","SpecularColor"),Pm=Cp(mm,"float","SpecularF90"),Fm=Cp(mm,"float","Shininess"),zm=Cp(mm,"vec4","Output"),Um=Cp(mm,"float","dashSize"),Om=Cp(mm,"float","gapSize"),Lm=Cp(mm,"float","pointWidth"),Vm=Cp(mm,"float","IOR"),Dm=Cp(mm,"float","Transmission"),km=Cp(mm,"float","Thickness"),Gm=Cp(mm,"float","AttenuationDistance"),Wm=Cp(mm,"color","AttenuationColor"),jm=Cp(mm,"float","Dispersion");class Hm extends kd{static get type(){return"AssignNode"}constructor(e,t){super(),this.targetNode=e,this.sourceNode=t}hasDependencies(){return!1}getNodeType(e,t){return"void"!==t?this.targetNode.getNodeType(e):"void"}needsSplitAssign(e){const{targetNode:t}=this;if(!1===e.isAvailable("swizzleAssign")&&t.isSplitNode&&t.components.length>1){const s=e.getTypeLength(t.node.getNodeType(e));return Ud.join("").slice(0,s)!==t.components}return!1}generate(e,t){const{targetNode:s,sourceNode:i}=this,r=this.needsSplitAssign(e),n=s.getNodeType(e),o=s.context({assign:!0}).build(e),a=i.build(e,n),h=i.getNodeType(e),u=e.getDataFromNode(this);let l;if(!0===u.initialized)"void"!==t&&(l=o);else if(r){const i=e.getVarFromNode(this,null,n),r=e.getPropertyName(i);e.addLineFlowCode(`${r} = ${a}`,this);const h=s.node.context({assign:!0}).build(e);for(let t=0;t(t=t.length>1||t[0]&&!0===t[0].isNode?Np(t):Mp(t[0]),Sp(new $m(Sp(e),t)));Jd("call",Xm);class Ym extends kd{static get type(){return"OperatorNode"}constructor(e,t,s,...i){if(super(),i.length>0){let r=new Ym(e,t,s);for(let t=0;t>"===s||"<<"===s)return e.getIntegerType(n);if("!"===s||"=="===s||"&&"===s||"||"===s||"^^"===s)return"bool";if("<"===s||">"===s||"<="===s||">="===s){const s=t?e.getTypeLength(t):Math.max(e.getTypeLength(n),e.getTypeLength(o));return s>1?`bvec${s}`:"bool"}return"float"===n&&e.isMatrix(o)?o:e.isMatrix(n)&&e.isVector(o)?e.getVectorFromMatrix(n):e.isVector(n)&&e.isMatrix(o)?e.getVectorFromMatrix(o):e.getTypeLength(o)>e.getTypeLength(n)?o:n}generate(e,t){const s=this.op,i=this.aNode,r=this.bNode,n=this.getNodeType(e,t);let o=null,a=null;"void"!==n?(o=i.getNodeType(e),a=void 0!==r?r.getNodeType(e):null,"<"===s||">"===s||"<="===s||">="===s||"=="===s?e.isVector(o)?a=o:o!==a&&(o=a="float"):">>"===s||"<<"===s?(o=n,a=e.changeComponentType(a,"uint")):e.isMatrix(o)&&e.isVector(a)?a=e.getVectorFromMatrix(o):o=e.isVector(o)&&e.isMatrix(a)?e.getVectorFromMatrix(a):a=n):o=a=n;const h=i.build(e,o),u=void 0!==r?r.build(e,a):null,l=e.getTypeLength(t),c=e.getFunctionOperator(s);return"void"!==t?"<"===s&&l>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThan",t)}( ${h}, ${u} )`,n,t):e.format(`( ${h} < ${u} )`,n,t):"<="===s&&l>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThanEqual",t)}( ${h}, ${u} )`,n,t):e.format(`( ${h} <= ${u} )`,n,t):">"===s&&l>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThan",t)}( ${h}, ${u} )`,n,t):e.format(`( ${h} > ${u} )`,n,t):">="===s&&l>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThanEqual",t)}( ${h}, ${u} )`,n,t):e.format(`( ${h} >= ${u} )`,n,t):"!"===s||"~"===s?e.format(`(${s}${h})`,o,t):c?e.format(`${c}( ${h}, ${u} )`,n,t):e.format(`( ${h} ${s} ${u} )`,n,t):"void"!==o?c?e.format(`${c}( ${h}, ${u} )`,n,t):e.format(`${h} ${s} ${u}`,n,t):void 0}serialize(e){super.serialize(e),e.op=this.op}deserialize(e){super.deserialize(e),this.op=e.op}}const Zm=Ap(Ym,"+"),Jm=Ap(Ym,"-"),Km=Ap(Ym,"*"),Qm=Ap(Ym,"/"),eg=Ap(Ym,"%"),tg=Ap(Ym,"=="),sg=Ap(Ym,"!="),ig=Ap(Ym,"<"),rg=Ap(Ym,">"),ng=Ap(Ym,"<="),og=Ap(Ym,">="),ag=Ap(Ym,"&&"),hg=Ap(Ym,"||"),ug=Ap(Ym,"!"),lg=Ap(Ym,"^^"),cg=Ap(Ym,"&"),dg=Ap(Ym,"~"),pg=Ap(Ym,"|"),mg=Ap(Ym,"^"),gg=Ap(Ym,"<<"),fg=Ap(Ym,">>");Jd("add",Zm),Jd("sub",Jm),Jd("mul",Km),Jd("div",Qm),Jd("modInt",eg),Jd("equal",tg),Jd("notEqual",sg),Jd("lessThan",ig),Jd("greaterThan",rg),Jd("lessThanEqual",ng),Jd("greaterThanEqual",og),Jd("and",ag),Jd("or",hg),Jd("not",ug),Jd("xor",lg),Jd("bitAnd",cg),Jd("bitNot",dg),Jd("bitOr",pg),Jd("bitXor",mg),Jd("shiftLeft",gg),Jd("shiftRight",fg);const yg=(...e)=>(console.warn("TSL.OperatorNode: .remainder() has been renamed to .modInt()."),eg(...e));Jd("remainder",yg);class xg extends kd{static get type(){return"MathNode"}constructor(e,t,s=null,i=null){super(),this.method=e,this.aNode=t,this.bNode=s,this.cNode=i}getInputType(e){const t=this.aNode.getNodeType(e),s=this.bNode?this.bNode.getNodeType(e):null,i=this.cNode?this.cNode.getNodeType(e):null,r=e.isMatrix(t)?0:e.getTypeLength(t),n=e.isMatrix(s)?0:e.getTypeLength(s),o=e.isMatrix(i)?0:e.getTypeLength(i);return r>n&&r>o?t:n>o?s:o>r?i:t}getNodeType(e){const t=this.method;return t===xg.LENGTH||t===xg.DISTANCE||t===xg.DOT?"float":t===xg.CROSS?"vec3":t===xg.ALL?"bool":t===xg.EQUALS?e.changeComponentType(this.aNode.getNodeType(e),"bool"):t===xg.MOD?this.aNode.getNodeType(e):this.getInputType(e)}generate(e,t){const s=this.method,i=this.getNodeType(e),r=this.getInputType(e),n=this.aNode,o=this.bNode,a=this.cNode,h=!0===e.renderer.isWebGLRenderer;if(s===xg.TRANSFORM_DIRECTION){let s=n,i=o;e.isMatrix(s.getNodeType(e))?i=Xp(jp(i),0):s=Xp(jp(s),0);const r=Km(s,i).xyz;return Ug(r).build(e,t)}if(s===xg.NEGATE)return e.format("( - "+n.build(e,r)+" )",i,t);if(s===xg.ONE_MINUS)return Jm(1,n).build(e,t);if(s===xg.RECIPROCAL)return Qm(1,n).build(e,t);if(s===xg.DIFFERENCE)return jg(Jm(n,o)).build(e,t);{const u=[];return s===xg.CROSS||s===xg.MOD?u.push(n.build(e,i),o.build(e,i)):h&&s===xg.STEP?u.push(n.build(e,1===e.getTypeLength(n.getNodeType(e))?"float":r),o.build(e,r)):h&&(s===xg.MIN||s===xg.MAX)||s===xg.MOD?u.push(n.build(e,r),o.build(e,1===e.getTypeLength(o.getNodeType(e))?"float":r)):s===xg.REFRACT?u.push(n.build(e,r),o.build(e,r),a.build(e,"float")):s===xg.MIX?u.push(n.build(e,r),o.build(e,r),a.build(e,1===e.getTypeLength(a.getNodeType(e))?"float":r)):(u.push(n.build(e,r)),null!==o&&u.push(o.build(e,r)),null!==a&&u.push(a.build(e,r))),e.format(`${e.getMethod(s,i)}( ${u.join(", ")} )`,i,t)}}serialize(e){super.serialize(e),e.method=this.method}deserialize(e){super.deserialize(e),this.method=e.method}}xg.ALL="all",xg.ANY="any",xg.EQUALS="equals",xg.RADIANS="radians",xg.DEGREES="degrees",xg.EXP="exp",xg.EXP2="exp2",xg.LOG="log",xg.LOG2="log2",xg.SQRT="sqrt",xg.INVERSE_SQRT="inversesqrt",xg.FLOOR="floor",xg.CEIL="ceil",xg.NORMALIZE="normalize",xg.FRACT="fract",xg.SIN="sin",xg.COS="cos",xg.TAN="tan",xg.ASIN="asin",xg.ACOS="acos",xg.ATAN="atan",xg.ABS="abs",xg.SIGN="sign",xg.LENGTH="length",xg.NEGATE="negate",xg.ONE_MINUS="oneMinus",xg.DFDX="dFdx",xg.DFDY="dFdy",xg.ROUND="round",xg.RECIPROCAL="reciprocal",xg.TRUNC="trunc",xg.FWIDTH="fwidth",xg.BITCAST="bitcast",xg.TRANSPOSE="transpose",xg.ATAN2="atan2",xg.MIN="min",xg.MAX="max",xg.MOD="mod",xg.STEP="step",xg.REFLECT="reflect",xg.DISTANCE="distance",xg.DIFFERENCE="difference",xg.DOT="dot",xg.CROSS="cross",xg.POW="pow",xg.TRANSFORM_DIRECTION="transformDirection",xg.MIX="mix",xg.CLAMP="clamp",xg.REFRACT="refract",xg.SMOOTHSTEP="smoothstep",xg.FACEFORWARD="faceforward";const bg=Up(1e-6),vg=Up(1e6),Tg=Up(Math.PI),_g=Up(2*Math.PI),wg=Ap(xg,xg.ALL),Sg=Ap(xg,xg.ANY),Mg=Ap(xg,xg.EQUALS),Ng=Ap(xg,xg.RADIANS),Ag=Ap(xg,xg.DEGREES),Cg=Ap(xg,xg.EXP),Rg=Ap(xg,xg.EXP2),Eg=Ap(xg,xg.LOG),Bg=Ap(xg,xg.LOG2),Ig=Ap(xg,xg.SQRT),Pg=Ap(xg,xg.INVERSE_SQRT),Fg=Ap(xg,xg.FLOOR),zg=Ap(xg,xg.CEIL),Ug=Ap(xg,xg.NORMALIZE),Og=Ap(xg,xg.FRACT),Lg=Ap(xg,xg.SIN),Vg=Ap(xg,xg.COS),Dg=Ap(xg,xg.TAN),kg=Ap(xg,xg.ASIN),Gg=Ap(xg,xg.ACOS),Wg=Ap(xg,xg.ATAN),jg=Ap(xg,xg.ABS),Hg=Ap(xg,xg.SIGN),qg=Ap(xg,xg.LENGTH),$g=Ap(xg,xg.NEGATE),Xg=Ap(xg,xg.ONE_MINUS),Yg=Ap(xg,xg.DFDX),Zg=Ap(xg,xg.DFDY),Jg=Ap(xg,xg.ROUND),Kg=Ap(xg,xg.RECIPROCAL),Qg=Ap(xg,xg.TRUNC),ef=Ap(xg,xg.FWIDTH),tf=Ap(xg,xg.BITCAST),sf=Ap(xg,xg.TRANSPOSE),rf=Ap(xg,xg.ATAN2),nf=Ap(xg,xg.MIN),of=Ap(xg,xg.MAX),af=Ap(xg,xg.MOD),hf=Ap(xg,xg.STEP),uf=Ap(xg,xg.REFLECT),lf=Ap(xg,xg.DISTANCE),cf=Ap(xg,xg.DIFFERENCE),df=Ap(xg,xg.DOT),pf=Ap(xg,xg.CROSS),mf=Ap(xg,xg.POW),gf=Ap(xg,xg.POW,2),ff=Ap(xg,xg.POW,3),yf=Ap(xg,xg.POW,4),xf=Ap(xg,xg.TRANSFORM_DIRECTION),bf=e=>Km(Hg(e),mf(jg(e),1/3)),vf=e=>df(e,e),Tf=Ap(xg,xg.MIX),_f=(e,t=0,s=1)=>Sp(new xg(xg.CLAMP,Sp(e),Sp(t),Sp(s))),wf=e=>_f(e),Sf=Ap(xg,xg.REFRACT),Mf=Ap(xg,xg.SMOOTHSTEP),Nf=Ap(xg,xg.FACEFORWARD),Af=Rp((([e])=>{const t=df(e.xy,Dp(12.9898,78.233)),s=af(t,Tg);return Og(Lg(s).mul(43758.5453))})),Cf=(e,t,s)=>Tf(t,s,e),Rf=(e,t,s)=>Mf(t,s,e);Jd("all",wg),Jd("any",Sg),Jd("equals",Mg),Jd("radians",Ng),Jd("degrees",Ag),Jd("exp",Cg),Jd("exp2",Rg),Jd("log",Eg),Jd("log2",Bg),Jd("sqrt",Ig),Jd("inverseSqrt",Pg),Jd("floor",Fg),Jd("ceil",zg),Jd("normalize",Ug),Jd("fract",Og),Jd("sin",Lg),Jd("cos",Vg),Jd("tan",Dg),Jd("asin",kg),Jd("acos",Gg),Jd("atan",Wg),Jd("abs",jg),Jd("sign",Hg),Jd("length",qg),Jd("lengthSq",vf),Jd("negate",$g),Jd("oneMinus",Xg),Jd("dFdx",Yg),Jd("dFdy",Zg),Jd("round",Jg),Jd("reciprocal",Kg),Jd("trunc",Qg),Jd("fwidth",ef),Jd("atan2",rf),Jd("min",nf),Jd("max",of),Jd("mod",af),Jd("step",hf),Jd("reflect",uf),Jd("distance",lf),Jd("dot",df),Jd("cross",pf),Jd("pow",mf),Jd("pow2",gf),Jd("pow3",ff),Jd("pow4",yf),Jd("transformDirection",xf),Jd("mix",Cf),Jd("clamp",_f),Jd("refract",Sf),Jd("smoothstep",Rf),Jd("faceForward",Nf),Jd("difference",cf),Jd("saturate",wf),Jd("cbrt",bf),Jd("transpose",sf),Jd("rand",Af);class Ef extends Ld{static get type(){return"ConditionalNode"}constructor(e,t,s=null){super(),this.condNode=e,this.ifNode=t,this.elseNode=s}getNodeType(e){const t=this.ifNode.getNodeType(e);if(null!==this.elseNode){const s=this.elseNode.getNodeType(e);if(e.getTypeLength(s)>e.getTypeLength(t))return s}return t}setup(e){const t=this.condNode.cache(),s=this.ifNode.cache(),i=this.elseNode?this.elseNode.cache():null,r=e.context.nodeBlock;e.getDataFromNode(s).parentNodeBlock=r,null!==i&&(e.getDataFromNode(i).parentNodeBlock=r);const n=e.getNodeProperties(this);n.condNode=t,n.ifNode=s.context({nodeBlock:s}),n.elseNode=i?i.context({nodeBlock:i}):null}generate(e,t){const s=this.getNodeType(e),i=e.getDataFromNode(this);if(void 0!==i.nodeProperty)return i.nodeProperty;const{condNode:r,ifNode:n,elseNode:o}=e.getNodeProperties(this),a="void"!==t,h=a?gm(s).build(e):"";i.nodeProperty=h;const u=r.build(e,"bool");e.addFlowCode(`\n${e.tab}if ( ${u} ) {\n\n`).addFlowTab();let l=n.build(e,s);if(l&&(l=a?h+" = "+l+";":"return "+l+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+l+"\n\n"+e.tab+"}"),null!==o){e.addFlowCode(" else {\n\n").addFlowTab();let t=o.build(e,s);t&&(t=a?h+" = "+t+";":"return "+t+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+t+"\n\n"+e.tab+"}\n\n")}else e.addFlowCode("\n\n");return e.format(h,s,t)}}const Bf=Ap(Ef);Jd("select",Bf);const If=(...e)=>(console.warn("TSL.ConditionalNode: cond() has been renamed to select()."),Bf(...e));Jd("cond",If);class Pf extends Ld{static get type(){return"ContextNode"}constructor(e,t={}){super(),this.isContextNode=!0,this.node=e,this.value=t}getScope(){return this.node.getScope()}getNodeType(e){return this.node.getNodeType(e)}analyze(e){this.node.build(e)}setup(e){const t=e.getContext();e.setContext({...e.context,...this.value});const s=this.node.build(e);return e.setContext(t),s}generate(e,t){const s=e.getContext();e.setContext({...e.context,...this.value});const i=this.node.build(e,t);return e.setContext(s),i}}const Ff=Ap(Pf),zf=(e,t)=>Ff(e,{label:t});Jd("context",Ff),Jd("label",zf);class Uf extends Ld{static get type(){return"VarNode"}constructor(e,t=null){super(),this.node=e,this.name=t,this.global=!0,this.isVarNode=!0}getHash(e){return this.name||super.getHash(e)}getNodeType(e){return this.node.getNodeType(e)}generate(e){const{node:t,name:s}=this,i=e.getVarFromNode(this,s,e.getVectorType(this.getNodeType(e))),r=e.getPropertyName(i),n=t.build(e,i.type);return e.addLineFlowCode(`${r} = ${n}`,this),r}}const Of=Ap(Uf);Jd("temp",Of),Jd("toVar",((...e)=>Of(...e).append()));class Lf extends Ld{static get type(){return"VaryingNode"}constructor(e,t=null){super(),this.node=e,this.name=t,this.isVaryingNode=!0}isGlobal(){return!0}getHash(e){return this.name||super.getHash(e)}getNodeType(e){return this.node.getNodeType(e)}setupVarying(e){const t=e.getNodeProperties(this);let s=t.varying;if(void 0===s){const i=this.name,r=this.getNodeType(e);t.varying=s=e.getVaryingFromNode(this,i,r),t.node=this.node}return s.needsInterpolation||(s.needsInterpolation="fragment"===e.shaderStage),s}setup(e){this.setupVarying(e)}analyze(e){return this.setupVarying(e),this.node.analyze(e)}generate(e){const t=e.getNodeProperties(this),s=this.setupVarying(e);if(void 0===t.propertyName){const i=this.getNodeType(e),r=e.getPropertyName(s,Ed.VERTEX);e.flowNodeFromShaderStage(Ed.VERTEX,this.node,i,r),t.propertyName=r}return e.getPropertyName(s)}}const Vf=Ap(Lf);Jd("varying",Vf);const Df="WorkingColorSpace",kf="OutputColorSpace";function Gf(e){let t=null;return e===Jt?t="Linear":e===Zt&&(t="sRGB"),t}function Wf(e,t){return Gf(e)+"To"+Gf(t)}class jf extends kd{static get type(){return"ColorSpaceNode"}constructor(e,t,s){super("vec4"),this.colorNode=e,this.source=t,this.target=s}getColorSpace(e,t){return t===Df?ci.workingColorSpace:t===kf?e.context.outputColorSpace||e.renderer.outputColorSpace:t}setup(e){const{renderer:t}=e,{colorNode:s}=this,i=this.getColorSpace(e,this.source),r=this.getColorSpace(e,this.target);if(i===r)return s;const n=Wf(i,r);let o=null;const a=t.nodes.library.getColorSpaceFunction(n);return null!==a?o=Xp(a(s.rgb),s.a):(console.error("ColorSpaceNode: Unsupported Color Space configuration.",n),o=s),o}}const Hf=e=>Sp(new jf(Sp(e),Df,kf)),qf=e=>Sp(new jf(Sp(e),kf,Df)),$f=(e,t)=>Sp(new jf(Sp(e),Df,t)),Xf=(e,t)=>Sp(new jf(Sp(e),t,Df));Jd("toOutputColorSpace",Hf),Jd("toWorkingColorSpace",qf),Jd("workingToColorSpace",$f),Jd("colorSpaceToWorking",Xf);let Yf=class extends Vd{static get type(){return"ReferenceElementNode"}constructor(e,t){super(e,t),this.referenceNode=e,this.isReferenceElementNode=!0}getNodeType(){return this.referenceNode.uniformType}generate(e){const t=super.generate(e),s=this.referenceNode.getNodeType(),i=this.getNodeType();return e.format(t,s,i)}};class Zf extends Ld{static get type(){return"ReferenceBaseNode"}constructor(e,t,s=null,i=null){super(),this.property=e,this.uniformType=t,this.object=s,this.count=i,this.properties=e.split("."),this.reference=s,this.node=null,this.group=null,this.updateType=Bd.OBJECT}setGroup(e){return this.group=e,this}element(e){return Sp(new Yf(this,Sp(e)))}setNodeType(e){const t=pm(null,e).getSelf();null!==this.group&&t.setGroup(this.group),this.node=t}getNodeType(e){return null===this.node&&(this.updateReference(e),this.updateValue()),this.node.getNodeType(e)}getValueFromReference(e=this.reference){const{properties:t}=this;let s=e[t[0]];for(let e=1;eSp(new Jf(e,t,s));class Qf extends kd{static get type(){return"ToneMappingNode"}constructor(e,t=ty,s=null){super("vec3"),this.toneMapping=e,this.exposureNode=t,this.colorNode=s}getCacheKey(){return _d(super.getCacheKey(),this.toneMapping)}setup(e){const t=this.colorNode||e.context.color,s=this.toneMapping;if(0===s)return t;let i=null;const r=e.renderer.nodes.library.getToneMappingFunction(s);return null!==r?i=Xp(r(t.rgb,this.exposureNode),t.a):(console.error("ToneMappingNode: Unsupported Tone Mapping configuration.",s),i=t),i}}const ey=(e,t,s)=>Sp(new Qf(e,Sp(t),Sp(s))),ty=Kf("toneMappingExposure","float");Jd("toneMapping",((e,t,s)=>ey(t,s,e)));class sy extends $d{static get type(){return"BufferAttributeNode"}constructor(e,t=null,s=0,i=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferStride=s,this.bufferOffset=i,this.usage=Cs,this.instanced=!1,this.attribute=null,this.global=!0,e&&!0===e.isBufferAttribute&&(this.attribute=e,this.usage=e.usage,this.instanced=e.isInstancedBufferAttribute)}getHash(e){if(0===this.bufferStride&&0===this.bufferOffset){let t=e.globalCache.getData(this.value);return void 0===t&&(t={node:this},e.globalCache.setData(this.value,t)),t.node.uuid}return this.uuid}getNodeType(e){return null===this.bufferType&&(this.bufferType=e.getTypeFromAttribute(this.attribute)),this.bufferType}setup(e){if(null!==this.attribute)return;const t=this.getNodeType(e),s=this.value,i=e.getTypeLength(t),r=this.bufferStride||i,n=this.bufferOffset,o=!0===s.isInterleavedBuffer?s:new so(s,r),a=new ro(o,i,n);o.setUsage(this.usage),this.attribute=a,this.attribute.isInstancedBufferAttribute=this.instanced}generate(e){const t=this.getNodeType(e),s=e.getBufferAttributeFromNode(this,t),i=e.getPropertyName(s);let r=null;if("vertex"===e.shaderStage||"compute"===e.shaderStage)this.name=i,r=i;else{r=Vf(this).build(e,t)}return r}getInputType(){return"bufferAttribute"}setUsage(e){return this.usage=e,this.attribute&&!0===this.attribute.isBufferAttribute&&(this.attribute.usage=e),this}setInstanced(e){return this.instanced=e,this}}const iy=(e,t,s,i)=>Sp(new sy(e,t,s,i)),ry=(e,t,s,i)=>iy(e,t,s,i).setUsage(Rs),ny=(e,t,s,i)=>iy(e,t,s,i).setInstanced(!0),oy=(e,t,s,i)=>ry(e,t,s,i).setInstanced(!0);Jd("toAttribute",(e=>iy(e.value)));class ay extends Ld{static get type(){return"ComputeNode"}constructor(e,t,s=[64]){super("void"),this.isComputeNode=!0,this.computeNode=e,this.count=t,this.workgroupSize=s,this.dispatchCount=0,this.version=1,this.updateBeforeType=Bd.OBJECT,this.updateDispatchCount()}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){!0===e&&this.version++}updateDispatchCount(){const{count:e,workgroupSize:t}=this;let s=t[0];for(let e=1;eSp(new ay(Sp(e),t,s));Jd("compute",hy);class uy extends Ld{static get type(){return"CacheNode"}constructor(e,t=!0){super(),this.node=e,this.parent=t,this.isCacheNode=!0}getNodeType(e){return this.node.getNodeType(e)}build(e,...t){const s=e.getCache(),i=e.getCacheFromNode(this,this.parent);e.setCache(i);const r=this.node.build(e,...t);return e.setCache(s),r}}const ly=(e,...t)=>Sp(new uy(Sp(e),...t));Jd("cache",ly);class cy extends Ld{static get type(){return"BypassNode"}constructor(e,t){super(),this.isBypassNode=!0,this.outputNode=e,this.callNode=t}getNodeType(e){return this.outputNode.getNodeType(e)}generate(e){const t=this.callNode.build(e,"void");return""!==t&&e.addLineFlowCode(t,this),this.outputNode.build(e)}}const dy=Ap(cy);Jd("bypass",dy);class py extends Ld{static get type(){return"RemapNode"}constructor(e,t,s,i=Up(0),r=Up(1)){super(),this.node=e,this.inLowNode=t,this.inHighNode=s,this.outLowNode=i,this.outHighNode=r,this.doClamp=!0}setup(){const{node:e,inLowNode:t,inHighNode:s,outLowNode:i,outHighNode:r,doClamp:n}=this;let o=e.sub(t).div(s.sub(t));return!0===n&&(o=o.clamp()),o.mul(r.sub(i)).add(i)}}const my=Ap(py,null,null,{doClamp:!1}),gy=Ap(py);Jd("remap",my),Jd("remapClamp",gy);class fy extends Ld{static get type(){return"ExpressionNode"}constructor(e="",t="void"){super(t),this.snippet=e}generate(e,t){const s=this.getNodeType(e),i=this.snippet;if("void"!==s)return e.format(`( ${i} )`,s,t);e.addLineFlowCode(i,this)}}const yy=Ap(fy),xy=e=>(e?Bf(e,yy("discard")):yy("discard")).append(),by=()=>yy("return").append();Jd("discard",xy);class vy extends kd{static get type(){return"RenderOutputNode"}constructor(e,t,s){super("vec4"),this.colorNode=e,this.toneMapping=t,this.outputColorSpace=s,this.isRenderOutput=!0}setup({context:e}){let t=this.colorNode||e.color;const s=(null!==this.toneMapping?this.toneMapping:e.toneMapping)||0,i=(null!==this.outputColorSpace?this.outputColorSpace:e.outputColorSpace)||Yt;return 0!==s&&(t=t.toneMapping(s)),i!==Yt&&i!==ci.workingColorSpace&&(t=t.workingToColorSpace(i)),t}}const Ty=(e,t=null,s=null)=>Sp(new vy(Sp(e),t,s));function _y(e){console.warn("THREE.TSLBase: AddNodeElement has been removed in favor of tree-shaking. Trying add",e)}Jd("renderOutput",Ty);class wy extends Ld{static get type(){return"AttributeNode"}constructor(e,t=null){super(t),this.global=!0,this._attributeName=e}getHash(e){return this.getAttributeName(e)}getNodeType(e){let t=this.nodeType;if(null===t){const s=this.getAttributeName(e);if(e.hasGeometryAttribute(s)){const i=e.geometry.getAttribute(s);t=e.getTypeFromAttribute(i)}else t="float"}return t}setAttributeName(e){return this._attributeName=e,this}getAttributeName(){return this._attributeName}generate(e){const t=this.getAttributeName(e),s=this.getNodeType(e);if(!0===e.hasGeometryAttribute(t)){const i=e.geometry.getAttribute(t),r=e.getTypeFromAttribute(i),n=e.getAttribute(t,r);if("vertex"===e.shaderStage)return e.format(n.name,r,s);return Vf(this).build(e,s)}return console.warn(`AttributeNode: Vertex attribute "${t}" not found on geometry.`),e.generateConst(s)}serialize(e){super.serialize(e),e.global=this.global,e._attributeName=this._attributeName}deserialize(e){super.deserialize(e),this.global=e.global,this._attributeName=e._attributeName}}const Sy=(e,t)=>Sp(new wy(e,t)),My=e=>Sy("uv"+(e>0?e:""),"vec2");class Ny extends Ld{static get type(){return"TextureSizeNode"}constructor(e,t=null){super("uvec2"),this.isTextureSizeNode=!0,this.textureNode=e,this.levelNode=t}generate(e,t){const s=this.textureNode.build(e,"property"),i=null===this.levelNode?"0":this.levelNode.build(e,"int");return e.format(`${e.getMethod("textureDimensions")}( ${s}, ${i} )`,this.getNodeType(e),t)}}const Ay=Ap(Ny);class Cy extends dm{static get type(){return"MaxMipLevelNode"}constructor(e){super(0),this._textureNode=e,this.updateType=Bd.FRAME}get textureNode(){return this._textureNode}get texture(){return this._textureNode.value}update(){const e=this.texture,t=e.images,s=t&&t.length>0?t[0]&&t[0].image||t[0]:e.image;if(s&&void 0!==s.width){const{width:e,height:t}=s;this.value=Math.log2(Math.max(e,t))}}}const Ry=Ap(Cy);class Ey extends dm{static get type(){return"TextureNode"}constructor(e,t=null,s=null,i=null){super(e),this.isTextureNode=!0,this.uvNode=t,this.levelNode=s,this.biasNode=i,this.compareNode=null,this.depthNode=null,this.gradNode=null,this.sampler=!0,this.updateMatrix=!1,this.updateType=Bd.NONE,this.referenceNode=null,this._value=e,this._matrixUniform=null,this.setUpdateMatrix(null===t)}set value(e){this.referenceNode?this.referenceNode.value=e:this._value=e}get value(){return this.referenceNode?this.referenceNode.value:this._value}getUniformHash(){return this.value.uuid}getNodeType(){return!0===this.value.isDepthTexture?"float":this.value.type===Be?"uvec4":this.value.type===Ee?"ivec4":"vec4"}getInputType(){return"texture"}getDefaultUV(){return My(this.value.channel)}updateReference(){return this.value}getTransformedUV(e){return null===this._matrixUniform&&(this._matrixUniform=pm(this.value.matrix)),this._matrixUniform.mul(jp(e,1)).xy}setUpdateMatrix(e){return this.updateMatrix=e,this.updateType=e?Bd.FRAME:Bd.NONE,this}setupUV(e,t){const s=this.value;return!e.isFlipY()||!0!==s.isRenderTargetTexture&&!0!==s.isFramebufferTexture&&!0!==s.isDepthTexture||(t=this.sampler?t.flipY():t.setY(Op(Ay(this,this.levelNode).y).sub(t.y).sub(1))),t}setup(e){const t=e.getNodeProperties(this);t.referenceNode=this.referenceNode;let s=this.uvNode;null!==s&&!0!==e.context.forceUVContext||!e.context.getUV||(s=e.context.getUV(this)),s||(s=this.getDefaultUV()),!0===this.updateMatrix&&(s=this.getTransformedUV(s)),s=this.setupUV(e,s);let i=this.levelNode;null===i&&e.context.getTextureLevel&&(i=e.context.getTextureLevel(this)),t.uvNode=s,t.levelNode=i,t.biasNode=this.biasNode,t.compareNode=this.compareNode,t.gradNode=this.gradNode,t.depthNode=this.depthNode}generateUV(e,t){return t.build(e,!0===this.sampler?"vec2":"ivec2")}generateSnippet(e,t,s,i,r,n,o,a){const h=this.value;let u;return u=i?e.generateTextureLevel(h,t,s,i,n):r?e.generateTextureBias(h,t,s,r,n):a?e.generateTextureGrad(h,t,s,a,n):o?e.generateTextureCompare(h,t,s,o,n):!1===this.sampler?e.generateTextureLoad(h,t,s,n):e.generateTexture(h,t,s,n),u}generate(e,t){const s=e.getNodeProperties(this),i=this.value;if(!i||!0!==i.isTexture)throw new Error("TextureNode: Need a three.js texture.");const r=super.generate(e,"property");if("sampler"===t)return r+"_sampler";if(e.isReference(t))return r;{const n=e.getDataFromNode(this);let o=n.propertyName;if(void 0===o){const{uvNode:t,levelNode:i,biasNode:a,compareNode:h,depthNode:u,gradNode:l}=s,c=this.generateUV(e,t),d=i?i.build(e,"float"):null,p=a?a.build(e,"float"):null,m=u?u.build(e,"int"):null,g=h?h.build(e,"float"):null,f=l?[l[0].build(e,"vec2"),l[1].build(e,"vec2")]:null,y=e.getVarFromNode(this);o=e.getPropertyName(y);const x=this.generateSnippet(e,r,c,d,p,m,g,f);e.addLineFlowCode(`${o} = ${x}`,this),n.snippet=x,n.propertyName=o}let a=o;const h=this.getNodeType(e);return e.needsToWorkingColorSpace(i)&&(a=Xf(yy(a,h),i.colorSpace).setup(e).build(e,h)),e.format(a,h,t)}}setSampler(e){return this.sampler=e,this}getSampler(){return this.sampler}uv(e){const t=this.clone();return t.uvNode=Sp(e),t.referenceNode=this.getSelf(),Sp(t)}blur(e){const t=this.clone();return t.biasNode=Sp(e).mul(Ry(t)),t.referenceNode=this.getSelf(),Sp(t)}level(e){const t=this.clone();return t.levelNode=Sp(e),t.referenceNode=this.getSelf(),Sp(t)}size(e){return Ay(this,e)}bias(e){const t=this.clone();return t.biasNode=Sp(e),t.referenceNode=this.getSelf(),Sp(t)}compare(e){const t=this.clone();return t.compareNode=Sp(e),t.referenceNode=this.getSelf(),Sp(t)}grad(e,t){const s=this.clone();return s.gradNode=[Sp(e),Sp(t)],s.referenceNode=this.getSelf(),Sp(s)}depth(e){const t=this.clone();return t.depthNode=Sp(e),t.referenceNode=this.getSelf(),Sp(t)}serialize(e){super.serialize(e),e.value=this.value.toJSON(e.meta).uuid,e.sampler=this.sampler,e.updateMatrix=this.updateMatrix,e.updateType=this.updateType}deserialize(e){super.deserialize(e),this.value=e.meta.textures[e.value],this.sampler=e.sampler,this.updateMatrix=e.updateMatrix,this.updateType=e.updateType}update(){const e=this.value,t=this._matrixUniform;null!==t&&(t.value=e.matrix),!0===e.matrixAutoUpdate&&e.updateMatrix()}clone(){const e=new this.constructor(this.value,this.uvNode,this.levelNode,this.biasNode);return e.sampler=this.sampler,e}}const By=Ap(Ey),Iy=(...e)=>By(...e).setSampler(!1),Py=e=>(!0===e.isNode?e:By(e)).convert("sampler"),Fy=pm("float").label("cameraNear").setGroup(lm).onRenderUpdate((({camera:e})=>e.near)),zy=pm("float").label("cameraFar").setGroup(lm).onRenderUpdate((({camera:e})=>e.far)),Uy=pm("float").label("cameraLogDepth").setGroup(lm).onRenderUpdate((({camera:e})=>2/(Math.log(e.far+1)/Math.LN2))),Oy=pm("mat4").label("cameraProjectionMatrix").setGroup(lm).onRenderUpdate((({camera:e})=>e.projectionMatrix)),Ly=pm("mat4").label("cameraProjectionMatrixInverse").setGroup(lm).onRenderUpdate((({camera:e})=>e.projectionMatrixInverse)),Vy=pm("mat4").label("cameraViewMatrix").setGroup(lm).onRenderUpdate((({camera:e})=>e.matrixWorldInverse)),Dy=pm("mat4").label("cameraWorldMatrix").setGroup(lm).onRenderUpdate((({camera:e})=>e.matrixWorld)),ky=pm("mat3").label("cameraNormalMatrix").setGroup(lm).onRenderUpdate((({camera:e})=>e.normalMatrix)),Gy=pm(new Ri).label("cameraPosition").setGroup(lm).onRenderUpdate((({camera:e},t)=>t.value.setFromMatrixPosition(e.matrixWorld)));class Wy extends Ld{static get type(){return"Object3DNode"}constructor(e,t=null){super(),this.scope=e,this.object3d=t,this.updateType=Bd.OBJECT,this._uniformNode=new dm(null)}getNodeType(){const e=this.scope;return e===Wy.WORLD_MATRIX?"mat4":e===Wy.POSITION||e===Wy.VIEW_POSITION||e===Wy.DIRECTION||e===Wy.SCALE?"vec3":void 0}update(e){const t=this.object3d,s=this._uniformNode,i=this.scope;if(i===Wy.WORLD_MATRIX)s.value=t.matrixWorld;else if(i===Wy.POSITION)s.value=s.value||new Ri,s.value.setFromMatrixPosition(t.matrixWorld);else if(i===Wy.SCALE)s.value=s.value||new Ri,s.value.setFromMatrixScale(t.matrixWorld);else if(i===Wy.DIRECTION)s.value=s.value||new Ri,t.getWorldDirection(s.value);else if(i===Wy.VIEW_POSITION){const i=e.camera;s.value=s.value||new Ri,s.value.setFromMatrixPosition(t.matrixWorld),s.value.applyMatrix4(i.matrixWorldInverse)}}generate(e){const t=this.scope;return t===Wy.WORLD_MATRIX?this._uniformNode.nodeType="mat4":t!==Wy.POSITION&&t!==Wy.VIEW_POSITION&&t!==Wy.DIRECTION&&t!==Wy.SCALE||(this._uniformNode.nodeType="vec3"),this._uniformNode.build(e)}serialize(e){super.serialize(e),e.scope=this.scope}deserialize(e){super.deserialize(e),this.scope=e.scope}}Wy.WORLD_MATRIX="worldMatrix",Wy.POSITION="position",Wy.SCALE="scale",Wy.VIEW_POSITION="viewPosition",Wy.DIRECTION="direction";const jy=Ap(Wy,Wy.DIRECTION),Hy=Ap(Wy,Wy.WORLD_MATRIX),qy=Ap(Wy,Wy.POSITION),$y=Ap(Wy,Wy.SCALE),Xy=Ap(Wy,Wy.VIEW_POSITION);class Yy extends Wy{static get type(){return"ModelNode"}constructor(e){super(e)}update(e){this.object3d=e.object,super.update(e)}}const Zy=Cp(Yy,Yy.DIRECTION),Jy=Cp(Yy,Yy.WORLD_MATRIX),Ky=Cp(Yy,Yy.POSITION),Qy=Cp(Yy,Yy.SCALE),ex=Cp(Yy,Yy.VIEW_POSITION),tx=pm(new ei).onObjectUpdate((({object:e},t)=>t.value.getNormalMatrix(e.matrixWorld))),sx=pm(new nr).onObjectUpdate((({object:e},t)=>t.value.copy(e.matrixWorld).invert())),ix=Vy.mul(Jy).toVar("modelViewMatrix"),rx=Rp((e=>(e.context.isHighPrecisionModelViewMatrix=!0,pm("mat4").onObjectUpdate((({object:e,camera:t})=>e.modelViewMatrix.multiplyMatrices(t.matrixWorldInverse,e.matrixWorld)))))).once()().toVar("highPrecisionModelViewMatrix"),nx=Rp((e=>{const t=e.context.isHighPrecisionModelViewMatrix;return pm("mat3").onObjectUpdate((({object:e,camera:s})=>(!0!==t&&e.modelViewMatrix.multiplyMatrices(s.matrixWorldInverse,e.matrixWorld),e.normalMatrix.getNormalMatrix(e.modelViewMatrix))))})).once()().toVar("highPrecisionModelNormalMatrix"),ox=Sy("position","vec3"),ax=ox.varying("positionLocal"),hx=ox.varying("positionPrevious"),ux=Jy.mul(ax).xyz.varying("v_positionWorld"),lx=ax.transformDirection(Jy).varying("v_positionWorldDirection").normalize().toVar("positionWorldDirection"),cx=ix.mul(ax).xyz.varying("v_positionView"),dx=cx.negate().varying("v_positionViewDirection").normalize().toVar("positionViewDirection");class px extends Ld{static get type(){return"FrontFacingNode"}constructor(){super("bool"),this.isFrontFacingNode=!0}generate(e){const{renderer:t,material:s}=e;return t.coordinateSystem===Vs&&s.side===d?"false":e.getFrontFacing()}}const mx=Cp(px),gx=Up(mx).mul(2).sub(1),fx=Sy("normal","vec3"),yx=Rp((e=>!1===e.geometry.hasAttribute("normal")?(console.warn('TSL.NormalNode: Vertex attribute "normal" not found on geometry.'),jp(0,1,0)):fx),"vec3").once()().toVar("normalLocal"),xx=cx.dFdx().cross(cx.dFdy()).normalize().toVar("normalFlat"),bx=Rp((e=>{let t;return t=!0===e.material.flatShading?xx:Vf(Mx(yx),"v_normalView").normalize(),t}),"vec3").once()().toVar("normalView"),vx=Vf(bx.transformDirection(Vy),"v_normalWorld").normalize().toVar("normalWorld"),Tx=Rp((e=>e.context.setupNormal()),"vec3").once()().mul(gx).toVar("transformedNormalView"),_x=Tx.transformDirection(Vy).toVar("transformedNormalWorld"),wx=Rp((e=>e.context.setupClearcoatNormal()),"vec3").once()().mul(gx).toVar("transformedClearcoatNormalView"),Sx=Rp((([e,t=Jy])=>{const s=Qp(t),i=e.div(jp(s[0].dot(s[0]),s[1].dot(s[1]),s[2].dot(s[2])));return s.mul(i).xyz})),Mx=Rp((([e],t)=>{const s=t.renderer.nodes.modelNormalViewMatrix;if(null!==s)return s.transformDirection(e);const i=tx.mul(e);return Vy.transformDirection(i)})),Nx=pm(0).onReference((({material:e})=>e)).onRenderUpdate((({material:e})=>e.refractionRatio)),Ax=dx.negate().reflect(Tx),Cx=dx.negate().refract(Tx,Nx),Rx=Ax.transformDirection(Vy).toVar("reflectVector"),Ex=Cx.transformDirection(Vy).toVar("reflectVector");class Bx extends Ey{static get type(){return"CubeTextureNode"}constructor(e,t=null,s=null,i=null){super(e,t,s,i),this.isCubeTextureNode=!0}getInputType(){return"cubeTexture"}getDefaultUV(){const e=this.value;return e.mapping===he?Rx:e.mapping===ue?Ex:(console.error('THREE.CubeTextureNode: Mapping "%s" not supported.',e.mapping),jp(0,0,0))}setUpdateMatrix(){}setupUV(e,t){const s=this.value;return e.renderer.coordinateSystem!==Ds&&s.isRenderTargetTexture?t:jp(t.x.negate(),t.yz)}generateUV(e,t){return t.build(e,"vec3")}}const Ix=Ap(Bx);class Px extends dm{static get type(){return"BufferNode"}constructor(e,t,s=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferCount=s}getElementType(e){return this.getNodeType(e)}getInputType(){return"buffer"}}const Fx=(e,t,s)=>Sp(new Px(e,t,s));class zx extends Vd{static get type(){return"UniformArrayElementNode"}constructor(e,t){super(e,t),this.isArrayBufferElementNode=!0}generate(e){const t=super.generate(e),s=this.getNodeType();return e.format(t,"vec4",s)}}class Ux extends Px{static get type(){return"UniformArrayNode"}constructor(e,t=null){super(null,"vec4"),this.array=e,this.elementType=t,this._elementType=null,this._elementLength=0,this.updateType=Bd.RENDER,this.isArrayBufferNode=!0}getElementType(){return this.elementType||this._elementType}getElementLength(){return this._elementLength}update(){const{array:e,value:t}=this,s=this.getElementLength(),i=this.getElementType();if(1===s)for(let s=0;sSp(new Ux(e,t)),Lx=(e,t)=>(console.warn("TSL.UniformArrayNode: uniforms() has been renamed to uniformArray()."),Sp(new Ux(e,t)));class Vx extends Vd{static get type(){return"ReferenceElementNode"}constructor(e,t){super(e,t),this.referenceNode=e,this.isReferenceElementNode=!0}getNodeType(){return this.referenceNode.uniformType}generate(e){const t=super.generate(e),s=this.referenceNode.getNodeType(),i=this.getNodeType();return e.format(t,s,i)}}class Dx extends Ld{static get type(){return"ReferenceNode"}constructor(e,t,s=null,i=null){super(),this.property=e,this.uniformType=t,this.object=s,this.count=i,this.properties=e.split("."),this.reference=s,this.node=null,this.group=null,this.name=null,this.updateType=Bd.OBJECT}element(e){return Sp(new Vx(this,Sp(e)))}setGroup(e){return this.group=e,this}label(e){return this.name=e,this}setNodeType(e){let t=null;t=null!==this.count?Fx(null,e,this.count):Array.isArray(this.getValueFromReference())?Ox(null,e):"texture"===e?By(null):"cubeTexture"===e?Ix(null):pm(null,e),null!==this.group&&t.setGroup(this.group),null!==this.name&&t.label(this.name),this.node=t.getSelf()}getNodeType(e){return null===this.node&&(this.updateReference(e),this.updateValue()),this.node.getNodeType(e)}getValueFromReference(e=this.reference){const{properties:t}=this;let s=e[t[0]];for(let e=1;eSp(new Dx(e,t,s)),Gx=(e,t,s,i)=>Sp(new Dx(e,t,i,s));class Wx extends Dx{static get type(){return"MaterialReferenceNode"}constructor(e,t,s=null){super(e,t,s),this.material=s,this.isMaterialReferenceNode=!0}updateReference(e){return this.reference=null!==this.material?this.material:e.material,this.reference}}const jx=(e,t,s)=>Sp(new Wx(e,t,s)),Hx=Rp((e=>(!1===e.geometry.hasAttribute("tangent")&&e.geometry.computeTangents(),Sy("tangent","vec4"))))(),qx=Hx.xyz.toVar("tangentLocal"),$x=ix.mul(Xp(qx,0)).xyz.varying("v_tangentView").normalize().toVar("tangentView"),Xx=$x.transformDirection(Vy).varying("v_tangentWorld").normalize().toVar("tangentWorld"),Yx=$x.toVar("transformedTangentView"),Zx=Yx.transformDirection(Vy).normalize().toVar("transformedTangentWorld"),Jx=e=>e.mul(Hx.w).xyz,Kx=Vf(Jx(fx.cross(Hx)),"v_bitangentGeometry").normalize().toVar("bitangentGeometry"),Qx=Vf(Jx(yx.cross(qx)),"v_bitangentLocal").normalize().toVar("bitangentLocal"),eb=Vf(Jx(bx.cross($x)),"v_bitangentView").normalize().toVar("bitangentView"),tb=Vf(Jx(vx.cross(Xx)),"v_bitangentWorld").normalize().toVar("bitangentWorld"),sb=Jx(Tx.cross(Yx)).normalize().toVar("transformedBitangentView"),ib=sb.transformDirection(Vy).normalize().toVar("transformedBitangentWorld"),rb=Qp($x,eb,bx),nb=dx.mul(rb),ob=(e,t)=>e.sub(nb.mul(t)),ab=(()=>{let e=Bm.cross(dx);return e=e.cross(Bm).normalize(),e=Tf(e,Tx,Rm.mul(bm.oneMinus()).oneMinus().pow2().pow2()).normalize(),e})(),hb=Rp((e=>{const{eye_pos:t,surf_norm:s,mapN:i,uv:r}=e,n=t.dFdx(),o=t.dFdy(),a=r.dFdx(),h=r.dFdy(),u=s,l=o.cross(u),c=u.cross(n),d=l.mul(a.x).add(c.mul(h.x)),p=l.mul(a.y).add(c.mul(h.y)),m=d.dot(d).max(p.dot(p)),g=gx.mul(m.inverseSqrt());return Zm(d.mul(i.x,g),p.mul(i.y,g),u.mul(i.z)).normalize()}));class ub extends kd{static get type(){return"NormalMapNode"}constructor(e,t=null){super("vec3"),this.node=e,this.scaleNode=t,this.normalMapType=0}setup(e){const{normalMapType:t,scaleNode:s}=this;let i=this.node.mul(2).sub(1);null!==s&&(i=jp(i.xy.mul(s),i.z));let r=null;if(1===t)r=Mx(i);else if(0===t){r=!0===e.hasGeometryAttribute("tangent")?rb.mul(i).normalize():hb({eye_pos:cx,surf_norm:bx,mapN:i,uv:My()})}return r}}const lb=Ap(ub),cb=Rp((({textureNode:e,bumpScale:t})=>{const s=t=>e.cache().context({getUV:e=>t(e.uvNode||My()),forceUVContext:!0}),i=Up(s((e=>e)));return Dp(Up(s((e=>e.add(e.dFdx())))).sub(i),Up(s((e=>e.add(e.dFdy())))).sub(i)).mul(t)})),db=Rp((e=>{const{surf_pos:t,surf_norm:s,dHdxy:i}=e,r=t.dFdx().normalize(),n=s,o=t.dFdy().normalize().cross(n),a=n.cross(r),h=r.dot(o).mul(gx),u=h.sign().mul(i.x.mul(o).add(i.y.mul(a)));return h.abs().mul(s).sub(u).normalize()}));class pb extends kd{static get type(){return"BumpMapNode"}constructor(e,t=null){super("vec3"),this.textureNode=e,this.scaleNode=t}setup(){const e=null!==this.scaleNode?this.scaleNode:1,t=cb({textureNode:this.textureNode,bumpScale:e});return db({surf_pos:cx,surf_norm:bx,dHdxy:t})}}const mb=Ap(pb),gb=new Map;class fb extends Ld{static get type(){return"MaterialNode"}constructor(e){super(),this.scope=e}getCache(e,t){let s=gb.get(e);return void 0===s&&(s=jx(e,t),gb.set(e,s)),s}getFloat(e){return this.getCache(e,"float")}getColor(e){return this.getCache(e,"color")}getTexture(e){return this.getCache("map"===e?"map":e+"Map","texture")}setup(e){const t=e.context.material,s=this.scope;let i=null;if(s===fb.COLOR){const e=void 0!==t.color?this.getColor(s):jp();i=t.map&&!0===t.map.isTexture?e.mul(this.getTexture("map")):e}else if(s===fb.OPACITY){const e=this.getFloat(s);i=t.alphaMap&&!0===t.alphaMap.isTexture?e.mul(this.getTexture("alpha")):e}else if(s===fb.SPECULAR_STRENGTH)i=t.specularMap&&!0===t.specularMap.isTexture?this.getTexture("specular").r:Up(1);else if(s===fb.SPECULAR_INTENSITY){const e=this.getFloat(s);i=t.specularMap?e.mul(this.getTexture(s).a):e}else if(s===fb.SPECULAR_COLOR){const e=this.getColor(s);i=t.specularColorMap&&!0===t.specularColorMap.isTexture?e.mul(this.getTexture(s).rgb):e}else if(s===fb.ROUGHNESS){const e=this.getFloat(s);i=t.roughnessMap&&!0===t.roughnessMap.isTexture?e.mul(this.getTexture(s).g):e}else if(s===fb.METALNESS){const e=this.getFloat(s);i=t.metalnessMap&&!0===t.metalnessMap.isTexture?e.mul(this.getTexture(s).b):e}else if(s===fb.EMISSIVE){const e=this.getFloat("emissiveIntensity"),r=this.getColor(s).mul(e);i=t.emissiveMap&&!0===t.emissiveMap.isTexture?r.mul(this.getTexture(s)):r}else if(s===fb.NORMAL)t.normalMap?(i=lb(this.getTexture("normal"),this.getCache("normalScale","vec2")),i.normalMapType=t.normalMapType):i=t.bumpMap?mb(this.getTexture("bump").r,this.getFloat("bumpScale")):bx;else if(s===fb.CLEARCOAT){const e=this.getFloat(s);i=t.clearcoatMap&&!0===t.clearcoatMap.isTexture?e.mul(this.getTexture(s).r):e}else if(s===fb.CLEARCOAT_ROUGHNESS){const e=this.getFloat(s);i=t.clearcoatRoughnessMap&&!0===t.clearcoatRoughnessMap.isTexture?e.mul(this.getTexture(s).r):e}else if(s===fb.CLEARCOAT_NORMAL)i=t.clearcoatNormalMap?lb(this.getTexture(s),this.getCache(s+"Scale","vec2")):bx;else if(s===fb.SHEEN){const e=this.getColor("sheenColor").mul(this.getFloat("sheen"));i=t.sheenColorMap&&!0===t.sheenColorMap.isTexture?e.mul(this.getTexture("sheenColor").rgb):e}else if(s===fb.SHEEN_ROUGHNESS){const e=this.getFloat(s);i=t.sheenRoughnessMap&&!0===t.sheenRoughnessMap.isTexture?e.mul(this.getTexture(s).a):e,i=i.clamp(.07,1)}else if(s===fb.ANISOTROPY)if(t.anisotropyMap&&!0===t.anisotropyMap.isTexture){const e=this.getTexture(s);i=Kp(ev.x,ev.y,ev.y.negate(),ev.x).mul(e.rg.mul(2).sub(Dp(1)).normalize().mul(e.b))}else i=ev;else if(s===fb.IRIDESCENCE_THICKNESS){const e=kx("1","float",t.iridescenceThicknessRange);if(t.iridescenceThicknessMap){const r=kx("0","float",t.iridescenceThicknessRange);i=e.sub(r).mul(this.getTexture(s).g).add(r)}else i=e}else if(s===fb.TRANSMISSION){const e=this.getFloat(s);i=t.transmissionMap?e.mul(this.getTexture(s).r):e}else if(s===fb.THICKNESS){const e=this.getFloat(s);i=t.thicknessMap?e.mul(this.getTexture(s).g):e}else if(s===fb.IOR)i=this.getFloat(s);else if(s===fb.LIGHT_MAP)i=this.getTexture(s).rgb.mul(this.getFloat("lightMapIntensity"));else if(s===fb.AO_MAP)i=this.getTexture(s).r.sub(1).mul(this.getFloat("aoMapIntensity")).add(1);else{const t=this.getNodeType(e);i=this.getCache(s,t)}return i}}fb.ALPHA_TEST="alphaTest",fb.COLOR="color",fb.OPACITY="opacity",fb.SHININESS="shininess",fb.SPECULAR="specular",fb.SPECULAR_STRENGTH="specularStrength",fb.SPECULAR_INTENSITY="specularIntensity",fb.SPECULAR_COLOR="specularColor",fb.REFLECTIVITY="reflectivity",fb.ROUGHNESS="roughness",fb.METALNESS="metalness",fb.NORMAL="normal",fb.CLEARCOAT="clearcoat",fb.CLEARCOAT_ROUGHNESS="clearcoatRoughness",fb.CLEARCOAT_NORMAL="clearcoatNormal",fb.EMISSIVE="emissive",fb.ROTATION="rotation",fb.SHEEN="sheen",fb.SHEEN_ROUGHNESS="sheenRoughness",fb.ANISOTROPY="anisotropy",fb.IRIDESCENCE="iridescence",fb.IRIDESCENCE_IOR="iridescenceIOR",fb.IRIDESCENCE_THICKNESS="iridescenceThickness",fb.IOR="ior",fb.TRANSMISSION="transmission",fb.THICKNESS="thickness",fb.ATTENUATION_DISTANCE="attenuationDistance",fb.ATTENUATION_COLOR="attenuationColor",fb.LINE_SCALE="scale",fb.LINE_DASH_SIZE="dashSize",fb.LINE_GAP_SIZE="gapSize",fb.LINE_WIDTH="linewidth",fb.LINE_DASH_OFFSET="dashOffset",fb.POINT_WIDTH="pointWidth",fb.DISPERSION="dispersion",fb.LIGHT_MAP="light",fb.AO_MAP="ao";const yb=Cp(fb,fb.ALPHA_TEST),xb=Cp(fb,fb.COLOR),bb=Cp(fb,fb.SHININESS),vb=Cp(fb,fb.EMISSIVE),Tb=Cp(fb,fb.OPACITY),_b=Cp(fb,fb.SPECULAR),wb=Cp(fb,fb.SPECULAR_INTENSITY),Sb=Cp(fb,fb.SPECULAR_COLOR),Mb=Cp(fb,fb.SPECULAR_STRENGTH),Nb=Cp(fb,fb.REFLECTIVITY),Ab=Cp(fb,fb.ROUGHNESS),Cb=Cp(fb,fb.METALNESS),Rb=Cp(fb,fb.NORMAL).context({getUV:null}),Eb=Cp(fb,fb.CLEARCOAT),Bb=Cp(fb,fb.CLEARCOAT_ROUGHNESS),Ib=Cp(fb,fb.CLEARCOAT_NORMAL).context({getUV:null}),Pb=Cp(fb,fb.ROTATION),Fb=Cp(fb,fb.SHEEN),zb=Cp(fb,fb.SHEEN_ROUGHNESS),Ub=Cp(fb,fb.ANISOTROPY),Ob=Cp(fb,fb.IRIDESCENCE),Lb=Cp(fb,fb.IRIDESCENCE_IOR),Vb=Cp(fb,fb.IRIDESCENCE_THICKNESS),Db=Cp(fb,fb.TRANSMISSION),kb=Cp(fb,fb.THICKNESS),Gb=Cp(fb,fb.IOR),Wb=Cp(fb,fb.ATTENUATION_DISTANCE),jb=Cp(fb,fb.ATTENUATION_COLOR),Hb=Cp(fb,fb.LINE_SCALE),qb=Cp(fb,fb.LINE_DASH_SIZE),$b=Cp(fb,fb.LINE_GAP_SIZE),Xb=Cp(fb,fb.LINE_WIDTH),Yb=Cp(fb,fb.LINE_DASH_OFFSET),Zb=Cp(fb,fb.POINT_WIDTH),Jb=Cp(fb,fb.DISPERSION),Kb=Cp(fb,fb.LIGHT_MAP),Qb=Cp(fb,fb.AO_MAP),ev=pm(new Qs).onReference((function(e){return e.material})).onRenderUpdate((function({material:e}){this.value.set(e.anisotropy*Math.cos(e.anisotropyRotation),e.anisotropy*Math.sin(e.anisotropyRotation))}));class tv extends kd{static get type(){return"ModelViewProjectionNode"}constructor(e=null){super("vec4"),this.positionNode=e}setup(e){if("fragment"===e.shaderStage)return Vf(e.context.mvp);const t=this.positionNode||ax,s=e.renderer.nodes.modelViewMatrix||ix;return Oy.mul(s).mul(t)}}const sv=Ap(tv);class iv extends Ld{static get type(){return"IndexNode"}constructor(e){super("uint"),this.scope=e,this.isInstanceIndexNode=!0}generate(e){const t=this.getNodeType(e),s=this.scope;let i,r;if(s===iv.VERTEX)i=e.getVertexIndex();else if(s===iv.INSTANCE)i=e.getInstanceIndex();else if(s===iv.DRAW)i=e.getDrawIndex();else if(s===iv.INVOCATION_LOCAL)i=e.getInvocationLocalIndex();else if(s===iv.INVOCATION_SUBGROUP)i=e.getInvocationSubgroupIndex();else{if(s!==iv.SUBGROUP)throw new Error("THREE.IndexNode: Unknown scope: "+s);i=e.getSubgroupIndex()}if("vertex"===e.shaderStage||"compute"===e.shaderStage)r=i;else{r=Vf(this).build(e,t)}return r}}iv.VERTEX="vertex",iv.INSTANCE="instance",iv.SUBGROUP="subgroup",iv.INVOCATION_LOCAL="invocationLocal",iv.INVOCATION_SUBGROUP="invocationSubgroup",iv.DRAW="draw";const rv=Cp(iv,iv.VERTEX),nv=Cp(iv,iv.INSTANCE),ov=Cp(iv,iv.SUBGROUP),av=Cp(iv,iv.INVOCATION_SUBGROUP),hv=Cp(iv,iv.INVOCATION_LOCAL),uv=Cp(iv,iv.DRAW);class lv extends Ld{static get type(){return"InstanceNode"}constructor(e){super("void"),this.instanceMesh=e,this.instanceMatrixNode=null,this.instanceColorNode=null,this.updateType=Bd.FRAME,this.buffer=null,this.bufferColor=null}setup(e){let t=this.instanceMatrixNode,s=this.instanceColorNode;const i=this.instanceMesh;if(null===t){const e=i.instanceMatrix;if(i.count<=1e3)t=Fx(e.array,"mat4",Math.max(i.count,1)).element(nv);else{const s=new wc(e.array,16,1);this.buffer=s;const i=e.usage===Rs?oy:ny,r=[i(s,"vec4",16,0),i(s,"vec4",16,4),i(s,"vec4",16,8),i(s,"vec4",16,12)];t=em(...r)}this.instanceMatrixNode=t}const r=i.instanceColor;if(r&&null===s){const e=new Do(r.array,3),t=r.usage===Rs?oy:ny;this.bufferColor=e,s=jp(t(e,"vec3",3,0)),this.instanceColorNode=s}const n=t.mul(ax).xyz;if(ax.assign(n),e.hasGeometryAttribute("normal")){const e=Sx(yx,t);yx.assign(e)}null!==this.instanceColorNode&&fm("vec3","vInstanceColor").assign(this.instanceColorNode)}update(){this.instanceMesh.instanceMatrix.usage!==Rs&&null!=this.buffer&&this.instanceMesh.instanceMatrix.version!==this.buffer.version&&(this.buffer.version=this.instanceMesh.instanceMatrix.version),this.instanceMesh.instanceColor&&this.instanceMesh.instanceColor.usage!==Rs&&null!=this.bufferColor&&this.instanceMesh.instanceColor.version!==this.bufferColor.version&&(this.bufferColor.version=this.instanceMesh.instanceColor.version)}}const cv=Ap(lv);class dv extends Ld{static get type(){return"BatchNode"}constructor(e){super("void"),this.batchMesh=e,this.batchingIdNode=null}setup(e){null===this.batchingIdNode&&(null===e.getDrawIndex()?this.batchingIdNode=nv:this.batchingIdNode=uv);const t=Rp((([e])=>{const t=Ay(Iy(this.batchMesh._indirectTexture),0),s=Op(e).modInt(Op(t)),i=Op(e).div(Op(t));return Iy(this.batchMesh._indirectTexture,kp(s,i)).x})).setLayout({name:"getIndirectIndex",type:"uint",inputs:[{name:"id",type:"int"}]}),s=t(Op(this.batchingIdNode)),i=this.batchMesh._matricesTexture,r=Ay(Iy(i),0),n=Up(s).mul(4).toInt().toVar(),o=n.modInt(r),a=n.div(Op(r)),h=em(Iy(i,kp(o,a)),Iy(i,kp(o.add(1),a)),Iy(i,kp(o.add(2),a)),Iy(i,kp(o.add(3),a))),u=this.batchMesh._colorsTexture;if(null!==u){const e=Rp((([e])=>{const t=Ay(Iy(u),0).x,s=e,i=s.modInt(t),r=s.div(t);return Iy(u,kp(i,r)).rgb})).setLayout({name:"getBatchingColor",type:"vec3",inputs:[{name:"id",type:"int"}]}),t=e(s);fm("vec3","vBatchColor").assign(t)}const l=Qp(h);ax.assign(h.mul(ax));const c=yx.div(jp(l[0].dot(l[0]),l[1].dot(l[1]),l[2].dot(l[2]))),d=l.mul(c).xyz;yx.assign(d),e.hasGeometryAttribute("tangent")&&qx.mulAssign(l)}}const pv=Ap(dv),mv=new WeakMap;class gv extends Ld{static get type(){return"SkinningNode"}constructor(e,t=!1){let s,i,r;super("void"),this.skinnedMesh=e,this.useReference=t,this.updateType=Bd.OBJECT,this.skinIndexNode=Sy("skinIndex","uvec4"),this.skinWeightNode=Sy("skinWeight","vec4"),t?(s=kx("bindMatrix","mat4"),i=kx("bindMatrixInverse","mat4"),r=Gx("skeleton.boneMatrices","mat4",e.skeleton.bones.length)):(s=pm(e.bindMatrix,"mat4"),i=pm(e.bindMatrixInverse,"mat4"),r=Fx(e.skeleton.boneMatrices,"mat4",e.skeleton.bones.length)),this.bindMatrixNode=s,this.bindMatrixInverseNode=i,this.boneMatricesNode=r,this.previousBoneMatricesNode=null}getSkinnedPosition(e=this.boneMatricesNode,t=ax){const{skinIndexNode:s,skinWeightNode:i,bindMatrixNode:r,bindMatrixInverseNode:n}=this,o=e.element(s.x),a=e.element(s.y),h=e.element(s.z),u=e.element(s.w),l=r.mul(t),c=Zm(o.mul(i.x).mul(l),a.mul(i.y).mul(l),h.mul(i.z).mul(l),u.mul(i.w).mul(l));return n.mul(c).xyz}getSkinnedNormal(e=this.boneMatricesNode,t=yx){const{skinIndexNode:s,skinWeightNode:i,bindMatrixNode:r,bindMatrixInverseNode:n}=this,o=e.element(s.x),a=e.element(s.y),h=e.element(s.z),u=e.element(s.w);let l=Zm(i.x.mul(o),i.y.mul(a),i.z.mul(h),i.w.mul(u));return l=n.mul(l).mul(r),l.transformDirection(t).xyz}getPreviousSkinnedPosition(e){const t=e.object;return null===this.previousBoneMatricesNode&&(t.skeleton.previousBoneMatrices=new Float32Array(t.skeleton.boneMatrices),this.previousBoneMatricesNode=Gx("skeleton.previousBoneMatrices","mat4",t.skeleton.bones.length)),this.getSkinnedPosition(this.previousBoneMatricesNode,hx)}needsPreviousBoneMatrices(e){const t=e.renderer.getMRT();return t&&t.has("velocity")}setup(e){this.needsPreviousBoneMatrices(e)&&hx.assign(this.getPreviousSkinnedPosition(e));const t=this.getSkinnedPosition();if(ax.assign(t),e.hasGeometryAttribute("normal")){const t=this.getSkinnedNormal();yx.assign(t),e.hasGeometryAttribute("tangent")&&qx.assign(t)}}generate(e,t){if("void"!==t)return ax.build(e,t)}update(e){const t=(this.useReference?e.object:this.skinnedMesh).skeleton;mv.get(t)!==e.frameId&&(mv.set(t,e.frameId),null!==this.previousBoneMatricesNode&&t.previousBoneMatrices.set(t.boneMatrices),t.update())}}const fv=e=>Sp(new gv(e)),yv=e=>Sp(new gv(e,!0));class xv extends Ld{static get type(){return"LoopNode"}constructor(e=[]){super(),this.params=e}getVarName(e){return String.fromCharCode("i".charCodeAt()+e)}getProperties(e){const t=e.getNodeProperties(this);if(void 0!==t.stackNode)return t;const s={};for(let e=0,t=this.params.length-1;eNumber(n)?">=":"<"));const l={start:r,end:n,condition:h},c=l.start,d=l.end;let p="",m="",g="";u||(u="int"===a||"uint"===a?h.includes("<")?"++":"--":h.includes("<")?"+= 1.":"-= 1."),p+=e.getVar(a,o)+" = "+c,m+=o+" "+h+" "+d,g+=o+" "+u;const f=`for ( ${p}; ${m}; ${g} )`;e.addFlowCode((0===t?"\n":"")+e.tab+f+" {\n\n").addFlowTab()}const r=i.build(e,"void"),n=t.returnsNode?t.returnsNode.build(e):"";e.removeFlowTab().addFlowCode("\n"+e.tab+r);for(let t=0,s=this.params.length-1;tSp(new xv(Np(e,"int"))).append(),vv=()=>yy("continue").append(),Tv=()=>yy("break").append(),_v=(...e)=>(console.warn("TSL.LoopNode: loop() has been renamed to Loop()."),bv(...e)),wv=new WeakMap,Sv=new Ti,Mv=Rp((({bufferMap:e,influence:t,stride:s,width:i,depth:r,offset:n})=>{const o=Op(rv).mul(s).add(n),a=o.div(i),h=o.sub(a.mul(i));return Iy(e,kp(h,a)).depth(r).mul(t)}));class Nv extends Ld{static get type(){return"MorphNode"}constructor(e){super("void"),this.mesh=e,this.morphBaseInfluence=pm(1),this.updateType=Bd.OBJECT}setup(e){const{geometry:t}=e,s=void 0!==t.morphAttributes.position,i=t.hasAttribute("normal")&&void 0!==t.morphAttributes.normal,r=t.morphAttributes.position||t.morphAttributes.normal||t.morphAttributes.color,n=void 0!==r?r.length:0,{texture:o,stride:a,size:h}=function(e){const t=void 0!==e.morphAttributes.position,s=void 0!==e.morphAttributes.normal,i=void 0!==e.morphAttributes.color,r=e.morphAttributes.position||e.morphAttributes.normal||e.morphAttributes.color,n=void 0!==r?r.length:0;let o=wv.get(e);if(void 0===o||o.count!==n){void 0!==o&&o.texture.dispose();const a=e.morphAttributes.position||[],h=e.morphAttributes.normal||[],u=e.morphAttributes.color||[];let l=0;!0===t&&(l=1),!0===s&&(l=2),!0===i&&(l=3);let c=e.attributes.position.count*l,d=1;const p=4096;c>p&&(d=Math.ceil(c/p),c=p);const m=new Float32Array(c*d*4*n),g=new Si(m,c,d,n);g.type=Ie,g.needsUpdate=!0;const f=4*l;for(let x=0;x{const t=Up(0).toVar();this.mesh.count>1&&null!==this.mesh.morphTexture&&void 0!==this.mesh.morphTexture?t.assign(Iy(this.mesh.morphTexture,kp(Op(e).add(1),Op(nv))).r):t.assign(kx("morphTargetInfluences","float").element(e).toVar()),!0===s&&ax.addAssign(Mv({bufferMap:o,influence:t,stride:a,width:u,depth:e,offset:Op(0)})),!0===i&&yx.addAssign(Mv({bufferMap:o,influence:t,stride:a,width:u,depth:e,offset:Op(1)}))}))}update(){const e=this.morphBaseInfluence;this.mesh.geometry.morphTargetsRelative?e.value=1:e.value=1-this.mesh.morphTargetInfluences.reduce(((e,t)=>e+t),0)}}const Av=Ap(Nv),Cv=(e,t)=>{for(const s of t)if(s.isAnalyticLightNode&&s.light.id===e)return s;return null},Rv=new WeakMap;class Ev extends Ld{static get type(){return"LightsNode"}constructor(e=[]){super("vec3"),this.totalDiffuseNode=jp().toVar("totalDiffuse"),this.totalSpecularNode=jp().toVar("totalSpecular"),this.outgoingLightNode=jp().toVar("outgoingLight"),this._lights=e,this._lightNodes=null,this._lightNodesHash=null,this.global=!0}getHash(e){if(null===this._lightNodesHash){null===this._lightNodes&&this.setupLightsNode(e);const t=[];for(const e of this._lightNodes)t.push(e.getHash());this._lightNodesHash="lights-"+t.join(",")}return this._lightNodesHash}analyze(e){const t=e.getDataFromNode(this);for(const s of t.nodes)s.build(e)}setupLightsNode(e){const t=[],s=this._lightNodes,i=(e=>e.sort(((e,t)=>e.id-t.id)))(this._lights),r=e.renderer.nodes.library;for(const e of i)if(e.isNode)t.push(Sp(e));else{let i=null;if(null!==s&&(i=Cv(e.id,s)),null===i){const s=r.getLightNodeClass(e.constructor);if(null===s){console.warn(`LightsNode.setupNodeLights: Light node not found for ${e.constructor.name}`);continue}let i=null;Rv.has(e)?i=Rv.get(e):(i=new s(e),Rv.set(e,i)),t.push(i)}}this._lightNodes=t}setup(e){null===this._lightNodes&&this.setupLightsNode(e);const t=e.context,s=t.lightingModel;let i=this.outgoingLightNode;if(s){const{_lightNodes:r,totalDiffuseNode:n,totalSpecularNode:o}=this;t.outgoingLight=i;const a=e.addStack();e.getDataFromNode(this).nodes=a.nodes,s.start(t,a,e);for(const t of r)t.build(e);s.indirect(t,a,e);const{backdrop:h,backdropAlpha:u}=t,{directDiffuse:l,directSpecular:c,indirectDiffuse:d,indirectSpecular:p}=t.reflectedLight;let m=l.add(d);null!==h&&(m=jp(null!==u?u.mix(m,h):h),t.material.transparent=!0),n.assign(m),o.assign(c.add(p)),i.assign(n.add(o)),s.finish(t,a,e),i=i.bypass(e.removeStack())}return i}setLights(e){return this._lights=e,this._lightNodes=null,this._lightNodesHash=null,this}getLights(){return this._lights}}const Bv=Ap(Ev);class Iv extends Ld{static get type(){return"LightingNode"}constructor(){super("vec3"),this.isLightingNode=!0}generate(){console.warn("Abstract function.")}}class Pv extends Iv{static get type(){return"AONode"}constructor(e=null){super(),this.aoNode=e}setup(e){e.context.ambientOcclusion.mulAssign(this.aoNode)}}class Fv extends Pf{static get type(){return"LightingContextNode"}constructor(e,t=null,s=null,i=null){super(e),this.lightingModel=t,this.backdropNode=s,this.backdropAlphaNode=i,this._value=null}getContext(){const{backdropNode:e,backdropAlphaNode:t}=this,s={directDiffuse:jp().toVar("directDiffuse"),directSpecular:jp().toVar("directSpecular"),indirectDiffuse:jp().toVar("indirectDiffuse"),indirectSpecular:jp().toVar("indirectSpecular")};return{radiance:jp().toVar("radiance"),irradiance:jp().toVar("irradiance"),iblIrradiance:jp().toVar("iblIrradiance"),ambientOcclusion:Up(1).toVar("ambientOcclusion"),reflectedLight:s,backdrop:e,backdropAlpha:t}}setup(e){return this.value=this._value||(this._value=this.getContext()),this.value.lightingModel=this.lightingModel||e.context.lightingModel,super.setup(e)}}const zv=Ap(Fv);class Uv extends Iv{static get type(){return"IrradianceNode"}constructor(e){super(),this.node=e}setup(e){e.context.irradiance.addAssign(this.node)}}let Ov,Lv;class Vv extends Ld{static get type(){return"ScreenNode"}constructor(e){super(),this.scope=e,this.isViewportNode=!0}getNodeType(){return this.scope===Vv.VIEWPORT?"vec4":"vec2"}getUpdateType(){let e=Bd.NONE;return this.scope!==Vv.SIZE&&this.scope!==Vv.VIEWPORT||(e=Bd.RENDER),this.updateType=e,e}update({renderer:e}){const t=e.getRenderTarget();this.scope===Vv.VIEWPORT?null!==t?Lv.copy(t.viewport):(e.getViewport(Lv),Lv.multiplyScalar(e.getPixelRatio())):null!==t?(Ov.width=t.width,Ov.height=t.height):e.getDrawingBufferSize(Ov)}setup(){const e=this.scope;let t=null;return t=e===Vv.SIZE?pm(Ov||(Ov=new Qs)):e===Vv.VIEWPORT?pm(Lv||(Lv=new Ti)):Dp(Gv.div(kv)),t}generate(e){if(this.scope===Vv.COORDINATE){let t=e.getFragCoord();if(e.isFlipY()){const s=e.getNodeProperties(kv).outputNode.build(e);t=`${e.getType("vec2")}( ${t}.x, ${s}.y - ${t}.y )`}return t}return super.generate(e)}}Vv.COORDINATE="coordinate",Vv.VIEWPORT="viewport",Vv.SIZE="size",Vv.UV="uv";const Dv=Cp(Vv,Vv.UV),kv=Cp(Vv,Vv.SIZE),Gv=Cp(Vv,Vv.COORDINATE),Wv=Cp(Vv,Vv.VIEWPORT),jv=Wv.zw,Hv=Gv.sub(Wv.xy),qv=Hv.div(jv),$v=Rp((()=>(console.warn('TSL.ViewportNode: "viewportResolution" is deprecated. Use "screenSize" instead.'),kv)),"vec2").once()(),Xv=Rp((()=>(console.warn('TSL.ViewportNode: "viewportTopLeft" is deprecated. Use "screenUV" instead.'),Dv)),"vec2").once()(),Yv=Rp((()=>(console.warn('TSL.ViewportNode: "viewportBottomLeft" is deprecated. Use "screenUV.flipY()" instead.'),Dv.flipY())),"vec2").once()(),Zv=new Qs;class Jv extends Ey{static get type(){return"ViewportTextureNode"}constructor(e=Dv,t=null,s=null){null===s&&((s=new ja).minFilter=Se),super(s,e,t),this.generateMipmaps=!1,this.isOutputTextureNode=!0,this.updateBeforeType=Bd.FRAME}updateBefore(e){const t=e.renderer;t.getDrawingBufferSize(Zv);const s=this.value;s.image.width===Zv.width&&s.image.height===Zv.height||(s.image.width=Zv.width,s.image.height=Zv.height,s.needsUpdate=!0);const i=s.generateMipmaps;s.generateMipmaps=this.generateMipmaps,t.copyFramebufferToTexture(s),s.generateMipmaps=i}clone(){const e=new this.constructor(this.uvNode,this.levelNode,this.value);return e.generateMipmaps=this.generateMipmaps,e}}const Kv=Ap(Jv),Qv=Ap(Jv,null,null,{generateMipmaps:!0});let eT=null;class tT extends Jv{static get type(){return"ViewportDepthTextureNode"}constructor(e=Dv,t=null){null===eT&&(eT=new Ya),super(e,t,eT)}}const sT=Ap(tT);class iT extends Ld{static get type(){return"ViewportDepthNode"}constructor(e,t=null){super("float"),this.scope=e,this.valueNode=t,this.isViewportDepthNode=!0}generate(e){const{scope:t}=this;return t===iT.DEPTH_BASE?e.getFragDepth():super.generate(e)}setup({camera:e}){const{scope:t}=this,s=this.valueNode;let i=null;if(t===iT.DEPTH_BASE)null!==s&&(i=hT().assign(s));else if(t===iT.DEPTH)i=e.isPerspectiveCamera?oT(cx.z,Fy,zy):rT(cx.z,Fy,zy);else if(t===iT.LINEAR_DEPTH)if(null!==s)if(e.isPerspectiveCamera){const e=aT(s,Fy,zy);i=rT(e,Fy,zy)}else i=s;else i=rT(cx.z,Fy,zy);return i}}iT.DEPTH_BASE="depthBase",iT.DEPTH="depth",iT.LINEAR_DEPTH="linearDepth";const rT=(e,t,s)=>e.add(t).div(t.sub(s)),nT=(e,t,s)=>t.sub(s).mul(e).sub(t),oT=(e,t,s)=>t.add(e).mul(s).div(s.sub(t).mul(e)),aT=(e,t,s)=>t.mul(s).div(s.sub(t).mul(e).sub(s)),hT=Ap(iT,iT.DEPTH_BASE),uT=Cp(iT,iT.DEPTH),lT=Ap(iT,iT.LINEAR_DEPTH),cT=lT(sT());uT.assign=e=>hT(e);class dT extends Ld{static get type(){return"ClippingNode"}constructor(e=dT.DEFAULT){super(),this.scope=e}setup(e){super.setup(e);const t=e.clippingContext,{localClipIntersection:s,localClippingCount:i,globalClippingCount:r}=t,n=r+i,o=s?n-i:n;return this.scope===dT.ALPHA_TO_COVERAGE?this.setupAlphaToCoverage(t.planes,n,o):this.setupDefault(t.planes,n,o)}setupAlphaToCoverage(e,t,s){return Rp((()=>{const i=Ox(e),r=gm("float","distanceToPlane"),n=gm("float","distanceToGradient"),o=gm("float","clipOpacity");let a;if(o.assign(1),bv(s,(({i:e})=>{a=i.element(e),r.assign(cx.dot(a.xyz).negate().add(a.w)),n.assign(r.fwidth().div(2)),o.mulAssign(Mf(n.negate(),n,r)),o.equal(0).discard()})),s{a=i.element(t),r.assign(cx.dot(a.xyz).negate().add(a.w)),n.assign(r.fwidth().div(2)),e.mulAssign(Mf(n.negate(),n,r).oneMinus())})),o.mulAssign(e.oneMinus())}ym.a.mulAssign(o),ym.a.equal(0).discard()}))()}setupDefault(e,t,s){return Rp((()=>{const i=Ox(e);let r;if(bv(s,(({i:e})=>{r=i.element(e),cx.dot(r.xyz).greaterThan(r.w).discard()})),s{r=i.element(t),e.assign(cx.dot(r.xyz).greaterThan(r.w).and(e))})),e.discard()}}))()}}dT.ALPHA_TO_COVERAGE="alphaToCoverage",dT.DEFAULT="default";class pT extends en{static get type(){return"NodeMaterial"}constructor(){super(),this.isNodeMaterial=!0,this.type=this.constructor.type,this.forceSinglePass=!1,this.fog=!0,this.lights=!1,this.lightsNode=null,this.envNode=null,this.aoNode=null,this.colorNode=null,this.normalNode=null,this.opacityNode=null,this.backdropNode=null,this.backdropAlphaNode=null,this.alphaTestNode=null,this.positionNode=null,this.depthNode=null,this.shadowNode=null,this.shadowPositionNode=null,this.outputNode=null,this.mrtNode=null,this.fragmentNode=null,this.vertexNode=null}customProgramCacheKey(){return this.type+wd(this)}build(e){this.setup(e)}setupObserver(e){return new xd(e)}setup(e){let t;e.context.setupNormal=()=>this.setupNormal(e),e.addStack(),e.stack.outputNode=this.vertexNode||this.setupPosition(e),e.addFlow("vertex",e.removeStack()),e.addStack();const s=this.setupClipping(e);if(!0===this.depthWrite&&this.setupDepth(e),null===this.fragmentNode){this.setupDiffuseColor(e),this.setupVariants(e);const i=this.setupLighting(e);null!==s&&e.stack.add(s);const r=Xp(i,ym.a).max(0);t=this.setupOutput(e,r),zm.assign(t),null!==this.outputNode&&(t=this.outputNode);if(null!==e.renderer.getRenderTarget()){const s=e.renderer.getMRT(),i=this.mrtNode;null!==s?(t=s,null!==i&&(t=s.merge(i))):null!==i&&(t=i)}}else{let s=this.fragmentNode;!0!==s.isOutputStructNode&&(s=Xp(s)),t=this.setupOutput(e,s)}e.stack.outputNode=t,e.addFlow("fragment",e.removeStack()),e.monitor=this.setupObserver(e)}setupClipping(e){if(null===e.clippingContext)return null;const{globalClippingCount:t,localClippingCount:s}=e.clippingContext;let i=null;if(t||s){const t=e.renderer.samples;this.alphaToCoverage&&t>1?i=Sp(new dT(dT.ALPHA_TO_COVERAGE)):e.stack.add(Sp(new dT))}return i}setupDepth(e){const{renderer:t}=e;let s=this.depthNode;if(null===s){const e=t.getMRT();if(e&&e.has("depth"))s=e.get("depth");else if(!0===t.logarithmicDepthBuffer){s=sv().w.add(1).log2().mul(Uy).mul(.5)}}null!==s&&uT.assign(s).append()}setupPosition(e){const{object:t}=e,s=t.geometry;if(e.addStack(),(s.morphAttributes.position||s.morphAttributes.normal||s.morphAttributes.color)&&Av(t).append(),!0===t.isSkinnedMesh&&yv(t).append(),this.displacementMap){const e=jx("displacementMap","texture"),t=jx("displacementScale","float"),s=jx("displacementBias","float");ax.addAssign(yx.normalize().mul(e.x.mul(t).add(s)))}t.isBatchedMesh&&pv(t).append(),t.instanceMatrix&&!0===t.instanceMatrix.isInstancedBufferAttribute&&cv(t).append(),null!==this.positionNode&&ax.assign(this.positionNode);const i=sv();return e.context.vertex=e.removeStack(),e.context.mvp=i,i}setupDiffuseColor({object:e,geometry:t}){let s=this.colorNode?Xp(this.colorNode):xb;if(!0===this.vertexColors&&t.hasAttribute("color")&&(s=Xp(s.xyz.mul(Sy("color","vec3")),s.a)),e.instanceColor){s=fm("vec3","vInstanceColor").mul(s)}if(e.isBatchedMesh&&e._colorsTexture){s=fm("vec3","vBatchColor").mul(s)}ym.assign(s);const i=this.opacityNode?Up(this.opacityNode):Tb;if(ym.a.assign(ym.a.mul(i)),null!==this.alphaTestNode||this.alphaTest>0){const e=null!==this.alphaTestNode?Up(this.alphaTestNode):yb;ym.a.lessThanEqual(e).discard()}!1===this.transparent&&1===this.blending&&!1===this.alphaToCoverage&&ym.a.assign(1)}setupVariants(){}setupOutgoingLight(){return!0===this.lights?jp(0):ym.rgb}setupNormal(){return this.normalNode?jp(this.normalNode):Rb}setupEnvironment(){let e=null;return this.envNode?e=this.envNode:this.envMap&&(e=this.envMap.isCubeTexture?jx("envMap","cubeTexture"):jx("envMap","texture")),e}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new Uv(Kb)),t}setupLights(e){const t=[],s=this.setupEnvironment(e);s&&s.isLightingNode&&t.push(s);const i=this.setupLightMap(e);if(i&&i.isLightingNode&&t.push(i),null!==this.aoNode||e.material.aoMap){const e=null!==this.aoNode?this.aoNode:Qb;t.push(new Pv(e))}let r=this.lightsNode||e.lightsNode;return t.length>0&&(r=Bv([...r.getLights(),...t])),r}setupLightingModel(){}setupLighting(e){const{material:t}=e,{backdropNode:s,backdropAlphaNode:i,emissiveNode:r}=this,n=!0===this.lights||null!==this.lightsNode?this.setupLights(e):null;let o=this.setupOutgoingLight(e);if(n&&n.getScope().getLights().length>0){const t=this.setupLightingModel(e);o=zv(n,t,s,i)}else null!==s&&(o=jp(null!==i?Tf(o,s,i):s));return(r&&!0===r.isNode||t.emissive&&!0===t.emissive.isColor)&&(xm.assign(jp(r||vb)),o=o.add(xm)),o}setupOutput(e,t){if(!0===this.fog){const s=e.fogNode;s&&(t=Xp(s.mix(t.rgb,s.colorNode),t.a))}return t}setDefaultValues(e){for(const t in e){const s=e[t];void 0===this[t]&&(this[t]=s,s&&s.clone&&(this[t]=s.clone()))}const t=Object.getOwnPropertyDescriptors(e.constructor.prototype);for(const e in t)void 0===Object.getOwnPropertyDescriptor(this.constructor.prototype,e)&&void 0!==t[e].get&&Object.defineProperty(this.constructor.prototype,e,t[e])}toJSON(e){const t=void 0===e||"string"==typeof e;t&&(e={textures:{},images:{},nodes:{}});const s=en.prototype.toJSON.call(this,e),i=Sd(this);s.inputNodes={};for(const{property:t,childNode:r}of i)s.inputNodes[t]=r.toJSON(e).uuid;function r(e){const t=[];for(const s in e){const i=e[s];delete i.metadata,t.push(i)}return t}if(t){const t=r(e.textures),i=r(e.images),n=r(e.nodes);t.length>0&&(s.textures=t),i.length>0&&(s.images=i),n.length>0&&(s.nodes=n)}return s}copy(e){return this.lightsNode=e.lightsNode,this.envNode=e.envNode,this.colorNode=e.colorNode,this.normalNode=e.normalNode,this.opacityNode=e.opacityNode,this.backdropNode=e.backdropNode,this.backdropAlphaNode=e.backdropAlphaNode,this.alphaTestNode=e.alphaTestNode,this.positionNode=e.positionNode,this.depthNode=e.depthNode,this.shadowNode=e.shadowNode,this.shadowPositionNode=e.shadowPositionNode,this.outputNode=e.outputNode,this.mrtNode=e.mrtNode,this.fragmentNode=e.fragmentNode,this.vertexNode=e.vertexNode,super.copy(e)}}const mT=new za;class gT extends pT{static get type(){return"InstancedPointsNodeMaterial"}constructor(e={}){super(),this.lights=!1,this.useAlphaToCoverage=!0,this.useColor=e.vertexColors,this.pointWidth=1,this.pointColorNode=null,this.pointWidthNode=null,this.setDefaultValues(mT),this.setValues(e)}setup(e){this.setupShaders(e),super.setup(e)}setupShaders({renderer:e}){const t=this.alphaToCoverage,s=this.useColor;this.vertexNode=Rp((()=>{const e=Sy("instancePosition").xyz,t=Xp(ix.mul(Xp(e,1))),s=Wv.z.div(Wv.w),i=Oy.mul(t),r=ox.xy.toVar();return r.mulAssign(this.pointWidthNode?this.pointWidthNode:Zb),r.assign(r.div(Wv.z)),r.y.assign(r.y.mul(s)),r.assign(r.mul(i.w)),i.addAssign(Xp(r,0,0)),i}))(),this.fragmentNode=Rp((()=>{const i=Up(1).toVar(),r=vf(My().mul(2).sub(1));if(t&&e.samples>1){const e=Up(r.fwidth()).toVar();i.assign(Mf(e.oneMinus(),e.add(1),r).oneMinus())}else r.greaterThan(1).discard();let n;if(this.pointColorNode)n=this.pointColorNode;else if(s){n=Sy("instanceColor").mul(xb)}else n=xb;return i.mulAssign(Tb),Xp(n,i)}))()}get alphaToCoverage(){return this.useAlphaToCoverage}set alphaToCoverage(e){this.useAlphaToCoverage!==e&&(this.useAlphaToCoverage=e,this.needsUpdate=!0)}}const fT=new Ta;class yT extends pT{static get type(){return"LineBasicNodeMaterial"}constructor(e){super(),this.isLineBasicNodeMaterial=!0,this.lights=!1,this.setDefaultValues(fT),this.setValues(e)}}const xT=new Bu;class bT extends pT{static get type(){return"LineDashedNodeMaterial"}constructor(e){super(),this.isLineDashedNodeMaterial=!0,this.lights=!1,this.setDefaultValues(xT),this.offsetNode=null,this.dashScaleNode=null,this.dashSizeNode=null,this.gapSizeNode=null,this.setValues(e)}setupVariants(){const e=this.offsetNode,t=this.dashScaleNode?Up(this.dashScaleNode):Hb,s=this.dashSizeNode?Up(this.dashSizeNode):qb,i=this.dashSizeNode?Up(this.dashGapNode):$b;Um.assign(s),Om.assign(i);const r=Vf(Sy("lineDistance").mul(t));(e?r.add(e):r).mod(Um.add(Om)).greaterThan(Um).discard()}}const vT=new Bu;class TT extends pT{static get type(){return"Line2NodeMaterial"}constructor(e={}){super(),this.lights=!1,this.setDefaultValues(vT),this.useAlphaToCoverage=!0,this.useColor=e.vertexColors,this.useDash=e.dashed,this.useWorldUnits=!1,this.dashOffset=0,this.lineWidth=1,this.lineColorNode=null,this.offsetNode=null,this.dashScaleNode=null,this.dashSizeNode=null,this.gapSizeNode=null,this.setValues(e)}setup(e){this.setupShaders(e),super.setup(e)}setupShaders({renderer:e}){const t=this.alphaToCoverage,s=this.useColor,i=this.dashed,r=this.worldUnits,n=Rp((({start:e,end:t})=>{const s=Oy.element(2).element(2),i=Oy.element(3).element(2).mul(-.5).div(s).sub(e.z).div(t.z.sub(e.z));return Xp(Tf(e.xyz,t.xyz,i),t.w)})).setLayout({name:"trimSegment",type:"vec4",inputs:[{name:"start",type:"vec4"},{name:"end",type:"vec4"}]});this.vertexNode=Rp((()=>{const e=Sy("instanceStart"),t=Sy("instanceEnd"),s=Xp(ix.mul(Xp(e,1))).toVar("start"),o=Xp(ix.mul(Xp(t,1))).toVar("end");r&&(fm("vec3","worldStart").assign(s.xyz),fm("vec3","worldEnd").assign(o.xyz));const a=Wv.z.div(Wv.w),h=Oy.element(2).element(3).equal(-1);Pp(h,(()=>{Pp(s.z.lessThan(0).and(o.z.greaterThan(0)),(()=>{o.assign(n({start:s,end:o}))})).ElseIf(o.z.lessThan(0).and(s.z.greaterThanEqual(0)),(()=>{s.assign(n({start:o,end:s}))}))}));const u=Oy.mul(s),l=Oy.mul(o),c=u.xyz.div(u.w),d=l.xyz.div(l.w),p=d.xy.sub(c.xy).toVar();p.x.assign(p.x.mul(a)),p.assign(p.normalize());const m=Xp().toVar();if(r){const e=o.xyz.sub(s.xyz).normalize(),t=Tf(s.xyz,o.xyz,.5).normalize(),r=e.cross(t).normalize(),n=e.cross(r),a=fm("vec4","worldPos");a.assign(ox.y.lessThan(.5).select(s,o));const h=Xb.mul(.5);a.addAssign(Xp(ox.x.lessThan(0).select(r.mul(h),r.mul(h).negate()),0)),i||(a.addAssign(Xp(ox.y.lessThan(.5).select(e.mul(h).negate(),e.mul(h)),0)),a.addAssign(Xp(n.mul(h),0)),Pp(ox.y.greaterThan(1).or(ox.y.lessThan(0)),(()=>{a.subAssign(Xp(n.mul(2).mul(h),0))}))),m.assign(Oy.mul(a));const u=jp().toVar();u.assign(ox.y.lessThan(.5).select(c,d)),m.z.assign(u.z.mul(m.w))}else{const e=Dp(p.y,p.x.negate()).toVar("offset");p.x.assign(p.x.div(a)),e.x.assign(e.x.div(a)),e.assign(ox.x.lessThan(0).select(e.negate(),e)),Pp(ox.y.lessThan(0),(()=>{e.assign(e.sub(p))})).ElseIf(ox.y.greaterThan(1),(()=>{e.assign(e.add(p))})),e.assign(e.mul(Xb)),e.assign(e.div(Wv.w)),m.assign(ox.y.lessThan(.5).select(u,l)),e.assign(e.mul(m.w)),m.assign(m.add(Xp(e,0,0)))}return m}))();const o=Rp((({p1:e,p2:t,p3:s,p4:i})=>{const r=e.sub(s),n=i.sub(s),o=t.sub(e),a=r.dot(n),h=n.dot(o),u=r.dot(o),l=n.dot(n),c=o.dot(o).mul(l).sub(h.mul(h)),d=a.mul(h).sub(u.mul(l)).div(c).clamp(),p=a.add(h.mul(d)).div(l).clamp();return Dp(d,p)}));this.fragmentNode=Rp((()=>{const n=My();if(i){const e=this.offsetNode?Up(this.offsetNodeNode):Yb,t=this.dashScaleNode?Up(this.dashScaleNode):Hb,s=this.dashSizeNode?Up(this.dashSizeNode):qb,i=this.dashSizeNode?Up(this.dashGapNode):$b;Um.assign(s),Om.assign(i);const r=Sy("instanceDistanceStart"),o=Sy("instanceDistanceEnd"),a=ox.y.lessThan(.5).select(t.mul(r),Hb.mul(o)),h=Vf(a.add(Yb)),u=e?h.add(e):h;n.y.lessThan(-1).or(n.y.greaterThan(1)).discard(),u.mod(Um.add(Om)).greaterThan(Um).discard()}const a=Up(1).toVar("alpha");if(r){const s=fm("vec3","worldStart"),r=fm("vec3","worldEnd"),n=fm("vec4","worldPos").xyz.normalize().mul(1e5),h=r.sub(s),u=o({p1:s,p2:r,p3:jp(0,0,0),p4:n}),l=s.add(h.mul(u.x)),c=n.mul(u.y),d=l.sub(c).length().div(Xb);if(!i)if(t&&e.samples>1){const e=d.fwidth();a.assign(Mf(e.negate().add(.5),e.add(.5),d).oneMinus())}else d.greaterThan(.5).discard()}else if(t&&e.samples>1){const e=n.x,t=n.y.greaterThan(0).select(n.y.sub(1),n.y.add(1)),s=e.mul(e).add(t.mul(t)),i=Up(s.fwidth()).toVar("dlen");Pp(n.y.abs().greaterThan(1),(()=>{a.assign(Mf(i.oneMinus(),i.add(1),s).oneMinus())}))}else Pp(n.y.abs().greaterThan(1),(()=>{const e=n.x,t=n.y.greaterThan(0).select(n.y.sub(1),n.y.add(1));e.mul(e).add(t.mul(t)).greaterThan(1).discard()}));let h;if(this.lineColorNode)h=this.lineColorNode;else if(s){const e=Sy("instanceColorStart"),t=Sy("instanceColorEnd");h=ox.y.lessThan(.5).select(e,t).mul(xb)}else h=xb;return Xp(h,a)}))()}get worldUnits(){return this.useWorldUnits}set worldUnits(e){this.useWorldUnits!==e&&(this.useWorldUnits=e,this.needsUpdate=!0)}get dashed(){return this.useDash}set dashed(e){this.useDash!==e&&(this.useDash=e,this.needsUpdate=!0)}get alphaToCoverage(){return this.useAlphaToCoverage}set alphaToCoverage(e){this.useAlphaToCoverage!==e&&(this.useAlphaToCoverage=e,this.needsUpdate=!0)}}const _T=e=>Sp(e).mul(.5).add(.5),wT=e=>Sp(e).mul(2).sub(1),ST=new Nu;class MT extends pT{static get type(){return"MeshNormalNodeMaterial"}constructor(e){super(),this.lights=!1,this.isMeshNormalNodeMaterial=!0,this.setDefaultValues(ST),this.setValues(e)}setupDiffuseColor(){const e=this.opacityNode?Up(this.opacityNode):Tb;ym.assign(Xp(_T(Tx),e))}}class NT extends kd{static get type(){return"EquirectUVNode"}constructor(e=lx){super("vec2"),this.dirNode=e}setup(){const e=this.dirNode,t=e.z.atan2(e.x).mul(1/(2*Math.PI)).add(.5),s=e.y.clamp(-1,1).asin().mul(1/Math.PI).add(.5);return Dp(t,s)}}const AT=Ap(NT);class CT extends Kn{constructor(e=1,t={}){super(e,t),this.isCubeRenderTarget=!0}fromEquirectangularTexture(e,t){const s=t.minFilter,i=t.generateMipmaps;t.generateMipmaps=!0,this.texture.type=t.type,this.texture.colorSpace=t.colorSpace,this.texture.generateMipmaps=t.generateMipmaps,this.texture.minFilter=t.minFilter,this.texture.magFilter=t.magFilter;const r=new kn(5,5,5),n=AT(lx),o=new pT;o.colorNode=By(t,n,0),o.side=d,o.blending=m;const a=new Vn(r,o),h=new to;h.add(a),t.minFilter===Se&&(t.minFilter=Te);const u=new Zn(1,10,this),l=e.getMRT();return e.setMRT(null),u.update(e,h),e.setMRT(l),t.minFilter=s,t.currentGenerateMipmaps=i,a.geometry.dispose(),a.material.dispose(),this}}const RT=new WeakMap;class ET extends kd{static get type(){return"CubeMapNode"}constructor(e){super("vec3"),this.envNode=e,this._cubeTexture=null,this._cubeTextureNode=Ix();const t=new Jn;t.isRenderTargetTexture=!0,this._defaultTexture=t,this.updateBeforeType=Bd.RENDER}updateBefore(e){const{renderer:t,material:s}=e,i=this.envNode;if(i.isTextureNode||i.isMaterialReferenceNode){const e=i.isTextureNode?i.value:s[i.property];if(e&&e.isTexture){const s=e.mapping;if(s===le||s===ce){if(RT.has(e)){const t=RT.get(e);IT(t,e.mapping),this._cubeTexture=t}else{const s=e.image;if(function(e){return null!=e&&e.height>0}(s)){const i=new CT(s.height);i.fromEquirectangularTexture(t,e),IT(i.texture,e.mapping),this._cubeTexture=i.texture,RT.set(e,i.texture),e.addEventListener("dispose",BT)}else this._cubeTexture=this._defaultTexture}this._cubeTextureNode.value=this._cubeTexture}else this._cubeTextureNode=this.envNode}}}setup(e){return this.updateBefore(e),this._cubeTextureNode}}function BT(e){const t=e.target;t.removeEventListener("dispose",BT);const s=RT.get(t);void 0!==s&&(RT.delete(t),s.dispose())}function IT(e,t){t===le?e.mapping=he:t===ce&&(e.mapping=ue)}const PT=Ap(ET);class FT extends Iv{static get type(){return"BasicEnvironmentNode"}constructor(e=null){super(),this.envNode=e}setup(e){e.context.environment=PT(this.envNode)}}class zT extends Iv{static get type(){return"BasicLightMapNode"}constructor(e=null){super(),this.lightMapNode=e}setup(e){const t=Up(1/Math.PI);e.context.irradianceLightMap=this.lightMapNode.mul(t)}}class UT{start(){}finish(){}direct(){}directRectArea(){}indirect(){}ambientOcclusion(){}}class OT extends UT{constructor(){super()}indirect(e,t,s){const i=e.ambientOcclusion,r=e.reflectedLight,n=s.context.irradianceLightMap;r.indirectDiffuse.assign(Xp(0)),n?r.indirectDiffuse.addAssign(n):r.indirectDiffuse.addAssign(Xp(1,1,1,0)),r.indirectDiffuse.mulAssign(i),r.indirectDiffuse.mulAssign(ym.rgb)}finish(e,t,s){const i=s.material,r=e.outgoingLight,n=s.context.environment;if(n)switch(i.combine){case 0:r.rgb.assign(Tf(r.rgb,r.rgb.mul(n.rgb),Mb.mul(Nb)));break;case 1:r.rgb.assign(Tf(r.rgb,n.rgb,Mb.mul(Nb)));break;case 2:r.rgb.addAssign(n.rgb.mul(Mb.mul(Nb)));break;default:console.warn("THREE.BasicLightingModel: Unsupported .combine value:",i.combine)}}}const LT=new tn;class VT extends pT{static get type(){return"MeshBasicNodeMaterial"}constructor(e){super(),this.isMeshBasicNodeMaterial=!0,this.lights=!0,this.setDefaultValues(LT),this.setValues(e)}setupNormal(){return bx}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new FT(t):null}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new zT(Kb)),t}setupOutgoingLight(){return ym.rgb}setupLightingModel(){return new OT}}const DT=Rp((({f0:e,f90:t,dotVH:s})=>{const i=s.mul(-5.55473).sub(6.98316).mul(s).exp2();return e.mul(i.oneMinus()).add(t.mul(i))})),kT=Rp((e=>e.diffuseColor.mul(1/Math.PI))),GT=Rp((({dotNH:e})=>Fm.mul(Up(.5)).add(1).mul(Up(1/Math.PI)).mul(e.pow(Fm)))),WT=Rp((({lightDirection:e})=>{const t=e.add(dx).normalize(),s=Tx.dot(t).clamp(),i=dx.dot(t).clamp(),r=DT({f0:Im,f90:1,dotVH:i}),n=Up(.25),o=GT({dotNH:s});return r.mul(n).mul(o)}));class jT extends OT{constructor(e=!0){super(),this.specular=e}direct({lightDirection:e,lightColor:t,reflectedLight:s}){const i=Tx.dot(e).clamp().mul(t);s.directDiffuse.addAssign(i.mul(kT({diffuseColor:ym.rgb}))),!0===this.specular&&s.directSpecular.addAssign(i.mul(WT({lightDirection:e})).mul(Mb))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:s}){s.indirectDiffuse.addAssign(t.mul(kT({diffuseColor:ym}))),s.indirectDiffuse.mulAssign(e)}}const HT=new Au;class qT extends pT{static get type(){return"MeshLambertNodeMaterial"}constructor(e){super(),this.isMeshLambertNodeMaterial=!0,this.lights=!0,this.setDefaultValues(HT),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new FT(t):null}setupLightingModel(){return new jT(!1)}}const $T=new Su;class XT extends pT{static get type(){return"MeshPhongNodeMaterial"}constructor(e){super(),this.isMeshPhongNodeMaterial=!0,this.lights=!0,this.shininessNode=null,this.specularNode=null,this.setDefaultValues($T),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new FT(t):null}setupLightingModel(){return new jT}setupVariants(){const e=(this.shininessNode?Up(this.shininessNode):bb).max(1e-4);Fm.assign(e);const t=this.specularNode||_b;Im.assign(t)}copy(e){return this.shininessNode=e.shininessNode,this.specularNode=e.specularNode,super.copy(e)}}const YT=Rp((()=>{const e=bx.dFdx().abs().max(bx.dFdy().abs());return e.x.max(e.y).max(e.z)})),ZT=Rp((e=>{const{roughness:t}=e,s=YT();let i=t.max(.0525);return i=i.add(s),i=i.min(1),i})),JT=Rp((({alpha:e,dotNL:t,dotNV:s})=>{const i=e.pow2(),r=t.mul(i.add(i.oneMinus().mul(s.pow2())).sqrt()),n=s.mul(i.add(i.oneMinus().mul(t.pow2())).sqrt());return Qm(.5,r.add(n).max(bg))})).setLayout({name:"V_GGX_SmithCorrelated",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNL",type:"float"},{name:"dotNV",type:"float"}]}),KT=Rp((({alphaT:e,alphaB:t,dotTV:s,dotBV:i,dotTL:r,dotBL:n,dotNV:o,dotNL:a})=>{const h=a.mul(jp(e.mul(s),t.mul(i),o).length()),u=o.mul(jp(e.mul(r),t.mul(n),a).length());return Qm(.5,h.add(u)).saturate()})).setLayout({name:"V_GGX_SmithCorrelated_Anisotropic",type:"float",inputs:[{name:"alphaT",type:"float",qualifier:"in"},{name:"alphaB",type:"float",qualifier:"in"},{name:"dotTV",type:"float",qualifier:"in"},{name:"dotBV",type:"float",qualifier:"in"},{name:"dotTL",type:"float",qualifier:"in"},{name:"dotBL",type:"float",qualifier:"in"},{name:"dotNV",type:"float",qualifier:"in"},{name:"dotNL",type:"float",qualifier:"in"}]}),QT=Rp((({alpha:e,dotNH:t})=>{const s=e.pow2(),i=t.pow2().mul(s.oneMinus()).oneMinus();return s.div(i.pow2()).mul(1/Math.PI)})).setLayout({name:"D_GGX",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNH",type:"float"}]}),e_=Up(1/Math.PI),t_=Rp((({alphaT:e,alphaB:t,dotNH:s,dotTH:i,dotBH:r})=>{const n=e.mul(t),o=jp(t.mul(i),e.mul(r),n.mul(s)),a=o.dot(o),h=n.div(a);return e_.mul(n.mul(h.pow2()))})).setLayout({name:"D_GGX_Anisotropic",type:"float",inputs:[{name:"alphaT",type:"float",qualifier:"in"},{name:"alphaB",type:"float",qualifier:"in"},{name:"dotNH",type:"float",qualifier:"in"},{name:"dotTH",type:"float",qualifier:"in"},{name:"dotBH",type:"float",qualifier:"in"}]}),s_=Rp((e=>{const{lightDirection:t,f0:s,f90:i,roughness:r,f:n,USE_IRIDESCENCE:o,USE_ANISOTROPY:a}=e,h=e.normalView||Tx,u=r.pow2(),l=t.add(dx).normalize(),c=h.dot(t).clamp(),d=h.dot(dx).clamp(),p=h.dot(l).clamp(),m=dx.dot(l).clamp();let g,f,y=DT({f0:s,f90:i,dotVH:m});if(Tp(o)&&(y=Mm.mix(y,n)),Tp(a)){const e=Em.dot(t),s=Em.dot(dx),i=Em.dot(l),r=Bm.dot(t),n=Bm.dot(dx),o=Bm.dot(l);g=KT({alphaT:Cm,alphaB:u,dotTV:s,dotBV:n,dotTL:e,dotBL:r,dotNV:d,dotNL:c}),f=t_({alphaT:Cm,alphaB:u,dotNH:p,dotTH:i,dotBH:o})}else g=JT({alpha:u,dotNL:c,dotNV:d}),f=QT({alpha:u,dotNH:p});return y.mul(g).mul(f)})),i_=Rp((({roughness:e,dotNV:t})=>{const s=Xp(-1,-.0275,-.572,.022),i=Xp(1,.0425,1.04,-.04),r=e.mul(s).add(i),n=r.x.mul(r.x).min(t.mul(-9.28).exp2()).mul(r.x).add(r.y);return Dp(-1.04,1.04).mul(n).add(r.zw)})).setLayout({name:"DFGApprox",type:"vec2",inputs:[{name:"roughness",type:"float"},{name:"dotNV",type:"vec3"}]}),r_=Rp((e=>{const{dotNV:t,specularColor:s,specularF90:i,roughness:r}=e,n=i_({dotNV:t,roughness:r});return s.mul(n.x).add(i.mul(n.y))})),n_=Rp((({f:e,f90:t,dotVH:s})=>{const i=s.oneMinus().saturate(),r=i.mul(i),n=i.mul(r,r).clamp(0,.9999);return e.sub(jp(t).mul(n)).div(n.oneMinus())})).setLayout({name:"Schlick_to_F0",type:"vec3",inputs:[{name:"f",type:"vec3"},{name:"f90",type:"float"},{name:"dotVH",type:"float"}]}),o_=Rp((({roughness:e,dotNH:t})=>{const s=e.pow2(),i=Up(1).div(s),r=t.pow2().oneMinus().max(.0078125);return Up(2).add(i).mul(r.pow(i.mul(.5))).div(2*Math.PI)})).setLayout({name:"D_Charlie",type:"float",inputs:[{name:"roughness",type:"float"},{name:"dotNH",type:"float"}]}),a_=Rp((({dotNV:e,dotNL:t})=>Up(1).div(Up(4).mul(t.add(e).sub(t.mul(e)))))).setLayout({name:"V_Neubelt",type:"float",inputs:[{name:"dotNV",type:"float"},{name:"dotNL",type:"float"}]}),h_=Rp((({lightDirection:e})=>{const t=e.add(dx).normalize(),s=Tx.dot(e).clamp(),i=Tx.dot(dx).clamp(),r=Tx.dot(t).clamp(),n=o_({roughness:Sm,dotNH:r}),o=a_({dotNV:i,dotNL:s});return wm.mul(n).mul(o)})),u_=Rp((({N:e,V:t,roughness:s})=>{const i=e.dot(t).saturate(),r=Dp(s,i.oneMinus().sqrt());return r.assign(r.mul(.984375).add(.0078125)),r})).setLayout({name:"LTC_Uv",type:"vec2",inputs:[{name:"N",type:"vec3"},{name:"V",type:"vec3"},{name:"roughness",type:"float"}]}),l_=Rp((({f:e})=>{const t=e.length();return of(t.mul(t).add(e.z).div(t.add(1)),0)})).setLayout({name:"LTC_ClippedSphereFormFactor",type:"float",inputs:[{name:"f",type:"vec3"}]}),c_=Rp((({v1:e,v2:t})=>{const s=e.dot(t),i=s.abs().toVar(),r=i.mul(.0145206).add(.4965155).mul(i).add(.8543985).toVar(),n=i.add(4.1616724).mul(i).add(3.417594).toVar(),o=r.div(n),a=s.greaterThan(0).select(o,of(s.mul(s).oneMinus(),1e-7).inverseSqrt().mul(.5).sub(o));return e.cross(t).mul(a)})).setLayout({name:"LTC_EdgeVectorFormFactor",type:"vec3",inputs:[{name:"v1",type:"vec3"},{name:"v2",type:"vec3"}]}),d_=Rp((({N:e,V:t,P:s,mInv:i,p0:r,p1:n,p2:o,p3:a})=>{const h=n.sub(r).toVar(),u=a.sub(r).toVar(),l=h.cross(u),c=jp().toVar();return Pp(l.dot(s.sub(r)).greaterThanEqual(0),(()=>{const h=t.sub(e.mul(t.dot(e))).normalize(),u=e.cross(h).negate(),l=i.mul(Qp(h,u,e).transpose()).toVar(),d=l.mul(r.sub(s)).normalize().toVar(),p=l.mul(n.sub(s)).normalize().toVar(),m=l.mul(o.sub(s)).normalize().toVar(),g=l.mul(a.sub(s)).normalize().toVar(),f=jp(0).toVar();f.addAssign(c_({v1:d,v2:p})),f.addAssign(c_({v1:p,v2:m})),f.addAssign(c_({v1:m,v2:g})),f.addAssign(c_({v1:g,v2:d})),c.assign(jp(l_({f:f})))})),c})).setLayout({name:"LTC_Evaluate",type:"vec3",inputs:[{name:"N",type:"vec3"},{name:"V",type:"vec3"},{name:"P",type:"vec3"},{name:"mInv",type:"mat3"},{name:"p0",type:"vec3"},{name:"p1",type:"vec3"},{name:"p2",type:"vec3"},{name:"p3",type:"vec3"}]}),p_=1/6,m_=e=>Km(p_,Km(e,Km(e,e.negate().add(3)).sub(3)).add(1)),g_=e=>Km(p_,Km(e,Km(e,Km(3,e).sub(6))).add(4)),f_=e=>Km(p_,Km(e,Km(e,Km(-3,e).add(3)).add(3)).add(1)),y_=e=>Km(p_,mf(e,3)),x_=e=>m_(e).add(g_(e)),b_=e=>f_(e).add(y_(e)),v_=e=>Zm(-1,g_(e).div(m_(e).add(g_(e)))),T_=e=>Zm(1,y_(e).div(f_(e).add(y_(e)))),__=(e,t,s)=>{const i=e.uvNode,r=Km(i,t.zw).add(.5),n=Fg(r),o=Og(r),a=x_(o.x),h=b_(o.x),u=v_(o.x),l=T_(o.x),c=v_(o.y),d=T_(o.y),p=Dp(n.x.add(u),n.y.add(c)).sub(.5).mul(t.xy),m=Dp(n.x.add(l),n.y.add(c)).sub(.5).mul(t.xy),g=Dp(n.x.add(u),n.y.add(d)).sub(.5).mul(t.xy),f=Dp(n.x.add(l),n.y.add(d)).sub(.5).mul(t.xy),y=x_(o.y).mul(Zm(a.mul(e.uv(p).level(s)),h.mul(e.uv(m).level(s)))),x=b_(o.y).mul(Zm(a.mul(e.uv(g).level(s)),h.mul(e.uv(f).level(s))));return y.add(x)},w_=Rp((([e,t=Up(3)])=>{const s=Dp(e.size(Op(t))),i=Dp(e.size(Op(t.add(1)))),r=Qm(1,s),n=Qm(1,i),o=__(e,Xp(r,s),Fg(t)),a=__(e,Xp(n,i),zg(t));return Og(t).mix(o,a)})),S_=Rp((([e,t,s,i,r])=>{const n=jp(Sf(t.negate(),Ug(e),Qm(1,i))),o=jp(qg(r[0].xyz),qg(r[1].xyz),qg(r[2].xyz));return Ug(n).mul(s.mul(o))})).setLayout({name:"getVolumeTransmissionRay",type:"vec3",inputs:[{name:"n",type:"vec3"},{name:"v",type:"vec3"},{name:"thickness",type:"float"},{name:"ior",type:"float"},{name:"modelMatrix",type:"mat4"}]}),M_=Rp((([e,t])=>e.mul(_f(t.mul(2).sub(2),0,1)))).setLayout({name:"applyIorToRoughness",type:"float",inputs:[{name:"roughness",type:"float"},{name:"ior",type:"float"}]}),N_=Qv(),A_=Rp((([e,t,s])=>{const i=N_.uv(e),r=Bg(Up(kv.x)).mul(M_(t,s));return w_(i,r)})),C_=Rp((([e,t,s])=>(Pp(s.notEqual(0),(()=>{const i=Eg(t).negate().div(s);return Cg(i.negate().mul(e))})),jp(1)))).setLayout({name:"volumeAttenuation",type:"vec3",inputs:[{name:"transmissionDistance",type:"float"},{name:"attenuationColor",type:"vec3"},{name:"attenuationDistance",type:"float"}]}),R_=Rp((([e,t,s,i,r,n,o,a,h,u,l,c,d,p,m])=>{let g,f;if(m){g=Xp().toVar(),f=jp().toVar();const r=l.sub(1).mul(m.mul(.025)),n=jp(l.sub(r),l,l.add(r));bv({start:0,end:3},(({i:r})=>{const l=n.element(r),m=S_(e,t,c,l,a),y=o.add(m),x=u.mul(h.mul(Xp(y,1))),b=Dp(x.xy.div(x.w)).toVar();b.addAssign(1),b.divAssign(2),b.assign(Dp(b.x,b.y.oneMinus()));const v=A_(b,s,l);g.element(r).assign(v.element(r)),g.a.addAssign(v.a),f.element(r).assign(i.element(r).mul(C_(qg(m),d,p).element(r)))})),g.a.divAssign(3)}else{const r=S_(e,t,c,l,a),n=o.add(r),m=u.mul(h.mul(Xp(n,1))),y=Dp(m.xy.div(m.w)).toVar();y.addAssign(1),y.divAssign(2),y.assign(Dp(y.x,y.y.oneMinus())),g=A_(y,s,l),f=i.mul(C_(qg(r),d,p))}const y=f.rgb.mul(g.rgb),x=e.dot(t).clamp(),b=jp(r_({dotNV:x,specularColor:r,specularF90:n,roughness:s})),v=f.r.add(f.g,f.b).div(3);return Xp(b.oneMinus().mul(y),g.a.oneMinus().mul(v).oneMinus())})),E_=Qp(3.2404542,-.969266,.0556434,-1.5371385,1.8760108,-.2040259,-.4985314,.041556,1.0572252),B_=(e,t)=>e.sub(t).div(e.add(t)).pow2(),I_=(e,t)=>{const s=e.mul(2*Math.PI*1e-9),i=jp(54856e-17,44201e-17,52481e-17),r=jp(1681e3,1795300,2208400),n=jp(43278e5,93046e5,66121e5),o=Up(9747e-17*Math.sqrt(2*Math.PI*45282e5)).mul(s.mul(2239900).add(t.x).cos()).mul(s.pow2().mul(-45282e5).exp());let a=i.mul(n.mul(2*Math.PI).sqrt()).mul(r.mul(s).add(t).cos()).mul(s.pow2().negate().mul(n).exp());a=jp(a.x.add(o),a.y,a.z).div(1.0685e-7);return E_.mul(a)},P_=Rp((({outsideIOR:e,eta2:t,cosTheta1:s,thinFilmThickness:i,baseF0:r})=>{const n=Tf(e,t,Mf(0,.03,i)),o=e.div(n).pow2().mul(Up(1).sub(s.pow2())),a=Up(1).sub(o).sqrt(),h=B_(n,e),u=DT({f0:h,f90:1,dotVH:s}),l=u.oneMinus(),c=n.lessThan(e).select(Math.PI,0),d=Up(Math.PI).sub(c),p=(e=>{const t=e.sqrt();return jp(1).add(t).div(jp(1).sub(t))})(r.clamp(0,.9999)),m=B_(p,n.toVec3()),g=DT({f0:m,f90:1,dotVH:a}),f=jp(p.x.lessThan(n).select(Math.PI,0),p.y.lessThan(n).select(Math.PI,0),p.z.lessThan(n).select(Math.PI,0)),y=n.mul(i,a,2),x=jp(d).add(f),b=u.mul(g).clamp(1e-5,.9999),v=b.sqrt(),T=l.pow2().mul(g).div(jp(1).sub(b));let _=u.add(T),w=T.sub(l);for(let e=1;e<=2;++e){w=w.mul(v);const t=I_(Up(e).mul(y),Up(e).mul(x)).mul(2);_=_.add(w.mul(t))}return _.max(jp(0))})).setLayout({name:"evalIridescence",type:"vec3",inputs:[{name:"outsideIOR",type:"float"},{name:"eta2",type:"float"},{name:"cosTheta1",type:"float"},{name:"thinFilmThickness",type:"float"},{name:"baseF0",type:"vec3"}]}),F_=Rp((({normal:e,viewDir:t,roughness:s})=>{const i=e.dot(t).saturate(),r=s.pow2(),n=Bf(s.lessThan(.25),Up(-339.2).mul(r).add(Up(161.4).mul(s)).sub(25.9),Up(-8.48).mul(r).add(Up(14.3).mul(s)).sub(9.95)),o=Bf(s.lessThan(.25),Up(44).mul(r).sub(Up(23.7).mul(s)).add(3.26),Up(1.97).mul(r).sub(Up(3.27).mul(s)).add(.72));return Bf(s.lessThan(.25),0,Up(.1).mul(s).sub(.025)).add(n.mul(i).add(o).exp()).mul(1/Math.PI).saturate()})),z_=jp(.04),U_=Up(1);class O_ extends UT{constructor(e=!1,t=!1,s=!1,i=!1,r=!1,n=!1){super(),this.clearcoat=e,this.sheen=t,this.iridescence=s,this.anisotropy=i,this.transmission=r,this.dispersion=n,this.clearcoatRadiance=null,this.clearcoatSpecularDirect=null,this.clearcoatSpecularIndirect=null,this.sheenSpecularDirect=null,this.sheenSpecularIndirect=null,this.iridescenceFresnel=null,this.iridescenceF0=null}start(e){if(!0===this.clearcoat&&(this.clearcoatRadiance=jp().toVar("clearcoatRadiance"),this.clearcoatSpecularDirect=jp().toVar("clearcoatSpecularDirect"),this.clearcoatSpecularIndirect=jp().toVar("clearcoatSpecularIndirect")),!0===this.sheen&&(this.sheenSpecularDirect=jp().toVar("sheenSpecularDirect"),this.sheenSpecularIndirect=jp().toVar("sheenSpecularIndirect")),!0===this.iridescence){const e=Tx.dot(dx).clamp();this.iridescenceFresnel=P_({outsideIOR:Up(1),eta2:Nm,cosTheta1:e,thinFilmThickness:Am,baseF0:Im}),this.iridescenceF0=n_({f:this.iridescenceFresnel,f90:1,dotVH:e})}if(!0===this.transmission){const t=ux,s=Gy.sub(ux).normalize(),i=_x;e.backdrop=R_(i,s,bm,ym,Im,Pm,t,Jy,Vy,Oy,Vm,km,Wm,Gm,this.dispersion?jm:null),e.backdropAlpha=Dm,ym.a.mulAssign(Tf(1,e.backdrop.a,Dm))}}computeMultiscattering(e,t,s){const i=Tx.dot(dx).clamp(),r=i_({roughness:bm,dotNV:i}),n=(this.iridescenceF0?Mm.mix(Im,this.iridescenceF0):Im).mul(r.x).add(s.mul(r.y)),o=r.x.add(r.y).oneMinus(),a=Im.add(Im.oneMinus().mul(.047619)),h=n.mul(a).div(o.mul(a).oneMinus());e.addAssign(n),t.addAssign(h.mul(o))}direct({lightDirection:e,lightColor:t,reflectedLight:s}){const i=Tx.dot(e).clamp().mul(t);if(!0===this.sheen&&this.sheenSpecularDirect.addAssign(i.mul(h_({lightDirection:e}))),!0===this.clearcoat){const s=wx.dot(e).clamp().mul(t);this.clearcoatSpecularDirect.addAssign(s.mul(s_({lightDirection:e,f0:z_,f90:U_,roughness:_m,normalView:wx})))}s.directDiffuse.addAssign(i.mul(kT({diffuseColor:ym.rgb}))),s.directSpecular.addAssign(i.mul(s_({lightDirection:e,f0:Im,f90:1,roughness:bm,iridescence:this.iridescence,f:this.iridescenceFresnel,USE_IRIDESCENCE:this.iridescence,USE_ANISOTROPY:this.anisotropy})))}directRectArea({lightColor:e,lightPosition:t,halfWidth:s,halfHeight:i,reflectedLight:r,ltc_1:n,ltc_2:o}){const a=t.add(s).sub(i),h=t.sub(s).sub(i),u=t.sub(s).add(i),l=t.add(s).add(i),c=Tx,d=dx,p=cx.toVar(),m=u_({N:c,V:d,roughness:bm}),g=n.uv(m).toVar(),f=o.uv(m).toVar(),y=Qp(jp(g.x,0,g.y),jp(0,1,0),jp(g.z,0,g.w)).toVar(),x=Im.mul(f.x).add(Im.oneMinus().mul(f.y)).toVar();r.directSpecular.addAssign(e.mul(x).mul(d_({N:c,V:d,P:p,mInv:y,p0:a,p1:h,p2:u,p3:l}))),r.directDiffuse.addAssign(e.mul(ym).mul(d_({N:c,V:d,P:p,mInv:Qp(1,0,0,0,1,0,0,0,1),p0:a,p1:h,p2:u,p3:l})))}indirect(e,t,s){this.indirectDiffuse(e,t,s),this.indirectSpecular(e,t,s),this.ambientOcclusion(e,t,s)}indirectDiffuse({irradiance:e,reflectedLight:t}){t.indirectDiffuse.addAssign(e.mul(kT({diffuseColor:ym})))}indirectSpecular({radiance:e,iblIrradiance:t,reflectedLight:s}){if(!0===this.sheen&&this.sheenSpecularIndirect.addAssign(t.mul(wm,F_({normal:Tx,viewDir:dx,roughness:Sm}))),!0===this.clearcoat){const e=wx.dot(dx).clamp(),t=r_({dotNV:e,specularColor:z_,specularF90:U_,roughness:_m});this.clearcoatSpecularIndirect.addAssign(this.clearcoatRadiance.mul(t))}const i=jp().toVar("singleScattering"),r=jp().toVar("multiScattering"),n=t.mul(1/Math.PI);this.computeMultiscattering(i,r,Pm);const o=i.add(r),a=ym.mul(o.r.max(o.g).max(o.b).oneMinus());s.indirectSpecular.addAssign(e.mul(i)),s.indirectSpecular.addAssign(r.mul(n)),s.indirectDiffuse.addAssign(a.mul(n))}ambientOcclusion({ambientOcclusion:e,reflectedLight:t}){const s=Tx.dot(dx).clamp().add(e),i=bm.mul(-16).oneMinus().negate().exp2(),r=e.sub(s.pow(i).oneMinus()).clamp();!0===this.clearcoat&&this.clearcoatSpecularIndirect.mulAssign(e),!0===this.sheen&&this.sheenSpecularIndirect.mulAssign(e),t.indirectDiffuse.mulAssign(e),t.indirectSpecular.mulAssign(r)}finish(e){const{outgoingLight:t}=e;if(!0===this.clearcoat){const e=wx.dot(dx).clamp(),s=DT({dotVH:e,f0:z_,f90:U_}),i=t.mul(Tm.mul(s).oneMinus()).add(this.clearcoatSpecularDirect.add(this.clearcoatSpecularIndirect).mul(Tm));t.assign(i)}if(!0===this.sheen){const e=wm.r.max(wm.g).max(wm.b).mul(.157).oneMinus(),s=t.mul(e).add(this.sheenSpecularDirect,this.sheenSpecularIndirect);t.assign(s)}}}const L_=Up(1),V_=Up(-2),D_=Up(.8),k_=Up(-1),G_=Up(.4),W_=Up(2),j_=Up(.305),H_=Up(3),q_=Up(.21),$_=Up(4),X_=Up(4),Y_=Up(16),Z_=Rp((([e])=>{const t=jp(jg(e)).toVar(),s=Up(-1).toVar();return Pp(t.x.greaterThan(t.z),(()=>{Pp(t.x.greaterThan(t.y),(()=>{s.assign(Bf(e.x.greaterThan(0),0,3))})).Else((()=>{s.assign(Bf(e.y.greaterThan(0),1,4))}))})).Else((()=>{Pp(t.z.greaterThan(t.y),(()=>{s.assign(Bf(e.z.greaterThan(0),2,5))})).Else((()=>{s.assign(Bf(e.y.greaterThan(0),1,4))}))})),s})).setLayout({name:"getFace",type:"float",inputs:[{name:"direction",type:"vec3"}]}),J_=Rp((([e,t])=>{const s=Dp().toVar();return Pp(t.equal(0),(()=>{s.assign(Dp(e.z,e.y).div(jg(e.x)))})).ElseIf(t.equal(1),(()=>{s.assign(Dp(e.x.negate(),e.z.negate()).div(jg(e.y)))})).ElseIf(t.equal(2),(()=>{s.assign(Dp(e.x.negate(),e.y).div(jg(e.z)))})).ElseIf(t.equal(3),(()=>{s.assign(Dp(e.z.negate(),e.y).div(jg(e.x)))})).ElseIf(t.equal(4),(()=>{s.assign(Dp(e.x.negate(),e.z).div(jg(e.y)))})).Else((()=>{s.assign(Dp(e.x,e.y).div(jg(e.z)))})),Km(.5,s.add(1))})).setLayout({name:"getUV",type:"vec2",inputs:[{name:"direction",type:"vec3"},{name:"face",type:"float"}]}),K_=Rp((([e])=>{const t=Up(0).toVar();return Pp(e.greaterThanEqual(D_),(()=>{t.assign(L_.sub(e).mul(k_.sub(V_)).div(L_.sub(D_)).add(V_))})).ElseIf(e.greaterThanEqual(G_),(()=>{t.assign(D_.sub(e).mul(W_.sub(k_)).div(D_.sub(G_)).add(k_))})).ElseIf(e.greaterThanEqual(j_),(()=>{t.assign(G_.sub(e).mul(H_.sub(W_)).div(G_.sub(j_)).add(W_))})).ElseIf(e.greaterThanEqual(q_),(()=>{t.assign(j_.sub(e).mul($_.sub(H_)).div(j_.sub(q_)).add(H_))})).Else((()=>{t.assign(Up(-2).mul(Bg(Km(1.16,e))))})),t})).setLayout({name:"roughnessToMip",type:"float",inputs:[{name:"roughness",type:"float"}]}),Q_=Rp((([e,t])=>{const s=e.toVar();s.assign(Km(2,s).sub(1));const i=jp(s,1).toVar();return Pp(t.equal(0),(()=>{i.assign(i.zyx)})).ElseIf(t.equal(1),(()=>{i.assign(i.xzy),i.xz.mulAssign(-1)})).ElseIf(t.equal(2),(()=>{i.x.mulAssign(-1)})).ElseIf(t.equal(3),(()=>{i.assign(i.zyx),i.xz.mulAssign(-1)})).ElseIf(t.equal(4),(()=>{i.assign(i.xzy),i.xy.mulAssign(-1)})).ElseIf(t.equal(5),(()=>{i.z.mulAssign(-1)})),i})).setLayout({name:"getDirection",type:"vec3",inputs:[{name:"uv",type:"vec2"},{name:"face",type:"float"}]}),ew=Rp((([e,t,s,i,r,n])=>{const o=Up(s),a=jp(t),h=_f(K_(o),V_,n),u=Og(h),l=Fg(h),c=jp(tw(e,a,l,i,r,n)).toVar();return Pp(u.notEqual(0),(()=>{const t=jp(tw(e,a,l.add(1),i,r,n)).toVar();c.assign(Tf(c,t,u))})),c})),tw=Rp((([e,t,s,i,r,n])=>{const o=Up(s).toVar(),a=jp(t),h=Up(Z_(a)).toVar(),u=Up(of(X_.sub(o),0)).toVar();o.assign(of(o,X_));const l=Up(Rg(o)).toVar(),c=Dp(J_(a,h).mul(l.sub(2)).add(1)).toVar();return Pp(h.greaterThan(2),(()=>{c.y.addAssign(l),h.subAssign(3)})),c.x.addAssign(h.mul(l)),c.x.addAssign(u.mul(Km(3,Y_))),c.y.addAssign(Km(4,Rg(n).sub(l))),c.x.mulAssign(i),c.y.mulAssign(r),e.uv(c).grad(Dp(),Dp())})),sw=Rp((({envMap:e,mipInt:t,outputDirection:s,theta:i,axis:r,CUBEUV_TEXEL_WIDTH:n,CUBEUV_TEXEL_HEIGHT:o,CUBEUV_MAX_MIP:a})=>{const h=Vg(i),u=s.mul(h).add(r.cross(s).mul(Lg(i))).add(r.mul(r.dot(s).mul(h.oneMinus())));return tw(e,u,t,n,o,a)})),iw=Rp((({n:e,latitudinal:t,poleAxis:s,outputDirection:i,weights:r,samples:n,dTheta:o,mipInt:a,envMap:h,CUBEUV_TEXEL_WIDTH:u,CUBEUV_TEXEL_HEIGHT:l,CUBEUV_MAX_MIP:c})=>{const d=jp(Bf(t,s,pf(s,i))).toVar();Pp(wg(d.equals(jp(0))),(()=>{d.assign(jp(i.z,0,i.x.negate()))})),d.assign(Ug(d));const p=jp().toVar();return p.addAssign(r.element(Op(0)).mul(sw({theta:0,axis:d,outputDirection:i,mipInt:a,envMap:h,CUBEUV_TEXEL_WIDTH:u,CUBEUV_TEXEL_HEIGHT:l,CUBEUV_MAX_MIP:c}))),bv({start:Op(1),end:e},(({i:e})=>{Pp(e.greaterThanEqual(n),(()=>{Tv()}));const t=Up(o.mul(Up(e))).toVar();p.addAssign(r.element(e).mul(sw({theta:t.mul(-1),axis:d,outputDirection:i,mipInt:a,envMap:h,CUBEUV_TEXEL_WIDTH:u,CUBEUV_TEXEL_HEIGHT:l,CUBEUV_MAX_MIP:c}))),p.addAssign(r.element(e).mul(sw({theta:t,axis:d,outputDirection:i,mipInt:a,envMap:h,CUBEUV_TEXEL_WIDTH:u,CUBEUV_TEXEL_HEIGHT:l,CUBEUV_MAX_MIP:c})))})),Xp(p,1)}));let rw=null;const nw=new WeakMap;function ow(e){let t=nw.get(e);if((void 0!==t?t.pmremVersion:-1)!==e.pmremVersion){const s=e.image;if(e.isCubeTexture){if(!function(e){if(null==e)return!1;let t=0;const s=6;for(let i=0;i0}(s))return null;t=rw.fromEquirectangular(e,t)}t.pmremVersion=e.pmremVersion,nw.set(e,t)}return t.texture}class aw extends kd{static get type(){return"PMREMNode"}constructor(e,t=null,s=null){super("vec3"),this._value=e,this._pmrem=null,this.uvNode=t,this.levelNode=s,this._generator=null;const i=new vi;i.isRenderTargetTexture=!0,this._texture=By(i),this._width=pm(0),this._height=pm(0),this._maxMip=pm(0),this.updateBeforeType=Bd.RENDER}set value(e){this._value=e,this._pmrem=null}get value(){return this._value}updateFromTexture(e){const t=function(e){const t=Math.log2(e)-2,s=1/e;return{texelWidth:1/(3*Math.max(Math.pow(2,t),112)),texelHeight:s,maxMip:t}}(e.image.height);this._texture.value=e,this._width.value=t.texelWidth,this._height.value=t.texelHeight,this._maxMip.value=t.maxMip}updateBefore(){let e=this._pmrem;const t=e?e.pmremVersion:-1,s=this._value;t!==s.pmremVersion&&(e=!0===s.isPMREMTexture?s:ow(s),null!==e&&(this._pmrem=e,this.updateFromTexture(e)))}setup(e){null===rw&&(rw=e.createPMREMGenerator()),this.updateBefore(e);let t=this.uvNode;null===t&&e.context.getUV&&(t=e.context.getUV(this));const s=this.value;e.renderer.coordinateSystem===Vs&&!0!==s.isPMREMTexture&&!0===s.isRenderTargetTexture&&(t=jp(t.x.negate(),t.yz));let i=this.levelNode;return null===i&&e.context.getTextureLevel&&(i=e.context.getTextureLevel(this)),ew(this._texture,t,i,this._width,this._height,this._maxMip)}}const hw=Ap(aw),uw=new WeakMap;class lw extends Iv{static get type(){return"EnvironmentNode"}constructor(e=null){super(),this.envNode=e}setup(e){const{material:t}=e;let s=this.envNode;if(s.isTextureNode||s.isMaterialReferenceNode){const e=s.isTextureNode?s.value:t[s.property];let i=uw.get(e);void 0===i&&(i=hw(e),uw.set(e,i)),s=i}const i=t.envMap?kx("envMapIntensity","float",e.material):kx("environmentIntensity","float",e.scene),r=!0===t.useAnisotropy||t.anisotropy>0?ab:Tx,n=s.context(cw(bm,r)).mul(i),o=s.context(dw(_x)).mul(Math.PI).mul(i),a=ly(n),h=ly(o);e.context.radiance.addAssign(a),e.context.iblIrradiance.addAssign(h);const u=e.context.lightingModel.clearcoatRadiance;if(u){const e=s.context(cw(_m,wx)).mul(i),t=ly(e);u.addAssign(t)}}}const cw=(e,t)=>{let s=null;return{getUV:()=>(null===s&&(s=dx.negate().reflect(t),s=e.mul(e).mix(s,t).normalize(),s=s.transformDirection(Vy)),s),getTextureLevel:()=>e}},dw=e=>({getUV:()=>e,getTextureLevel:()=>Up(1)}),pw=new _u;class mw extends pT{static get type(){return"MeshStandardNodeMaterial"}constructor(e){super(),this.isMeshStandardNodeMaterial=!0,this.lights=!0,this.emissiveNode=null,this.metalnessNode=null,this.roughnessNode=null,this.setDefaultValues(pw),this.setValues(e)}setupEnvironment(e){let t=super.setupEnvironment(e);return null===t&&e.environmentNode&&(t=e.environmentNode),t?new lw(t):null}setupLightingModel(){return new O_}setupSpecular(){const e=Tf(jp(.04),ym.rgb,vm);Im.assign(e),Pm.assign(1)}setupVariants(){const e=this.metalnessNode?Up(this.metalnessNode):Cb;vm.assign(e);let t=this.roughnessNode?Up(this.roughnessNode):Ab;t=ZT({roughness:t}),bm.assign(t),this.setupSpecular(),ym.assign(Xp(ym.rgb.mul(e.oneMinus()),ym.a))}copy(e){return this.emissiveNode=e.emissiveNode,this.metalnessNode=e.metalnessNode,this.roughnessNode=e.roughnessNode,super.copy(e)}}const gw=new wu;class fw extends mw{static get type(){return"MeshPhysicalNodeMaterial"}constructor(e){super(),this.isMeshPhysicalNodeMaterial=!0,this.clearcoatNode=null,this.clearcoatRoughnessNode=null,this.clearcoatNormalNode=null,this.sheenNode=null,this.sheenRoughnessNode=null,this.iridescenceNode=null,this.iridescenceIORNode=null,this.iridescenceThicknessNode=null,this.specularIntensityNode=null,this.specularColorNode=null,this.iorNode=null,this.transmissionNode=null,this.thicknessNode=null,this.attenuationDistanceNode=null,this.attenuationColorNode=null,this.dispersionNode=null,this.anisotropyNode=null,this.setDefaultValues(gw),this.setValues(e)}get useClearcoat(){return this.clearcoat>0||null!==this.clearcoatNode}get useIridescence(){return this.iridescence>0||null!==this.iridescenceNode}get useSheen(){return this.sheen>0||null!==this.sheenNode}get useAnisotropy(){return this.anisotropy>0||null!==this.anisotropyNode}get useTransmission(){return this.transmission>0||null!==this.transmissionNode}get useDispersion(){return this.dispersion>0||null!==this.dispersionNode}setupSpecular(){const e=this.iorNode?Up(this.iorNode):Gb;Vm.assign(e),Im.assign(Tf(nf(gf(Vm.sub(1).div(Vm.add(1))).mul(Sb),jp(1)).mul(wb),ym.rgb,vm)),Pm.assign(Tf(wb,1,vm))}setupLightingModel(){return new O_(this.useClearcoat,this.useSheen,this.useIridescence,this.useAnisotropy,this.useTransmission,this.useDispersion)}setupVariants(e){if(super.setupVariants(e),this.useClearcoat){const e=this.clearcoatNode?Up(this.clearcoatNode):Eb,t=this.clearcoatRoughnessNode?Up(this.clearcoatRoughnessNode):Bb;Tm.assign(e),_m.assign(ZT({roughness:t}))}if(this.useSheen){const e=this.sheenNode?jp(this.sheenNode):Fb,t=this.sheenRoughnessNode?Up(this.sheenRoughnessNode):zb;wm.assign(e),Sm.assign(t)}if(this.useIridescence){const e=this.iridescenceNode?Up(this.iridescenceNode):Ob,t=this.iridescenceIORNode?Up(this.iridescenceIORNode):Lb,s=this.iridescenceThicknessNode?Up(this.iridescenceThicknessNode):Vb;Mm.assign(e),Nm.assign(t),Am.assign(s)}if(this.useAnisotropy){const e=(this.anisotropyNode?Dp(this.anisotropyNode):Ub).toVar();Rm.assign(e.length()),Pp(Rm.equal(0),(()=>{e.assign(Dp(1,0))})).Else((()=>{e.divAssign(Dp(Rm)),Rm.assign(Rm.saturate())})),Cm.assign(Rm.pow2().mix(bm.pow2(),1)),Em.assign(rb[0].mul(e.x).add(rb[1].mul(e.y))),Bm.assign(rb[1].mul(e.x).sub(rb[0].mul(e.y)))}if(this.useTransmission){const e=this.transmissionNode?Up(this.transmissionNode):Db,t=this.thicknessNode?Up(this.thicknessNode):kb,s=this.attenuationDistanceNode?Up(this.attenuationDistanceNode):Wb,i=this.attenuationColorNode?jp(this.attenuationColorNode):jb;if(Dm.assign(e),km.assign(t),Gm.assign(s),Wm.assign(i),this.useDispersion){const e=this.dispersionNode?Up(this.dispersionNode):Jb;jm.assign(e)}}}setupClearcoatNormal(){return this.clearcoatNormalNode?jp(this.clearcoatNormalNode):Ib}setup(e){e.context.setupClearcoatNormal=()=>this.setupClearcoatNormal(e),super.setup(e)}copy(e){return this.clearcoatNode=e.clearcoatNode,this.clearcoatRoughnessNode=e.clearcoatRoughnessNode,this.clearcoatNormalNode=e.clearcoatNormalNode,this.sheenNode=e.sheenNode,this.sheenRoughnessNode=e.sheenRoughnessNode,this.iridescenceNode=e.iridescenceNode,this.iridescenceIORNode=e.iridescenceIORNode,this.iridescenceThicknessNode=e.iridescenceThicknessNode,this.specularIntensityNode=e.specularIntensityNode,this.specularColorNode=e.specularColorNode,this.transmissionNode=e.transmissionNode,this.thicknessNode=e.thicknessNode,this.attenuationDistanceNode=e.attenuationDistanceNode,this.attenuationColorNode=e.attenuationColorNode,this.dispersionNode=e.dispersionNode,this.anisotropyNode=e.anisotropyNode,super.copy(e)}}class yw extends O_{constructor(e,t,s,i){super(e,t,s),this.useSSS=i}direct({lightDirection:e,lightColor:t,reflectedLight:s},i,r){if(!0===this.useSSS){const i=r.material,{thicknessColorNode:n,thicknessDistortionNode:o,thicknessAmbientNode:a,thicknessAttenuationNode:h,thicknessPowerNode:u,thicknessScaleNode:l}=i,c=e.add(Tx.mul(o)).normalize(),d=Up(dx.dot(c.negate()).saturate().pow(u).mul(l)),p=jp(d.add(a).mul(n));s.directDiffuse.addAssign(p.mul(h.mul(t)))}super.direct({lightDirection:e,lightColor:t,reflectedLight:s},i,r)}}class xw extends fw{static get type(){return"MeshSSSNodeMaterial"}constructor(e){super(e),this.thicknessColorNode=null,this.thicknessDistortionNode=Up(.1),this.thicknessAmbientNode=Up(0),this.thicknessAttenuationNode=Up(.1),this.thicknessPowerNode=Up(2),this.thicknessScaleNode=Up(10)}get useSSS(){return null!==this.thicknessColorNode}setupLightingModel(){return new yw(this.useClearcoat,this.useSheen,this.useIridescence,this.useSSS)}copy(e){return this.thicknessColorNode=e.thicknessColorNode,this.thicknessDistortionNode=e.thicknessDistortionNode,this.thicknessAmbientNode=e.thicknessAmbientNode,this.thicknessAttenuationNode=e.thicknessAttenuationNode,this.thicknessPowerNode=e.thicknessPowerNode,this.thicknessScaleNode=e.thicknessScaleNode,super.copy(e)}}const bw=Rp((({normal:e,lightDirection:t,builder:s})=>{const i=e.dot(t),r=Dp(i.mul(.5).add(.5),0);if(s.material.gradientMap){const e=jx("gradientMap","texture").context({getUV:()=>r});return jp(e.r)}{const e=r.fwidth().mul(.5);return Tf(jp(.7),jp(1),Mf(Up(.7).sub(e.x),Up(.7).add(e.x),r.x))}}));class vw extends UT{direct({lightDirection:e,lightColor:t,reflectedLight:s},i,r){const n=bw({normal:fx,lightDirection:e,builder:r}).mul(t);s.directDiffuse.addAssign(n.mul(kT({diffuseColor:ym.rgb})))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:s}){s.indirectDiffuse.addAssign(t.mul(kT({diffuseColor:ym}))),s.indirectDiffuse.mulAssign(e)}}const Tw=new Mu;class _w extends pT{static get type(){return"MeshToonNodeMaterial"}constructor(e){super(),this.isMeshToonNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Tw),this.setValues(e)}setupLightingModel(){return new vw}}class ww extends kd{static get type(){return"MatcapUVNode"}constructor(){super("vec2")}setup(){const e=jp(dx.z,0,dx.x.negate()).normalize(),t=dx.cross(e);return Dp(e.dot(Tx),t.dot(Tx)).mul(.495).add(.5)}}const Sw=Cp(ww),Mw=new Eu;class Nw extends pT{static get type(){return"MeshMatcapNodeMaterial"}constructor(e){super(),this.lights=!1,this.isMeshMatcapNodeMaterial=!0,this.setDefaultValues(Mw),this.setValues(e)}setupVariants(e){const t=Sw;let s;s=e.material.matcap?jx("matcap","texture").context({getUV:()=>t}):jp(Tf(.2,.8,t.y)),ym.rgb.mulAssign(s.rgb)}}const Aw=new za;class Cw extends pT{static get type(){return"PointsNodeMaterial"}constructor(e){super(),this.isPointsNodeMaterial=!0,this.lights=!1,this.transparent=!0,this.sizeNode=null,this.setDefaultValues(Aw),this.setValues(e)}copy(e){return this.sizeNode=e.sizeNode,super.copy(e)}}class Rw extends kd{static get type(){return"RotateNode"}constructor(e,t){super(),this.positionNode=e,this.rotationNode=t}getNodeType(e){return this.positionNode.getNodeType(e)}setup(e){const{rotationNode:t,positionNode:s}=this;if("vec2"===this.getNodeType(e)){const e=t.cos(),i=t.sin();return Kp(e,i,i.negate(),e).mul(s)}{const e=t,i=em(Xp(1,0,0,0),Xp(0,Vg(e.x),Lg(e.x).negate(),0),Xp(0,Lg(e.x),Vg(e.x),0),Xp(0,0,0,1)),r=em(Xp(Vg(e.y),0,Lg(e.y),0),Xp(0,1,0,0),Xp(Lg(e.y).negate(),0,Vg(e.y),0),Xp(0,0,0,1)),n=em(Xp(Vg(e.z),Lg(e.z).negate(),0,0),Xp(Lg(e.z),Vg(e.z),0,0),Xp(0,0,1,0),Xp(0,0,0,1));return i.mul(r).mul(n).mul(Xp(s,1)).xyz}}}const Ew=Ap(Rw),Bw=new no;class Iw extends pT{static get type(){return"SpriteNodeMaterial"}constructor(e){super(),this.isSpriteNodeMaterial=!0,this.lights=!1,this._useSizeAttenuation=!0,this.positionNode=null,this.rotationNode=null,this.scaleNode=null,this.setDefaultValues(Bw),this.setValues(e)}setupPosition({object:e,camera:t,context:s}){const i=this.sizeAttenuation,{positionNode:r,rotationNode:n,scaleNode:o}=this,a=ax;let h=ix.mul(jp(r||0)),u=Dp(Jy[0].xyz.length(),Jy[1].xyz.length());null!==o&&(u=u.mul(o)),!i&&t.isPerspectiveCamera&&(u=u.mul(h.z.negate()));let l=a.xy;if(e.center&&!0===e.center.isVector2){const e=((e,t,s)=>Sp(new Zf(e,t,s)))("center","vec2");l=l.sub(e.sub(.5))}l=l.mul(u);const c=Up(n||Pb),d=Ew(l,c);h=Xp(h.xy.add(d),h.zw);const p=Oy.mul(h);return s.vertex=a,p}copy(e){return this.positionNode=e.positionNode,this.rotationNode=e.rotationNode,this.scaleNode=e.scaleNode,super.copy(e)}get sizeAttenuation(){return this._useSizeAttenuation}set sizeAttenuation(e){this._useSizeAttenuation!==e&&(this._useSizeAttenuation=e,this.needsUpdate=!0)}}class Pw extends UT{constructor(){super(),this.shadowNode=Up(1).toVar("shadowMask")}direct({shadowMask:e}){this.shadowNode.mulAssign(e)}finish(e){ym.a.mulAssign(this.shadowNode.oneMinus()),e.outgoingLight.rgb.assign(ym.rgb)}}const Fw=new vu;class zw extends pT{static get type(){return"ShadowNodeMaterial"}constructor(e){super(),this.isShadowNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Fw),this.setValues(e)}setupLightingModel(){return new Pw}}const Uw=Rp((({texture:e,uv:t})=>{const s=1e-4,i=jp().toVar();return Pp(t.x.lessThan(s),(()=>{i.assign(jp(1,0,0))})).ElseIf(t.y.lessThan(s),(()=>{i.assign(jp(0,1,0))})).ElseIf(t.z.lessThan(s),(()=>{i.assign(jp(0,0,1))})).ElseIf(t.x.greaterThan(.9999),(()=>{i.assign(jp(-1,0,0))})).ElseIf(t.y.greaterThan(.9999),(()=>{i.assign(jp(0,-1,0))})).ElseIf(t.z.greaterThan(.9999),(()=>{i.assign(jp(0,0,-1))})).Else((()=>{const s=.01,r=e.uv(t.add(jp(-.01,0,0))).r.sub(e.uv(t.add(jp(s,0,0))).r),n=e.uv(t.add(jp(0,-.01,0))).r.sub(e.uv(t.add(jp(0,s,0))).r),o=e.uv(t.add(jp(0,0,-.01))).r.sub(e.uv(t.add(jp(0,0,s))).r);i.assign(jp(r,n,o))})),i.normalize()}));class Ow extends Ey{static get type(){return"Texture3DNode"}constructor(e,t=null,s=null){super(e,t,s),this.isTexture3DNode=!0}getInputType(){return"texture3D"}getDefaultUV(){return jp(.5,.5,.5)}setUpdateMatrix(){}setupUV(e,t){return t}generateUV(e,t){return t.build(e,"vec3")}normal(e){return Uw({texture:this,uv:e})}}const Lw=Ap(Ow);class Vw extends pT{static get type(){return"VolumeNodeMaterial"}constructor(e={}){super(),this.lights=!1,this.isVolumeNodeMaterial=!0,this.testNode=null,this.setValues(e)}setup(e){const t=Lw(this.map,null,0),s=Rp((({orig:e,dir:t})=>{const s=jp(-.5),i=jp(.5),r=t.reciprocal(),n=s.sub(e).mul(r),o=i.sub(e).mul(r),a=nf(n,o),h=of(n,o),u=of(a.x,of(a.y,a.z)),l=nf(h.x,nf(h.y,h.z));return Dp(u,l)}));this.fragmentNode=Rp((()=>{const e=Vf(jp(sx.mul(Xp(Gy,1)))),i=Vf(ox.sub(e)).normalize(),r=Dp(s({orig:e,dir:i})).toVar();r.x.greaterThan(r.y).discard(),r.assign(Dp(of(r.x,0),r.y));const n=jp(e.add(r.x.mul(i))).toVar(),o=jp(i.abs().reciprocal()).toVar(),a=Up(nf(o.x,nf(o.y,o.z))).toVar("delta");a.divAssign(jx("steps","float"));const h=Xp(jx("base","color"),0).toVar();return bv({type:"float",start:r.x,end:r.y,update:"+= delta"},(()=>{const e=gm("float","d").assign(t.uv(n.add(.5)).r);null!==this.testNode?this.testNode({map:t,mapValue:e,probe:n,finalColor:h}).append():(h.a.assign(1),Tv()),n.addAssign(i.mul(a))})),h.a.equal(0).discard(),Xp(h)}))(),super.setup(e)}}class Dw{constructor(e,t){this.nodes=e,this.info=t,this.animationLoop=null,this.requestId=null,this._init()}_init(){const e=(t,s)=>{this.requestId=self.requestAnimationFrame(e),!0===this.info.autoReset&&this.info.reset(),this.nodes.nodeFrame.update(),this.info.frame=this.nodes.nodeFrame.frameId,null!==this.animationLoop&&this.animationLoop(t,s)};e()}dispose(){self.cancelAnimationFrame(this.requestId),this.requestId=null}setAnimationLoop(e){this.animationLoop=e}}class kw{constructor(){this.weakMap=new WeakMap}get(e){let t=this.weakMap;for(let s=0;s{this.dispose()},this.material.addEventListener("dispose",this.onMaterialDispose)}updateClipping(e){const t=this.material;let s=this.clippingContext;Array.isArray(t.clippingPlanes)?(s!==e&&s||(s=new Ww,this.clippingContext=s),s.update(e,t)):this.clippingContext!==e&&(this.clippingContext=e)}get clippingNeedsUpdate(){return this.clippingContext.version!==this.clippingContextVersion&&(this.clippingContextVersion=this.clippingContext.version,!0)}getNodeBuilderState(){return this._nodeBuilderState||(this._nodeBuilderState=this._nodes.getForRender(this))}getMonitor(){return this._monitor||(this._monitor=this.getNodeBuilderState().monitor)}getBindings(){return this._bindings||(this._bindings=this.getNodeBuilderState().createBindings())}getIndex(){return this._geometries.getIndex(this)}getChainArray(){return[this.object,this.material,this.context,this.lightsNode]}getAttributes(){if(null!==this.attributes)return this.attributes;const e=this.getNodeBuilderState().nodeAttributes,t=this.geometry,s=[],i=new Set;for(const r of e){const e=r.node&&r.node.attribute?r.node.attribute:t.getAttribute(r.name);if(void 0===e)continue;s.push(e);const n=e.isInterleavedBufferAttribute?e.data:e;i.add(n)}return this.attributes=s,this.vertexBuffers=Array.from(i.values()),s}getVertexBuffers(){return null===this.vertexBuffers&&this.getAttributes(),this.vertexBuffers}getDrawParameters(){const{object:e,material:t,geometry:s,group:i,drawRange:r}=this,n=this.drawParams||(this.drawParams={vertexCount:0,firstVertex:0,instanceCount:0,firstInstance:0}),o=this.getIndex(),a=null!==o,h=s.isInstancedBufferGeometry?s.instanceCount:e.count>1?e.count:1;if(0===h)return null;if(n.instanceCount=h,!0===e.isBatchedMesh)return n;let u=1;!0!==t.wireframe||e.isPoints||e.isLineSegments||e.isLine||e.isLineLoop||(u=2);let l=r.start*u,c=(r.start+r.count)*u;null!==i&&(l=Math.max(l,i.start*u),c=Math.min(c,(i.start+i.count)*u));const d=!0===a?o.count:s.attributes.position.count;l=Math.max(l,0),c=Math.min(c,d);const p=c-l;return p<0||p===1/0?null:(n.vertexCount=p,n.firstVertex=l,n)}getGeometryCacheKey(){const{geometry:e}=this;let t="";for(const s of Object.keys(e.attributes).sort()){const i=e.attributes[s];t+=s+",",i.data&&(t+=i.data.stride+","),i.offset&&(t+=i.offset+","),i.itemSize&&(t+=i.itemSize+","),i.normalized&&(t+="n,")}return e.index&&(t+="index,"),t}getMaterialCacheKey(){const{object:e,material:t}=this;let s=t.customProgramCacheKey();for(const e of function(e){const t=Object.keys(e);let s=Object.getPrototypeOf(e);for(;s;){const e=Object.getOwnPropertyDescriptors(s);for(const s in e)if(void 0!==e[s]){const i=e[s];i&&"function"==typeof i.get&&t.push(s)}s=Object.getPrototypeOf(s)}return t}(t)){if(/^(is[A-Z]|_)|^(visible|version|uuid|name|opacity|userData)$/.test(e))continue;const i=t[e];let r;if(null!==i){const e=typeof i;"number"===e?r=0!==i?"1":"0":"object"===e?(r="{",i.isTexture&&(r+=i.mapping),r+="}"):r=String(i)}else r=String(i);s+=r+","}return s+=this.clippingContext.cacheKey+",",e.geometry&&(s+=this.getGeometryCacheKey()),e.skeleton&&(s+=e.skeleton.bones.length+","),e.morphTargetInfluences&&(s+=e.morphTargetInfluences.length+","),e.isBatchedMesh&&(s+=e._matricesTexture.uuid+",",null!==e._colorsTexture&&(s+=e._colorsTexture.uuid+",")),e.count>1&&(s+=e.uuid+","),vd(s)}get needsUpdate(){return this.initialNodesCacheKey!==this.getDynamicCacheKey()||this.clippingNeedsUpdate}getDynamicCacheKey(){let e=this._nodes.getCacheKey(this.scene,this.lightsNode);return this.object.receiveShadow&&(e+=1),e}getCacheKey(){return this.getMaterialCacheKey()+this.getDynamicCacheKey()}dispose(){this.material.removeEventListener("dispose",this.onMaterialDispose),this.onDispose()}}const qw=[];class $w{constructor(e,t,s,i,r,n){this.renderer=e,this.nodes=t,this.geometries=s,this.pipelines=i,this.bindings=r,this.info=n,this.chainMaps={}}get(e,t,s,i,r,n,o){const a=this.getChainMap(o);qw[0]=e,qw[1]=t,qw[2]=n,qw[3]=r;let h=a.get(qw);return void 0===h?(h=this.createRenderObject(this.nodes,this.geometries,this.renderer,e,t,s,i,r,n,o),a.set(qw,h)):(h.updateClipping(n.clippingContext),(h.version!==t.version||h.needsUpdate)&&(h.initialCacheKey!==h.getCacheKey()?(h.dispose(),h=this.get(e,t,s,i,r,n,o)):h.version=t.version)),h}getChainMap(e="default"){return this.chainMaps[e]||(this.chainMaps[e]=new kw)}dispose(){this.chainMaps={}}createRenderObject(e,t,s,i,r,n,o,a,h,u){const l=this.getChainMap(u),c=new Hw(e,t,s,i,r,n,o,a,h);return c.onDispose=()=>{this.pipelines.delete(c),this.bindings.delete(c),this.nodes.delete(c),l.delete(c.getChainArray())},c}}class Xw{constructor(){this.data=new WeakMap}get(e){let t=this.data.get(e);return void 0===t&&(t={},this.data.set(e,t)),t}delete(e){let t;return this.data.has(e)&&(t=this.data.get(e),this.data.delete(e)),t}has(e){return this.data.has(e)}dispose(){this.data=new WeakMap}}const Yw=1,Zw=2,Jw=4,Kw=16;class Qw extends Xw{constructor(e){super(),this.backend=e}delete(e){const t=super.delete(e);return void 0!==t&&this.backend.destroyAttribute(e),t}update(e,t){const s=this.get(e);if(void 0===s.version)t===Yw?this.backend.createAttribute(e):t===Zw?this.backend.createIndexAttribute(e):t===Jw&&this.backend.createStorageAttribute(e),s.version=this._getBufferAttribute(e).version;else{const t=this._getBufferAttribute(e);(s.version=0;--t)if(e[t]>=65535)return!0;return!1}(t)?yn:gn)(t,1);return r.version=eS(e),r}class sS extends Xw{constructor(e,t){super(),this.attributes=e,this.info=t,this.wireframes=new WeakMap,this.attributeCall=new WeakMap}has(e){const t=e.geometry;return super.has(t)&&!0===this.get(t).initialized}updateForRender(e){!1===this.has(e)&&this.initGeometry(e),this.updateAttributes(e)}initGeometry(e){const t=e.geometry;this.get(t).initialized=!0,this.info.memory.geometries++;const s=()=>{this.info.memory.geometries--;const i=t.index,r=e.getAttributes();null!==i&&this.attributes.delete(i);for(const e of r)this.attributes.delete(e);const n=this.wireframes.get(t);void 0!==n&&this.attributes.delete(n),t.removeEventListener("dispose",s)};t.addEventListener("dispose",s)}updateAttributes(e){const t=e.getAttributes();for(const e of t)e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute?this.updateAttribute(e,Jw):this.updateAttribute(e,Yw);const s=this.getIndex(e);null!==s&&this.updateAttribute(s,Zw)}updateAttribute(e,t){const s=this.info.render.calls;e.isInterleavedBufferAttribute?void 0===this.attributeCall.get(e)?(this.attributes.update(e,t),this.attributeCall.set(e,s)):this.attributeCall.get(e.data)!==s&&(this.attributes.update(e,t),this.attributeCall.set(e.data,s),this.attributeCall.set(e,s)):this.attributeCall.get(e)!==s&&(this.attributes.update(e,t),this.attributeCall.set(e,s))}getIndex(e){const{geometry:t,material:s}=e;let i=t.index;if(!0===s.wireframe){const e=this.wireframes;let s=e.get(t);void 0===s?(s=tS(t),e.set(t,s)):s.version!==eS(t)&&(this.attributes.delete(s),s=tS(t),e.set(t,s)),i=s}return i}}class iS{constructor(){this.autoReset=!0,this.frame=0,this.calls=0,this.render={calls:0,frameCalls:0,drawCalls:0,triangles:0,points:0,lines:0,timestamp:0,previousFrameCalls:0,timestampCalls:0},this.compute={calls:0,frameCalls:0,timestamp:0,previousFrameCalls:0,timestampCalls:0},this.memory={geometries:0,textures:0}}update(e,t,s){this.render.drawCalls++,e.isMesh||e.isSprite?this.render.triangles+=s*(t/3):e.isPoints?this.render.points+=s*t:e.isLineSegments?this.render.lines+=s*(t/2):e.isLine?this.render.lines+=s*(t-1):console.error("THREE.WebGPUInfo: Unknown object type.")}updateTimestamp(e,t){0===this[e].timestampCalls&&(this[e].timestamp=0),this[e].timestamp+=t,this[e].timestampCalls++,this[e].timestampCalls>=this[e].previousFrameCalls&&(this[e].timestampCalls=0)}reset(){const e=this.render.frameCalls;this.render.previousFrameCalls=e;const t=this.compute.frameCalls;this.compute.previousFrameCalls=t,this.render.drawCalls=0,this.render.frameCalls=0,this.compute.frameCalls=0,this.render.triangles=0,this.render.points=0,this.render.lines=0}dispose(){this.reset(),this.calls=0,this.render.calls=0,this.compute.calls=0,this.render.timestamp=0,this.compute.timestamp=0,this.memory.geometries=0,this.memory.textures=0}}class rS{constructor(e){this.cacheKey=e,this.usedTimes=0}}class nS extends rS{constructor(e,t,s){super(e),this.vertexProgram=t,this.fragmentProgram=s}}class oS extends rS{constructor(e,t){super(e),this.computeProgram=t,this.isComputePipeline=!0}}let aS=0;class hS{constructor(e,t,s=null,i=null){this.id=aS++,this.code=e,this.stage=t,this.transforms=s,this.attributes=i,this.usedTimes=0}}class uS extends Xw{constructor(e,t){super(),this.backend=e,this.nodes=t,this.bindings=null,this.caches=new Map,this.programs={vertex:new Map,fragment:new Map,compute:new Map}}getForCompute(e,t){const{backend:s}=this,i=this.get(e);if(this._needsComputeUpdate(e)){const r=i.pipeline;r&&(r.usedTimes--,r.computeProgram.usedTimes--);const n=this.nodes.getForCompute(e);let o=this.programs.compute.get(n.computeShader);void 0===o&&(r&&0===r.computeProgram.usedTimes&&this._releaseProgram(r.computeProgram),o=new hS(n.computeShader,"compute",n.transforms,n.nodeAttributes),this.programs.compute.set(n.computeShader,o),s.createProgram(o));const a=this._getComputeCacheKey(e,o);let h=this.caches.get(a);void 0===h&&(r&&0===r.usedTimes&&this._releasePipeline(r),h=this._getComputePipeline(e,o,a,t)),h.usedTimes++,o.usedTimes++,i.version=e.version,i.pipeline=h}return i.pipeline}getForRender(e,t=null){const{backend:s}=this,i=this.get(e);if(this._needsRenderUpdate(e)){const r=i.pipeline;r&&(r.usedTimes--,r.vertexProgram.usedTimes--,r.fragmentProgram.usedTimes--);const n=e.getNodeBuilderState();let o=this.programs.vertex.get(n.vertexShader);void 0===o&&(r&&0===r.vertexProgram.usedTimes&&this._releaseProgram(r.vertexProgram),o=new hS(n.vertexShader,"vertex"),this.programs.vertex.set(n.vertexShader,o),s.createProgram(o));let a=this.programs.fragment.get(n.fragmentShader);void 0===a&&(r&&0===r.fragmentProgram.usedTimes&&this._releaseProgram(r.fragmentProgram),a=new hS(n.fragmentShader,"fragment"),this.programs.fragment.set(n.fragmentShader,a),s.createProgram(a));const h=this._getRenderCacheKey(e,o,a);let u=this.caches.get(h);void 0===u?(r&&0===r.usedTimes&&this._releasePipeline(r),u=this._getRenderPipeline(e,o,a,h,t)):e.pipeline=u,u.usedTimes++,o.usedTimes++,a.usedTimes++,i.pipeline=u}return i.pipeline}delete(e){const t=this.get(e).pipeline;return t&&(t.usedTimes--,0===t.usedTimes&&this._releasePipeline(t),t.isComputePipeline?(t.computeProgram.usedTimes--,0===t.computeProgram.usedTimes&&this._releaseProgram(t.computeProgram)):(t.fragmentProgram.usedTimes--,t.vertexProgram.usedTimes--,0===t.vertexProgram.usedTimes&&this._releaseProgram(t.vertexProgram),0===t.fragmentProgram.usedTimes&&this._releaseProgram(t.fragmentProgram))),super.delete(e)}dispose(){super.dispose(),this.caches=new Map,this.programs={vertex:new Map,fragment:new Map,compute:new Map}}updateForRender(e){this.getForRender(e)}_getComputePipeline(e,t,s,i){s=s||this._getComputeCacheKey(e,t);let r=this.caches.get(s);return void 0===r&&(r=new oS(s,t),this.caches.set(s,r),this.backend.createComputePipeline(r,i)),r}_getRenderPipeline(e,t,s,i,r){i=i||this._getRenderCacheKey(e,t,s);let n=this.caches.get(i);return void 0===n&&(n=new nS(i,t,s),this.caches.set(i,n),e.pipeline=n,this.backend.createRenderPipeline(e,r)),n}_getComputeCacheKey(e,t){return e.id+","+t.id}_getRenderCacheKey(e,t,s){return t.id+","+s.id+","+this.backend.getRenderCacheKey(e)}_releasePipeline(e){this.caches.delete(e.cacheKey)}_releaseProgram(e){const t=e.code,s=e.stage;this.programs[s].delete(t)}_needsComputeUpdate(e){const t=this.get(e);return void 0===t.pipeline||t.version!==e.version}_needsRenderUpdate(e){return void 0===this.get(e).pipeline||this.backend.needsRenderUpdate(e)}}class lS extends Xw{constructor(e,t,s,i,r,n){super(),this.backend=e,this.textures=s,this.pipelines=r,this.attributes=i,this.nodes=t,this.info=n,this.pipelines.bindings=this}getForRender(e){const t=e.getBindings();for(const e of t){const s=this.get(e);void 0===s.bindGroup&&(this._init(e),this.backend.createBindings(e,t),s.bindGroup=e)}return t}getForCompute(e){const t=this.nodes.getForCompute(e).bindings;for(const e of t){const s=this.get(e);void 0===s.bindGroup&&(this._init(e),this.backend.createBindings(e,t),s.bindGroup=e)}return t}updateForCompute(e){this._updateBindings(this.getForCompute(e))}updateForRender(e){this._updateBindings(this.getForRender(e))}_updateBindings(e){for(const t of e)this._update(t,e)}_init(e){for(const t of e.bindings)if(t.isSampledTexture)this.textures.updateTexture(t.texture);else if(t.isStorageBuffer){const e=t.attribute;this.attributes.update(e,Jw)}}_update(e,t){const{backend:s}=this;let i=!1;for(const t of e.bindings){if(t.isNodeUniformsGroup){if(!this.nodes.updateGroup(t))continue}if(t.isUniformBuffer){t.update()&&s.updateBinding(t)}else if(t.isSampler)t.update();else if(t.isSampledTexture){t.needsBindingsUpdate(this.textures.get(t.texture).generation)&&(i=!0);const e=t.update(),r=t.texture;e&&this.textures.updateTexture(r);const n=s.get(r);if(!0===s.isWebGPUBackend&&void 0===n.texture&&void 0===n.externalTexture&&(console.error("Bindings._update: binding should be available:",t,e,r,t.textureNode.value,i),this.textures.updateTexture(r),i=!0),!0===r.isStorageTexture){const e=this.get(r);!0===t.store?e.needsMipmap=!0:!0===r.generateMipmaps&&this.textures.needsMipmaps(r)&&!0===e.needsMipmap&&(this.backend.generateMipmaps(r),e.needsMipmap=!1)}}}!0===i&&this.backend.updateBindings(e,t)}}class cS{constructor(e,t,s=null){this.isNodeAttribute=!0,this.name=e,this.type=t,this.node=s}}class dS{constructor(e,t,s){this.isNodeUniform=!0,this.name=e,this.type=t,this.node=s.getSelf()}get value(){return this.node.value}set value(e){this.node.value=e}get id(){return this.node.id}get groupNode(){return this.node.groupNode}}class pS{constructor(e,t){this.isNodeVar=!0,this.name=e,this.type=t}}class mS extends pS{constructor(e,t){super(e,t),this.needsInterpolation=!1,this.isNodeVarying=!0}}class gS{constructor(e,t,s=""){this.name=e,this.type=t,this.code=s,Object.defineProperty(this,"isNodeCode",{value:!0})}}let fS=0;class yS{constructor(e=null){this.id=fS++,this.nodesData=new WeakMap,this.parent=e}getData(e){let t=this.nodesData.get(e);return void 0===t&&null!==this.parent&&(t=this.parent.getData(e)),t}setData(e,t){this.nodesData.set(e,t)}}class xS extends mm{static get type(){return"ParameterNode"}constructor(e,t=null){super(e,t),this.isParameterNode=!0}getHash(){return this.uuid}generate(){return this.name}}const bS=(e,t)=>Sp(new xS(e,t));class vS extends Ld{static get type(){return"CodeNode"}constructor(e="",t=[],s=""){super("code"),this.isCodeNode=!0,this.code=e,this.language=s,this.includes=t}isGlobal(){return!0}setIncludes(e){return this.includes=e,this}getIncludes(){return this.includes}generate(e){const t=this.getIncludes(e);for(const s of t)s.build(e);const s=e.getCodeFromNode(this,this.getNodeType(e));return s.code=this.code,s.code}serialize(e){super.serialize(e),e.code=this.code,e.language=this.language}deserialize(e){super.deserialize(e),this.code=e.code,this.language=e.language}}const TS=Ap(vS),_S=(e,t)=>TS(e,t,"js"),wS=(e,t)=>TS(e,t,"wgsl"),SS=(e,t)=>TS(e,t,"glsl");class MS extends vS{static get type(){return"FunctionNode"}constructor(e="",t=[],s=""){super(e,t,s)}getNodeType(e){return this.getNodeFunction(e).type}getInputs(e){return this.getNodeFunction(e).inputs}getNodeFunction(e){const t=e.getDataFromNode(this);let s=t.nodeFunction;return void 0===s&&(s=e.parser.parseFunction(this.code),t.nodeFunction=s),s}generate(e,t){super.generate(e);const s=this.getNodeFunction(e),i=s.name,r=s.type,n=e.getCodeFromNode(this,r);""!==i&&(n.name=i);const o=e.getPropertyName(n),a=this.getNodeFunction(e).getCode(o);return n.code=a+"\n","property"===t?o:e.format(`${o}()`,r,t)}}const NS=(e,t=[],s="")=>{for(let e=0;ei.call(...e);return r.functionNode=i,r},AS=(e,t)=>NS(e,t,"glsl"),CS=(e,t)=>NS(e,t,"wgsl");class RS{constructor(e,t){this.name=e,this.value=t,this.boundary=0,this.itemSize=0,this.offset=0}setValue(e){this.value=e}getValue(){return this.value}}class ES extends RS{constructor(e,t=0){super(e,t),this.isNumberUniform=!0,this.boundary=4,this.itemSize=1}}class BS extends RS{constructor(e,t=new Qs){super(e,t),this.isVector2Uniform=!0,this.boundary=8,this.itemSize=2}}class IS extends RS{constructor(e,t=new Ri){super(e,t),this.isVector3Uniform=!0,this.boundary=16,this.itemSize=3}}class PS extends RS{constructor(e,t=new Ti){super(e,t),this.isVector4Uniform=!0,this.boundary=16,this.itemSize=4}}class FS extends RS{constructor(e,t=new Jr){super(e,t),this.isColorUniform=!0,this.boundary=16,this.itemSize=3}}class zS extends RS{constructor(e,t=new ei){super(e,t),this.isMatrix3Uniform=!0,this.boundary=48,this.itemSize=12}}class US extends RS{constructor(e,t=new nr){super(e,t),this.isMatrix4Uniform=!0,this.boundary=64,this.itemSize=16}}class OS extends ES{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class LS extends BS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class VS extends IS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class DS extends PS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class kS extends FS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class GS extends zS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class WS extends US{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class jS extends Ld{static get type(){return"StackNode"}constructor(e=null){super(),this.nodes=[],this.outputNode=null,this.parent=e,this._currentCond=null,this.isStackNode=!0}getNodeType(e){return this.outputNode?this.outputNode.getNodeType(e):"void"}add(e){return this.nodes.push(e),this}If(e,t){const s=new wp(t);return this._currentCond=Bf(e,s),this.add(this._currentCond)}ElseIf(e,t){const s=new wp(t),i=Bf(e,s);return this._currentCond.elseNode=i,this._currentCond=i,this}Else(e){return this._currentCond.elseNode=new wp(e),this}build(e,...t){const s=Ip();Bp(this);for(const t of this.nodes)t.build(e,"void");return Bp(s),this.outputNode?this.outputNode.build(e,...t):super.build(e,...t)}else(...e){return console.warn("TSL.StackNode: .else() has been renamed to .Else()."),this.Else(...e)}elseif(...e){return console.warn("TSL.StackNode: .elseif() has been renamed to .ElseIf()."),this.ElseIf(...e)}}const HS=Ap(jS),qS=[.125,.215,.35,.446,.526,.582],$S=20,XS=new Sl(-1,1,1,-1,0,1),YS=new Xn(90,1),ZS=new Jr;let JS=null,KS=0,QS=0;const eM=(1+Math.sqrt(5))/2,tM=1/eM,sM=[new Ri(-eM,tM,0),new Ri(eM,tM,0),new Ri(-tM,0,eM),new Ri(tM,0,eM),new Ri(0,eM,-tM),new Ri(0,eM,tM),new Ri(-1,1,-1),new Ri(1,1,-1),new Ri(-1,1,1),new Ri(1,1,1)],iM=[3,1,5,0,4,2],rM=Q_(My(),Sy("faceIndex")).normalize(),nM=jp(rM.x,rM.y.negate(),rM.z);class oM{constructor(e){this._renderer=e,this._pingPongRenderTarget=null,this._lodMax=0,this._cubeSize=0,this._lodPlanes=[],this._sizeLods=[],this._sigmas=[],this._lodMeshes=[],this._blurMaterial=null,this._cubemapMaterial=null,this._equirectMaterial=null,this._backgroundBox=null}fromScene(e,t=0,s=.1,i=100){JS=this._renderer.getRenderTarget(),KS=this._renderer.getActiveCubeFace(),QS=this._renderer.getActiveMipmapLevel(),this._setSize(256);const r=this._allocateTargets();return r.depthBuffer=!0,this._sceneToCubeUV(e,s,i,r),t>0&&this._blur(r,0,0,t),this._applyPMREM(r),this._cleanup(r),r}fromEquirectangular(e,t=null){return this._fromTexture(e,t)}fromCubemap(e,t=null){return this._fromTexture(e,t)}async compileCubemapShader(){null===this._cubemapMaterial&&(this._cubemapMaterial=lM(),await this._compileMaterial(this._cubemapMaterial))}async compileEquirectangularShader(){null===this._equirectMaterial&&(this._equirectMaterial=cM(),await this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),null!==this._cubemapMaterial&&this._cubemapMaterial.dispose(),null!==this._equirectMaterial&&this._equirectMaterial.dispose(),null!==this._backgroundBox&&(this._backgroundBox.geometry.dispose(),this._backgroundBox.material.dispose())}_setSize(e){this._lodMax=Math.floor(Math.log2(e)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){null!==this._blurMaterial&&this._blurMaterial.dispose(),null!==this._pingPongRenderTarget&&this._pingPongRenderTarget.dispose();for(let e=0;ee-4?h=qS[a-e+4-1]:0===a&&(h=0),i.push(h);const u=1/(o-2),l=-u,c=1+u,d=[l,l,c,l,c,c,l,l,c,c,l,c],p=6,m=6,g=3,f=2,y=1,x=new Float32Array(g*m*p),b=new Float32Array(f*m*p),v=new Float32Array(y*m*p);for(let e=0;e2?0:-1,i=[t,s,0,t+2/3,s,0,t+2/3,s+1,0,t,s,0,t+2/3,s+1,0,t,s+1,0],r=iM[e];x.set(i,g*m*r),b.set(d,f*m*r);const n=[r,r,r,r,r,r];v.set(n,y*m*r)}const T=new An;T.setAttribute("position",new ln(x,g)),T.setAttribute("uv",new ln(b,f)),T.setAttribute("faceIndex",new ln(v,y)),t.push(T),r.push(new Vn(T,null)),n>4&&n--}return{lodPlanes:t,sizeLods:s,sigmas:i,lodMeshes:r}}(i)),this._blurMaterial=function(e,t,s){const i=Ox(new Array($S).fill(0)),r=pm(new Ri(0,1,0)),n=pm(0),o=Up($S),a=pm(0),h=pm(1),u=By(null),l=pm(0),c=Up(1/t),d=Up(1/s),p=Up(e),m={n:o,latitudinal:a,weights:i,poleAxis:r,outputDirection:nM,dTheta:n,samples:h,envMap:u,mipInt:l,CUBEUV_TEXEL_WIDTH:c,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:p},g=uM("blur");return g.uniforms=m,g.fragmentNode=iw({...m,latitudinal:a.equal(1)}),g}(i,e,t)}return i}async _compileMaterial(e){const t=new Vn(this._lodPlanes[0],e);await this._renderer.compile(t,XS)}_sceneToCubeUV(e,t,s,i){const r=YS;r.near=t,r.far=s;const n=[-1,1,-1,-1,-1,-1],o=[1,1,1,-1,-1,-1],a=this._renderer,h=a.autoClear;a.getClearColor(ZS),a.autoClear=!1;let u=this._backgroundBox;if(null===u){const e=new tn({name:"PMREM.Background",side:d,depthWrite:!1,depthTest:!1});u=new Vn(new kn,e)}let l=!1;const c=e.background;c?c.isColor&&(u.material.color.copy(c),e.background=null,l=!0):(u.material.color.copy(ZS),l=!0),a.setRenderTarget(i),a.clear(),l&&a.render(u,r);for(let t=0;t<6;t++){const s=t%3;0===s?(r.up.set(0,n[t],0),r.lookAt(o[t],0,0)):1===s?(r.up.set(0,0,n[t]),r.lookAt(0,o[t],0)):(r.up.set(0,n[t],0),r.lookAt(0,0,o[t]));const h=this._cubeSize;hM(i,s*h,t>2?h:0,h,h),a.render(e,r)}a.autoClear=h,e.background=c}_textureToCubeUV(e,t){const s=this._renderer,i=e.mapping===he||e.mapping===ue;i?null===this._cubemapMaterial&&(this._cubemapMaterial=lM(e)):null===this._equirectMaterial&&(this._equirectMaterial=cM(e));const r=i?this._cubemapMaterial:this._equirectMaterial;r.fragmentNode.value=e;const n=this._lodMeshes[0];n.material=r;const o=this._cubeSize;hM(t,0,0,3*o,2*o),s.setRenderTarget(t),s.render(n,XS)}_applyPMREM(e){const t=this._renderer,s=t.autoClear;t.autoClear=!1;const i=this._lodPlanes.length;for(let t=1;t$S&&console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${m} samples when the maximum is set to 20`);const g=[];let f=0;for(let e=0;e<$S;++e){const t=e/p,s=Math.exp(-t*t/2);g.push(s),0===e?f+=s:ey-4?i-y+4:0),4*(this._cubeSize-x),3*x,2*x),a.setRenderTarget(t),a.render(u,XS)}}function aM(e,t,s){const i=new _i(e,t,s);return i.texture.mapping=de,i.texture.name="PMREM.cubeUv",i.texture.isPMREMTexture=!0,i.scissorTest=!0,i}function hM(e,t,s,i,r){e.viewport.set(t,s,i,r),e.scissor.set(t,s,i,r)}function uM(e){const t=new pT;return t.depthTest=!1,t.depthWrite=!1,t.blending=m,t.name=`PMREM_${e}`,t}function lM(e){const t=uM("cubemap");return t.fragmentNode=Ix(e,nM),t}function cM(e){const t=uM("equirect");return t.fragmentNode=By(e,AT(nM),0),t}let dM=0;class pM{constructor(e="",t=[],s=0,i=[]){this.name=e,this.bindings=t,this.index=s,this.bindingsReference=i,this.id=dM++}}const mM=new WeakMap,gM=new Map([[2,"vec2"],[3,"vec3"],[4,"vec4"],[9,"mat3"],[16,"mat4"]]),fM=new Map([[Int8Array,"int"],[Int16Array,"int"],[Int32Array,"int"],[Uint8Array,"uint"],[Uint16Array,"uint"],[Uint32Array,"uint"],[Float32Array,"float"]]),yM=e=>(e=Number(e))+(e%1?"":".0");class xM{constructor(e,t,s){this.object=e,this.material=e&&e.material||null,this.geometry=e&&e.geometry||null,this.renderer=t,this.parser=s,this.scene=null,this.camera=null,this.nodes=[],this.updateNodes=[],this.updateBeforeNodes=[],this.updateAfterNodes=[],this.hashNodes={},this.monitor=null,this.lightsNode=null,this.environmentNode=null,this.fogNode=null,this.clippingContext=null,this.vertexShader=null,this.fragmentShader=null,this.computeShader=null,this.flowNodes={vertex:[],fragment:[],compute:[]},this.flowCode={vertex:"",fragment:"",compute:""},this.uniforms={vertex:[],fragment:[],compute:[],index:0},this.structs={vertex:[],fragment:[],compute:[],index:0},this.bindings={vertex:{},fragment:{},compute:{}},this.bindingsIndexes={},this.bindGroups=null,this.attributes=[],this.bufferAttributes=[],this.varyings=[],this.codes={},this.vars={},this.flow={code:""},this.chaining=[],this.stack=HS(),this.stacks=[],this.tab="\t",this.currentFunctionNode=null,this.context={material:this.material},this.cache=new yS,this.globalCache=this.cache,this.flowsData=new WeakMap,this.shaderStage=null,this.buildStage=null,this.useComparisonMethod=!1}getBindGroupsCache(){let e=mM.get(this.renderer);return void 0===e&&(e=new kw,mM.set(this.renderer,e)),e}createRenderTarget(e,t,s){return new _i(e,t,s)}createCubeRenderTarget(e,t){return new CT(e,t)}createPMREMGenerator(){return new oM(this.renderer)}includes(e){return this.nodes.includes(e)}_getBindGroup(e,t){const s=this.getBindGroupsCache(),i=[];let r,n=!0;for(const e of t)i.push(e),n=n&&!0!==e.groupNode.shared;return n?(r=s.get(i),void 0===r&&(r=new pM(e,i,this.bindingsIndexes[e].group,i),s.set(i,r))):r=new pM(e,i,this.bindingsIndexes[e].group,i),r}getBindGroupArray(e,t){const s=this.bindings[t];let i=s[e];return void 0===i&&(void 0===this.bindingsIndexes[e]&&(this.bindingsIndexes[e]={binding:0,group:Object.keys(this.bindingsIndexes).length}),s[e]=i=[]),i}getBindings(){let e=this.bindGroups;if(null===e){const t={},s=this.bindings;for(const e of zd)for(const i in s[e]){const r=s[e][i];(t[i]||(t[i]=[])).push(...r)}e=[];for(const s in t){const i=t[s],r=this._getBindGroup(s,i);e.push(r)}this.bindGroups=e}return e}sortBindingGroups(){const e=this.getBindings();e.sort(((e,t)=>e.bindings[0].groupNode.order-t.bindings[0].groupNode.order));for(let t=0;t=0?`${Math.round(t)}u`:"0u";if("bool"===e)return t?"true":"false";if("color"===e)return`${this.getType("vec3")}( ${yM(t.r)}, ${yM(t.g)}, ${yM(t.b)} )`;const s=this.getTypeLength(e),i=this.getComponentType(e),r=e=>this.generateConst(i,e);if(2===s)return`${this.getType(e)}( ${r(t.x)}, ${r(t.y)} )`;if(3===s)return`${this.getType(e)}( ${r(t.x)}, ${r(t.y)}, ${r(t.z)} )`;if(4===s)return`${this.getType(e)}( ${r(t.x)}, ${r(t.y)}, ${r(t.z)}, ${r(t.w)} )`;if(s>4&&t&&(t.isMatrix3||t.isMatrix4))return`${this.getType(e)}( ${t.elements.map(r).join(", ")} )`;if(s>4)return`${this.getType(e)}()`;throw new Error(`NodeBuilder: Type '${e}' not found in generate constant attempt.`)}getType(e){return"color"===e?"vec3":e}hasGeometryAttribute(e){return this.geometry&&void 0!==this.geometry.getAttribute(e)}getAttribute(e,t){const s=this.attributes;for(const t of s)if(t.name===e)return t;const i=new cS(e,t);return s.push(i),i}getPropertyName(e){return e.name}isVector(e){return/vec\d/.test(e)}isMatrix(e){return/mat\d/.test(e)}isReference(e){return"void"===e||"property"===e||"sampler"===e||"texture"===e||"cubeTexture"===e||"storageTexture"===e||"depthTexture"===e||"texture3D"===e}needsToWorkingColorSpace(){return!1}getComponentTypeFromTexture(e){const t=e.type;if(e.isDataTexture){if(t===Ee)return"int";if(t===Be)return"uint"}return"float"}getElementType(e){return"mat2"===e?"vec2":"mat3"===e?"vec3":"mat4"===e?"vec4":this.getComponentType(e)}getComponentType(e){if("float"===(e=this.getVectorType(e))||"bool"===e||"int"===e||"uint"===e)return e;const t=/(b|i|u|)(vec|mat)([2-4])/.exec(e);return null===t?null:"b"===t[1]?"bool":"i"===t[1]?"int":"u"===t[1]?"uint":"float"}getVectorType(e){return"color"===e?"vec3":"texture"===e||"cubeTexture"===e||"storageTexture"===e||"texture3D"===e?"vec4":e}getTypeFromLength(e,t="float"){if(1===e)return t;const s=gM.get(e);return("float"===t?"":t[0])+s}getTypeFromArray(e){return fM.get(e.constructor)}getTypeFromAttribute(e){let t=e;e.isInterleavedBufferAttribute&&(t=e.data);const s=t.array,i=e.itemSize,r=e.normalized;let n;return e instanceof xn||!0===r||(n=this.getTypeFromArray(s)),this.getTypeFromLength(i,n)}getTypeLength(e){const t=this.getVectorType(e),s=/vec([2-4])/.exec(t);return null!==s?Number(s[1]):"float"===t||"bool"===t||"int"===t||"uint"===t?1:!0===/mat2/.test(e)?4:!0===/mat3/.test(e)?9:!0===/mat4/.test(e)?16:0}getVectorFromMatrix(e){return e.replace("mat","vec")}changeComponentType(e,t){return this.getTypeFromLength(this.getTypeLength(e),t)}getIntegerType(e){const t=this.getComponentType(e);return"int"===t||"uint"===t?e:this.changeComponentType(e,"int")}addStack(){return this.stack=HS(this.stack),this.stacks.push(Ip()||this.stack),Bp(this.stack),this.stack}removeStack(){const e=this.stack;return this.stack=e.parent,Bp(this.stacks.pop()),e}getDataFromNode(e,t=this.shaderStage,s=null){let i=(s=null===s?e.isGlobal(this)?this.globalCache:this.cache:s).getData(e);return void 0===i&&(i={},s.setData(e,i)),void 0===i[t]&&(i[t]={}),i[t]}getNodeProperties(e,t="any"){const s=this.getDataFromNode(e,t);return s.properties||(s.properties={outputNode:null})}getBufferAttributeFromNode(e,t){const s=this.getDataFromNode(e);let i=s.bufferAttribute;if(void 0===i){const r=this.uniforms.index++;i=new cS("nodeAttribute"+r,t,e),this.bufferAttributes.push(i),s.bufferAttribute=i}return i}getStructTypeFromNode(e,t=this.shaderStage){const s=this.getDataFromNode(e,t);if(void 0===s.structType){const i=this.structs.index++;e.name=`StructType${i}`,this.structs[t].push(e),s.structType=e}return e}getUniformFromNode(e,t,s=this.shaderStage,i=null){const r=this.getDataFromNode(e,s,this.globalCache);let n=r.uniform;if(void 0===n){const o=this.uniforms.index++;n=new dS(i||"nodeUniform"+o,t,e),this.uniforms[s].push(n),r.uniform=n}return n}getVarFromNode(e,t=null,s=e.getNodeType(this),i=this.shaderStage){const r=this.getDataFromNode(e,i);let n=r.variable;if(void 0===n){const e=this.vars[i]||(this.vars[i]=[]);null===t&&(t="nodeVar"+e.length),n=new pS(t,s),e.push(n),r.variable=n}return n}getVaryingFromNode(e,t=null,s=e.getNodeType(this)){const i=this.getDataFromNode(e,"any");let r=i.varying;if(void 0===r){const e=this.varyings,n=e.length;null===t&&(t="nodeVarying"+n),r=new mS(t,s),e.push(r),i.varying=r}return r}getCodeFromNode(e,t,s=this.shaderStage){const i=this.getDataFromNode(e);let r=i.code;if(void 0===r){const e=this.codes[s]||(this.codes[s]=[]),n=e.length;r=new gS("nodeCode"+n,t),e.push(r),i.code=r}return r}addFlowCodeHierarchy(e,t){const{flowCodes:s,flowCodeBlock:i}=this.getDataFromNode(e);let r=!0,n=t;for(;n;){if(!0===i.get(n)){r=!1;break}n=this.getDataFromNode(n).parentNodeBlock}if(r)for(const e of s)this.addLineFlowCode(e)}addLineFlowCodeBlock(e,t,s){const i=this.getDataFromNode(e),r=i.flowCodes||(i.flowCodes=[]),n=i.flowCodeBlock||(i.flowCodeBlock=new WeakMap);r.push(t),n.set(s,!0)}addLineFlowCode(e,t=null){return""===e||(null!==t&&this.context.nodeBlock&&this.addLineFlowCodeBlock(t,e,this.context.nodeBlock),e=this.tab+e,/;\s*$/.test(e)||(e+=";\n"),this.flow.code+=e),this}addFlowCode(e){return this.flow.code+=e,this}addFlowTab(){return this.tab+="\t",this}removeFlowTab(){return this.tab=this.tab.slice(0,-1),this}getFlowData(e){return this.flowsData.get(e)}flowNode(e){const t=e.getNodeType(this),s=this.flowChildNode(e,t);return this.flowsData.set(e,s),s}buildFunctionNode(e){const t=new MS,s=this.currentFunctionNode;return this.currentFunctionNode=t,t.code=this.buildFunctionCode(e),this.currentFunctionNode=s,t}flowShaderNode(e){const t=e.layout,s={[Symbol.iterator](){let e=0;const t=Object.values(this);return{next:()=>({value:t[e],done:e++>=t.length})}}};for(const e of t.inputs)s[e.name]=new xS(e.type,e.name);e.layout=null;const i=e.call(s),r=this.flowStagesNode(i,t.type);return e.layout=t,r}flowStagesNode(e,t=null){const s=this.flow,i=this.vars,r=this.cache,n=this.buildStage,o=this.stack,a={code:""};this.flow=a,this.vars={},this.cache=new yS,this.stack=HS();for(const s of Fd)this.setBuildStage(s),a.result=e.build(this,t);return a.vars=this.getVars(this.shaderStage),this.flow=s,this.vars=i,this.cache=r,this.stack=o,this.setBuildStage(n),a}getFunctionOperator(){return null}flowChildNode(e,t=null){const s=this.flow,i={code:""};return this.flow=i,i.result=e.build(this,t),this.flow=s,i}flowNodeFromShaderStage(e,t,s=null,i=null){const r=this.shaderStage;this.setShaderStage(e);const n=this.flowChildNode(t,s);return null!==i&&(n.code+=`${this.tab+i} = ${n.result};\n`),this.flowCode[e]=this.flowCode[e]+n.code,this.setShaderStage(r),n}getAttributesArray(){return this.attributes.concat(this.bufferAttributes)}getAttributes(){console.warn("Abstract function.")}getVaryings(){console.warn("Abstract function.")}getVar(e,t){return`${this.getType(e)} ${t}`}getVars(e){let t="";const s=this.vars[e];if(void 0!==s)for(const e of s)t+=`${this.getVar(e.type,e.name)}; `;return t}getUniforms(){console.warn("Abstract function.")}getCodes(e){const t=this.codes[e];let s="";if(void 0!==t)for(const e of t)s+=e.code+"\n";return s}getHash(){return this.vertexShader+this.fragmentShader+this.computeShader}setShaderStage(e){this.shaderStage=e}getShaderStage(){return this.shaderStage}setBuildStage(e){this.buildStage=e}getBuildStage(){return this.buildStage}buildCode(){console.warn("Abstract function.")}build(){const{object:e,material:t,renderer:s}=this;if(null!==t){let e=s.nodes.library.fromMaterial(t);null===e&&(console.error(`NodeMaterial: Material "${t.type}" is not compatible.`),e=new pT),e.build(this)}else this.addFlow("compute",e);for(const e of Fd){this.setBuildStage(e),this.context.vertex&&this.context.vertex.isNode&&this.flowNodeFromShaderStage("vertex",this.context.vertex);for(const t of zd){this.setShaderStage(t);const s=this.flowNodes[t];for(const t of s)"generate"===e?this.flowNode(t):t.build(this)}}return this.setBuildStage(null),this.setShaderStage(null),this.buildCode(),this.buildUpdateNodes(),this}getNodeUniform(e,t){if("float"===t||"int"===t||"uint"===t)return new OS(e);if("vec2"===t||"ivec2"===t||"uvec2"===t)return new LS(e);if("vec3"===t||"ivec3"===t||"uvec3"===t)return new VS(e);if("vec4"===t||"ivec4"===t||"uvec4"===t)return new DS(e);if("color"===t)return new kS(e);if("mat3"===t)return new GS(e);if("mat4"===t)return new WS(e);throw new Error(`Uniform "${t}" not declared.`)}createNodeMaterial(e="NodeMaterial"){throw new Error(`THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${e}() instead.`)}format(e,t,s){if((t=this.getVectorType(t))===(s=this.getVectorType(s))||null===s||this.isReference(s))return e;const i=this.getTypeLength(t),r=this.getTypeLength(s);return 16===i&&9===r?`${this.getType(s)}(${e}[0].xyz, ${e}[1].xyz, ${e}[2].xyz)`:9===i&&4===r?`${this.getType(s)}(${e}[0].xy, ${e}[1].xy)`:i>4||r>4||0===r?e:i===r?`${this.getType(s)}( ${e} )`:i>r?this.format(`${e}.${"xyz".slice(0,r)}`,this.getTypeFromLength(r,this.getComponentType(t)),s):4===r&&i>1?`${this.getType(s)}( ${this.format(e,t,"vec3")}, 1.0 )`:2===i?`${this.getType(s)}( ${this.format(e,t,"vec2")}, 0.0 )`:(1===i&&r>1&&t!==this.getComponentType(s)&&(e=`${this.getType(this.getComponentType(s))}( ${e} )`),`${this.getType(s)}( ${e} )`)}getSignature(){return`// Three.js r${e} - Node System\n`}}class bM{constructor(){this.time=0,this.deltaTime=0,this.frameId=0,this.renderId=0,this.startTime=null,this.updateMap=new WeakMap,this.updateBeforeMap=new WeakMap,this.updateAfterMap=new WeakMap,this.renderer=null,this.material=null,this.camera=null,this.object=null,this.scene=null}_getMaps(e,t){let s=e.get(t);return void 0===s&&(s={renderMap:new WeakMap,frameMap:new WeakMap},e.set(t,s)),s}updateBeforeNode(e){const t=e.getUpdateBeforeType(),s=e.updateReference(this);if(t===Bd.FRAME){const{frameMap:t}=this._getMaps(this.updateBeforeMap,s);t.get(s)!==this.frameId&&!1!==e.updateBefore(this)&&t.set(s,this.frameId)}else if(t===Bd.RENDER){const{renderMap:t}=this._getMaps(this.updateBeforeMap,s);t.get(s)!==this.renderId&&!1!==e.updateBefore(this)&&t.set(s,this.renderId)}else t===Bd.OBJECT&&e.updateBefore(this)}updateAfterNode(e){const t=e.getUpdateAfterType(),s=e.updateReference(this);if(t===Bd.FRAME){const{frameMap:t}=this._getMaps(this.updateAfterMap,s);t.get(s)!==this.frameId&&!1!==e.updateAfter(this)&&t.set(s,this.frameId)}else if(t===Bd.RENDER){const{renderMap:t}=this._getMaps(this.updateAfterMap,s);t.get(s)!==this.renderId&&!1!==e.updateAfter(this)&&t.set(s,this.renderId)}else t===Bd.OBJECT&&e.updateAfter(this)}updateNode(e){const t=e.getUpdateType(),s=e.updateReference(this);if(t===Bd.FRAME){const{frameMap:t}=this._getMaps(this.updateMap,s);t.get(s)!==this.frameId&&!1!==e.update(this)&&t.set(s,this.frameId)}else if(t===Bd.RENDER){const{renderMap:t}=this._getMaps(this.updateMap,s);t.get(s)!==this.renderId&&!1!==e.update(this)&&t.set(s,this.renderId)}else t===Bd.OBJECT&&e.update(this)}update(){this.frameId++,void 0===this.lastTime&&(this.lastTime=performance.now()),this.deltaTime=(performance.now()-this.lastTime)/1e3,this.lastTime=performance.now(),this.time+=this.deltaTime}}class vM{constructor(e,t,s=null,i="",r=!1){this.type=e,this.name=t,this.count=s,this.qualifier=i,this.isConst=r}}vM.isNodeFunctionInput=!0;class TM extends Ld{static get type(){return"StructTypeNode"}constructor(e){super(),this.types=e,this.isStructTypeNode=!0}getMemberTypes(){return this.types}}class _M extends Ld{static get type(){return"OutputStructNode"}constructor(...e){super(),this.members=e,this.isOutputStructNode=!0}setup(e){super.setup(e);const t=this.members,s=[];for(let i=0;ir&&(i=s,r=n)}}this._candidateFnCall=s=i(...t)}return s}}const CM=Ap(AM),RM=e=>(...t)=>CM(e,...t);class EM extends dm{static get type(){return"TimerNode"}constructor(e=EM.LOCAL,t=1,s=0){super(s),this.scope=e,this.scale=t,this.updateType=Bd.FRAME}update(e){const t=this.scope,s=this.scale;t===EM.LOCAL?this.value+=e.deltaTime*s:t===EM.DELTA?this.value=e.deltaTime*s:t===EM.FRAME?this.value=e.frameId:this.value=e.time*s}serialize(e){super.serialize(e),e.scope=this.scope,e.scale=this.scale}deserialize(e){super.deserialize(e),this.scope=e.scope,this.scale=e.scale}}EM.LOCAL="local",EM.GLOBAL="global",EM.DELTA="delta",EM.FRAME="frame";const BM=(e,t=0)=>Sp(new EM(EM.LOCAL,e,t)),IM=(e,t=0)=>Sp(new EM(EM.GLOBAL,e,t)),PM=(e,t=0)=>Sp(new EM(EM.DELTA,e,t)),FM=Cp(EM,EM.FRAME).toUint();class zM extends Ld{static get type(){return"OscNode"}constructor(e=zM.SINE,t=BM()){super(),this.method=e,this.timeNode=t}getNodeType(e){return this.timeNode.getNodeType(e)}setup(){const e=this.method,t=Sp(this.timeNode);let s=null;return e===zM.SINE?s=t.add(.75).mul(2*Math.PI).sin().mul(.5).add(.5):e===zM.SQUARE?s=t.fract().round():e===zM.TRIANGLE?s=t.add(.5).fract().mul(2).sub(1).abs():e===zM.SAWTOOTH&&(s=t.fract()),s}serialize(e){super.serialize(e),e.method=this.method}deserialize(e){super.deserialize(e),this.method=e.method}}zM.SINE="sine",zM.SQUARE="square",zM.TRIANGLE="triangle",zM.SAWTOOTH="sawtooth";const UM=Ap(zM,zM.SINE),OM=Ap(zM,zM.SQUARE),LM=Ap(zM,zM.TRIANGLE),VM=Ap(zM,zM.SAWTOOTH);class DM extends Ld{static get type(){return"SpriteSheetUVNode"}constructor(e,t=My(),s=Up(0)){super("vec2"),this.countNode=e,this.uvNode=t,this.frameNode=s}setup(){const{frameNode:e,uvNode:t,countNode:s}=this,{width:i,height:r}=s,n=e.mod(i.mul(r)).floor(),o=n.mod(i),a=r.sub(n.add(1).div(i).ceil()),h=s.reciprocal(),u=Dp(o,a);return t.add(u).mul(h)}}const kM=Ap(DM);class GM extends Vd{static get type(){return"StorageArrayElementNode"}constructor(e,t){super(e,t),this.isStorageArrayElementNode=!0}set storageBufferNode(e){this.node=e}get storageBufferNode(){return this.node}setup(e){return!1===e.isAvailable("storageBuffer")&&!0===this.node.bufferObject&&e.setupPBO(this.node),super.setup(e)}generate(e,t){let s;const i=e.context.assign;if(s=!1===e.isAvailable("storageBuffer")?!0===this.node.bufferObject&&!0!==i?e.generatePBO(this):this.node.build(e):super.generate(e),!0!==i){const i=this.getNodeType(e);s=e.format(s,i,t)}return s}}const WM=Ap(GM);class jM extends Ld{static get type(){return"TriplanarTexturesNode"}constructor(e,t=null,s=null,i=Up(1),r=ax,n=yx){super("vec4"),this.textureXNode=e,this.textureYNode=t,this.textureZNode=s,this.scaleNode=i,this.positionNode=r,this.normalNode=n}setup(){const{textureXNode:e,textureYNode:t,textureZNode:s,scaleNode:i,positionNode:r,normalNode:n}=this;let o=n.abs().normalize();o=o.div(o.dot(jp(1)));const a=r.yz.mul(i),h=r.zx.mul(i),u=r.xy.mul(i),l=e.value,c=null!==t?t.value:l,d=null!==s?s.value:l,p=By(l,a).mul(o.x),m=By(c,h).mul(o.y),g=By(d,u).mul(o.z);return Zm(p,m,g)}}const HM=Ap(jM),qM=(...e)=>HM(...e),$M=new Ko,XM=new Ri,YM=new Ri,ZM=new Ri,JM=new nr,KM=new Ri(0,0,-1),QM=new Ti,eN=new Ri,tN=new Ri,sN=new Ti,iN=new Qs,rN=new _i,nN=Dv.flipX();let oN=!1;class aN extends Ey{static get type(){return"ReflectorNode"}constructor(e={}){super(rN.texture,nN);const{target:t=new Ir,resolution:s=1,generateMipmaps:i=!1,bounces:r=!0}=e;this.target=t,this.resolution=s,this.generateMipmaps=i,this.bounces=r,this.updateBeforeType=r?Bd.RENDER:Bd.FRAME,this.virtualCameras=new WeakMap,this.renderTargets=new WeakMap}_updateResolution(e,t){const s=this.resolution;t.getDrawingBufferSize(iN),e.setSize(Math.round(iN.width*s),Math.round(iN.height*s))}setup(e){return this._updateResolution(rN,e.renderer),super.setup(e)}getTextureNode(){return this.textureNode}getVirtualCamera(e){let t=this.virtualCameras.get(e);return void 0===t&&(t=e.clone(),this.virtualCameras.set(e,t)),t}getRenderTarget(e){let t=this.renderTargets.get(e);return void 0===t&&(t=new _i(0,0,{type:Pe}),!0===this.generateMipmaps&&(t.texture.minFilter=1008,t.texture.generateMipmaps=!0),this.renderTargets.set(e,t)),t}updateBefore(e){if(!1===this.bounces&&oN)return!1;oN=!0;const{scene:t,camera:s,renderer:i,material:r}=e,{target:n}=this,o=this.getVirtualCamera(s),a=this.getRenderTarget(o);if(i.getDrawingBufferSize(iN),this._updateResolution(a,i),YM.setFromMatrixPosition(n.matrixWorld),ZM.setFromMatrixPosition(s.matrixWorld),JM.extractRotation(n.matrixWorld),XM.set(0,0,1),XM.applyMatrix4(JM),eN.subVectors(YM,ZM),eN.dot(XM)>0)return;eN.reflect(XM).negate(),eN.add(YM),JM.extractRotation(s.matrixWorld),KM.set(0,0,-1),KM.applyMatrix4(JM),KM.add(ZM),tN.subVectors(YM,KM),tN.reflect(XM).negate(),tN.add(YM),o.coordinateSystem=s.coordinateSystem,o.position.copy(eN),o.up.set(0,1,0),o.up.applyMatrix4(JM),o.up.reflect(XM),o.lookAt(tN),o.near=s.near,o.far=s.far,o.updateMatrixWorld(),o.projectionMatrix.copy(s.projectionMatrix),$M.setFromNormalAndCoplanarPoint(XM,YM),$M.applyMatrix4(o.matrixWorldInverse),QM.set($M.normal.x,$M.normal.y,$M.normal.z,$M.constant);const h=o.projectionMatrix;sN.x=(Math.sign(QM.x)+h.elements[8])/h.elements[0],sN.y=(Math.sign(QM.y)+h.elements[9])/h.elements[5],sN.z=-1,sN.w=(1+h.elements[10])/h.elements[14],QM.multiplyScalar(1/QM.dot(sN));h.elements[2]=QM.x,h.elements[6]=QM.y,h.elements[10]=QM.z-0,h.elements[14]=QM.w,this.value=a.texture,r.visible=!1;const u=i.getRenderTarget(),l=i.getMRT();i.setMRT(null),i.setRenderTarget(a),i.render(t,o),i.setMRT(l),i.setRenderTarget(u),r.visible=!0,oN=!1}}const hN=e=>Sp(new aN(e)),uN=new Sl(-1,1,1,-1,0,1);class lN extends An{constructor(e=!1){super();const t=!1===e?[0,-1,0,1,2,1]:[0,2,0,0,2,0];this.setAttribute("position",new bn([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new bn(t,2))}}const cN=new lN;class dN extends Vn{constructor(e=null){super(cN,e),this.camera=uN,this.isQuadMesh=!0}renderAsync(e){return e.renderAsync(this,uN)}render(e){e.render(this,uN)}}const pN=new Qs;class mN extends Ey{static get type(){return"RTTNode"}constructor(e,t=null,s=null,i={type:Pe}){const r=new _i(t,s,i);super(r.texture,My()),this.node=e,this.width=t,this.height=s,this.renderTarget=r,this.textureNeedsUpdate=!0,this.autoUpdate=!0,this.updateMap=new WeakMap,this._rttNode=null,this._quadMesh=new dN(new pT),this.updateBeforeType=Bd.RENDER}get autoSize(){return null===this.width}setup(e){return this._rttNode=this.node.context(e.getSharedContext()),this._quadMesh.material.name="RTT",this._quadMesh.material.needsUpdate=!0,super.setup(e)}setSize(e,t){this.width=e,this.height=t;const s=e*this.pixelRatio,i=t*this.pixelRatio;this.renderTarget.setSize(s,i),this.textureNeedsUpdate=!0}setPixelRatio(e){this.pixelRatio=e,this.setSize(this.width,this.height)}updateBefore({renderer:e}){if(!1===this.textureNeedsUpdate&&!1===this.autoUpdate)return;if(this.textureNeedsUpdate=!1,!0===this.autoSize){this.pixelRatio=e.getPixelRatio();const t=e.getSize(pN);this.setSize(t.width,t.height)}this._quadMesh.material.fragmentNode=this._rttNode;const t=e.getRenderTarget();e.setRenderTarget(this.renderTarget),this._quadMesh.render(e),e.setRenderTarget(t)}clone(){const e=new Ey(this.value,this.uvNode,this.levelNode);return e.sampler=this.sampler,e.referenceNode=this,e}}const gN=(e,...t)=>Sp(new mN(Sp(e),...t)),fN=(e,...t)=>e.isTextureNode?e:gN(e,...t);class yN extends wy{static get type(){return"VertexColorNode"}constructor(e=0){super(null,"vec4"),this.isVertexColorNode=!0,this.index=e}getAttributeName(){const e=this.index;return"color"+(e>0?e:"")}generate(e){const t=this.getAttributeName(e);let s;return s=!0===e.hasGeometryAttribute(t)?super.generate(e):e.generateConst(this.nodeType,new Ti(1,1,1,1)),s}serialize(e){super.serialize(e),e.index=this.index}deserialize(e){super.deserialize(e),this.index=e.index}}const xN=(...e)=>Sp(new yN(...e));class bN extends Ld{static get type(){return"PointUVNode"}constructor(){super("vec2"),this.isPointUVNode=!0}generate(){return"vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )"}}const vN=Cp(bN);class TN extends Ld{static get type(){return"SceneNode"}constructor(e=TN.BACKGROUND_BLURRINESS,t=null){super(),this.scope=e,this.scene=t}setup(e){const t=this.scope,s=null!==this.scene?this.scene:e.scene;let i;return t===TN.BACKGROUND_BLURRINESS?i=kx("backgroundBlurriness","float",s):t===TN.BACKGROUND_INTENSITY?i=kx("backgroundIntensity","float",s):console.error("THREE.SceneNode: Unknown scope:",t),i}}TN.BACKGROUND_BLURRINESS="backgroundBlurriness",TN.BACKGROUND_INTENSITY="backgroundIntensity";const _N=Cp(TN,TN.BACKGROUND_BLURRINESS),wN=Cp(TN,TN.BACKGROUND_INTENSITY),SN="point-list",MN="line-list",NN="line-strip",AN="triangle-list",CN="triangle-strip",RN="never",EN="less",BN="equal",IN="less-equal",PN="greater",FN="not-equal",zN="greater-equal",UN="always",ON="store",LN="load",VN="clear",DN="ccw",kN="none",GN="front",WN="back",jN="uint16",HN="uint32",qN={R8Unorm:"r8unorm",R8Snorm:"r8snorm",R8Uint:"r8uint",R8Sint:"r8sint",R16Uint:"r16uint",R16Sint:"r16sint",R16Float:"r16float",RG8Unorm:"rg8unorm",RG8Snorm:"rg8snorm",RG8Uint:"rg8uint",RG8Sint:"rg8sint",R32Uint:"r32uint",R32Sint:"r32sint",R32Float:"r32float",RG16Uint:"rg16uint",RG16Sint:"rg16sint",RG16Float:"rg16float",RGBA8Unorm:"rgba8unorm",RGBA8UnormSRGB:"rgba8unorm-srgb",RGBA8Snorm:"rgba8snorm",RGBA8Uint:"rgba8uint",RGBA8Sint:"rgba8sint",BGRA8Unorm:"bgra8unorm",BGRA8UnormSRGB:"bgra8unorm-srgb",RGB9E5UFloat:"rgb9e5ufloat",RGB10A2Unorm:"rgb10a2unorm",RG11B10uFloat:"rgb10a2unorm",RG32Uint:"rg32uint",RG32Sint:"rg32sint",RG32Float:"rg32float",RGBA16Uint:"rgba16uint",RGBA16Sint:"rgba16sint",RGBA16Float:"rgba16float",RGBA32Uint:"rgba32uint",RGBA32Sint:"rgba32sint",RGBA32Float:"rgba32float",Stencil8:"stencil8",Depth16Unorm:"depth16unorm",Depth24Plus:"depth24plus",Depth24PlusStencil8:"depth24plus-stencil8",Depth32Float:"depth32float",Depth32FloatStencil8:"depth32float-stencil8",BC1RGBAUnorm:"bc1-rgba-unorm",BC1RGBAUnormSRGB:"bc1-rgba-unorm-srgb",BC2RGBAUnorm:"bc2-rgba-unorm",BC2RGBAUnormSRGB:"bc2-rgba-unorm-srgb",BC3RGBAUnorm:"bc3-rgba-unorm",BC3RGBAUnormSRGB:"bc3-rgba-unorm-srgb",BC4RUnorm:"bc4-r-unorm",BC4RSnorm:"bc4-r-snorm",BC5RGUnorm:"bc5-rg-unorm",BC5RGSnorm:"bc5-rg-snorm",BC6HRGBUFloat:"bc6h-rgb-ufloat",BC6HRGBFloat:"bc6h-rgb-float",BC7RGBAUnorm:"bc7-rgba-unorm",BC7RGBAUnormSRGB:"bc7-rgba-srgb",ETC2RGB8Unorm:"etc2-rgb8unorm",ETC2RGB8UnormSRGB:"etc2-rgb8unorm-srgb",ETC2RGB8A1Unorm:"etc2-rgb8a1unorm",ETC2RGB8A1UnormSRGB:"etc2-rgb8a1unorm-srgb",ETC2RGBA8Unorm:"etc2-rgba8unorm",ETC2RGBA8UnormSRGB:"etc2-rgba8unorm-srgb",EACR11Unorm:"eac-r11unorm",EACR11Snorm:"eac-r11snorm",EACRG11Unorm:"eac-rg11unorm",EACRG11Snorm:"eac-rg11snorm",ASTC4x4Unorm:"astc-4x4-unorm",ASTC4x4UnormSRGB:"astc-4x4-unorm-srgb",ASTC5x4Unorm:"astc-5x4-unorm",ASTC5x4UnormSRGB:"astc-5x4-unorm-srgb",ASTC5x5Unorm:"astc-5x5-unorm",ASTC5x5UnormSRGB:"astc-5x5-unorm-srgb",ASTC6x5Unorm:"astc-6x5-unorm",ASTC6x5UnormSRGB:"astc-6x5-unorm-srgb",ASTC6x6Unorm:"astc-6x6-unorm",ASTC6x6UnormSRGB:"astc-6x6-unorm-srgb",ASTC8x5Unorm:"astc-8x5-unorm",ASTC8x5UnormSRGB:"astc-8x5-unorm-srgb",ASTC8x6Unorm:"astc-8x6-unorm",ASTC8x6UnormSRGB:"astc-8x6-unorm-srgb",ASTC8x8Unorm:"astc-8x8-unorm",ASTC8x8UnormSRGB:"astc-8x8-unorm-srgb",ASTC10x5Unorm:"astc-10x5-unorm",ASTC10x5UnormSRGB:"astc-10x5-unorm-srgb",ASTC10x6Unorm:"astc-10x6-unorm",ASTC10x6UnormSRGB:"astc-10x6-unorm-srgb",ASTC10x8Unorm:"astc-10x8-unorm",ASTC10x8UnormSRGB:"astc-10x8-unorm-srgb",ASTC10x10Unorm:"astc-10x10-unorm",ASTC10x10UnormSRGB:"astc-10x10-unorm-srgb",ASTC12x10Unorm:"astc-12x10-unorm",ASTC12x10UnormSRGB:"astc-12x10-unorm-srgb",ASTC12x12Unorm:"astc-12x12-unorm",ASTC12x12UnormSRGB:"astc-12x12-unorm-srgb"},$N="clamp-to-edge",XN="repeat",YN="mirror-repeat",ZN="linear",JN="nearest",KN="zero",QN="one",eA="src",tA="one-minus-src",sA="src-alpha",iA="one-minus-src-alpha",rA="dst",nA="one-minus-dst",oA="dst-alpha",aA="one-minus-dst-alpha",hA="src-alpha-saturated",uA="constant",lA="one-minus-constant",cA="add",dA="subtract",pA="reverse-subtract",mA="min",gA="max",fA=0,yA=15,xA="keep",bA="zero",vA="replace",TA="invert",_A="increment-clamp",wA="decrement-clamp",SA="increment-wrap",MA="decrement-wrap",NA="storage",AA="read-only-storage",CA="write-only",RA="read-only",EA="float",BA="unfilterable-float",IA="depth",PA="sint",FA="uint",zA="2d",UA="3d",OA="2d",LA="2d-array",VA="cube",DA="3d",kA="all",GA="vertex",WA="instance",jA={DepthClipControl:"depth-clip-control",Depth32FloatStencil8:"depth32float-stencil8",TextureCompressionBC:"texture-compression-bc",TextureCompressionETC2:"texture-compression-etc2",TextureCompressionASTC:"texture-compression-astc",TimestampQuery:"timestamp-query",IndirectFirstInstance:"indirect-first-instance",ShaderF16:"shader-f16",RG11B10UFloat:"rg11b10ufloat-renderable",BGRA8UNormStorage:"bgra8unorm-storage",Float32Filterable:"float32-filterable",ClipDistances:"clip-distances",DualSourceBlending:"dual-source-blending",Subgroups:"subgroups"};class HA extends Px{static get type(){return"StorageBufferNode"}constructor(e,t,s=0){super(e,t,s),this.isStorageBufferNode=!0,this.access=NA,this.isAtomic=!1,this.bufferObject=!1,this.bufferCount=s,this._attribute=null,this._varying=null,this.global=!0,!0!==e.isStorageBufferAttribute&&!0!==e.isStorageInstancedBufferAttribute&&(e.isInstancedBufferAttribute?e.isStorageInstancedBufferAttribute=!0:e.isStorageBufferAttribute=!0)}getHash(e){if(0===this.bufferCount){let t=e.globalCache.getData(this.value);return void 0===t&&(t={node:this},e.globalCache.setData(this.value,t)),t.node.uuid}return this.uuid}getInputType(){return"storageBuffer"}element(e){return WM(this,e)}setBufferObject(e){return this.bufferObject=e,this}setAccess(e){return this.access=e,this}toReadOnly(){return this.setAccess(AA)}setAtomic(e){return this.isAtomic=e,this}toAtomic(){return this.setAtomic(!0)}generate(e){if(e.isAvailable("storageBuffer"))return super.generate(e);const t=this.getNodeType(e);null===this._attribute&&(this._attribute=iy(this.value),this._varying=Vf(this._attribute));const s=this._varying.build(e,t);return e.registerTransform(s,this._attribute),s}}const qA=(e,t,s)=>Sp(new HA(e,t,s)),$A=(e,t,s)=>Sp(new HA(e,t,s).setBufferObject(!0));class XA extends Ey{static get type(){return"StorageTextureNode"}constructor(e,t,s=null){super(e,t),this.storeNode=s,this.isStorageTextureNode=!0,this.access=CA}getInputType(){return"storageTexture"}setup(e){super.setup(e);e.getNodeProperties(this).storeNode=this.storeNode}setAccess(e){return this.access=e,this}generate(e,t){let s;return s=null!==this.storeNode?this.generateStore(e):super.generate(e,t),s}toReadOnly(){return this.setAccess(RA)}toWriteOnly(){return this.setAccess(CA)}generateStore(e){const t=e.getNodeProperties(this),{uvNode:s,storeNode:i}=t,r=super.generate(e,"property"),n=s.build(e,"uvec2"),o=i.build(e,"vec4"),a=e.generateTextureStore(e,r,n,o);e.addLineFlowCode(a,this)}}const YA=Ap(XA),ZA=(e,t,s)=>{const i=YA(e,t,s);return null!==s&&i.append(),i};class JA extends Dx{static get type(){return"UserDataNode"}constructor(e,t,s=null){super(e,t,s),this.userData=s}updateReference(e){return this.reference=null!==this.userData?this.userData:e.object.userData,this.reference}}const KA=(e,t,s)=>Sp(new JA(e,t,s));class QA extends kd{static get type(){return"PosterizeNode"}constructor(e,t){super(),this.sourceNode=e,this.stepsNode=t}setup(){const{sourceNode:e,stepsNode:t}=this;return e.mul(t).floor().div(t)}}const eC=Ap(QA);let tC=null;class sC extends Jv{static get type(){return"ViewportSharedTextureNode"}constructor(e=Dv,t=null){null===tC&&(tC=new ja),super(e,t,tC)}updateReference(){return this}}const iC=Ap(sC),rC=new Qs;class nC extends Ey{static get type(){return"PassTextureNode"}constructor(e,t){super(t),this.passNode=e,this.setUpdateMatrix(!1)}setup(e){return e.object.isQuadMesh&&this.passNode.build(e),super.setup(e)}clone(){return new this.constructor(this.passNode,this.value)}}class oC extends nC{static get type(){return"PassMultipleTextureNode"}constructor(e,t,s=!1){super(e,null),this.textureName=t,this.previousTexture=s}updateTexture(){this.value=this.previousTexture?this.passNode.getPreviousTexture(this.textureName):this.passNode.getTexture(this.textureName)}setup(e){return this.updateTexture(),super.setup(e)}clone(){return new this.constructor(this.passNode,this.textureName,this.previousTexture)}}class aC extends kd{static get type(){return"PassNode"}constructor(e,t,s,i={}){super("vec4"),this.scope=e,this.scene=t,this.camera=s,this.options=i,this._pixelRatio=1,this._width=1,this._height=1;const r=new Ya;r.isRenderTargetTexture=!0,r.name="depth";const n=new _i(this._width*this._pixelRatio,this._height*this._pixelRatio,{type:Pe,...i});n.texture.name="output",n.depthTexture=r,this.renderTarget=n,this.updateBeforeType=Bd.FRAME,this._textures={output:n.texture,depth:r},this._textureNodes={},this._linearDepthNodes={},this._viewZNodes={},this._previousTextures={},this._previousTextureNodes={},this._cameraNear=pm(0),this._cameraFar=pm(0),this._mrt=null,this.isPassNode=!0}setMRT(e){return this._mrt=e,this}getMRT(){return this._mrt}isGlobal(){return!0}getTexture(e){let t=this._textures[e];if(void 0===t){t=this.renderTarget.texture.clone(),t.isRenderTargetTexture=!0,t.name=e,this._textures[e]=t,this.renderTarget.textures.push(t)}return t}getPreviousTexture(e){let t=this._previousTextures[e];return void 0===t&&(t=this.getTexture(e).clone(),t.isRenderTargetTexture=!0,this._previousTextures[e]=t),t}toggleTexture(e){const t=this._previousTextures[e];if(void 0!==t){const s=this._textures[e],i=this.renderTarget.textures.indexOf(s);this.renderTarget.textures[i]=t,this._textures[e]=t,this._previousTextures[e]=s,this._textureNodes[e].updateTexture(),this._previousTextureNodes[e].updateTexture()}}getTextureNode(e="output"){let t=this._textureNodes[e];return void 0===t&&(this._textureNodes[e]=t=Sp(new oC(this,e)),this._textureNodes[e].updateTexture()),t}getPreviousTextureNode(e="output"){let t=this._previousTextureNodes[e];return void 0===t&&(void 0===this._textureNodes[e]&&this.getTextureNode(e),this._previousTextureNodes[e]=t=Sp(new oC(this,e,!0)),this._previousTextureNodes[e].updateTexture()),t}getViewZNode(e="depth"){let t=this._viewZNodes[e];if(void 0===t){const s=this._cameraNear,i=this._cameraFar;this._viewZNodes[e]=t=aT(this.getTextureNode(e),s,i)}return t}getLinearDepthNode(e="depth"){let t=this._linearDepthNodes[e];if(void 0===t){const s=this._cameraNear,i=this._cameraFar,r=this.getViewZNode(e);this._linearDepthNodes[e]=t=rT(r,s,i)}return t}setup({renderer:e}){return this.renderTarget.samples=void 0===this.options.samples?e.samples:this.options.samples,!0===e.backend.isWebGLBackend&&(this.renderTarget.samples=0),this.renderTarget.depthTexture.isMultisampleRenderTargetTexture=this.renderTarget.samples>1,this.scope===aC.COLOR?this.getTextureNode():this.getLinearDepthNode()}updateBefore(e){const{renderer:t}=e,{scene:s,camera:i}=this;this._pixelRatio=t.getPixelRatio();const r=t.getSize(rC);this.setSize(r.width,r.height);const n=t.getRenderTarget(),o=t.getMRT();this._cameraNear.value=i.near,this._cameraFar.value=i.far;for(const e in this._previousTextures)this.toggleTexture(e);t.setRenderTarget(this.renderTarget),t.setMRT(this._mrt),t.render(s,i),t.setRenderTarget(n),t.setMRT(o)}setSize(e,t){this._width=e,this._height=t;const s=this._width*this._pixelRatio,i=this._height*this._pixelRatio;this.renderTarget.setSize(s,i)}setPixelRatio(e){this._pixelRatio=e,this.setSize(this._width,this._height)}dispose(){this.renderTarget.dispose()}}aC.COLOR="color",aC.DEPTH="depth";const hC=(e,t,s)=>Sp(new aC(aC.COLOR,e,t,s)),uC=(e,t)=>Sp(new nC(e,t)),lC=(e,t)=>Sp(new aC(aC.DEPTH,e,t)),cC=new dN,dC=new dN;class pC extends kd{static get type(){return"GaussianBlurNode"}constructor(e,t=null,s=2){super("vec4"),this.textureNode=e,this.directionNode=t,this.sigma=s,this._invSize=pm(new Qs),this._passDirection=pm(new Qs),this._horizontalRT=new _i,this._horizontalRT.texture.name="GaussianBlurNode.horizontal",this._verticalRT=new _i,this._verticalRT.texture.name="GaussianBlurNode.vertical",this._textureNode=uC(this,this._verticalRT.texture),this.updateBeforeType=Bd.RENDER,this.resolution=new Qs(1,1)}setSize(e,t){e=Math.max(Math.round(e*this.resolution.x),1),t=Math.max(Math.round(t*this.resolution.y),1),this._invSize.value.set(1/e,1/t),this._horizontalRT.setSize(e,t),this._verticalRT.setSize(e,t)}updateBefore(e){const{renderer:t}=e,s=this.textureNode,i=s.value,r=t.getRenderTarget(),n=t.getMRT(),o=s.value;cC.material=this._material,dC.material=this._material,this.setSize(i.image.width,i.image.height);const a=i.type;this._horizontalRT.texture.type=a,this._verticalRT.texture.type=a,t.setMRT(null),t.setRenderTarget(this._horizontalRT),this._passDirection.value.set(1,0),cC.render(t),s.value=this._horizontalRT.texture,t.setRenderTarget(this._verticalRT),this._passDirection.value.set(0,1),dC.render(t),t.setRenderTarget(r),t.setMRT(n),s.value=o}getTextureNode(){return this._textureNode}setup(e){const t=this.textureNode;if(!0!==t.isTextureNode)return console.error("GaussianBlurNode requires a TextureNode."),Xp();const s=t.uvNode||My(),i=Dp(this.directionNode||1),r=e=>t.uv(e),n=Rp((()=>{const e=3+2*this.sigma,t=this._getCoefficients(e),n=this._invSize,o=i.mul(this._passDirection),a=Up(t[0]).toVar(),h=Xp(r(s).mul(a)).toVar();for(let i=1;iSp(new pC(fN(e),t,s)),gC=new Qs,fC=new dN;class yC extends kd{static get type(){return"AfterImageNode"}constructor(e,t=.96){super(e),this.textureNode=e,this.textureNodeOld=By(),this.damp=pm(t),this._compRT=new _i,this._compRT.texture.name="AfterImageNode.comp",this._oldRT=new _i,this._oldRT.texture.name="AfterImageNode.old",this._textureNode=uC(this,this._compRT.texture),this.updateBeforeType=Bd.RENDER}getTextureNode(){return this._textureNode}setSize(e,t){this._compRT.setSize(e,t),this._oldRT.setSize(e,t)}updateBefore(e){const{renderer:t}=e,s=this.textureNode,i=s.value.type;this._compRT.texture.type=i,this._oldRT.texture.type=i,t.getDrawingBufferSize(gC),this.setSize(gC.x,gC.y);const r=t.getRenderTarget(),n=s.value;this.textureNodeOld.value=this._oldRT.texture,t.setRenderTarget(this._compRT),fC.render(t);const o=this._oldRT;this._oldRT=this._compRT,this._compRT=o,t.setRenderTarget(r),s.value=n}setup(e){const t=this.textureNode,s=this.textureNodeOld,i=t.uvNode||My();s.uvNode=i;const r=Rp((([e,t])=>{const s=Up(t).toVar(),i=Xp(e).toVar();return of(Hg(i.sub(s)),0)})),n=Rp((()=>{const e=Xp(s),n=Xp((e=>t.uv(e))(i));return e.mulAssign(this.damp.mul(r(e,.1))),of(n,e)})),o=this._materialComposed||(this._materialComposed=new pT);o.name="AfterImage",o.fragmentNode=n(),fC.material=o;return e.getNodeProperties(this).textureNode=t,this._textureNode}dispose(){this._compRT.dispose(),this._oldRT.dispose()}}const xC=(e,t)=>Sp(new yC(fN(e),t)),bC=Rp((([e])=>SC(e.rgb))),vC=Rp((([e,t=Up(1)])=>t.mix(SC(e.rgb),e.rgb))),TC=Rp((([e,t=Up(1)])=>{const s=Zm(e.r,e.g,e.b).div(3),i=e.r.max(e.g.max(e.b)),r=i.sub(s).mul(t).mul(-3);return Tf(e.rgb,i,r)})),_C=Rp((([e,t=Up(1)])=>{const s=jp(.57735,.57735,.57735),i=t.cos();return jp(e.rgb.mul(i).add(s.cross(e.rgb).mul(t.sin()).add(s.mul(df(s,e.rgb).mul(i.oneMinus())))))})),wC=new Ri,SC=(e,t=jp(...ci.getLuminanceCoefficients(wC)))=>df(e,t),MC=(e,t)=>Tf(jp(0),e,SC(e).sub(t).max(0)),NC=new dN;class AC extends kd{static get type(){return"AnamorphicNode"}constructor(e,t,s,i){super("vec4"),this.textureNode=e,this.tresholdNode=t,this.scaleNode=s,this.colorNode=jp(.1,0,1),this.samples=i,this.resolution=new Qs(1,1),this._renderTarget=new _i,this._renderTarget.texture.name="anamorphic",this._invSize=pm(new Qs),this._textureNode=uC(this,this._renderTarget.texture),this.updateBeforeType=Bd.RENDER}getTextureNode(){return this._textureNode}setSize(e,t){this._invSize.value.set(1/e,1/t),e=Math.max(Math.round(e*this.resolution.x),1),t=Math.max(Math.round(t*this.resolution.y),1),this._renderTarget.setSize(e,t)}updateBefore(e){const{renderer:t}=e,s=this.textureNode,i=s.value;this._renderTarget.texture.type=i.type;const r=t.getRenderTarget(),n=s.value;NC.material=this._material,this.setSize(i.image.width,i.image.height),t.setRenderTarget(this._renderTarget),NC.render(t),t.setRenderTarget(r),s.value=n}setup(e){const t=this.textureNode,s=t.uvNode||My(),i=Rp((()=>{const e=this.samples,i=Math.floor(e/2),r=jp(0).toVar();return bv({start:-i,end:i},(({i:e})=>{const n=Up(e).abs().div(i).oneMinus(),o=(e=>t.uv(e))(Dp(s.x.add(this._invSize.x.mul(e).mul(this.scaleNode)),s.y)),a=MC(o,this.tresholdNode).mul(n);r.addAssign(a)})),r.mul(this.colorNode)})),r=this._material||(this._material=new pT);r.name="Anamorphic",r.fragmentNode=i();return e.getNodeProperties(this).textureNode=t,this._textureNode}dispose(){this._renderTarget.dispose()}}const CC=(e,t=.9,s=3,i=32)=>Sp(new AC(fN(e),Sp(t),Sp(s),i));class RC extends kd{static get type(){return"SobelOperatorNode"}constructor(e){super(),this.textureNode=e,this.updateBeforeType=Bd.RENDER,this._invSize=pm(new Qs)}updateBefore(){const e=this.textureNode.value;this._invSize.value.set(1/e.image.width,1/e.image.height)}setup(){const{textureNode:e}=this,t=e.uvNode||My(),s=t=>e.uv(t);return Rp((()=>{const e=this._invSize,i=Qp(-1,-2,-1,0,0,0,1,2,1),r=Qp(-1,0,1,-2,0,2,-1,0,1),n=SC(s(t.add(e.mul(Dp(-1,-1)))).xyz),o=SC(s(t.add(e.mul(Dp(-1,0)))).xyz),a=SC(s(t.add(e.mul(Dp(-1,1)))).xyz),h=SC(s(t.add(e.mul(Dp(0,-1)))).xyz),u=SC(s(t.add(e.mul(Dp(0,0)))).xyz),l=SC(s(t.add(e.mul(Dp(0,1)))).xyz),c=SC(s(t.add(e.mul(Dp(1,-1)))).xyz),d=SC(s(t.add(e.mul(Dp(1,0)))).xyz),p=SC(s(t.add(e.mul(Dp(1,1)))).xyz),m=Zm(i[0][0].mul(n),i[1][0].mul(h),i[2][0].mul(c),i[0][1].mul(o),i[1][1].mul(u),i[2][1].mul(d),i[0][2].mul(a),i[1][2].mul(l),i[2][2].mul(p)),g=Zm(r[0][0].mul(n),r[1][0].mul(h),r[2][0].mul(c),r[0][1].mul(o),r[1][1].mul(u),r[2][1].mul(d),r[0][2].mul(a),r[1][2].mul(l),r[2][2].mul(p)),f=m.mul(m).add(g.mul(g)).sqrt();return Xp(jp(f),1)}))()}}const EC=e=>Sp(new RC(fN(e)));class BC extends kd{static get type(){return"DepthOfFieldNode"}constructor(e,t,s,i,r){super(),this.textureNode=e,this.viewZNode=t,this.focusNode=s,this.apertureNode=i,this.maxblurNode=r,this._aspect=pm(0),this.updateBeforeType=Bd.RENDER}updateBefore(){const e=this.textureNode.value;this._aspect.value=e.image.width/e.image.height}setup(){const e=this.textureNode,t=e.uvNode||My(),s=t=>e.uv(t);return Rp((()=>{const e=Dp(1,this._aspect),i=this.focusNode.add(this.viewZNode),r=Dp(_f(i.mul(this.apertureNode),this.maxblurNode.negate(),this.maxblurNode)),n=r.mul(.9),o=r.mul(.7),a=r.mul(.4);let h=Xp(0);return h=h.add(s(t)),h=h.add(s(t.add(Dp(0,.4).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.15,.37).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.29,.29).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.37,.15).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.4,0).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.37,-.15).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.29,-.29).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.15,-.37).mul(e).mul(r)))),h=h.add(s(t.add(Dp(0,-.4).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.15,.37).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.29,.29).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.37,.15).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.4,0).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.37,-.15).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.29,-.29).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.15,-.37).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.15,.37).mul(e).mul(n)))),h=h.add(s(t.add(Dp(-.37,.15).mul(e).mul(n)))),h=h.add(s(t.add(Dp(.37,-.15).mul(e).mul(n)))),h=h.add(s(t.add(Dp(-.15,-.37).mul(e).mul(n)))),h=h.add(s(t.add(Dp(-.15,.37).mul(e).mul(n)))),h=h.add(s(t.add(Dp(.37,.15).mul(e).mul(n)))),h=h.add(s(t.add(Dp(-.37,-.15).mul(e).mul(n)))),h=h.add(s(t.add(Dp(.15,-.37).mul(e).mul(n)))),h=h.add(s(t.add(Dp(.29,.29).mul(e).mul(o)))),h=h.add(s(t.add(Dp(.4,0).mul(e).mul(o)))),h=h.add(s(t.add(Dp(.29,-.29).mul(e).mul(o)))),h=h.add(s(t.add(Dp(0,-.4).mul(e).mul(o)))),h=h.add(s(t.add(Dp(-.29,.29).mul(e).mul(o)))),h=h.add(s(t.add(Dp(-.4,0).mul(e).mul(o)))),h=h.add(s(t.add(Dp(-.29,-.29).mul(e).mul(o)))),h=h.add(s(t.add(Dp(0,.4).mul(e).mul(o)))),h=h.add(s(t.add(Dp(.29,.29).mul(e).mul(a)))),h=h.add(s(t.add(Dp(.4,0).mul(e).mul(a)))),h=h.add(s(t.add(Dp(.29,-.29).mul(e).mul(a)))),h=h.add(s(t.add(Dp(0,-.4).mul(e).mul(a)))),h=h.add(s(t.add(Dp(-.29,.29).mul(e).mul(a)))),h=h.add(s(t.add(Dp(-.4,0).mul(e).mul(a)))),h=h.add(s(t.add(Dp(-.29,-.29).mul(e).mul(a)))),h=h.add(s(t.add(Dp(0,.4).mul(e).mul(a)))),h=h.div(41),h.a=1,Xp(h)}))()}}const IC=(e,t,s=1,i=.025,r=1)=>Sp(new BC(fN(e),Sp(t),Sp(s),Sp(i),Sp(r)));class PC extends kd{static get type(){return"DotScreenNode"}constructor(e,t=new Qs(.5,.5),s=1.57,i=1){super("vec4"),this.inputNode=e,this.center=pm(t),this.angle=pm(s),this.scale=pm(i)}setup(){const e=this.inputNode,t=Rp((()=>{const e=Lg(this.angle),t=Vg(this.angle),s=My().mul(kv).sub(this.center),i=Dp(t.mul(s.x).sub(e.mul(s.y)),e.mul(s.x).add(t.mul(s.y))).mul(this.scale);return Lg(i.x).mul(Lg(i.y)).mul(4)})),s=Rp((()=>{const s=e,i=Zm(s.r,s.g,s.b).div(3);return Xp(jp(i.mul(10).sub(5).add(t())),s.a)}));return s()}}const FC=(e,t,s,i)=>Sp(new PC(Sp(e),t,s,i));class zC extends kd{static get type(){return"RGBShiftNode"}constructor(e,t=.005,s=0){super("vec4"),this.textureNode=e,this.amount=pm(t),this.angle=pm(s)}setup(){const{textureNode:e}=this,t=e.uvNode||My(),s=t=>e.uv(t);return Rp((()=>{const e=Dp(Vg(this.angle),Lg(this.angle)).mul(this.amount),i=s(t.add(e)),r=s(t),n=s(t.sub(e));return Xp(i.r,r.g,n.b,r.a)}))()}}const UC=(e,t,s)=>Sp(new zC(fN(e),t,s));class OC extends kd{static get type(){return"FilmNode"}constructor(e,t=null,s=null){super(),this.inputNode=e,this.intensityNode=t,this.uvNode=s}setup(){const e=this.uvNode||My(),t=Rp((()=>{const t=this.inputNode.rgb,s=Af(Og(e.add(BM())));let i=t.add(t.mul(_f(s.add(.1),0,1)));return null!==this.intensityNode&&(i=Tf(t,i,this.intensityNode)),Xp(i,this.inputNode.a)}));return t()}}const LC=Ap(OC);class VC extends kd{static get type(){return"Lut3DNode"}constructor(e,t,s,i){super(),this.inputNode=e,this.lutNode=t,this.size=pm(s),this.intensityNode=i}setup(){const{inputNode:e,lutNode:t}=this,s=Rp((()=>{const s=e,i=Up(1).div(this.size),r=Up(.5).div(this.size),n=jp(r).add(s.rgb.mul(Up(1).sub(i))),o=Xp((e=>t.uv(e))(n).rgb,s.a);return Xp(Tf(s,o,this.intensityNode))}));return s()}}const DC=(e,t,s,i)=>Sp(new VC(Sp(e),Sp(t),s,Sp(i))),kC=new dN,GC=new Jr,WC=new Qs;class jC extends kd{static get type(){return"GTAONode"}constructor(e,t,s){super(),this.depthNode=e,this.normalNode=t,this.radius=pm(.25),this.resolution=pm(new Qs),this.thickness=pm(1),this.distanceExponent=pm(1),this.distanceFallOff=pm(1),this.scale=pm(1),this.noiseNode=By(function(e=5){const t=Math.floor(e)%2==0?Math.floor(e)+1:Math.floor(e),s=function(e){const t=Math.floor(e)%2==0?Math.floor(e)+1:Math.floor(e),s=t*t,i=Array(s).fill(0);let r=Math.floor(t/2),n=t-1;for(let e=1;e<=s;)-1===r&&n===t?(n=t-2,r=0):(n===t&&(n=0),r<0&&(r=t-1)),0===i[r*t+n]?(i[r*t+n]=e++,n++,r--):(n-=2,r++);return i}(t),i=s.length,r=new Uint8Array(4*i);for(let e=0;ethis.depthNode.uv(e).x,i=e=>this.noiseNode.uv(e),r=Rp((([e])=>{const t=this.cameraProjectionMatrix.mul(Xp(e,1));let i=t.xy.div(t.w).mul(.5).add(.5).toVar();i=Dp(i.x,i.y.oneMinus());const r=s(i);return jp(i,r)})),n=Rp((([e,t])=>{e=Dp(e.x,e.y.oneMinus()).mul(2).sub(1);const s=Xp(jp(e,t),1),i=Xp(this.cameraProjectionMatrixInverse.mul(s));return i.xyz.div(i.w)})),o=Rp((()=>{const e=s(t);e.greaterThanEqual(1).discard();const o=n(t,e),a=this.normalNode.rgb.normalize(),h=this.radius,u=Ay(this.noiseNode,0);let l=Dp(t.x,t.y.oneMinus());l=l.mul(this.resolution.div(u));const c=i(l),d=c.xyz.mul(2).sub(1),p=jp(d.xy,0).normalize(),m=jp(p.y.mul(-1),p.x,0),g=Qp(p,m,jp(0,0,1)),f=this.SAMPLES.lessThan(30).select(3,5),y=Zm(this.SAMPLES,f.sub(1)).div(f),x=Up(0).toVar();return bv({start:Op(0),end:f,type:"int",condition:"<"},(({i:e})=>{const t=Up(e).div(Up(f)).mul(Tg),s=Xp(Vg(t),Lg(t),0,Zm(.5,Km(.5,c.w)));s.xyz=Ug(g.mul(s.xyz));const i=Ug(o.xyz.negate()),u=Ug(pf(s.xyz,i)),l=pf(u,i),d=Ug(a.sub(u.mul(df(a,u)))),p=pf(d,u),m=Dp(df(i,p),df(i,p.negate())).toVar();bv({end:y,type:"int",name:"j",condition:"<"},(({j:e})=>{const t=s.xyz.mul(h).mul(s.w).mul(mf(Qm(Up(e).add(1),Up(y)),this.distanceExponent)),a=r(o.add(t)),u=n(a.xy,a.z).sub(o);Pp(jg(u.z).lessThan(this.thickness),(()=>{const t=df(i,Ug(u));m.x.addAssign(of(0,Km(t.sub(m.x),Tf(1,Up(2).div(Up(e).add(2)),this.distanceFallOff))))}));const l=r(o.sub(t)),c=n(l.xy,l.z).sub(o);Pp(jg(c.z).lessThan(this.thickness),(()=>{const t=df(i,Ug(c));m.y.addAssign(of(0,Km(t.sub(m.y),Tf(1,Up(2).div(Up(e).add(2)),this.distanceFallOff))))}))}));const b=Ig(Jm(1,m.mul(m))),v=df(d,l),T=df(d,i),_=Km(.5,Gg(m.y).sub(Gg(m.x)).add(b.x.mul(m.x).sub(b.y.mul(m.y)))),w=Km(.5,Jm(2,m.x.mul(m.x)).sub(m.y.mul(m.y))),S=v.mul(_).add(T.mul(w));x.addAssign(S)})),x.assign(_f(x.div(f),0,1)),x.assign(mf(x,this.scale)),Xp(jp(x),1)})),a=this._material||(this._material=new pT);return a.fragmentNode=o().context(e.getSharedContext()),a.name="GTAO",a.needsUpdate=!0,this._textureNode}dispose(){this._aoRenderTarget.dispose()}}const HC=(e,t,s)=>Sp(new jC(Sp(e),Sp(t),s));class qC extends kd{static get type(){return"DenoiseNode"}constructor(e,t,s,i,r){super(),this.textureNode=e,this.depthNode=t,this.normalNode=s,this.noiseNode=i,this.cameraProjectionMatrixInverse=pm(r.projectionMatrixInverse),this.lumaPhi=pm(5),this.depthPhi=pm(5),this.normalPhi=pm(5),this.radius=pm(5),this.index=pm(0),this._resolution=pm(new Qs),this._sampleVectors=Ox(function(e,t,s){const i=function(e,t,s){const i=[];for(let r=0;rthis.textureNode.uv(e),s=e=>this.depthNode.uv(e).x,i=e=>this.normalNode.uv(e),r=e=>this.noiseNode.uv(e),n=Rp((([e,t])=>{e=Dp(e.x,e.y.oneMinus()).mul(2).sub(1);const s=Xp(jp(e,t),1),i=Xp(this.cameraProjectionMatrixInverse.mul(s));return i.xyz.div(i.w)})),o=Rp((([e,r,o,a])=>{const h=t(a),u=s(a),l=i(a).rgb.normalize(),c=h.rgb,d=n(a,u),p=df(r,l).toVar(),m=mf(of(p,0),this.normalPhi).toVar(),g=jg(SC(c).sub(SC(e))).toVar(),f=of(Up(1).sub(g.div(this.lumaPhi)),0).toVar(),y=jg(df(o.sub(d),r)).toVar(),x=of(Up(1).sub(y.div(this.depthPhi)),0),b=f.mul(x).mul(m);return Xp(c.mul(b),b)})),a=Rp((([e])=>{const a=s(e),h=i(e).rgb.normalize(),u=t(e);Pp(a.greaterThanEqual(1).or(df(h,h).equal(0)),(()=>u));const l=jp(u.rgb),c=n(e,a),d=Ay(this.noiseNode,0);let p=Dp(e.x,e.y.oneMinus());p=p.mul(this._resolution.div(d));const m=r(p),g=Lg(m.element(this.index.mod(4).mul(2).mul(Tg))),f=Vg(m.element(this.index.mod(4).mul(2).mul(Tg))),y=Dp(g,f),x=Kp(y.x,y.y.negate(),y.x,y.y),b=Up(1).toVar(),v=jp(u.rgb).toVar();return bv({start:Op(0),end:Op(16),type:"int",condition:"<"},(({i:t})=>{const s=this._sampleVectors.element(t).toVar(),i=x.mul(s.xy.mul(Up(1).add(s.z.mul(this.radius.sub(1))))).div(this._resolution).toVar(),r=e.add(i).toVar(),n=o(l,h,c,r);v.addAssign(n.xyz),b.addAssign(n.w)})),Pp(b.greaterThan(Up(0)),(()=>{v.divAssign(b)})),Xp(v,u.a)})).setLayout({name:"denoise",type:"vec4",inputs:[{name:"uv",type:"vec2"}]});return Rp((()=>a(e)))()}}const $C=(e,t,s,i,r)=>Sp(new qC(fN(e),Sp(t),Sp(s),Sp(i),r));class XC extends kd{static get type(){return"FXAANode"}constructor(e){super(),this.textureNode=e,this.updateBeforeType=Bd.RENDER,this._invSize=pm(new Qs)}updateBefore(){const e=this.textureNode.value;this._invSize.value.set(1/e.image.width,1/e.image.height)}setup(){const e=this.textureNode.bias(-100),t=e.uvNode||My(),s=t=>e.uv(t),i=(t,s,i)=>e.uv(t.add(s.mul(i))),r=Op(5),n=Rp((([e,t])=>{const s=Xp(t).toVar(),i=Xp(e).toVar(),r=Xp(jg(i.sub(s))).toVar();return of(of(of(r.r,r.g),r.b),r.a)})),o=Rp((([e,t,o,a])=>{const h=s(e).toVar(),u=i(e,Dp(0,-1),t.xy).toVar(),l=i(e,Dp(1,0),t.xy).toVar(),c=i(e,Dp(0,1),t.xy).toVar(),d=i(e,Dp(-1,0),t.xy).toVar(),p=n(h,c).toVar(),m=n(h,u).toVar(),g=n(h,l).toVar(),f=n(h,d).toVar(),y=of(p,of(m,of(g,f))).toVar();Pp(y.lessThan(o),(()=>h));const x=Jm(p.add(m),g.add(f)).toVar();x.mulAssign(a),Pp(jg(x).lessThan(.3),(()=>{const s=g.greaterThan(f).select(1,-1).toVar(),r=m.greaterThan(p).select(1,-1).toVar(),o=Dp(s,r).toVar(),y=i(e,Dp(o.x,o.y),t.xy),b=n(h,y).toVar(),v=i(e,Dp(o.x.negate(),o.y.negate()),t.xy),T=n(h,v).toVar();x.assign(T.sub(b)),x.mulAssign(a),Pp(jg(x).lessThan(.3),(()=>{const e=c.add(u).add(l).add(d);return Tf(h,e.mul(.25),.4)}))}));const b=Dp().toVar();Pp(x.lessThanEqual(0),(()=>{c.assign(d),u.assign(l),b.x.assign(0),b.y.assign(t.y)})).Else((()=>{b.x.assign(t.x),b.y.assign(0)}));const v=n(h,c).toVar(),T=n(h,u).toVar();Pp(v.lessThanEqual(T),(()=>{c.assign(u)}));const _=Op(0).toVar(),w=Op(0).toVar(),S=Up(0).toVar(),M=Up(0).toVar(),N=Dp(e).toVar(),A=Dp(e).toVar(),C=Op(0).toVar(),R=Op(0).toVar();bv(r,(({i:t})=>{const i=t.add(1).toVar();Pp(_.equal(0),(()=>{S.addAssign(i),N.assign(e.add(b.mul(S)));const r=s(N.xy),o=n(r,h).toVar(),a=n(r,c).toVar();Pp(o.greaterThan(a),(()=>{_.assign(1)})),C.assign(t)})),Pp(w.equal(0),(()=>{M.addAssign(i),A.assign(e.sub(b.mul(M)));const r=s(A.xy),o=n(r,h).toVar(),a=n(r,c).toVar();Pp(o.greaterThan(a),(()=>{w.assign(1)})),R.assign(t)})),Pp(_.equal(1).or(w.equal(1)),(()=>{Tv()}))})),Pp(_.equal(0).and(w.equal(0)),(()=>h));const E=Up(1).toVar(),B=Up(1).toVar();Pp(_.equal(1),(()=>{E.assign(Up(C).div(Up(r.sub(1))))})),Pp(w.equal(1),(()=>{B.assign(Up(R).div(Up(r.sub(1))))}));const I=nf(E,B);return I.assign(mf(I,.5)),I.assign(Up(1).sub(I)),Tf(h,c,I.mul(.5))})).setLayout({name:"FxaaPixelShader",type:"vec4",inputs:[{name:"uv",type:"vec2"},{name:"fxaaQualityRcpFrame",type:"vec2"},{name:"fxaaQualityEdgeThreshold",type:"float"},{name:"fxaaQualityinvEdgeThreshold",type:"float"}]});return Rp((()=>{const e=Up(.2),s=Up(1).div(e);return o(t,this._invSize,e,s)}))()}}const YC=e=>Sp(new XC(fN(e))),ZC=new dN,JC=new Jr(0,0,0),KC=new Jr,QC=new Qs,eR=new Qs(1,0),tR=new Qs(0,1);class sR extends kd{static get type(){return"BloomNode"}constructor(e,t=1,s=0,i=0){super(),this.inputNode=e,this.strength=pm(t),this.radius=pm(s),this.threshold=pm(i),this.smoothWidth=pm(.01),this._renderTargetsHorizontal=[],this._renderTargetsVertical=[],this._nMips=5,this._renderTargetBright=new _i(1,1,{type:Pe}),this._renderTargetBright.texture.name="UnrealBloomPass.bright",this._renderTargetBright.texture.generateMipmaps=!1;for(let e=0;e{const e=this.inputNode,t=SC(e.rgb),s=Mf(this.threshold,this.threshold.add(this.smoothWidth),t);return Tf(Xp(0),e,s)}));this._highPassFilterMaterial=this._highPassFilterMaterial||new pT,this._highPassFilterMaterial.fragmentNode=t().context(e.getSharedContext()),this._highPassFilterMaterial.name="Bloom_highPass",this._highPassFilterMaterial.needsUpdate=!0;const s=[3,5,7,9,11];for(let t=0;t{const s=Up(1.2).sub(e);return Tf(e,s,t)})).setLayout({name:"lerpBloomFactor",type:"float",inputs:[{name:"factor",type:"float"},{name:"radius",type:"float"}]}),o=Rp((()=>{const e=n(i.element(0),this.radius).mul(Xp(r.element(0),1)).mul(this._textureNodeBlur0),t=n(i.element(1),this.radius).mul(Xp(r.element(1),1)).mul(this._textureNodeBlur1),s=n(i.element(2),this.radius).mul(Xp(r.element(2),1)).mul(this._textureNodeBlur2),o=n(i.element(3),this.radius).mul(Xp(r.element(3),1)).mul(this._textureNodeBlur3),a=n(i.element(4),this.radius).mul(Xp(r.element(4),1)).mul(this._textureNodeBlur4);return e.add(t).add(s).add(o).add(a).mul(this.strength)}));return this._compositeMaterial=this._compositeMaterial||new pT,this._compositeMaterial.fragmentNode=o().context(e.getSharedContext()),this._compositeMaterial.name="Bloom_comp",this._compositeMaterial.needsUpdate=!0,this._textureOutput}dispose(){for(let e=0;ei.uv(e),u=Rp((()=>{const e=r.element(0).toVar(),s=h(a).rgb.mul(e).toVar();return bv({start:Op(1),end:Op(t),type:"int",condition:"<"},(({i:t})=>{const i=Up(t),u=r.element(t),l=o.mul(n).mul(i),c=h(a.add(l)).rgb,d=h(a.sub(l)).rgb;s.addAssign(Zm(c,d).mul(u)),e.addAssign(Up(2).mul(u))})),Xp(s.div(e),1)})),l=new pT;return l.fragmentNode=u().context(e.getSharedContext()),l.name="Bloom_seperable",l.needsUpdate=!0,l.colorTexture=i,l.direction=o,l.invSize=n,l}}const iR=(e,t,s,i)=>Sp(new sR(Sp(e),t,s,i));class rR extends kd{static get type(){return"TransitionNode"}constructor(e,t,s,i,r,n){super(),this.textureNodeA=e,this.textureNodeB=t,this.mixTextureNode=s,this.mixRatioNode=i,this.thresholdNode=r,this.useTextureNode=n}setup(){const{textureNodeA:e,textureNodeB:t,mixTextureNode:s,mixRatioNode:i,thresholdNode:r,useTextureNode:n}=this,o=e=>{const t=e.uvNode||My();return e.uv(t)},a=Rp((()=>{const a=o(e),h=o(t),u=Xp().toVar();return Pp(n.equal(Op(1)),(()=>{const e=o(s),t=i.mul(r.mul(2).add(1)).sub(r),n=_f(Jm(e.r,t).mul(Up(1).div(r)),0,1);u.assign(Tf(a,h,n))})).Else((()=>{u.assign(Tf(h,a,i))})),u}));return a()}}const nR=(e,t,s,i=0,r=.1,n=0)=>Sp(new rR(fN(e),fN(t),fN(s),Sp(i),Sp(r),Sp(n)));class oR extends kd{static get type(){return"PixelationNode"}constructor(e,t,s,i,r,n){super(),this.textureNode=e,this.depthNode=t,this.normalNode=s,this.pixelSize=i,this.normalEdgeStrength=r,this.depthEdgeStrength=n,this._resolution=pm(new Ti),this.updateBeforeType=Bd.RENDER}updateBefore(){const e=this.textureNode.value,t=e.image.width,s=e.image.height;this._resolution.value.set(t,s,1/t,1/s)}setup(){const{textureNode:e,depthNode:t,normalNode:s}=this,i=e.uvNode||My(),r=t.uvNode||My(),n=s.uvNode||My(),o=(e,s)=>t.uv(r.add(Dp(e,s).mul(this._resolution.zw))).r,a=(e,t)=>s.uv(n.add(Dp(e,t).mul(this._resolution.zw))).rgb.normalize(),h=(e,t,s,i)=>{const r=o(e,t).sub(s),n=a(e,t),h=jp(1,1,1),u=df(i.sub(n),h),l=_f(Mf(-.01,.01,u),0,1),c=_f(Hg(r.mul(.25).add(.0025)),0,1);return Up(1).sub(df(i,n)).mul(c).mul(l)},u=Rp((()=>{const t=e.uv(i),s=gm("float","depth"),r=gm("vec3","normal");Pp(this.depthEdgeStrength.greaterThan(0).or(this.normalEdgeStrength.greaterThan(0)),(()=>{s.assign(o(0,0)),r.assign(a(0,0))}));const n=gm("float","dei");Pp(this.depthEdgeStrength.greaterThan(0),(()=>{n.assign((e=>{const t=gm("float","diff");return t.addAssign(_f(o(1,0).sub(e))),t.addAssign(_f(o(-1,0).sub(e))),t.addAssign(_f(o(0,1).sub(e))),t.addAssign(_f(o(0,-1).sub(e))),Fg(Mf(.01,.02,t).mul(2)).div(2)})(s))}));const u=gm("float","nei");Pp(this.normalEdgeStrength.greaterThan(0),(()=>{u.assign(((e,t)=>{const s=gm("float","indicator");return s.addAssign(h(0,-1,e,t)),s.addAssign(h(0,1,e,t)),s.addAssign(h(-1,0,e,t)),s.addAssign(h(1,0,e,t)),hf(.1,s)})(s,r))}));const l=n.greaterThan(0).select(Up(1).sub(n.mul(this.depthEdgeStrength)),u.mul(this.normalEdgeStrength).add(1));return t.mul(l)}));return u()}}class aR extends aC{static get type(){return"PixelationPassNode"}constructor(e,t,s=6,i=.3,r=.4){super("color",e,t,{minFilter:fe,magFilter:fe}),this.pixelSize=s,this.normalEdgeStrength=i,this.depthEdgeStrength=r,this.isPixelationPassNode=!0,this._mrt=NM({output:zm,normal:bx})}setSize(e,t){const s=this.pixelSize.value?this.pixelSize.value:this.pixelSize,i=Math.floor(e/s),r=Math.floor(t/s);super.setSize(i,r)}setup(){return((e,t,s,i=6,r=.3,n=.4)=>Sp(new oR(fN(e),fN(t),fN(s),Sp(i),Sp(r),Sp(n))))(super.getTextureNode("output"),super.getTextureNode("depth"),super.getTextureNode("normal"),this.pixelSize,this.normalEdgeStrength,this.depthEdgeStrength)}}const hR=(e,t,s,i,r)=>Sp(new aR(e,t,s,i,r)),uR=new Qs;class lR extends aC{static get type(){return"SSAAPassNode"}constructor(e,t){super(aC.COLOR,e,t),this.isSSAAPassNode=!0,this.sampleLevel=4,this.unbiased=!0,this.clearColor=new Jr(0),this.clearAlpha=0,this._currentClearColor=new Jr,this.sampleWeight=pm(1),this.sampleRenderTarget=null,this._quadMesh=new dN}updateBefore(e){const{renderer:t}=e,{scene:s,camera:i}=this;this._pixelRatio=t.getPixelRatio();const r=t.getSize(uR);this.setSize(r.width,r.height),this.sampleRenderTarget.setSize(this.renderTarget.width,this.renderTarget.height),t.getClearColor(this._currentClearColor);const n=t.getClearAlpha(),o=t.getRenderTarget(),a=t.getMRT(),h=t.autoClear;this._cameraNear.value=i.near,this._cameraFar.value=i.far,t.setMRT(this.getMRT()),t.autoClear=!1;const u=cR[Math.max(0,Math.min(this.sampleLevel,5))],l=1/u.length,c={fullWidth:this.renderTarget.width,fullHeight:this.renderTarget.height,offsetX:0,offsetY:0,width:this.renderTarget.width,height:this.renderTarget.height},d=Object.assign({},i.view);d.enabled&&Object.assign(c,d);for(let e=0;e=0&&(e[t]=By(this.sampleRenderTarget.textures[s]).mul(this.sampleWeight))}t=NM(e)}else t=By(this.sampleRenderTarget.texture).mul(this.sampleWeight);return this._quadMesh.material=new pT,this._quadMesh.material.fragmentNode=t,this._quadMesh.material.transparent=!0,this._quadMesh.material.depthTest=!1,this._quadMesh.material.depthWrite=!1,this._quadMesh.material.premultipliedAlpha=!0,this._quadMesh.material.blending=2,this._quadMesh.material.normals=!1,this._quadMesh.material.name="SSAA",super.setup(e)}dispose(){super.dispose(),null!==this.sampleRenderTarget&&this.sampleRenderTarget.dispose()}}const cR=[[[0,0]],[[4,4],[-4,-4]],[[-2,-6],[6,-2],[-6,2],[2,6]],[[1,-3],[-1,3],[5,1],[-3,-5],[-5,5],[-7,-1],[3,7],[7,-7]],[[1,1],[-1,-3],[-3,2],[4,-1],[-5,-2],[2,5],[5,3],[3,-5],[-2,6],[0,-7],[-4,-6],[-6,4],[-8,0],[7,-4],[6,7],[-7,-8]],[[-4,-7],[-7,-5],[-3,-5],[-5,-4],[-1,-4],[-2,-2],[-6,-1],[-4,0],[-7,1],[-1,2],[-6,3],[-3,3],[-7,6],[-3,6],[-5,7],[-1,7],[5,-7],[1,-6],[6,-5],[4,-4],[2,-3],[7,-2],[1,-1],[4,-1],[2,1],[6,2],[0,4],[4,4],[2,5],[7,5],[5,6],[3,7]]],dR=(e,t)=>Sp(new lR(e,t)),pR=new Qs;class mR extends aC{static get type(){return"StereoPassNode"}constructor(e,t){super(aC.COLOR,e,t),this.isStereoPassNode=!0,this.stereo=new ql,this.stereo.aspect=.5}updateBefore(e){const{renderer:t}=e,{scene:s,camera:i,stereo:r,renderTarget:n}=this;this._pixelRatio=t.getPixelRatio(),r.cameraL.coordinateSystem=t.coordinateSystem,r.cameraR.coordinateSystem=t.coordinateSystem,r.update(i);const o=t.getSize(pR);this.setSize(o.width,o.height);const a=t.autoClear;t.autoClear=!1;const h=t.getRenderTarget(),u=t.getMRT();this._cameraNear.value=i.near,this._cameraFar.value=i.far;for(const e in this._previousTextures)this.toggleTexture(e);t.setRenderTarget(n),t.setMRT(this._mrt),t.clear(),n.scissorTest=!0,n.scissor.set(0,0,n.width/2,n.height),n.viewport.set(0,0,n.width/2,n.height),t.render(s,r.cameraL),n.scissor.set(n.width/2,0,n.width/2,n.height),n.viewport.set(n.width/2,0,n.width/2,n.height),t.render(s,r.cameraR),n.scissorTest=!1,t.setRenderTarget(h),t.setMRT(u),t.autoClear=a}}const gR=(e,t)=>Sp(new mR(e,t)),fR=new Qs,yR=new dN;class xR extends aC{static get type(){return"StereoCompositePassNode"}constructor(e,t){super(aC.COLOR,e,t),this.isStereoCompositePassNode=!0,this.stereo=new ql;const s={minFilter:Te,magFilter:fe,type:Pe};this._renderTargetL=new _i(1,1,s),this._renderTargetR=new _i(1,1,s),this._mapLeft=By(this._renderTargetL.texture),this._mapRight=By(this._renderTargetR.texture),this._material=null}updateStereoCamera(e){this.stereo.cameraL.coordinateSystem=e,this.stereo.cameraR.coordinateSystem=e,this.stereo.update(this.camera)}setSize(e,t){super.setSize(e,t),this._renderTargetL.setSize(this.renderTarget.width,this.renderTarget.height),this._renderTargetR.setSize(this.renderTarget.width,this.renderTarget.height)}updateBefore(e){const{renderer:t}=e,{scene:s,stereo:i,renderTarget:r}=this;this._pixelRatio=t.getPixelRatio(),this.updateStereoCamera(t.coordinateSystem);const n=t.getSize(fR);this.setSize(n.width,n.height);const o=t.getRenderTarget();t.setRenderTarget(this._renderTargetL),t.render(s,i.cameraL),t.setRenderTarget(this._renderTargetR),t.render(s,i.cameraR),t.setRenderTarget(r),yR.material=this._material,yR.render(t),t.setRenderTarget(o)}dispose(){super.dispose(),this._renderTargetL.dispose(),this._renderTargetR.dispose(),null!==this._material&&this._material.dispose()}}class bR extends xR{static get type(){return"AnaglyphPassNode"}constructor(e,t){super(e,t),this.isAnaglyphPassNode=!0,this._colorMatrixLeft=pm((new ei).fromArray([.4561,-.0400822,-.0152161,.500484,-.0378246,-.0205971,.176381,-.0157589,-.00546856])),this._colorMatrixRight=pm((new ei).fromArray([-.0434706,.378476,-.0721527,-.0879388,.73364,-.112961,-.00155529,-.0184503,1.2264]))}setup(e){const t=My(),s=Rp((()=>{const e=this._mapLeft.uv(t),s=this._mapRight.uv(t),i=_f(this._colorMatrixLeft.mul(e.rgb).add(this._colorMatrixRight.mul(s.rgb)));return Xp(i.rgb,of(e.a,s.a))})),i=this._material||(this._material=new pT);return i.fragmentNode=s().context(e.getSharedContext()),i.name="Anaglyph",i.needsUpdate=!0,super.setup(e)}}const vR=(e,t)=>Sp(new bR(e,t));class TR extends xR{static get type(){return"ParallaxBarrierPassNode"}constructor(e,t){super(e,t),this.isParallaxBarrierPassNode=!0}setup(e){const t=My(),s=Rp((()=>{const e=Xp().toVar();return Pp(af(Gv.y,2).greaterThan(1),(()=>{e.assign(this._mapLeft.uv(t))})).Else((()=>{e.assign(this._mapRight.uv(t))})),e})),i=this._material||(this._material=new pT);return i.fragmentNode=s().context(e.getSharedContext()),i.needsUpdate=!0,super.setup(e)}}const _R=(e,t)=>Sp(new TR(e,t));class wR extends aC{static get type(){return"ToonOutlinePassNode"}constructor(e,t,s,i,r){super(aC.COLOR,e,t),this.colorNode=s,this.thicknessNode=i,this.alphaNode=r,this._materialCache=new WeakMap}updateBefore(e){const{renderer:t}=e,s=t.getRenderObjectFunction();t.setRenderObjectFunction(((e,s,i,r,n,o,a)=>{if((n.isMeshToonMaterial||n.isMeshToonNodeMaterial)&&!1===n.wireframe){const h=this._getOutlineMaterial(n);t.renderObject(e,s,i,r,h,o,a)}t.renderObject(e,s,i,r,n,o,a)})),super.updateBefore(e),t.setRenderObjectFunction(s)}_createMaterial(){const e=new pT;e.isMeshToonOutlineMaterial=!0,e.name="Toon_Outline",e.side=d;const t=yx.negate(),s=Oy.mul(ix),i=Up(1),r=s.mul(Xp(ax,1)),n=s.mul(Xp(ax.add(t),1)),o=Ug(r.sub(n));return e.vertexNode=r.add(o.mul(this.thicknessNode).mul(r.w).mul(i)),e.colorNode=Xp(this.colorNode,this.alphaNode),e}_getOutlineMaterial(e){let t=this._materialCache.get(e);return void 0===t&&(t=this._createMaterial(),this._materialCache.set(e,t)),t}}const SR=(e,t,s=new Jr(0,0,0),i=.003,r=1)=>Sp(new wR(e,t,Sp(s),Sp(i),Sp(r)));class MR extends Ld{static get type(){return"ScriptableValueNode"}constructor(e=null){super(),this._value=e,this._cache=null,this.inputType=null,this.outpuType=null,this.events=new ks,this.isScriptableValueNode=!0}get isScriptableOutputNode(){return null!==this.outputType}set value(e){this._value!==e&&(this._cache&&"URL"===this.inputType&&this.value.value instanceof ArrayBuffer&&(URL.revokeObjectURL(this._cache),this._cache=null),this._value=e,this.events.dispatchEvent({type:"change"}),this.refresh())}get value(){return this._value}refresh(){this.events.dispatchEvent({type:"refresh"})}getValue(){const e=this.value;if(e&&null===this._cache&&"URL"===this.inputType&&e.value instanceof ArrayBuffer)this._cache=URL.createObjectURL(new Blob([e.value]));else if(e&&null!==e.value&&void 0!==e.value&&(("URL"===this.inputType||"String"===this.inputType)&&"string"==typeof e.value||"Number"===this.inputType&&"number"==typeof e.value||"Vector2"===this.inputType&&e.value.isVector2||"Vector3"===this.inputType&&e.value.isVector3||"Vector4"===this.inputType&&e.value.isVector4||"Color"===this.inputType&&e.value.isColor||"Matrix3"===this.inputType&&e.value.isMatrix3||"Matrix4"===this.inputType&&e.value.isMatrix4))return e.value;return this._cache||e}getNodeType(e){return this.value&&this.value.isNode?this.value.getNodeType(e):"float"}setup(){return this.value&&this.value.isNode?this.value:Up()}serialize(e){super.serialize(e),null!==this.value?"ArrayBuffer"===this.inputType?e.value=Ad(this.value):e.value=this.value?this.value.toJSON(e.meta).uuid:null:e.value=null,e.inputType=this.inputType,e.outputType=this.outputType}deserialize(e){super.deserialize(e);let t=null;null!==e.value&&(t="ArrayBuffer"===e.inputType?Cd(e.value):"Texture"===e.inputType?e.meta.textures[e.value]:e.meta.nodes[e.value]||null),this.value=t,this.inputType=e.inputType,this.outputType=e.outputType}}const NR=Ap(MR);class AR extends Map{get(e,t=null,...s){if(this.has(e))return super.get(e);if(null!==t){const i=t(...s);return this.set(e,i),i}}}class CR{constructor(e){this.scriptableNode=e}get parameters(){return this.scriptableNode.parameters}get layout(){return this.scriptableNode.getLayout()}getInputLayout(e){return this.scriptableNode.getInputLayout(e)}get(e){const t=this.parameters[e];return t?t.getValue():null}}const RR=new AR;class ER extends Ld{static get type(){return"ScriptableNode"}constructor(e=null,t={}){super(),this.codeNode=e,this.parameters=t,this._local=new AR,this._output=NR(),this._outputs={},this._source=this.source,this._method=null,this._object=null,this._value=null,this._needsOutputUpdate=!0,this.onRefresh=this.onRefresh.bind(this),this.isScriptableNode=!0}get source(){return this.codeNode?this.codeNode.code:""}setLocal(e,t){return this._local.set(e,t)}getLocal(e){return this._local.get(e)}onRefresh(){this._refresh()}getInputLayout(e){for(const t of this.getLayout())if(t.inputType&&(t.id===e||t.name===e))return t}getOutputLayout(e){for(const t of this.getLayout())if(t.outputType&&(t.id===e||t.name===e))return t}setOutput(e,t){const s=this._outputs;return void 0===s[e]?s[e]=NR(t):s[e].value=t,this}getOutput(e){return this._outputs[e]}getParameter(e){return this.parameters[e]}setParameter(e,t){const s=this.parameters;return t&&t.isScriptableNode?(this.deleteParameter(e),s[e]=t,s[e].getDefaultOutput().events.addEventListener("refresh",this.onRefresh)):t&&t.isScriptableValueNode?(this.deleteParameter(e),s[e]=t,s[e].events.addEventListener("refresh",this.onRefresh)):void 0===s[e]?(s[e]=NR(t),s[e].events.addEventListener("refresh",this.onRefresh)):s[e].value=t,this}getValue(){return this.getDefaultOutput().getValue()}deleteParameter(e){let t=this.parameters[e];return t&&(t.isScriptableNode&&(t=t.getDefaultOutput()),t.events.removeEventListener("refresh",this.onRefresh)),this}clearParameters(){for(const e of Object.keys(this.parameters))this.deleteParameter(e);return this.needsUpdate=!0,this}call(e,...t){const s=this.getObject()[e];if("function"==typeof s)return s(...t)}async callAsync(e,...t){const s=this.getObject()[e];if("function"==typeof s)return"AsyncFunction"===s.constructor.name?await s(...t):s(...t)}getNodeType(e){return this.getDefaultOutputNode().getNodeType(e)}refresh(e=null){null!==e?this.getOutput(e).refresh():this._refresh()}getObject(){if(this.needsUpdate&&this.dispose(),null!==this._object)return this._object;const e=new CR(this),t=RR.get("THREE"),s=RR.get("TSL"),i=this.getMethod(this.codeNode),r=[e,this._local,RR,()=>this.refresh(),(e,t)=>this.setOutput(e,t),t,s];this._object=i(...r);const n=this._object.layout;if(n&&(!1===n.cache&&this._local.clear(),this._output.outputType=n.outputType||null,Array.isArray(n.elements)))for(const e of n.elements){const t=e.id||e.name;e.inputType&&(void 0===this.getParameter(t)&&this.setParameter(t,null),this.getParameter(t).inputType=e.inputType),e.outputType&&(void 0===this.getOutput(t)&&this.setOutput(t,null),this.getOutput(t).outputType=e.outputType)}return this._object}deserialize(e){super.deserialize(e);for(const e in this.parameters){let t=this.parameters[e];t.isScriptableNode&&(t=t.getDefaultOutput()),t.events.addEventListener("refresh",this.onRefresh)}}getLayout(){return this.getObject().layout}getDefaultOutputNode(){const e=this.getDefaultOutput().value;return e&&e.isNode?e:Up()}getDefaultOutput(){return this._exec()._output}getMethod(){if(this.needsUpdate&&this.dispose(),null!==this._method)return this._method;const e=["layout","init","main","dispose"].join(", "),t="\nreturn { ...output, "+e+" };",s="var "+e+"; var output = {};\n"+this.codeNode.code+t;return this._method=new Function(...["parameters","local","global","refresh","setOutput","THREE","TSL"],s),this._method}dispose(){null!==this._method&&(this._object&&"function"==typeof this._object.dispose&&this._object.dispose(),this._method=null,this._object=null,this._source=null,this._value=null,this._needsOutputUpdate=!0,this._output.value=null,this._outputs={})}setup(){return this.getDefaultOutputNode()}getCacheKey(e){const t=[vd(this.source),this.getDefaultOutputNode().getCacheKey(e)];for(const s in this.parameters)t.push(this.parameters[s].getCacheKey(e));return Td(t)}set needsUpdate(e){!0===e&&this.dispose()}get needsUpdate(){return this.source!==this._source}_exec(){return null===this.codeNode||(!0===this._needsOutputUpdate&&(this._value=this.call("main"),this._needsOutputUpdate=!1),this._output.value=this._value),this}_refresh(){this.needsUpdate=!0,this._exec(),this._output.refresh()}}const BR=Ap(ER);class IR extends Ld{static get type(){return"FogNode"}constructor(e,t){super("float"),this.isFogNode=!0,this.colorNode=e,this.factorNode=t}getViewZNode(e){let t;const s=e.context.getViewZ;return void 0!==s&&(t=s(this)),(t||cx.z).negate()}setup(){return this.factorNode}}const PR=Ap(IR);class FR extends IR{static get type(){return"FogRangeNode"}constructor(e,t,s){super(e),this.isFogRangeNode=!0,this.nearNode=t,this.farNode=s}setup(e){const t=this.getViewZNode(e);return Mf(this.nearNode,this.farNode,t)}}const zR=Ap(FR);class UR extends IR{static get type(){return"FogExp2Node"}constructor(e,t){super(e),this.isFogExp2Node=!0,this.densityNode=t}setup(e){const t=this.getViewZNode(e),s=this.densityNode;return s.mul(s,t,t).negate().exp().oneMinus()}}const OR=Ap(UR);let LR=null,VR=null;class DR extends Ld{static get type(){return"RangeNode"}constructor(e=Up(),t=Up()){super(),this.minNode=e,this.maxNode=t}getVectorLength(e){const t=e.getTypeLength(Md(this.minNode.value)),s=e.getTypeLength(Md(this.maxNode.value));return t>s?t:s}getNodeType(e){return e.object.count>1?e.getTypeFromLength(this.getVectorLength(e)):"float"}setup(e){const t=e.object;let s=null;if(t.count>1){const i=this.minNode.value,r=this.maxNode.value,n=e.getTypeLength(Md(i)),o=e.getTypeLength(Md(r));LR=LR||new Ti,VR=VR||new Ti,LR.setScalar(0),VR.setScalar(0),1===n?LR.setScalar(i):i.isColor?LR.set(i.r,i.g,i.b):LR.set(i.x,i.y,i.z||0,i.w||0),1===o?VR.setScalar(r):r.isColor?VR.set(r.r,r.g,r.b):VR.set(r.x,r.y,r.z||0,r.w||0);const a=4,h=a*t.count,u=new Float32Array(h);for(let e=0;eBy(e,t.xy).compare(t.z))),WR=Rp((({depthTexture:e,shadowCoord:t,shadow:s})=>{const i=(t,s)=>By(e,t).compare(s),r=kx("mapSize","vec2",s).setGroup(lm),n=kx("radius","float",s).setGroup(lm),o=Dp(1).div(r),a=o.x.negate().mul(n),h=o.y.negate().mul(n),u=o.x.mul(n),l=o.y.mul(n),c=a.div(2),d=h.div(2),p=u.div(2),m=l.div(2);return Zm(i(t.xy.add(Dp(a,h)),t.z),i(t.xy.add(Dp(0,h)),t.z),i(t.xy.add(Dp(u,h)),t.z),i(t.xy.add(Dp(c,d)),t.z),i(t.xy.add(Dp(0,d)),t.z),i(t.xy.add(Dp(p,d)),t.z),i(t.xy.add(Dp(a,0)),t.z),i(t.xy.add(Dp(c,0)),t.z),i(t.xy,t.z),i(t.xy.add(Dp(p,0)),t.z),i(t.xy.add(Dp(u,0)),t.z),i(t.xy.add(Dp(c,m)),t.z),i(t.xy.add(Dp(0,m)),t.z),i(t.xy.add(Dp(p,m)),t.z),i(t.xy.add(Dp(a,l)),t.z),i(t.xy.add(Dp(0,l)),t.z),i(t.xy.add(Dp(u,l)),t.z)).mul(1/17)})),jR=Rp((({depthTexture:e,shadowCoord:t,shadow:s})=>{const i=(t,s)=>By(e,t).compare(s),r=kx("mapSize","vec2",s).setGroup(lm),n=Dp(1).div(r),o=n.x,a=n.y,h=t.xy,u=Og(h.mul(r).add(.5));return h.subAssign(u.mul(n)),Zm(i(h,t.z),i(h.add(Dp(o,0)),t.z),i(h.add(Dp(0,a)),t.z),i(h.add(n),t.z),Tf(i(h.add(Dp(o.negate(),0)),t.z),i(h.add(Dp(o.mul(2),0)),t.z),u.x),Tf(i(h.add(Dp(o.negate(),a)),t.z),i(h.add(Dp(o.mul(2),a)),t.z),u.x),Tf(i(h.add(Dp(0,a.negate())),t.z),i(h.add(Dp(0,a.mul(2))),t.z),u.y),Tf(i(h.add(Dp(o,a.negate())),t.z),i(h.add(Dp(o,a.mul(2))),t.z),u.y),Tf(Tf(i(h.add(Dp(o.negate(),a.negate())),t.z),i(h.add(Dp(o.mul(2),a.negate())),t.z),u.x),Tf(i(h.add(Dp(o.negate(),a.mul(2))),t.z),i(h.add(Dp(o.mul(2),a.mul(2))),t.z),u.x),u.y)).mul(1/9)})),HR=Rp((({depthTexture:e,shadowCoord:t})=>{const s=Up(1).toVar(),i=By(e).uv(t.xy).rg,r=hf(t.z,i.x);return Pp(r.notEqual(Up(1)),(()=>{const e=t.z.sub(i.x),n=of(0,i.y.mul(i.y));let o=n.div(n.add(e.mul(e)));o=_f(Jm(o,.3).div(.95-.3)),s.assign(_f(of(r,o)))})),s})),qR=Rp((({samples:e,radius:t,size:s,shadowPass:i})=>{const r=Up(0).toVar(),n=Up(0).toVar(),o=e.lessThanEqual(Up(1)).select(Up(0),Up(2).div(e.sub(1))),a=e.lessThanEqual(Up(1)).select(Up(0),Up(-1));bv({start:Op(0),end:Op(e),type:"int",condition:"<"},(({i:e})=>{const h=a.add(Up(e).mul(o)),u=i.uv(Zm(Gv.xy,Dp(0,h).mul(t)).div(s)).x;r.addAssign(u),n.addAssign(u.mul(u))})),r.divAssign(e),n.divAssign(e);const h=Ig(n.sub(r.mul(r)));return Dp(r,h)})),$R=Rp((({samples:e,radius:t,size:s,shadowPass:i})=>{const r=Up(0).toVar(),n=Up(0).toVar(),o=e.lessThanEqual(Up(1)).select(Up(0),Up(2).div(e.sub(1))),a=e.lessThanEqual(Up(1)).select(Up(0),Up(-1));bv({start:Op(0),end:Op(e),type:"int",condition:"<"},(({i:e})=>{const h=a.add(Up(e).mul(o)),u=i.uv(Zm(Gv.xy,Dp(h,0).mul(t)).div(s));r.addAssign(u.x),n.addAssign(Zm(u.y.mul(u.y),u.x.mul(u.x)))})),r.divAssign(e),n.divAssign(e);const h=Ig(n.sub(r.mul(r)));return Dp(r,h)})),XR=[GR,WR,jR,HR];let YR=null;const ZR=new dN;class JR extends Iv{static get type(){return"AnalyticLightNode"}constructor(e=null){super(),this.updateType=Bd.FRAME,this.light=e,this.color=new Jr,this.colorNode=pm(this.color).setGroup(lm),this.baseColorNode=null,this.shadowMap=null,this.shadowNode=null,this.shadowColorNode=null,this.vsmShadowMapVertical=null,this.vsmShadowMapHorizontal=null,this.vsmMaterialVertical=null,this.vsmMaterialHorizontal=null,this.isAnalyticLightNode=!0}getCacheKey(){return _d(super.getCacheKey(),this.light.id,this.light.castShadow?1:0)}getHash(){return this.light.uuid}setupShadow(e){const{object:t,renderer:s}=e;if(!1===s.shadowMap.enabled)return;let i=this.shadowColorNode;if(null===i){null===YR&&(YR=new pT,YR.fragmentNode=Xp(0,0,0,1),YR.isShadowNodeMaterial=!0,YR.name="ShadowMaterial");const r=s.shadowMap.type,n=this.light.shadow,o=new Ya;o.compareFunction=Ts;const a=e.createRenderTarget(n.mapSize.width,n.mapSize.height);if(a.depthTexture=o,n.camera.updateProjectionMatrix(),3===r){o.compareFunction=null,this.vsmShadowMapVertical=e.createRenderTarget(n.mapSize.width,n.mapSize.height,{format:$e,type:Pe}),this.vsmShadowMapHorizontal=e.createRenderTarget(n.mapSize.width,n.mapSize.height,{format:$e,type:Pe});const t=By(o),s=By(this.vsmShadowMapVertical.texture),i=kx("blurSamples","float",n).setGroup(lm),r=kx("radius","float",n).setGroup(lm),a=kx("mapSize","vec2",n).setGroup(lm);let h=this.vsmMaterialVertical||(this.vsmMaterialVertical=new pT);h.fragmentNode=qR({samples:i,radius:r,size:a,shadowPass:t}).context(e.getSharedContext()),h.name="VSMVertical",h=this.vsmMaterialHorizontal||(this.vsmMaterialHorizontal=new pT),h.fragmentNode=$R({samples:i,radius:r,size:a,shadowPass:s}).context(e.getSharedContext()),h.name="VSMHorizontal"}const h=kx("intensity","float",n).setGroup(lm),u=kx("bias","float",n).setGroup(lm),l=kx("normalBias","float",n).setGroup(lm),c=t.material.shadowPositionNode||ux;let d=pm(n.matrix).setGroup(lm).mul(c.add(vx.mul(l)));d=d.xyz.div(d.w);let p=d.z.add(u);s.coordinateSystem===Ds&&(p=p.mul(2).sub(1)),d=jp(d.x,d.y.oneMinus(),p);const m=d.x.greaterThanEqual(0).and(d.x.lessThanEqual(1)).and(d.y.greaterThanEqual(0)).and(d.y.lessThanEqual(1)).and(d.z.lessThanEqual(1)),g=n.filterNode||XR[s.shadowMap.type]||null;if(null===g)throw new Error("THREE.WebGPURenderer: Shadow map type not supported yet.");const f=By(a.texture,d),y=m.select(g({depthTexture:3===r?this.vsmShadowMapHorizontal.texture:o,shadowCoord:d,shadow:n}),Up(1));this.shadowMap=a,this.light.shadow.map=a,this.shadowNode=y,this.shadowColorNode=i=this.colorNode.mul(Tf(1,y.rgb.mix(f,1),h.mul(f.a))),this.baseColorNode=this.colorNode}this.colorNode=i,this.updateBeforeType=Bd.RENDER}setup(e){this.colorNode=this.baseColorNode||this.colorNode,this.light.castShadow?e.object.receiveShadow&&this.setupShadow(e):null!==this.shadowNode&&this.disposeShadow()}updateShadow(e){const{shadowMap:t,light:s}=this,{renderer:i,scene:r,camera:n}=e,o=i.shadowMap.type,a=t.depthTexture.version;this._depthVersionCached=a;const h=r.overrideMaterial;r.overrideMaterial=YR,t.setSize(s.shadow.mapSize.width,s.shadow.mapSize.height),s.shadow.updateMatrices(s),s.shadow.camera.layers.mask=n.layers.mask;const u=i.getRenderTarget(),l=i.getRenderObjectFunction();i.setRenderObjectFunction(((e,...t)=>{(!0===e.castShadow||e.receiveShadow&&3===o)&&i.renderObject(e,...t)})),i.setRenderTarget(t),i.render(r,s.shadow.camera),i.setRenderObjectFunction(l),!0!==s.isPointLight&&3===o&&this.vsmPass(e,s),i.setRenderTarget(u),r.overrideMaterial=h}vsmPass(e,t){const{renderer:s}=e;this.vsmShadowMapVertical.setSize(t.shadow.mapSize.width,t.shadow.mapSize.height),this.vsmShadowMapHorizontal.setSize(t.shadow.mapSize.width,t.shadow.mapSize.height),s.setRenderTarget(this.vsmShadowMapVertical),ZR.material=this.vsmMaterialVertical,ZR.render(s),s.setRenderTarget(this.vsmShadowMapHorizontal),ZR.material=this.vsmMaterialHorizontal,ZR.render(s)}disposeShadow(){this.shadowMap.dispose(),this.shadowMap=null,null!==this.vsmShadowMapVertical&&(this.vsmShadowMapVertical.dispose(),this.vsmShadowMapVertical=null,this.vsmMaterialVertical.dispose(),this.vsmMaterialVertical=null),null!==this.vsmShadowMapHorizontal&&(this.vsmShadowMapHorizontal.dispose(),this.vsmShadowMapHorizontal=null,this.vsmMaterialHorizontal.dispose(),this.vsmMaterialHorizontal=null),this.shadowNode=null,this.shadowColorNode=null,this.baseColorNode=null,this.updateBeforeType=Bd.NONE}updateBefore(e){const t=this.light.shadow;(t.needsUpdate||t.autoUpdate)&&(this.updateShadow(e),this.shadowMap.depthTexture.version===this._depthVersionCached&&(t.needsUpdate=!1))}update(){const{light:e}=this;this.color.copy(e.color).multiplyScalar(e.intensity)}}const KR=Rp((e=>{const{lightDistance:t,cutoffDistance:s,decayExponent:i}=e,r=t.pow(i).max(.01).reciprocal();return s.greaterThan(0).select(r.mul(t.div(s).pow4().oneMinus().clamp().pow2()),r)}));let QR;function eE(e){QR=QR||new WeakMap;let t=QR.get(e);return void 0===t&&QR.set(e,t={}),t}function tE(e){const t=eE(e);return t.position||(t.position=pm(new Ri).setGroup(lm).onRenderUpdate(((t,s)=>s.value.setFromMatrixPosition(e.matrixWorld))))}function sE(e){const t=eE(e);return t.targetPosition||(t.targetPosition=pm(new Ri).setGroup(lm).onRenderUpdate(((t,s)=>s.value.setFromMatrixPosition(e.target.matrixWorld))))}function iE(e){const t=eE(e);return t.viewPosition||(t.viewPosition=pm(new Ri).setGroup(lm).onRenderUpdate((({camera:t},s)=>{s.value=s.value||new Ri,s.value.setFromMatrixPosition(e.matrixWorld),s.value.applyMatrix4(t.matrixWorldInverse)})))}const rE=e=>Vy.transformDirection(tE(e).sub(sE(e))),nE=Rp((([e])=>{const t=e.toUint().mul(747796405).add(2891336453),s=t.shiftRight(t.shiftRight(28).add(4)).bitXor(t).mul(277803737);return s.shiftRight(22).bitXor(s).toFloat().mul(1/2**32)})),oE=(e,t)=>mf(Km(4,e.mul(Jm(1,e))),t),aE=(e,t)=>e.lessThan(.5)?oE(e.mul(2),t).div(2):Jm(1,oE(Km(Jm(1,e),2),t).div(2)),hE=(e,t,s)=>mf(Qm(mf(e,t),Zm(mf(e,t),mf(Jm(1,e),s))),1/t),uE=(e,t)=>Lg(Tg.mul(t.mul(e).sub(1))).div(Tg.mul(t.mul(e).sub(1))),lE=Rp((([e])=>e.fract().sub(.5).abs())).setLayout({name:"tri",type:"float",inputs:[{name:"x",type:"float"}]}),cE=Rp((([e])=>jp(lE(e.z.add(lE(e.y.mul(1)))),lE(e.z.add(lE(e.x.mul(1)))),lE(e.y.add(lE(e.x.mul(1))))))).setLayout({name:"tri3",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),dE=Rp((([e,t,s])=>{const i=jp(e).toVar(),r=Up(1.4).toVar(),n=Up(0).toVar(),o=jp(i).toVar();return bv({start:Up(0),end:Up(3),type:"float",condition:"<="},(()=>{const e=jp(cE(o.mul(2))).toVar();i.addAssign(e.add(s.mul(Up(.1).mul(t)))),o.mulAssign(1.8),r.mulAssign(1.5),i.mulAssign(1.2);const a=Up(lE(i.z.add(lE(i.x.add(lE(i.y)))))).toVar();n.addAssign(a.div(r)),o.addAssign(.14)})),n})).setLayout({name:"triNoise3D",type:"float",inputs:[{name:"p",type:"vec3"},{name:"spd",type:"float"},{name:"time",type:"float"}]}),pE=Rp((([e,t,s=Dp(.5)])=>Ew(e.sub(s),t).add(s))),mE=Rp((([e,t,s=Dp(.5)])=>{const i=e.sub(s),r=i.dot(i),n=r.mul(r).mul(t);return e.add(i.mul(n))})),gE=Rp((({position:e=null,horizontal:t=!0,vertical:s=!1})=>{let i;null!==e?(i=Jy.toVar(),i[3][0]=e.x,i[3][1]=e.y,i[3][2]=e.z):i=Jy;const r=Vy.mul(i);return Tp(t)&&(r[0][0]=Jy[0].length(),r[0][1]=0,r[0][2]=0),Tp(s)&&(r[1][0]=0,r[1][1]=Jy[1].length(),r[1][2]=0),r[2][0]=0,r[2][1]=0,r[2][2]=1,Oy.mul(r).mul(ax)})),fE=Rp((([e=null])=>{const t=lT();return lT(sT(e)).sub(t).lessThan(0).select(Dv,e)})),yE=new WeakMap;class xE extends kd{static get type(){return"VelocityNode"}constructor(){super("vec2"),this.updateType=Bd.OBJECT,this.updateAfterType=Bd.OBJECT,this.previousModelWorldMatrix=pm(new nr),this.previousProjectionMatrix=pm(new nr).setGroup(lm),this.previousCameraViewMatrix=pm(new nr)}update({frameId:e,camera:t,object:s}){const i=vE(s);this.previousModelWorldMatrix.value.copy(i);const r=bE(t);r.frameId!==e&&(r.frameId=e,void 0===r.previousProjectionMatrix?(r.previousProjectionMatrix=new nr,r.previousCameraViewMatrix=new nr,r.currentProjectionMatrix=new nr,r.currentCameraViewMatrix=new nr,r.previousProjectionMatrix.copy(t.projectionMatrix),r.previousCameraViewMatrix.copy(t.matrixWorldInverse)):(r.previousProjectionMatrix.copy(r.currentProjectionMatrix),r.previousCameraViewMatrix.copy(r.currentCameraViewMatrix)),r.currentProjectionMatrix.copy(t.projectionMatrix),r.currentCameraViewMatrix.copy(t.matrixWorldInverse),this.previousProjectionMatrix.value.copy(r.previousProjectionMatrix),this.previousCameraViewMatrix.value.copy(r.previousCameraViewMatrix))}updateAfter({object:e}){vE(e).copy(e.matrixWorld)}setup(){const e=this.previousCameraViewMatrix.mul(this.previousModelWorldMatrix),t=Oy.mul(ix).mul(ax),s=this.previousProjectionMatrix.mul(e).mul(hx),i=t.xy.div(t.w),r=s.xy.div(s.w);return Jm(i,r)}}function bE(e){let t=yE.get(e);return void 0===t&&(t={},yE.set(e,t)),t}function vE(e,t=0){const s=bE(e);let i=s[t];return void 0===i&&(s[t]=i=new nr),i}const TE=Cp(xE),_E=Rp((([e,t])=>nf(1,e.oneMinus().div(t)).oneMinus())).setLayout({name:"burnBlend",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),wE=Rp((([e,t])=>nf(e.div(t.oneMinus()),1))).setLayout({name:"dodgeBlend",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),SE=Rp((([e,t])=>e.oneMinus().mul(t.oneMinus()).oneMinus())).setLayout({name:"screenBlend",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),ME=Rp((([e,t])=>Tf(e.mul(2).mul(t),e.oneMinus().mul(2).mul(t.oneMinus()).oneMinus(),hf(.5,e)))).setLayout({name:"overlayBlend",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),NE=Rp((([e,t,s=Op(16)])=>{const i=t=>e.uv(t),r=My(),n=i(r).toVar(),o=Up(s);return bv({start:Op(1),end:s,type:"int",condition:"<="},(({i:e})=>{const s=t.mul(Up(e).div(o.sub(1)).sub(.5));n.addAssign(i(r.add(s)))})),n.divAssign(o),n})),AE=Rp((([e,t=1])=>{const s=e,i=SC(s.rgb),r=jp(i),n=nf(1,of(0,Up(10).mul(i.sub(.45)))),o=r.mul(s.rgb).mul(2),a=Up(2).mul(r.oneMinus()).mul(s.rgb.oneMinus()).oneMinus(),h=Tf(o,a,n),u=s.a.mul(t),l=u.mul(h.rgb);return l.addAssign(s.rgb.mul(u.oneMinus())),Xp(l,s.a)})),CE=Rp((([e])=>{const t=jp(e);return Xp(df(t,jp(.393,.769,.189)),df(t,jp(.349,.686,.168)),df(t,jp(.272,.534,.131)),e.a)})),RE=Rp((([e])=>{const t=e.mul(.9478672986).add(.0521327014).pow(2.4),s=e.mul(.0773993808),i=e.lessThanEqual(.04045);return Tf(t,s,i)})).setLayout({name:"sRGBToLinearSRGB",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),EE=Rp((([e])=>{const t=e.pow(.41666).mul(1.055).sub(.055),s=e.mul(12.92),i=e.lessThanEqual(.0031308);return Tf(t,s,i)})).setLayout({name:"linearSRGBTosRGB",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),BE=Rp((([e,t])=>e.mul(t).clamp())).setLayout({name:"linearToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),IE=Rp((([e,t])=>(e=e.mul(t)).div(e.add(1)).clamp())).setLayout({name:"reinhardToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),PE=Rp((([e,t])=>{const s=(e=(e=e.mul(t)).sub(.004).max(0)).mul(e.mul(6.2).add(.5)),i=e.mul(e.mul(6.2).add(1.7)).add(.06);return s.div(i).pow(2.2)})).setLayout({name:"cineonToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),FE=Rp((([e])=>{const t=e.mul(e.add(.0245786)).sub(90537e-9),s=e.mul(e.add(.432951).mul(.983729)).add(.238081);return t.div(s)})),zE=Rp((([e,t])=>{const s=Qp(.59719,.35458,.04823,.076,.90834,.01566,.0284,.13383,.83777),i=Qp(1.60475,-.53108,-.07367,-.10208,1.10813,-.00605,-.00327,-.07276,1.07602);return e=e.mul(t).div(.6),e=s.mul(e),e=FE(e),(e=i.mul(e)).clamp()})).setLayout({name:"acesFilmicToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),UE=Qp(jp(1.6605,-.1246,-.0182),jp(-.5876,1.1329,-.1006),jp(-.0728,-.0083,1.1187)),OE=Qp(jp(.6274,.0691,.0164),jp(.3293,.9195,.088),jp(.0433,.0113,.8956)),LE=Rp((([e])=>{const t=jp(e).toVar(),s=jp(t.mul(t)).toVar(),i=jp(s.mul(s)).toVar();return Up(15.5).mul(i.mul(s)).sub(Km(40.14,i.mul(t))).add(Km(31.96,i).sub(Km(6.868,s.mul(t))).add(Km(.4298,s).add(Km(.1191,t).sub(.00232))))})),VE=Rp((([e,t])=>{const s=jp(e).toVar(),i=Qp(jp(.856627153315983,.137318972929847,.11189821299995),jp(.0951212405381588,.761241990602591,.0767994186031903),jp(.0482516061458583,.101439036467562,.811302368396859)),r=Qp(jp(1.1271005818144368,-.1413297634984383,-.14132976349843826),jp(-.11060664309660323,1.157823702216272,-.11060664309660294),jp(-.016493938717834573,-.016493938717834257,1.2519364065950405)),n=Up(-12.47393),o=Up(4.026069);return s.mulAssign(t),s.assign(OE.mul(s)),s.assign(i.mul(s)),s.assign(of(s,1e-10)),s.assign(Bg(s)),s.assign(s.sub(n).div(o.sub(n))),s.assign(_f(s,0,1)),s.assign(LE(s)),s.assign(r.mul(s)),s.assign(mf(of(jp(0),s),jp(2.2))),s.assign(UE.mul(s)),s.assign(_f(s,0,1)),s})).setLayout({name:"agxToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),DE=Rp((([e,t])=>{const s=Up(.76),i=Up(.15);e=e.mul(t);const r=nf(e.r,nf(e.g,e.b)),n=Bf(r.lessThan(.08),r.sub(Km(6.25,r.mul(r))),.04);e.subAssign(n);const o=of(e.r,of(e.g,e.b));Pp(o.lessThan(s),(()=>e));const a=Jm(1,s),h=Jm(1,a.mul(a).div(o.add(a.sub(s))));e.mulAssign(h.div(o));const u=Jm(1,Qm(1,i.mul(o.sub(h)).add(1)));return Tf(e,jp(h),u)})).setLayout({name:"neutralToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]});class kE extends Ld{static get type(){return"ComputeBuiltinNode"}constructor(e,t){super(t),this._builtinName=e}getHash(e){return this.getBuiltinName(e)}getNodeType(){return this.nodeType}setBuiltinName(e){return this._builtinName=e,this}getBuiltinName(){return this._builtinName}hasBuiltin(e){e.hasBuiltin(this._builtinName)}generate(e,t){const s=this.getBuiltinName(e),i=this.getNodeType(e);return"compute"===e.shaderStage?e.format(s,i,t):(console.warn(`ComputeBuiltinNode: Compute built-in value ${s} can not be accessed in the ${e.shaderStage} stage`),e.generateConst(i))}serialize(e){super.serialize(e),e.global=this.global,e._builtinName=this._builtinName}deserialize(e){super.deserialize(e),this.global=e.global,this._builtinName=e._builtinName}}const GE=(e,t)=>Sp(new kE(e,t)),WE=GE("numWorkgroups","uvec3"),jE=GE("workgroupId","uvec3"),HE=GE("localId","uvec3"),qE=GE("subgroupSize","uint");const $E=Ap(class extends Ld{constructor(e){super(),this.scope=e}generate(e){const{scope:t}=this,{renderer:s}=e;!0===s.backend.isWebGLBackend?e.addFlowCode(`\t// ${t}Barrier \n`):e.addLineFlowCode(`${t}Barrier()`,this)}}),XE=()=>$E("workgroup").append(),YE=()=>$E("storage").append(),ZE=()=>$E("texture").append();class JE extends Vd{constructor(e,t){super(e,t),this.isWorkgroupInfoElementNode=!0}generate(e,t){let s;const i=e.context.assign;if(s=super.generate(e),!0!==i){const i=this.getNodeType(e);s=e.format(s,i,t)}return s}}class KE extends Ld{constructor(e,t,s=0){super(t),this.bufferType=t,this.bufferCount=s,this.isWorkgroupInfoNode=!0,this.scope=e}label(e){return this.name=e,this}getHash(){return this.uuid}setScope(e){return this.scope=e,this}getInputType(){return`${this.scope}Array`}element(e){return Sp(new JE(this,e))}generate(e){return e.getScopedArray(this.name||`${this.scope}Array_${this.id}`,this.scope.toLowerCase(),this.bufferType,this.bufferCount)}}const QE=(e,t)=>Sp(new KE("Workgroup",e,t));class eB extends kd{static get type(){return"AtomicFunctionNode"}constructor(e,t,s,i=null){super("uint"),this.method=e,this.pointerNode=t,this.valueNode=s,this.storeNode=i}getInputType(e){return this.pointerNode.getNodeType(e)}getNodeType(e){return this.getInputType(e)}generate(e){const t=this.method,s=this.getNodeType(e),i=this.getInputType(e),r=this.pointerNode,n=this.valueNode,o=[];o.push(`&${r.build(e,i)}`),o.push(n.build(e,i));const a=`${e.getMethod(t,s)}( ${o.join(", ")} )`;if(null!==this.storeNode){const t=this.storeNode.build(e,i);e.addLineFlowCode(`${t} = ${a}`,this)}else e.addLineFlowCode(a,this)}}eB.ATOMIC_LOAD="atomicLoad",eB.ATOMIC_STORE="atomicStore",eB.ATOMIC_ADD="atomicAdd",eB.ATOMIC_SUB="atomicSub",eB.ATOMIC_MAX="atomicMax",eB.ATOMIC_MIN="atomicMin",eB.ATOMIC_AND="atomicAnd",eB.ATOMIC_OR="atomicOr",eB.ATOMIC_XOR="atomicXor";const tB=Ap(eB),sB=(e,t,s,i)=>{const r=tB(e,t,s,i);return r.append(),r},iB=(e,t,s=null)=>sB(eB.ATOMIC_STORE,e,t,s),rB=(e,t,s=null)=>sB(eB.ATOMIC_ADD,e,t,s),nB=(e,t,s=null)=>sB(eB.ATOMIC_SUB,e,t,s),oB=(e,t,s=null)=>sB(eB.ATOMIC_MAX,e,t,s),aB=(e,t,s=null)=>sB(eB.ATOMIC_MIN,e,t,s),hB=(e,t,s=null)=>sB(eB.ATOMIC_AND,e,t,s),uB=(e,t,s=null)=>sB(eB.ATOMIC_OR,e,t,s),lB=(e,t,s=null)=>sB(eB.ATOMIC_XOR,e,t,s),cB=Rp((([e=t()])=>{const t=e.mul(2),s=t.x.floor(),i=t.y.floor();return s.add(i).mod(2).sign()})),dB=Rp((([e,t,s])=>{const i=Up(s).toVar(),r=Up(t).toVar(),n=Vp(e).toVar();return Bf(n,r,i)})).setLayout({name:"mx_select",type:"float",inputs:[{name:"b",type:"bool"},{name:"t",type:"float"},{name:"f",type:"float"}]}),pB=Rp((([e,t])=>{const s=Vp(t).toVar(),i=Up(e).toVar();return Bf(s,i.negate(),i)})).setLayout({name:"mx_negate_if",type:"float",inputs:[{name:"val",type:"float"},{name:"b",type:"bool"}]}),mB=Rp((([e])=>{const t=Up(e).toVar();return Op(Fg(t))})).setLayout({name:"mx_floor",type:"int",inputs:[{name:"x",type:"float"}]}),gB=Rp((([e,t])=>{const s=Up(e).toVar();return t.assign(mB(s)),s.sub(Up(t))})),fB=RM([Rp((([e,t,s,i,r,n])=>{const o=Up(n).toVar(),a=Up(r).toVar(),h=Up(i).toVar(),u=Up(s).toVar(),l=Up(t).toVar(),c=Up(e).toVar(),d=Up(Jm(1,a)).toVar();return Jm(1,o).mul(c.mul(d).add(l.mul(a))).add(o.mul(u.mul(d).add(h.mul(a))))})).setLayout({name:"mx_bilerp_0",type:"float",inputs:[{name:"v0",type:"float"},{name:"v1",type:"float"},{name:"v2",type:"float"},{name:"v3",type:"float"},{name:"s",type:"float"},{name:"t",type:"float"}]}),Rp((([e,t,s,i,r,n])=>{const o=Up(n).toVar(),a=Up(r).toVar(),h=jp(i).toVar(),u=jp(s).toVar(),l=jp(t).toVar(),c=jp(e).toVar(),d=Up(Jm(1,a)).toVar();return Jm(1,o).mul(c.mul(d).add(l.mul(a))).add(o.mul(u.mul(d).add(h.mul(a))))})).setLayout({name:"mx_bilerp_1",type:"vec3",inputs:[{name:"v0",type:"vec3"},{name:"v1",type:"vec3"},{name:"v2",type:"vec3"},{name:"v3",type:"vec3"},{name:"s",type:"float"},{name:"t",type:"float"}]})]),yB=RM([Rp((([e,t,s,i,r,n,o,a,h,u,l])=>{const c=Up(l).toVar(),d=Up(u).toVar(),p=Up(h).toVar(),m=Up(a).toVar(),g=Up(o).toVar(),f=Up(n).toVar(),y=Up(r).toVar(),x=Up(i).toVar(),b=Up(s).toVar(),v=Up(t).toVar(),T=Up(e).toVar(),_=Up(Jm(1,p)).toVar(),w=Up(Jm(1,d)).toVar();return Up(Jm(1,c)).toVar().mul(w.mul(T.mul(_).add(v.mul(p))).add(d.mul(b.mul(_).add(x.mul(p))))).add(c.mul(w.mul(y.mul(_).add(f.mul(p))).add(d.mul(g.mul(_).add(m.mul(p))))))})).setLayout({name:"mx_trilerp_0",type:"float",inputs:[{name:"v0",type:"float"},{name:"v1",type:"float"},{name:"v2",type:"float"},{name:"v3",type:"float"},{name:"v4",type:"float"},{name:"v5",type:"float"},{name:"v6",type:"float"},{name:"v7",type:"float"},{name:"s",type:"float"},{name:"t",type:"float"},{name:"r",type:"float"}]}),Rp((([e,t,s,i,r,n,o,a,h,u,l])=>{const c=Up(l).toVar(),d=Up(u).toVar(),p=Up(h).toVar(),m=jp(a).toVar(),g=jp(o).toVar(),f=jp(n).toVar(),y=jp(r).toVar(),x=jp(i).toVar(),b=jp(s).toVar(),v=jp(t).toVar(),T=jp(e).toVar(),_=Up(Jm(1,p)).toVar(),w=Up(Jm(1,d)).toVar();return Up(Jm(1,c)).toVar().mul(w.mul(T.mul(_).add(v.mul(p))).add(d.mul(b.mul(_).add(x.mul(p))))).add(c.mul(w.mul(y.mul(_).add(f.mul(p))).add(d.mul(g.mul(_).add(m.mul(p))))))})).setLayout({name:"mx_trilerp_1",type:"vec3",inputs:[{name:"v0",type:"vec3"},{name:"v1",type:"vec3"},{name:"v2",type:"vec3"},{name:"v3",type:"vec3"},{name:"v4",type:"vec3"},{name:"v5",type:"vec3"},{name:"v6",type:"vec3"},{name:"v7",type:"vec3"},{name:"s",type:"float"},{name:"t",type:"float"},{name:"r",type:"float"}]})]),xB=Rp((([e,t,s])=>{const i=Up(s).toVar(),r=Up(t).toVar(),n=Lp(e).toVar(),o=Lp(n.bitAnd(Lp(7))).toVar(),a=Up(dB(o.lessThan(Lp(4)),r,i)).toVar(),h=Up(Km(2,dB(o.lessThan(Lp(4)),i,r))).toVar();return pB(a,Vp(o.bitAnd(Lp(1)))).add(pB(h,Vp(o.bitAnd(Lp(2)))))})).setLayout({name:"mx_gradient_float_0",type:"float",inputs:[{name:"hash",type:"uint"},{name:"x",type:"float"},{name:"y",type:"float"}]}),bB=Rp((([e,t,s,i])=>{const r=Up(i).toVar(),n=Up(s).toVar(),o=Up(t).toVar(),a=Lp(e).toVar(),h=Lp(a.bitAnd(Lp(15))).toVar(),u=Up(dB(h.lessThan(Lp(8)),o,n)).toVar(),l=Up(dB(h.lessThan(Lp(4)),n,dB(h.equal(Lp(12)).or(h.equal(Lp(14))),o,r))).toVar();return pB(u,Vp(h.bitAnd(Lp(1)))).add(pB(l,Vp(h.bitAnd(Lp(2)))))})).setLayout({name:"mx_gradient_float_1",type:"float",inputs:[{name:"hash",type:"uint"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]}),vB=RM([xB,bB]),TB=Rp((([e,t,s])=>{const i=Up(s).toVar(),r=Up(t).toVar(),n=qp(e).toVar();return jp(vB(n.x,r,i),vB(n.y,r,i),vB(n.z,r,i))})).setLayout({name:"mx_gradient_vec3_0",type:"vec3",inputs:[{name:"hash",type:"uvec3"},{name:"x",type:"float"},{name:"y",type:"float"}]}),_B=Rp((([e,t,s,i])=>{const r=Up(i).toVar(),n=Up(s).toVar(),o=Up(t).toVar(),a=qp(e).toVar();return jp(vB(a.x,o,n,r),vB(a.y,o,n,r),vB(a.z,o,n,r))})).setLayout({name:"mx_gradient_vec3_1",type:"vec3",inputs:[{name:"hash",type:"uvec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]}),wB=RM([TB,_B]),SB=Rp((([e])=>{const t=Up(e).toVar();return Km(.6616,t)})).setLayout({name:"mx_gradient_scale2d_0",type:"float",inputs:[{name:"v",type:"float"}]}),MB=Rp((([e])=>{const t=Up(e).toVar();return Km(.982,t)})).setLayout({name:"mx_gradient_scale3d_0",type:"float",inputs:[{name:"v",type:"float"}]}),NB=RM([SB,Rp((([e])=>{const t=jp(e).toVar();return Km(.6616,t)})).setLayout({name:"mx_gradient_scale2d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),AB=RM([MB,Rp((([e])=>{const t=jp(e).toVar();return Km(.982,t)})).setLayout({name:"mx_gradient_scale3d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),CB=Rp((([e,t])=>{const s=Op(t).toVar(),i=Lp(e).toVar();return i.shiftLeft(s).bitOr(i.shiftRight(Op(32).sub(s)))})).setLayout({name:"mx_rotl32",type:"uint",inputs:[{name:"x",type:"uint"},{name:"k",type:"int"}]}),RB=Rp((([e,t,s])=>{e.subAssign(s),e.bitXorAssign(CB(s,Op(4))),s.addAssign(t),t.subAssign(e),t.bitXorAssign(CB(e,Op(6))),e.addAssign(s),s.subAssign(t),s.bitXorAssign(CB(t,Op(8))),t.addAssign(e),e.subAssign(s),e.bitXorAssign(CB(s,Op(16))),s.addAssign(t),t.subAssign(e),t.bitXorAssign(CB(e,Op(19))),e.addAssign(s),s.subAssign(t),s.bitXorAssign(CB(t,Op(4))),t.addAssign(e)})),EB=Rp((([e,t,s])=>{const i=Lp(s).toVar(),r=Lp(t).toVar(),n=Lp(e).toVar();return i.bitXorAssign(r),i.subAssign(CB(r,Op(14))),n.bitXorAssign(i),n.subAssign(CB(i,Op(11))),r.bitXorAssign(n),r.subAssign(CB(n,Op(25))),i.bitXorAssign(r),i.subAssign(CB(r,Op(16))),n.bitXorAssign(i),n.subAssign(CB(i,Op(4))),r.bitXorAssign(n),r.subAssign(CB(n,Op(14))),i.bitXorAssign(r),i.subAssign(CB(r,Op(24))),i})).setLayout({name:"mx_bjfinal",type:"uint",inputs:[{name:"a",type:"uint"},{name:"b",type:"uint"},{name:"c",type:"uint"}]}),BB=Rp((([e])=>{const t=Lp(e).toVar();return Up(t).div(Up(Lp(Op(4294967295))))})).setLayout({name:"mx_bits_to_01",type:"float",inputs:[{name:"bits",type:"uint"}]}),IB=Rp((([e])=>{const t=Up(e).toVar();return t.mul(t).mul(t).mul(t.mul(t.mul(6).sub(15)).add(10))})).setLayout({name:"mx_fade",type:"float",inputs:[{name:"t",type:"float"}]}),PB=RM([Rp((([e])=>{const t=Op(e).toVar(),s=Lp(Lp(1)).toVar(),i=Lp(Lp(Op(3735928559)).add(s.shiftLeft(Lp(2))).add(Lp(13))).toVar();return EB(i.add(Lp(t)),i,i)})).setLayout({name:"mx_hash_int_0",type:"uint",inputs:[{name:"x",type:"int"}]}),Rp((([e,t])=>{const s=Op(t).toVar(),i=Op(e).toVar(),r=Lp(Lp(2)).toVar(),n=Lp().toVar(),o=Lp().toVar(),a=Lp().toVar();return n.assign(o.assign(a.assign(Lp(Op(3735928559)).add(r.shiftLeft(Lp(2))).add(Lp(13))))),n.addAssign(Lp(i)),o.addAssign(Lp(s)),EB(n,o,a)})).setLayout({name:"mx_hash_int_1",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Op(t).toVar(),n=Op(e).toVar(),o=Lp(Lp(3)).toVar(),a=Lp().toVar(),h=Lp().toVar(),u=Lp().toVar();return a.assign(h.assign(u.assign(Lp(Op(3735928559)).add(o.shiftLeft(Lp(2))).add(Lp(13))))),a.addAssign(Lp(n)),h.addAssign(Lp(r)),u.addAssign(Lp(i)),EB(a,h,u)})).setLayout({name:"mx_hash_int_2",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]}),Rp((([e,t,s,i])=>{const r=Op(i).toVar(),n=Op(s).toVar(),o=Op(t).toVar(),a=Op(e).toVar(),h=Lp(Lp(4)).toVar(),u=Lp().toVar(),l=Lp().toVar(),c=Lp().toVar();return u.assign(l.assign(c.assign(Lp(Op(3735928559)).add(h.shiftLeft(Lp(2))).add(Lp(13))))),u.addAssign(Lp(a)),l.addAssign(Lp(o)),c.addAssign(Lp(n)),RB(u,l,c),u.addAssign(Lp(r)),EB(u,l,c)})).setLayout({name:"mx_hash_int_3",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"},{name:"xx",type:"int"}]}),Rp((([e,t,s,i,r])=>{const n=Op(r).toVar(),o=Op(i).toVar(),a=Op(s).toVar(),h=Op(t).toVar(),u=Op(e).toVar(),l=Lp(Lp(5)).toVar(),c=Lp().toVar(),d=Lp().toVar(),p=Lp().toVar();return c.assign(d.assign(p.assign(Lp(Op(3735928559)).add(l.shiftLeft(Lp(2))).add(Lp(13))))),c.addAssign(Lp(u)),d.addAssign(Lp(h)),p.addAssign(Lp(a)),RB(c,d,p),c.addAssign(Lp(o)),d.addAssign(Lp(n)),EB(c,d,p)})).setLayout({name:"mx_hash_int_4",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"},{name:"xx",type:"int"},{name:"yy",type:"int"}]})]),FB=RM([Rp((([e,t])=>{const s=Op(t).toVar(),i=Op(e).toVar(),r=Lp(PB(i,s)).toVar(),n=qp().toVar();return n.x.assign(r.bitAnd(Op(255))),n.y.assign(r.shiftRight(Op(8)).bitAnd(Op(255))),n.z.assign(r.shiftRight(Op(16)).bitAnd(Op(255))),n})).setLayout({name:"mx_hash_vec3_0",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Op(t).toVar(),n=Op(e).toVar(),o=Lp(PB(n,r,i)).toVar(),a=qp().toVar();return a.x.assign(o.bitAnd(Op(255))),a.y.assign(o.shiftRight(Op(8)).bitAnd(Op(255))),a.z.assign(o.shiftRight(Op(16)).bitAnd(Op(255))),a})).setLayout({name:"mx_hash_vec3_1",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]})]),zB=RM([Rp((([e])=>{const t=Dp(e).toVar(),s=Op().toVar(),i=Op().toVar(),r=Up(gB(t.x,s)).toVar(),n=Up(gB(t.y,i)).toVar(),o=Up(IB(r)).toVar(),a=Up(IB(n)).toVar(),h=Up(fB(vB(PB(s,i),r,n),vB(PB(s.add(Op(1)),i),r.sub(1),n),vB(PB(s,i.add(Op(1))),r,n.sub(1)),vB(PB(s.add(Op(1)),i.add(Op(1))),r.sub(1),n.sub(1)),o,a)).toVar();return NB(h)})).setLayout({name:"mx_perlin_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"}]}),Rp((([e])=>{const t=jp(e).toVar(),s=Op().toVar(),i=Op().toVar(),r=Op().toVar(),n=Up(gB(t.x,s)).toVar(),o=Up(gB(t.y,i)).toVar(),a=Up(gB(t.z,r)).toVar(),h=Up(IB(n)).toVar(),u=Up(IB(o)).toVar(),l=Up(IB(a)).toVar(),c=Up(yB(vB(PB(s,i,r),n,o,a),vB(PB(s.add(Op(1)),i,r),n.sub(1),o,a),vB(PB(s,i.add(Op(1)),r),n,o.sub(1),a),vB(PB(s.add(Op(1)),i.add(Op(1)),r),n.sub(1),o.sub(1),a),vB(PB(s,i,r.add(Op(1))),n,o,a.sub(1)),vB(PB(s.add(Op(1)),i,r.add(Op(1))),n.sub(1),o,a.sub(1)),vB(PB(s,i.add(Op(1)),r.add(Op(1))),n,o.sub(1),a.sub(1)),vB(PB(s.add(Op(1)),i.add(Op(1)),r.add(Op(1))),n.sub(1),o.sub(1),a.sub(1)),h,u,l)).toVar();return AB(c)})).setLayout({name:"mx_perlin_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"}]})]),UB=RM([Rp((([e])=>{const t=Dp(e).toVar(),s=Op().toVar(),i=Op().toVar(),r=Up(gB(t.x,s)).toVar(),n=Up(gB(t.y,i)).toVar(),o=Up(IB(r)).toVar(),a=Up(IB(n)).toVar(),h=jp(fB(wB(FB(s,i),r,n),wB(FB(s.add(Op(1)),i),r.sub(1),n),wB(FB(s,i.add(Op(1))),r,n.sub(1)),wB(FB(s.add(Op(1)),i.add(Op(1))),r.sub(1),n.sub(1)),o,a)).toVar();return NB(h)})).setLayout({name:"mx_perlin_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),Rp((([e])=>{const t=jp(e).toVar(),s=Op().toVar(),i=Op().toVar(),r=Op().toVar(),n=Up(gB(t.x,s)).toVar(),o=Up(gB(t.y,i)).toVar(),a=Up(gB(t.z,r)).toVar(),h=Up(IB(n)).toVar(),u=Up(IB(o)).toVar(),l=Up(IB(a)).toVar(),c=jp(yB(wB(FB(s,i,r),n,o,a),wB(FB(s.add(Op(1)),i,r),n.sub(1),o,a),wB(FB(s,i.add(Op(1)),r),n,o.sub(1),a),wB(FB(s.add(Op(1)),i.add(Op(1)),r),n.sub(1),o.sub(1),a),wB(FB(s,i,r.add(Op(1))),n,o,a.sub(1)),wB(FB(s.add(Op(1)),i,r.add(Op(1))),n.sub(1),o,a.sub(1)),wB(FB(s,i.add(Op(1)),r.add(Op(1))),n,o.sub(1),a.sub(1)),wB(FB(s.add(Op(1)),i.add(Op(1)),r.add(Op(1))),n.sub(1),o.sub(1),a.sub(1)),h,u,l)).toVar();return AB(c)})).setLayout({name:"mx_perlin_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"}]})]),OB=RM([Rp((([e])=>{const t=Up(e).toVar(),s=Op(mB(t)).toVar();return BB(PB(s))})).setLayout({name:"mx_cell_noise_float_0",type:"float",inputs:[{name:"p",type:"float"}]}),Rp((([e])=>{const t=Dp(e).toVar(),s=Op(mB(t.x)).toVar(),i=Op(mB(t.y)).toVar();return BB(PB(s,i))})).setLayout({name:"mx_cell_noise_float_1",type:"float",inputs:[{name:"p",type:"vec2"}]}),Rp((([e])=>{const t=jp(e).toVar(),s=Op(mB(t.x)).toVar(),i=Op(mB(t.y)).toVar(),r=Op(mB(t.z)).toVar();return BB(PB(s,i,r))})).setLayout({name:"mx_cell_noise_float_2",type:"float",inputs:[{name:"p",type:"vec3"}]}),Rp((([e])=>{const t=Xp(e).toVar(),s=Op(mB(t.x)).toVar(),i=Op(mB(t.y)).toVar(),r=Op(mB(t.z)).toVar(),n=Op(mB(t.w)).toVar();return BB(PB(s,i,r,n))})).setLayout({name:"mx_cell_noise_float_3",type:"float",inputs:[{name:"p",type:"vec4"}]})]),LB=RM([Rp((([e])=>{const t=Up(e).toVar(),s=Op(mB(t)).toVar();return jp(BB(PB(s,Op(0))),BB(PB(s,Op(1))),BB(PB(s,Op(2))))})).setLayout({name:"mx_cell_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"float"}]}),Rp((([e])=>{const t=Dp(e).toVar(),s=Op(mB(t.x)).toVar(),i=Op(mB(t.y)).toVar();return jp(BB(PB(s,i,Op(0))),BB(PB(s,i,Op(1))),BB(PB(s,i,Op(2))))})).setLayout({name:"mx_cell_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),Rp((([e])=>{const t=jp(e).toVar(),s=Op(mB(t.x)).toVar(),i=Op(mB(t.y)).toVar(),r=Op(mB(t.z)).toVar();return jp(BB(PB(s,i,r,Op(0))),BB(PB(s,i,r,Op(1))),BB(PB(s,i,r,Op(2))))})).setLayout({name:"mx_cell_noise_vec3_2",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),Rp((([e])=>{const t=Xp(e).toVar(),s=Op(mB(t.x)).toVar(),i=Op(mB(t.y)).toVar(),r=Op(mB(t.z)).toVar(),n=Op(mB(t.w)).toVar();return jp(BB(PB(s,i,r,n,Op(0))),BB(PB(s,i,r,n,Op(1))),BB(PB(s,i,r,n,Op(2))))})).setLayout({name:"mx_cell_noise_vec3_3",type:"vec3",inputs:[{name:"p",type:"vec4"}]})]),VB=Rp((([e,t,s,i])=>{const r=Up(i).toVar(),n=Up(s).toVar(),o=Op(t).toVar(),a=jp(e).toVar(),h=Up(0).toVar(),u=Up(1).toVar();return bv(o,(()=>{h.addAssign(u.mul(zB(a))),u.mulAssign(r),a.mulAssign(n)})),h})).setLayout({name:"mx_fractal_noise_float",type:"float",inputs:[{name:"p",type:"vec3"},{name:"octaves",type:"int"},{name:"lacunarity",type:"float"},{name:"diminish",type:"float"}]}),DB=Rp((([e,t,s,i])=>{const r=Up(i).toVar(),n=Up(s).toVar(),o=Op(t).toVar(),a=jp(e).toVar(),h=jp(0).toVar(),u=Up(1).toVar();return bv(o,(()=>{h.addAssign(u.mul(UB(a))),u.mulAssign(r),a.mulAssign(n)})),h})).setLayout({name:"mx_fractal_noise_vec3",type:"vec3",inputs:[{name:"p",type:"vec3"},{name:"octaves",type:"int"},{name:"lacunarity",type:"float"},{name:"diminish",type:"float"}]}),kB=Rp((([e,t,s,i])=>{const r=Up(i).toVar(),n=Up(s).toVar(),o=Op(t).toVar(),a=jp(e).toVar();return Dp(VB(a,o,n,r),VB(a.add(jp(Op(19),Op(193),Op(17))),o,n,r))})).setLayout({name:"mx_fractal_noise_vec2",type:"vec2",inputs:[{name:"p",type:"vec3"},{name:"octaves",type:"int"},{name:"lacunarity",type:"float"},{name:"diminish",type:"float"}]}),GB=Rp((([e,t,s,i])=>{const r=Up(i).toVar(),n=Up(s).toVar(),o=Op(t).toVar(),a=jp(e).toVar(),h=jp(DB(a,o,n,r)).toVar(),u=Up(VB(a.add(jp(Op(19),Op(193),Op(17))),o,n,r)).toVar();return Xp(h,u)})).setLayout({name:"mx_fractal_noise_vec4",type:"vec4",inputs:[{name:"p",type:"vec3"},{name:"octaves",type:"int"},{name:"lacunarity",type:"float"},{name:"diminish",type:"float"}]}),WB=Rp((([e,t,s,i,r,n,o])=>{const a=Op(o).toVar(),h=Up(n).toVar(),u=Op(r).toVar(),l=Op(i).toVar(),c=Op(s).toVar(),d=Op(t).toVar(),p=Dp(e).toVar(),m=jp(LB(Dp(d.add(l),c.add(u)))).toVar(),g=Dp(m.x,m.y).toVar();g.subAssign(.5),g.mulAssign(h),g.addAssign(.5);const f=Dp(Dp(Up(d),Up(c)).add(g)).toVar(),y=Dp(f.sub(p)).toVar();return Pp(a.equal(Op(2)),(()=>jg(y.x).add(jg(y.y)))),Pp(a.equal(Op(3)),(()=>of(jg(y.x),jg(y.y)))),df(y,y)})).setLayout({name:"mx_worley_distance_0",type:"float",inputs:[{name:"p",type:"vec2"},{name:"x",type:"int"},{name:"y",type:"int"},{name:"xoff",type:"int"},{name:"yoff",type:"int"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),jB=RM([WB,Rp((([e,t,s,i,r,n,o,a,h])=>{const u=Op(h).toVar(),l=Up(a).toVar(),c=Op(o).toVar(),d=Op(n).toVar(),p=Op(r).toVar(),m=Op(i).toVar(),g=Op(s).toVar(),f=Op(t).toVar(),y=jp(e).toVar(),x=jp(LB(jp(f.add(p),g.add(d),m.add(c)))).toVar();x.subAssign(.5),x.mulAssign(l),x.addAssign(.5);const b=jp(jp(Up(f),Up(g),Up(m)).add(x)).toVar(),v=jp(b.sub(y)).toVar();return Pp(u.equal(Op(2)),(()=>jg(v.x).add(jg(v.y)).add(jg(v.z)))),Pp(u.equal(Op(3)),(()=>of(of(jg(v.x),jg(v.y)),jg(v.z)))),df(v,v)})).setLayout({name:"mx_worley_distance_1",type:"float",inputs:[{name:"p",type:"vec3"},{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"},{name:"xoff",type:"int"},{name:"yoff",type:"int"},{name:"zoff",type:"int"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),HB=Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Up(t).toVar(),n=Dp(e).toVar(),o=Op().toVar(),a=Op().toVar(),h=Dp(gB(n.x,o),gB(n.y,a)).toVar(),u=Up(1e6).toVar();return bv({start:-1,end:Op(1),name:"x",condition:"<="},(({x:e})=>{bv({start:-1,end:Op(1),name:"y",condition:"<="},(({y:t})=>{const s=Up(jB(h,e,t,o,a,r,i)).toVar();u.assign(nf(u,s))}))})),Pp(i.equal(Op(0)),(()=>{u.assign(Ig(u))})),u})).setLayout({name:"mx_worley_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),qB=Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Up(t).toVar(),n=Dp(e).toVar(),o=Op().toVar(),a=Op().toVar(),h=Dp(gB(n.x,o),gB(n.y,a)).toVar(),u=Dp(1e6,1e6).toVar();return bv({start:-1,end:Op(1),name:"x",condition:"<="},(({x:e})=>{bv({start:-1,end:Op(1),name:"y",condition:"<="},(({y:t})=>{const s=Up(jB(h,e,t,o,a,r,i)).toVar();Pp(s.lessThan(u.x),(()=>{u.y.assign(u.x),u.x.assign(s)})).ElseIf(s.lessThan(u.y),(()=>{u.y.assign(s)}))}))})),Pp(i.equal(Op(0)),(()=>{u.assign(Ig(u))})),u})).setLayout({name:"mx_worley_noise_vec2_0",type:"vec2",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),$B=Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Up(t).toVar(),n=Dp(e).toVar(),o=Op().toVar(),a=Op().toVar(),h=Dp(gB(n.x,o),gB(n.y,a)).toVar(),u=jp(1e6,1e6,1e6).toVar();return bv({start:-1,end:Op(1),name:"x",condition:"<="},(({x:e})=>{bv({start:-1,end:Op(1),name:"y",condition:"<="},(({y:t})=>{const s=Up(jB(h,e,t,o,a,r,i)).toVar();Pp(s.lessThan(u.x),(()=>{u.z.assign(u.y),u.y.assign(u.x),u.x.assign(s)})).ElseIf(s.lessThan(u.y),(()=>{u.z.assign(u.y),u.y.assign(s)})).ElseIf(s.lessThan(u.z),(()=>{u.z.assign(s)}))}))})),Pp(i.equal(Op(0)),(()=>{u.assign(Ig(u))})),u})).setLayout({name:"mx_worley_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),XB=RM([HB,Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Up(t).toVar(),n=jp(e).toVar(),o=Op().toVar(),a=Op().toVar(),h=Op().toVar(),u=jp(gB(n.x,o),gB(n.y,a),gB(n.z,h)).toVar(),l=Up(1e6).toVar();return bv({start:-1,end:Op(1),name:"x",condition:"<="},(({x:e})=>{bv({start:-1,end:Op(1),name:"y",condition:"<="},(({y:t})=>{bv({start:-1,end:Op(1),name:"z",condition:"<="},(({z:s})=>{const n=Up(jB(u,e,t,s,o,a,h,r,i)).toVar();l.assign(nf(l,n))}))}))})),Pp(i.equal(Op(0)),(()=>{l.assign(Ig(l))})),l})).setLayout({name:"mx_worley_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),YB=RM([qB,Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Up(t).toVar(),n=jp(e).toVar(),o=Op().toVar(),a=Op().toVar(),h=Op().toVar(),u=jp(gB(n.x,o),gB(n.y,a),gB(n.z,h)).toVar(),l=Dp(1e6,1e6).toVar();return bv({start:-1,end:Op(1),name:"x",condition:"<="},(({x:e})=>{bv({start:-1,end:Op(1),name:"y",condition:"<="},(({y:t})=>{bv({start:-1,end:Op(1),name:"z",condition:"<="},(({z:s})=>{const n=Up(jB(u,e,t,s,o,a,h,r,i)).toVar();Pp(n.lessThan(l.x),(()=>{l.y.assign(l.x),l.x.assign(n)})).ElseIf(n.lessThan(l.y),(()=>{l.y.assign(n)}))}))}))})),Pp(i.equal(Op(0)),(()=>{l.assign(Ig(l))})),l})).setLayout({name:"mx_worley_noise_vec2_1",type:"vec2",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),ZB=RM([$B,Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Up(t).toVar(),n=jp(e).toVar(),o=Op().toVar(),a=Op().toVar(),h=Op().toVar(),u=jp(gB(n.x,o),gB(n.y,a),gB(n.z,h)).toVar(),l=jp(1e6,1e6,1e6).toVar();return bv({start:-1,end:Op(1),name:"x",condition:"<="},(({x:e})=>{bv({start:-1,end:Op(1),name:"y",condition:"<="},(({y:t})=>{bv({start:-1,end:Op(1),name:"z",condition:"<="},(({z:s})=>{const n=Up(jB(u,e,t,s,o,a,h,r,i)).toVar();Pp(n.lessThan(l.x),(()=>{l.z.assign(l.y),l.y.assign(l.x),l.x.assign(n)})).ElseIf(n.lessThan(l.y),(()=>{l.z.assign(l.y),l.y.assign(n)})).ElseIf(n.lessThan(l.z),(()=>{l.z.assign(n)}))}))}))})),Pp(i.equal(Op(0)),(()=>{l.assign(Ig(l))})),l})).setLayout({name:"mx_worley_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),JB=Rp((([e])=>{const t=e.y,s=e.z,i=jp().toVar();return Pp(t.lessThan(1e-4),(()=>{i.assign(jp(s,s,s))})).Else((()=>{let r=e.x;r=r.sub(Fg(r)).mul(6).toVar();const n=Op(Qg(r)),o=r.sub(Up(n)),a=s.mul(t.oneMinus()),h=s.mul(t.mul(o).oneMinus()),u=s.mul(t.mul(o.oneMinus()).oneMinus());Pp(n.equal(Op(0)),(()=>{i.assign(jp(s,u,a))})).ElseIf(n.equal(Op(1)),(()=>{i.assign(jp(h,s,a))})).ElseIf(n.equal(Op(2)),(()=>{i.assign(jp(a,s,u))})).ElseIf(n.equal(Op(3)),(()=>{i.assign(jp(a,h,s))})).ElseIf(n.equal(Op(4)),(()=>{i.assign(jp(u,a,s))})).Else((()=>{i.assign(jp(s,a,h))}))})),i})).setLayout({name:"mx_hsvtorgb",type:"vec3",inputs:[{name:"hsv",type:"vec3"}]}),KB=Rp((([e])=>{const t=jp(e).toVar(),s=Up(t.x).toVar(),i=Up(t.y).toVar(),r=Up(t.z).toVar(),n=Up(nf(s,nf(i,r))).toVar(),o=Up(of(s,of(i,r))).toVar(),a=Up(o.sub(n)).toVar(),h=Up().toVar(),u=Up().toVar(),l=Up().toVar();return l.assign(o),Pp(o.greaterThan(0),(()=>{u.assign(a.div(o))})).Else((()=>{u.assign(0)})),Pp(u.lessThanEqual(0),(()=>{h.assign(0)})).Else((()=>{Pp(s.greaterThanEqual(o),(()=>{h.assign(i.sub(r).div(a))})).ElseIf(i.greaterThanEqual(o),(()=>{h.assign(Zm(2,r.sub(s).div(a)))})).Else((()=>{h.assign(Zm(4,s.sub(i).div(a)))})),h.mulAssign(1/6),Pp(h.lessThan(0),(()=>{h.addAssign(1)}))})),jp(h,u,l)})).setLayout({name:"mx_rgbtohsv",type:"vec3",inputs:[{name:"c",type:"vec3"}]}),QB=Rp((([e])=>{const t=jp(e).toVar(),s=$p(rg(t,jp(.04045))).toVar(),i=jp(t.div(12.92)).toVar(),r=jp(mf(of(t.add(jp(.055)),jp(0)).div(1.055),jp(2.4))).toVar();return Tf(i,r,s)})).setLayout({name:"mx_srgb_texture_to_lin_rec709",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),eI=(e,t)=>{e=Up(e),t=Up(t);const s=Dp(t.dFdx(),t.dFdy()).length().mul(.7071067811865476);return Mf(e.sub(s),e.add(s),t)},tI=(e,t,s,i)=>Tf(e,t,s[i].clamp()),sI=(e,t,s=My())=>tI(e,t,s,"x"),iI=(e,t,s=My())=>tI(e,t,s,"y"),rI=(e,t,s,i,r)=>Tf(e,t,eI(s,i[r])),nI=(e,t,s,i=My())=>rI(e,t,s,i,"x"),oI=(e,t,s,i=My())=>rI(e,t,s,i,"y"),aI=(e=1,t=0,s=My())=>s.mul(e).add(t),hI=(e,t=1)=>(e=Up(e)).abs().pow(t).mul(e.sign()),uI=(e,t=1,s=.5)=>Up(e).sub(s).mul(t).add(s),lI=(e=My(),t=1,s=0)=>zB(e.convert("vec2|vec3")).mul(t).add(s),cI=(e=My(),t=1,s=0)=>UB(e.convert("vec2|vec3")).mul(t).add(s),dI=(e=My(),t=1,s=0)=>{e=e.convert("vec2|vec3");return Xp(UB(e),zB(e.add(Dp(19,73)))).mul(t).add(s)},pI=(e=My(),t=1)=>XB(e.convert("vec2|vec3"),t,Op(1)),mI=(e=My(),t=1)=>YB(e.convert("vec2|vec3"),t,Op(1)),gI=(e=My(),t=1)=>ZB(e.convert("vec2|vec3"),t,Op(1)),fI=(e=My())=>OB(e.convert("vec2|vec3")),yI=(e=My(),t=3,s=2,i=.5,r=1)=>VB(e,Op(t),s,i).mul(r),xI=(e=My(),t=3,s=2,i=.5,r=1)=>kB(e,Op(t),s,i).mul(r),bI=(e=My(),t=3,s=2,i=.5,r=1)=>DB(e,Op(t),s,i).mul(r),vI=(e=My(),t=3,s=2,i=.5,r=1)=>GB(e,Op(t),s,i).mul(r),TI=Rp((([e,t])=>{const s=e.x,i=e.y,r=e.z;let n=t.element(0).mul(.886227);return n=n.add(t.element(1).mul(1.023328).mul(i)),n=n.add(t.element(2).mul(1.023328).mul(r)),n=n.add(t.element(3).mul(1.023328).mul(s)),n=n.add(t.element(4).mul(.858086).mul(s).mul(i)),n=n.add(t.element(5).mul(.858086).mul(i).mul(r)),n=n.add(t.element(6).mul(r.mul(r).mul(.743125).sub(.247708))),n=n.add(t.element(7).mul(.858086).mul(s).mul(r)),n=n.add(t.element(8).mul(.429043).mul(Km(s,s).sub(Km(i,i)))),n}));class _I extends JR{static get type(){return"PointLightNode"}constructor(e=null){super(e),this.cutoffDistanceNode=pm(0).setGroup(lm),this.decayExponentNode=pm(0).setGroup(lm)}update(e){const{light:t}=this;super.update(e),this.cutoffDistanceNode.value=t.distance,this.decayExponentNode.value=t.decay}setup(e){const{colorNode:t,cutoffDistanceNode:s,decayExponentNode:i,light:r}=this,n=e.context.lightingModel,o=iE(r).sub(cx),a=o.normalize(),h=o.length(),u=KR({lightDistance:h,cutoffDistance:s,decayExponent:i}),l=t.mul(u),c=e.context.reflectedLight;n.direct({lightDirection:a,lightColor:l,reflectedLight:c},e.stack,e)}}class wI extends JR{static get type(){return"DirectionalLightNode"}constructor(e=null){super(e)}setup(e){super.setup(e);const t=e.context.lightingModel,s=this.colorNode,i=rE(this.light),r=e.context.reflectedLight;t.direct({lightDirection:i,lightColor:s,reflectedLight:r},e.stack,e)}}const SI=new nr,MI=new nr;let NI=null;class AI extends JR{static get type(){return"RectAreaLightNode"}constructor(e=null){super(e),this.halfHeight=pm(new Ri).setGroup(lm),this.halfWidth=pm(new Ri).setGroup(lm)}update(e){super.update(e);const{light:t}=this,s=e.camera.matrixWorldInverse;MI.identity(),SI.copy(t.matrixWorld),SI.premultiply(s),MI.extractRotation(SI),this.halfWidth.value.set(.5*t.width,0,0),this.halfHeight.value.set(0,.5*t.height,0),this.halfWidth.value.applyMatrix4(MI),this.halfHeight.value.applyMatrix4(MI)}setup(e){let t,s;super.setup(e),e.isAvailable("float32Filterable")?(t=By(NI.LTC_FLOAT_1),s=By(NI.LTC_FLOAT_2)):(t=By(NI.LTC_HALF_1),s=By(NI.LTC_HALF_2));const{colorNode:i,light:r}=this,n=e.context.lightingModel,o=iE(r),a=e.context.reflectedLight;n.directRectArea({lightColor:i,lightPosition:o,halfWidth:this.halfWidth,halfHeight:this.halfHeight,reflectedLight:a,ltc_1:t,ltc_2:s},e.stack,e)}static setLTC(e){NI=e}}class CI extends JR{static get type(){return"SpotLightNode"}constructor(e=null){super(e),this.coneCosNode=pm(0).setGroup(lm),this.penumbraCosNode=pm(0).setGroup(lm),this.cutoffDistanceNode=pm(0).setGroup(lm),this.decayExponentNode=pm(0).setGroup(lm)}update(e){super.update(e);const{light:t}=this;this.coneCosNode.value=Math.cos(t.angle),this.penumbraCosNode.value=Math.cos(t.angle*(1-t.penumbra)),this.cutoffDistanceNode.value=t.distance,this.decayExponentNode.value=t.decay}getSpotAttenuation(e){const{coneCosNode:t,penumbraCosNode:s}=this;return Mf(t,s,e)}setup(e){super.setup(e);const t=e.context.lightingModel,{colorNode:s,cutoffDistanceNode:i,decayExponentNode:r,light:n}=this,o=iE(n).sub(cx),a=o.normalize(),h=a.dot(rE(n)),u=this.getSpotAttenuation(h),l=o.length(),c=KR({lightDistance:l,cutoffDistance:i,decayExponent:r}),d=s.mul(u).mul(c),p=e.context.reflectedLight;t.direct({lightDirection:a,lightColor:d,reflectedLight:p},e.stack,e)}}class RI extends CI{static get type(){return"IESSpotLightNode"}getSpotAttenuation(e){const t=this.light.iesMap;let s=null;if(t&&!0===t.isTexture){const i=e.acos().mul(1/Math.PI);s=By(t,Dp(i,0),0).r}else s=super.getSpotAttenuation(e);return s}}class EI extends JR{static get type(){return"AmbientLightNode"}constructor(e=null){super(e)}setup({context:e}){e.irradiance.addAssign(this.colorNode)}}class BI extends JR{static get type(){return"HemisphereLightNode"}constructor(e=null){super(e),this.lightPositionNode=tE(e),this.lightDirectionNode=this.lightPositionNode.normalize(),this.groundColorNode=pm(new Jr).setGroup(lm)}update(e){const{light:t}=this;super.update(e),this.lightPositionNode.object3d=t,this.groundColorNode.value.copy(t.groundColor).multiplyScalar(t.intensity)}setup(e){const{colorNode:t,groundColorNode:s,lightDirectionNode:i}=this,r=bx.dot(i).mul(.5).add(.5),n=Tf(s,t,r);e.context.irradiance.addAssign(n)}}class II extends JR{static get type(){return"LightProbeNode"}constructor(e=null){super(e);const t=[];for(let e=0;e<9;e++)t.push(new Ri);this.lightProbe=Ox(t)}update(e){const{light:t}=this;super.update(e);for(let e=0;e<9;e++)this.lightProbe.array[e].copy(t.sh.coefficients[e]).multiplyScalar(t.intensity)}setup(e){const t=TI(vx,this.lightProbe);e.context.irradiance.addAssign(t)}}class PI{parseFunction(){console.warn("Abstract function.")}}class FI{constructor(e,t,s="",i=""){this.type=e,this.inputs=t,this.name=s,this.precision=i}getCode(){console.warn("Abstract function.")}}FI.isNodeFunction=!0;const zI=/^\s*(highp|mediump|lowp)?\s*([a-z_0-9]+)\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)/i,UI=/[a-z_0-9]+/gi,OI="#pragma main";class LI extends FI{constructor(e){const{type:t,inputs:s,name:i,precision:r,inputsCode:n,blockCode:o,headerCode:a}=(e=>{const t=(e=e.trim()).indexOf(OI),s=-1!==t?e.slice(t+12):e,i=s.match(zI);if(null!==i&&5===i.length){const r=i[4],n=[];let o=null;for(;null!==(o=UI.exec(r));)n.push(o);const a=[];let h=0;for(;h0?this.transparent:this.opaque).push(o)}unshift(e,t,s,i,r,n){const o=this.getNextRenderItem(e,t,s,i,r,n);(!0===s.transparent?this.transparent:this.opaque).unshift(o)}pushBundle(e){this.bundles.push(e)}pushLight(e){this.lightsArray.push(e)}getLightsNode(){return this.lightsNode.fromLights(this.lightsArray)}sort(e,t){this.opaque.length>1&&this.opaque.sort(e||DI),this.transparent.length>1&&this.transparent.sort(t||kI)}finish(){this.lightsNode.setLights(this.lightsArray);for(let e=this.renderItemsIndex,t=this.renderItems.length;e>t,h=o.height>>t;let u=e.depthTexture||r[t],l=!1;void 0===u&&(u=new Ya,u.format=e.stencilBuffer?je:We,u.type=e.stencilBuffer?Ue:Be,u.image.width=a,u.image.height=h,r[t]=u),s.width===o.width&&o.height===s.height||(l=!0,u.needsUpdate=!0,u.image.width=a,u.image.height=h),s.width=o.width,s.height=o.height,s.textures=n,s.depthTexture=u,s.depth=e.depthBuffer,s.stencil=e.stencilBuffer,s.renderTarget=e,s.sampleCount!==i&&(l=!0,u.needsUpdate=!0,s.sampleCount=i);const c={sampleCount:i};for(let e=0;e{e.removeEventListener("dispose",t);for(let e=0;e0){const i=e.image;if(void 0===i)console.warn("THREE.Renderer: Texture marked for update but image is undefined.");else if(!1===i.complete)console.warn("THREE.Renderer: Texture marked for update but image is incomplete.");else{if(e.images){const s=[];for(const t of e.images)s.push(t);t.images=s}else t.image=i;void 0!==s.isDefaultTexture&&!0!==s.isDefaultTexture||(r.createTexture(e,t),s.isDefaultTexture=!1,s.generation=e.version),!0===e.source.dataReady&&r.updateTexture(e,t),t.needsMipmaps&&0===e.mipmaps.length&&r.generateMipmaps(e)}}else r.createDefaultTexture(e),s.isDefaultTexture=!0,s.generation=e.version}if(!0!==s.initialized){s.initialized=!0,s.generation=e.version,this.info.memory.textures++;const t=()=>{e.removeEventListener("dispose",t),this._destroyTexture(e),this.info.memory.textures--};e.addEventListener("dispose",t)}s.version=e.version}getSize(e,t=XI){let s=e.images?e.images[0]:e.image;return s?(void 0!==s.image&&(s=s.image),t.width=s.width,t.height=s.height,t.depth=e.isCubeTexture?6:s.depth||1):t.width=t.height=t.depth=1,t}getMipLevels(e,t,s){let i;return i=e.isCompressedTexture?e.mipmaps.length:Math.floor(Math.log2(Math.max(t,s)))+1,i}needsMipmaps(e){return!!this.isEnvironmentTexture(e)||(!0===e.isCompressedTexture||e.minFilter!==fe&&e.minFilter!==Te)}isEnvironmentTexture(e){const t=e.mapping;return t===le||t===ce||t===he||t===ue}_destroyTexture(e){this.backend.destroySampler(e),this.backend.destroyTexture(e),this.delete(e)}}class ZI extends Jr{constructor(e,t,s,i=1){super(e,t,s),this.a=i}set(e,t,s,i=1){return this.a=i,super.set(e,t,s)}copy(e){return void 0!==e.a&&(this.a=e.a),super.copy(e)}clone(){return new this.constructor(this.r,this.g,this.b,this.a)}}const JI=new ZI;class KI extends Xw{constructor(e,t){super(),this.renderer=e,this.nodes=t}update(e,t,s){const i=this.renderer,r=this.nodes.getBackgroundNode(e)||e.background;let n=!1;if(null===r)i._clearColor.getRGB(JI,Jt),JI.a=i._clearColor.a;else if(!0===r.isColor)r.getRGB(JI,Jt),JI.a=1,n=!0;else if(!0===r.isNode){const s=this.get(e),n=r;JI.copy(i._clearColor);let o=s.backgroundMesh;if(void 0===o){const e=Ff(Xp(n).mul(wN),{getUV:()=>vx,getTextureLevel:()=>_N});let t=sv();t=t.setZ(t.w);const i=new pT;i.name="Background.material",i.side=d,i.depthTest=!1,i.depthWrite=!1,i.fog=!1,i.lights=!1,i.vertexNode=t,i.colorNode=e,s.backgroundMeshNode=e,s.backgroundMesh=o=new Vn(new du(1,32,32),i),o.frustumCulled=!1,o.name="Background.mesh",o.onBeforeRender=function(e,t,s){this.matrixWorld.copyPosition(s.matrixWorld)}}const a=n.getCacheKey();s.backgroundCacheKey!==a&&(s.backgroundMeshNode.node=Xp(n).mul(wN),s.backgroundMeshNode.needsUpdate=!0,o.material.needsUpdate=!0,s.backgroundCacheKey=a),t.unshift(o,o.geometry,o.material,0,0,null)}else console.error("THREE.Renderer: Unsupported background configuration.",r);if(!0===i.autoClear||!0===n){JI.multiplyScalar(JI.a);const e=s.clearColorValue;e.r=JI.r,e.g=JI.g,e.b=JI.b,e.a=JI.a,s.depthClearValue=i._clearDepth,s.stencilClearValue=i._clearStencil,s.clearColor=!0===i.autoClearColor,s.clearDepth=!0===i.autoClearDepth,s.clearStencil=!0===i.autoClearStencil}else s.clearColor=!1,s.clearDepth=!1,s.clearStencil=!1}}class QI{constructor(e,t,s,i,r,n,o,a,h,u=[]){this.vertexShader=e,this.fragmentShader=t,this.computeShader=s,this.transforms=u,this.nodeAttributes=i,this.bindings=r,this.updateNodes=n,this.updateBeforeNodes=o,this.updateAfterNodes=a,this.monitor=h,this.usedTimes=0}createBindings(){const e=[];for(const t of this.bindings){if(!0!==t.bindings[0].groupNode.shared){const s=new pM(t.name,[],t.index,t);e.push(s);for(const e of t.bindings)s.bindings.push(e.clone())}else e.push(t)}return e}}const eP=new WeakMap;class tP extends Xw{constructor(e,t){super(),this.renderer=e,this.backend=t,this.nodeFrame=new bM,this.nodeBuilderCache=new Map,this.callHashCache=new kw,this.groupsData=new kw}updateGroup(e){const t=e.groupNode,s=t.name;if(s===cm.name)return!0;if(s===lm.name){const t=this.get(e),s=this.nodeFrame.renderId;return t.renderId!==s&&(t.renderId=s,!0)}if(s===um.name){const t=this.get(e),s=this.nodeFrame.frameId;return t.frameId!==s&&(t.frameId=s,!0)}const i=[t,e];let r=this.groupsData.get(i);return void 0===r&&this.groupsData.set(i,r={}),r.version!==t.version&&(r.version=t.version,!0)}getForRenderCacheKey(e){return e.initialCacheKey}getForRender(e){const t=this.get(e);let s=t.nodeBuilderState;if(void 0===s){const{nodeBuilderCache:i}=this,r=this.getForRenderCacheKey(e);if(s=i.get(r),void 0===s){const t=this.backend.createNodeBuilder(e.object,this.renderer);t.scene=e.scene,t.material=e.material,t.camera=e.camera,t.context.material=e.material,t.lightsNode=e.lightsNode,t.environmentNode=this.getEnvironmentNode(e.scene),t.fogNode=this.getFogNode(e.scene),t.clippingContext=e.clippingContext,t.build(),s=this._createNodeBuilderState(t),i.set(r,s)}s.usedTimes++,t.nodeBuilderState=s}return s}delete(e){if(e.isRenderObject){const t=this.get(e).nodeBuilderState;t.usedTimes--,0===t.usedTimes&&this.nodeBuilderCache.delete(this.getForRenderCacheKey(e))}return super.delete(e)}getForCompute(e){const t=this.get(e);let s=t.nodeBuilderState;if(void 0===s){const i=this.backend.createNodeBuilder(e,this.renderer);i.build(),s=this._createNodeBuilderState(i),t.nodeBuilderState=s}return s}_createNodeBuilderState(e){return new QI(e.vertexShader,e.fragmentShader,e.computeShader,e.getAttributesArray(),e.getBindings(),e.updateNodes,e.updateBeforeNodes,e.updateAfterNodes,e.monitor,e.transforms)}getEnvironmentNode(e){return e.environmentNode||this.get(e).environmentNode||null}getBackgroundNode(e){return e.backgroundNode||this.get(e).backgroundNode||null}getFogNode(e){return e.fogNode||this.get(e).fogNode||null}getCacheKey(e,t){const s=[e,t],i=this.renderer.info.calls;let r=this.callHashCache.get(s);if(void 0===r||r.callId!==i){const n=this.getEnvironmentNode(e),o=this.getFogNode(e),a=[];t&&a.push(t.getCacheKey(!0)),n&&a.push(n.getCacheKey()),o&&a.push(o.getCacheKey()),a.push(this.renderer.shadowMap.enabled?1:0),r={callId:i,cacheKey:Td(a)},this.callHashCache.set(s,r)}return r.cacheKey}updateScene(e){this.updateEnvironment(e),this.updateFog(e),this.updateBackground(e)}get isToneMappingState(){return!this.renderer.getRenderTarget()}updateBackground(e){const t=this.get(e),s=e.background;if(s){const i=0===e.backgroundBlurriness&&t.backgroundBlurriness>0||e.backgroundBlurriness>0&&0===t.backgroundBlurriness;if(t.background!==s||i){let i=null;if(!0===s.isCubeTexture||s.mapping===le||s.mapping===ce||s.mapping===de)if(e.backgroundBlurriness>0||s.mapping===de)i=hw(s,vx);else{let e;e=!0===s.isCubeTexture?Ix(s):By(s),i=PT(e)}else!0===s.isTexture?i=By(s,Dv.flipY()).setUpdateMatrix(!0):!0!==s.isColor&&console.error("WebGPUNodes: Unsupported background configuration.",s);t.backgroundNode=i,t.background=s,t.backgroundBlurriness=e.backgroundBlurriness}}else t.backgroundNode&&(delete t.backgroundNode,delete t.background)}updateFog(e){const t=this.get(e),s=e.fog;if(s){if(t.fog!==s){let e=null;if(s.isFogExp2){const t=kx("color","color",s).setGroup(lm),i=kx("density","float",s).setGroup(lm);e=OR(t,i)}else if(s.isFog){const t=kx("color","color",s).setGroup(lm),i=kx("near","float",s).setGroup(lm),r=kx("far","float",s).setGroup(lm);e=zR(t,i,r)}else console.error("WebGPUNodes: Unsupported fog configuration.",s);t.fogNode=e,t.fog=s}}else delete t.fogNode,delete t.fog}updateEnvironment(e){const t=this.get(e),s=e.environment;if(s){if(t.environment!==s){let e=null;!0===s.isCubeTexture?e=Ix(s):!0===s.isTexture?e=By(s):console.error("Nodes: Unsupported environment configuration.",s),t.environmentNode=e,t.environment=s}}else t.environmentNode&&(delete t.environmentNode,delete t.environment)}getNodeFrame(e=this.renderer,t=null,s=null,i=null,r=null){const n=this.nodeFrame;return n.renderer=e,n.scene=t,n.object=s,n.camera=i,n.material=r,n}getNodeFrameForRender(e){return this.getNodeFrame(e.renderer,e.scene,e.object,e.camera,e.material)}getOutputCacheKey(){const e=this.renderer;return e.toneMapping+","+e.currentColorSpace}hasOutputChange(e){return eP.get(e)!==this.getOutputCacheKey()}getOutputNode(e){const t=this.renderer,s=this.getOutputCacheKey(),i=By(e,Dv).renderOutput(t.toneMapping,t.currentColorSpace);return eP.set(e,s),i}updateBefore(e){const t=e.getNodeBuilderState();for(const s of t.updateBeforeNodes)this.getNodeFrameForRender(e).updateBeforeNode(s)}updateAfter(e){const t=e.getNodeBuilderState();for(const s of t.updateAfterNodes)this.getNodeFrameForRender(e).updateAfterNode(s)}updateForCompute(e){const t=this.getNodeFrame(),s=this.getForCompute(e);for(const e of s.updateNodes)t.updateNode(e)}updateForRender(e){const t=this.getNodeFrameForRender(e),s=e.getNodeBuilderState();for(const e of s.updateNodes)t.updateNode(e)}needsRefresh(e){const t=this.getNodeFrameForRender(e);return e.getMonitor().needsRefresh(e,t)}dispose(){super.dispose(),this.nodeFrame=new bM,this.nodeBuilderCache=new Map}}class sP{constructor(e,t){this.scene=e,this.camera=t}clone(){return Object.assign(new this.constructor,this)}}class iP{constructor(){this.lists=new kw}get(e,t){const s=this.lists,i=[e,t];let r=s.get(i);return void 0===r&&(r=new sP(e,t),s.set(i,r)),r}dispose(){this.lists=new kw}}class rP{constructor(){this.lightNodes=new WeakMap,this.materialNodes=new Map,this.toneMappingNodes=new Map,this.colorSpaceNodes=new Map}fromMaterial(e){if(e.isNodeMaterial)return e;let t=null;const s=this.getMaterialNodeClass(e.type);if(null!==s){t=new s;for(const s in e)t[s]=e[s]}return t}addColorSpace(e,t){this.addType(e,t,this.colorSpaceNodes)}getColorSpaceFunction(e){return this.colorSpaceNodes.get(e)||null}addToneMapping(e,t){this.addType(e,t,this.toneMappingNodes)}getToneMappingFunction(e){return this.toneMappingNodes.get(e)||null}getMaterialNodeClass(e){return this.materialNodes.get(e)||null}addMaterial(e,t){this.addType(e,t.name,this.materialNodes)}getLightNodeClass(e){return this.lightNodes.get(e)||null}addLight(e,t){this.addClass(e,t,this.lightNodes)}addType(e,t,s){if(s.has(t))console.warn(`Redefinition of node ${t}`);else{if("function"!=typeof e)throw new Error(`Node class ${e.name} is not a class.`);if("function"==typeof t||"object"==typeof t)throw new Error(`Base class ${t} is not a class.`);s.set(t,e)}}addClass(e,t,s){if(s.has(t))console.warn(`Redefinition of node ${t.name}`);else{if("function"!=typeof e)throw new Error(`Node class ${e.name} is not a class.`);if("function"!=typeof t)throw new Error(`Base class ${t.name} is not a class.`);s.set(t,e)}}}const nP=new to,oP=new Qs,aP=new Ti,hP=new ta,uP=new nr,lP=new Ti;class cP{constructor(e,t={}){this.isRenderer=!0;const{logarithmicDepthBuffer:s=!1,alpha:i=!0,depth:r=!0,stencil:n=!1,antialias:o=!1,samples:a=0,getFallback:h=null}=t;this.domElement=e.getDomElement(),this.backend=e,this.samples=a||!0===o?4:0,this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.alpha=i,this.logarithmicDepthBuffer=s,this.outputColorSpace=Zt,this.toneMapping=0,this.toneMappingExposure=1,this.sortObjects=!0,this.depth=r,this.stencil=n,this.clippingPlanes=[],this.info=new iS,this.nodes={library:new rP,modelViewMatrix:null,modelNormalViewMatrix:null},this._getFallback=h,this._pixelRatio=1,this._width=this.domElement.width,this._height=this.domElement.height,this._viewport=new Ti(0,0,this._width,this._height),this._scissor=new Ti(0,0,this._width,this._height),this._scissorTest=!1,this._attributes=null,this._geometries=null,this._nodes=null,this._animation=null,this._bindings=null,this._objects=null,this._pipelines=null,this._bundles=null,this._renderLists=null,this._renderContexts=null,this._textures=null,this._background=null,this._quad=new dN(new pT),this._quad.material.type="Renderer_output",this._currentRenderContext=null,this._opaqueSort=null,this._transparentSort=null,this._frameBufferTarget=null;const u=!0===this.alpha?0:1;this._clearColor=new ZI(0,0,0,u),this._clearDepth=1,this._clearStencil=0,this._renderTarget=null,this._activeCubeFace=0,this._activeMipmapLevel=0,this._mrt=null,this._renderObjectFunction=null,this._currentRenderObjectFunction=null,this._currentRenderBundle=null,this._handleObjectFunction=this._renderObjectDirect,this._initialized=!1,this._initPromise=null,this._compilationPromises=null,this.transparent=!0,this.opaque=!0,this.shadowMap={enabled:!1,type:1},this.xr={enabled:!1},this.debug={checkShaderErrors:!0,onShaderError:null,getShaderAsync:async(e,t,s)=>{await this.compileAsync(e,t);const i=this._renderLists.get(e,t),r=this._renderContexts.get(e,t,this._renderTarget),n=e.overrideMaterial||s.material,o=this._objects.get(s,n,e,t,i.lightsNode,r),{fragmentShader:a,vertexShader:h}=o.getNodeBuilderState();return{fragmentShader:a,vertexShader:h}}}}async init(){if(this._initialized)throw new Error("Renderer: Backend has already been initialized.");return null!==this._initPromise||(this._initPromise=new Promise((async(e,t)=>{let s=this.backend;try{await s.init(this)}catch(e){if(null===this._getFallback)return void t(e);try{this.backend=s=this._getFallback(e),await s.init(this)}catch(e){return void t(e)}}this._nodes=new tP(this,s),this._animation=new Dw(this._nodes,this.info),this._attributes=new Qw(s),this._background=new KI(this,this._nodes),this._geometries=new sS(this._attributes,this.info),this._textures=new YI(this,s,this.info),this._pipelines=new uS(s,this._nodes),this._bindings=new lS(s,this._nodes,this._textures,this._attributes,this._pipelines,this.info),this._objects=new $w(this,this._nodes,this._geometries,this._pipelines,this._bindings,this.info),this._renderLists=new WI,this._bundles=new iP,this._renderContexts=new $I,this._initialized=!0,e()}))),this._initPromise}get coordinateSystem(){return this.backend.coordinateSystem}async compileAsync(e,t,s=null){!1===this._initialized&&await this.init();const i=this._nodes.nodeFrame,r=i.renderId,n=this._currentRenderContext,o=this._currentRenderObjectFunction,a=this._compilationPromises,h=!0===e.isScene?e:nP;null===s&&(s=e);const u=this._renderTarget,l=this._renderContexts.get(s,t,u),c=this._activeMipmapLevel,d=[];this._currentRenderContext=l,this._currentRenderObjectFunction=this.renderObject,this._handleObjectFunction=this._createObjectPipeline,this._compilationPromises=d,i.renderId++,i.update(),l.depth=this.depth,l.stencil=this.stencil,l.clippingContext||(l.clippingContext=new Ww),l.clippingContext.updateGlobal(this,t),h.onBeforeRender(this,e,t,u);const p=this._renderLists.get(e,t);if(p.begin(),this._projectObject(e,t,0,p),s!==e&&s.traverseVisible((function(e){e.isLight&&e.layers.test(t.layers)&&p.pushLight(e)})),p.finish(),null!==u){this._textures.updateRenderTarget(u,c);const e=this._textures.get(u);l.textures=e.textures,l.depthTexture=e.depthTexture}else l.textures=null,l.depthTexture=null;this._nodes.updateScene(h),this._background.update(h,p,l);const m=p.opaque,g=p.transparent,f=p.lightsNode;!0===this.opaque&&m.length>0&&this._renderObjects(m,t,h,f),!0===this.transparent&&g.length>0&&this._renderObjects(g,t,h,f),i.renderId=r,this._currentRenderContext=n,this._currentRenderObjectFunction=o,this._compilationPromises=a,this._handleObjectFunction=this._renderObjectDirect,await Promise.all(d)}async renderAsync(e,t){!1===this._initialized&&await this.init();const s=this._renderScene(e,t);await this.backend.resolveTimestampAsync(s,"render")}setMRT(e){return this._mrt=e,this}getMRT(){return this._mrt}_renderBundle(e,t,s){const{bundleGroup:i,camera:r,renderList:n}=e,o=this._currentRenderContext,a=this._bundles.get(i,r),h=this.backend.get(a);void 0===h.renderContexts&&(h.renderContexts=new Set);const u=i.version!==h.version,l=!1===h.renderContexts.has(o)||u;if(h.renderContexts.add(o),l){this.backend.beginBundle(o),(void 0===h.renderObjects||u)&&(h.renderObjects=[]),this._currentRenderBundle=a;const e=n.opaque;e.length>0&&this._renderObjects(e,r,t,s),this._currentRenderBundle=null,this.backend.finishBundle(o,a),h.version=i.version}else{const{renderObjects:e}=h;for(let t=0,s=e.length;t>=c,p.viewportValue.height>>=c,p.viewportValue.minDepth=x,p.viewportValue.maxDepth=b,p.viewport=!1===p.viewportValue.equals(aP),p.scissorValue.copy(f).multiplyScalar(y).floor(),p.scissor=this._scissorTest&&!1===p.scissorValue.equals(aP),p.scissorValue.width>>=c,p.scissorValue.height>>=c,p.clippingContext||(p.clippingContext=new Ww),p.clippingContext.updateGlobal(this,t),h.onBeforeRender(this,e,t,d),uP.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),hP.setFromProjectionMatrix(uP,m);const v=this._renderLists.get(e,t);if(v.begin(),this._projectObject(e,t,0,v),v.finish(),!0===this.sortObjects&&v.sort(this._opaqueSort,this._transparentSort),null!==d){this._textures.updateRenderTarget(d,c);const e=this._textures.get(d);p.textures=e.textures,p.depthTexture=e.depthTexture,p.width=e.width,p.height=e.height,p.renderTarget=d,p.depth=d.depthBuffer,p.stencil=d.stencilBuffer}else p.textures=null,p.depthTexture=null,p.width=this.domElement.width,p.height=this.domElement.height,p.depth=this.depth,p.stencil=this.stencil;p.width>>=c,p.height>>=c,p.activeCubeFace=l,p.activeMipmapLevel=c,p.occlusionQueryCount=v.occlusionQueryCount,this._nodes.updateScene(h),this._background.update(h,v,p),this.backend.beginRender(p);const{bundles:T,lightsNode:_,transparent:w,opaque:S}=v;if(T.length>0&&this._renderBundles(T,h,_),!0===this.opaque&&S.length>0&&this._renderObjects(S,t,h,_),!0===this.transparent&&w.length>0&&this._renderObjects(w,t,h,_),this.backend.finishRender(p),r.renderId=n,this._currentRenderContext=o,this._currentRenderObjectFunction=a,null!==i){this.setRenderTarget(u,l,c);const e=this._quad;this._nodes.hasOutputChange(d.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(d.texture),e.material.needsUpdate=!0),this._renderScene(e,e.camera,!1)}return h.onAfterRender(this,e,t,d),p}getMaxAnisotropy(){return this.backend.getMaxAnisotropy()}getActiveCubeFace(){return this._activeCubeFace}getActiveMipmapLevel(){return this._activeMipmapLevel}async setAnimationLoop(e){!1===this._initialized&&await this.init(),this._animation.setAnimationLoop(e)}async getArrayBufferAsync(e){return await this.backend.getArrayBufferAsync(e)}getContext(){return this.backend.getContext()}getPixelRatio(){return this._pixelRatio}getDrawingBufferSize(e){return e.set(this._width*this._pixelRatio,this._height*this._pixelRatio).floor()}getSize(e){return e.set(this._width,this._height)}setPixelRatio(e=1){this._pixelRatio=e,this.setSize(this._width,this._height,!1)}setDrawingBufferSize(e,t,s){this._width=e,this._height=t,this._pixelRatio=s,this.domElement.width=Math.floor(e*s),this.domElement.height=Math.floor(t*s),this.setViewport(0,0,e,t),this._initialized&&this.backend.updateSize()}setSize(e,t,s=!0){this._width=e,this._height=t,this.domElement.width=Math.floor(e*this._pixelRatio),this.domElement.height=Math.floor(t*this._pixelRatio),!0===s&&(this.domElement.style.width=e+"px",this.domElement.style.height=t+"px"),this.setViewport(0,0,e,t),this._initialized&&this.backend.updateSize()}setOpaqueSort(e){this._opaqueSort=e}setTransparentSort(e){this._transparentSort=e}getScissor(e){const t=this._scissor;return e.x=t.x,e.y=t.y,e.width=t.width,e.height=t.height,e}setScissor(e,t,s,i){const r=this._scissor;e.isVector4?r.copy(e):r.set(e,t,s,i)}getScissorTest(){return this._scissorTest}setScissorTest(e){this._scissorTest=e,this.backend.setScissorTest(e)}getViewport(e){return e.copy(this._viewport)}setViewport(e,t,s,i,r=0,n=1){const o=this._viewport;e.isVector4?o.copy(e):o.set(e,t,s,i),o.minDepth=r,o.maxDepth=n}getClearColor(e){return e.copy(this._clearColor)}setClearColor(e,t=1){this._clearColor.set(e),this._clearColor.a=t}getClearAlpha(){return this._clearColor.a}setClearAlpha(e){this._clearColor.a=e}getClearDepth(){return this._clearDepth}setClearDepth(e){this._clearDepth=e}getClearStencil(){return this._clearStencil}setClearStencil(e){this._clearStencil=e}isOccluded(e){const t=this._currentRenderContext;return t&&this.backend.isOccluded(t,e)}clear(e=!0,t=!0,s=!0){if(!1===this._initialized)return console.warn("THREE.Renderer: .clear() called before the backend is initialized. Try using .clearAsync() instead."),this.clearAsync(e,t,s);const i=this._renderTarget||this._getFrameBufferTarget();let r=null;if(null!==i&&(this._textures.updateRenderTarget(i),r=this._textures.get(i)),this.backend.clear(e,t,s,r),null!==i&&null===this._renderTarget){const e=this._quad;this._nodes.hasOutputChange(i.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(i.texture),e.material.needsUpdate=!0),this._renderScene(e,e.camera,!1)}}clearColor(){return this.clear(!0,!1,!1)}clearDepth(){return this.clear(!1,!0,!1)}clearStencil(){return this.clear(!1,!1,!0)}async clearAsync(e=!0,t=!0,s=!0){!1===this._initialized&&await this.init(),this.clear(e,t,s)}clearColorAsync(){return this.clearAsync(!0,!1,!1)}clearDepthAsync(){return this.clearAsync(!1,!0,!1)}clearStencilAsync(){return this.clearAsync(!1,!1,!0)}get currentToneMapping(){return null!==this._renderTarget?0:this.toneMapping}get currentColorSpace(){return null!==this._renderTarget?Jt:this.outputColorSpace}dispose(){this.info.dispose(),this._animation.dispose(),this._objects.dispose(),this._pipelines.dispose(),this._nodes.dispose(),this._bindings.dispose(),this._renderLists.dispose(),this._renderContexts.dispose(),this._textures.dispose(),this.setRenderTarget(null),this.setAnimationLoop(null)}setRenderTarget(e,t=0,s=0){this._renderTarget=e,this._activeCubeFace=t,this._activeMipmapLevel=s}getRenderTarget(){return this._renderTarget}setRenderObjectFunction(e){this._renderObjectFunction=e}getRenderObjectFunction(){return this._renderObjectFunction}async computeAsync(e){!1===this._initialized&&await this.init();const t=this._nodes.nodeFrame,s=t.renderId;this.info.calls++,this.info.compute.calls++,this.info.compute.frameCalls++,t.renderId=this.info.calls;const i=this.backend,r=this._pipelines,n=this._bindings,o=this._nodes,a=Array.isArray(e)?e:[e];if(void 0===a[0]||!0!==a[0].isComputeNode)throw new Error("THREE.Renderer: .compute() expects a ComputeNode.");i.beginCompute(e);for(const t of a){if(!1===r.has(t)){const e=()=>{t.removeEventListener("dispose",e),r.delete(t),n.delete(t),o.delete(t)};t.addEventListener("dispose",e),t.onInit({renderer:this})}o.updateForCompute(t),n.updateForCompute(t);const s=n.getForCompute(t),a=r.getForCompute(t,s);i.compute(e,t,s,a)}i.finishCompute(e),await this.backend.resolveTimestampAsync(e,"compute"),t.renderId=s}async hasFeatureAsync(e){return!1===this._initialized&&await this.init(),this.backend.hasFeature(e)}hasFeature(e){return!1===this._initialized?(console.warn("THREE.Renderer: .hasFeature() called before the backend is initialized. Try using .hasFeatureAsync() instead."),!1):this.backend.hasFeature(e)}copyFramebufferToTexture(e,t=null){const s=this._currentRenderContext;this._textures.updateTexture(e),t=null===t?lP.set(0,0,e.image.width,e.image.height):t,this.backend.copyFramebufferToTexture(e,s,t)}copyTextureToTexture(e,t,s=null,i=null,r=0){this._textures.updateTexture(e),this._textures.updateTexture(t),this.backend.copyTextureToTexture(e,t,s,i,r)}readRenderTargetPixelsAsync(e,t,s,i,r,n=0,o=0){return this.backend.copyTextureToBuffer(e.textures[n],t,s,i,r,o)}_projectObject(e,t,s,i){if(!1===e.visible)return;if(e.layers.test(t.layers))if(e.isGroup)s=e.renderOrder;else if(e.isLOD)!0===e.autoUpdate&&e.update(t);else if(e.isLight)i.pushLight(e);else if(e.isSprite){if(!e.frustumCulled||hP.intersectsSprite(e)){!0===this.sortObjects&&lP.setFromMatrixPosition(e.matrixWorld).applyMatrix4(uP);const{geometry:t,material:r}=e;r.visible&&i.push(e,t,r,s,lP.z,null)}}else if(e.isLineLoop)console.error("THREE.Renderer: Objects of type THREE.LineLoop are not supported. Please use THREE.Line or THREE.LineSegments.");else if((e.isMesh||e.isLine||e.isPoints)&&(!e.frustumCulled||hP.intersectsObject(e))){const{geometry:t,material:r}=e;if(!0===this.sortObjects&&(null===t.boundingSphere&&t.computeBoundingSphere(),lP.copy(t.boundingSphere.center).applyMatrix4(e.matrixWorld).applyMatrix4(uP)),Array.isArray(r)){const n=t.groups;for(let o=0,a=n.length;o0?i:"";t=`${e.name} {\n\t${s} ${r.name}[${n}];\n};\n`}else{t=`${this.getVectorType(r.type)} ${this.getPropertyName(r,e)};`,n=!0}const o=r.node.precision;if(null!==o&&(t=NP[o]+" "+t),n){t="\t"+t;const e=r.groupNode.name;(i[e]||(i[e]=[])).push(t)}else t="uniform "+t,s.push(t)}let r="";for(const t in i){const s=i[t];r+=this._getGLSLUniformStruct(e+"_"+t,s.join("\n"))+"\n"}return r+=s.join("\n"),r}getTypeFromAttribute(e){let t=super.getTypeFromAttribute(e);if(/^[iu]/.test(t)&&e.gpuType!==Ee){let s=e;e.isInterleavedBufferAttribute&&(s=e.data);const i=s.array;!1==(i instanceof Uint32Array||i instanceof Int32Array)&&(t=t.slice(1))}return t}getAttributes(e){let t="";if("vertex"===e||"compute"===e){const e=this.getAttributesArray();let s=0;for(const i of e)t+=`layout( location = ${s++} ) in ${i.type} ${i.name};\n`}return t}getStructMembers(e){const t=[],s=e.getMemberTypes();for(let e=0;ee*t),1)}u`}getDrawIndex(){return this.renderer.backend.extensions.has("WEBGL_multi_draw")?"uint( gl_DrawID )":null}getFrontFacing(){return"gl_FrontFacing"}getFragCoord(){return"gl_FragCoord.xy"}getFragDepth(){return"gl_FragDepth"}enableExtension(e,t,s=this.shaderStage){const i=this.extensions[s]||(this.extensions[s]=new Map);!1===i.has(e)&&i.set(e,{name:e,behavior:t})}getExtensions(e){const t=[];if("vertex"===e){const t=this.renderer.backend.extensions;this.object.isBatchedMesh&&t.has("WEBGL_multi_draw")&&this.enableExtension("GL_ANGLE_multi_draw","require",e)}const s=this.extensions[e];if(void 0!==s)for(const{name:e,behavior:i}of s.values())t.push(`#extension ${e} : ${i}`);return t.join("\n")}isAvailable(e){let t=AP[e];if(void 0===t){if("float32Filterable"===e){const e=this.renderer.backend.extensions;e.has("OES_texture_float_linear")?(e.get("OES_texture_float_linear"),t=!0):t=!1}AP[e]=t}return t}isFlipY(){return!0}registerTransform(e,t){this.transforms.push({varyingName:e,attributeNode:t})}getTransforms(){const e=this.transforms;let t="";for(let s=0;s0&&(s+="\n"),s+=`\t// flow -> ${n}\n\t`),s+=`${i.code}\n\t`,e===r&&"compute"!==t&&(s+="// result\n\t","vertex"===t?(s+="gl_Position = ",s+=`${i.result};`):"fragment"===t&&(e.outputNode.isOutputStructNode||(s+="fragColor = ",s+=`${i.result};`)))}const n=e[t];n.extensions=this.getExtensions(t),n.uniforms=this.getUniforms(t),n.attributes=this.getAttributes(t),n.varyings=this.getVaryings(t),n.vars=this.getVars(t),n.structs=this.getStructs(t),n.codes=this.getCodes(t),n.transforms=this.getTransforms(t),n.flow=s}null!==this.material?(this.vertexShader=this._getGLSLVertexCode(e.vertex),this.fragmentShader=this._getGLSLFragmentCode(e.fragment)):this.computeShader=this._getGLSLVertexCode(e.compute)}getUniformFromNode(e,t,s,i=null){const r=super.getUniformFromNode(e,t,s,i),n=this.getDataFromNode(e,s,this.globalCache);let o=n.uniformGPU;if(void 0===o){const i=e.groupNode,a=i.name,h=this.getBindGroupArray(a,s);if("texture"===t)o=new _P(r.name,r.node,i),h.push(o);else if("cubeTexture"===t)o=new wP(r.name,r.node,i),h.push(o);else if("texture3D"===t)o=new SP(r.name,r.node,i),h.push(o);else if("buffer"===t){e.name=`NodeBuffer_${e.id}`,r.name=`buffer${e.id}`;const t=new fP(e,i);t.name=e.name,h.push(t),o=t}else{const e=this.uniformGroups[s]||(this.uniformGroups[s]={});let n=e[a];void 0===n&&(n=new bP(s+"_"+a,i),e[a]=n,h.push(n)),o=this.getNodeUniform(r,t),n.addUniform(o)}n.uniformGPU=o}return r}}let EP=null,BP=null,IP=null;class PP{constructor(e={}){this.parameters=Object.assign({},e),this.data=new WeakMap,this.renderer=null,this.domElement=null}async init(e){this.renderer=e}begin(){}finish(){}draw(){}createProgram(){}destroyProgram(){}createBindings(){}updateBindings(){}createRenderPipeline(){}createComputePipeline(){}destroyPipeline(){}needsRenderUpdate(){}getRenderCacheKey(){}createNodeBuilder(){}createSampler(){}createDefaultTexture(){}createTexture(){}copyTextureToBuffer(){}createAttribute(){}createIndexAttribute(){}updateAttribute(){}destroyAttribute(){}getContext(){}updateSize(){}resolveTimestampAsync(){}hasFeatureAsync(){}hasFeature(){}getInstanceCount(e){const{object:t,geometry:s}=e;return s.isInstancedBufferGeometry?s.instanceCount:t.count>1?t.count:1}getDrawingBufferSize(){return EP=EP||new Qs,this.renderer.getDrawingBufferSize(EP)}getScissor(){return BP=BP||new Ti,this.renderer.getScissor(BP)}setScissorTest(){}getClearColor(){const e=this.renderer;return IP=IP||new ZI,e.getClearColor(IP),IP.getRGB(IP,this.renderer.currentColorSpace),IP}getDomElement(){let t=this.domElement;return null===t&&(t=void 0!==this.parameters.canvas?this.parameters.canvas:ni(),"setAttribute"in t&&t.setAttribute("data-engine",`three.js r${e} webgpu`),this.domElement=t),t}set(e,t){this.data.set(e,t)}get(e){let t=this.data.get(e);return void 0===t&&(t={},this.data.set(e,t)),t}has(e){return this.data.has(e)}delete(e){this.data.delete(e)}}let FP=0;class zP{constructor(e,t){this.buffers=[e.bufferGPU,t],this.type=e.type,this.bufferType=e.bufferType,this.pbo=e.pbo,this.byteLength=e.byteLength,this.bytesPerElement=e.BYTES_PER_ELEMENT,this.version=e.version,this.isInteger=e.isInteger,this.activeBufferIndex=0,this.baseId=e.id}get id(){return`${this.baseId}|${this.activeBufferIndex}`}get bufferGPU(){return this.buffers[this.activeBufferIndex]}get transformBuffer(){return this.buffers[1^this.activeBufferIndex]}switchBuffers(){this.activeBufferIndex^=1}}class UP{constructor(e){this.backend=e}createAttribute(e,t){const s=this.backend,{gl:i}=s,r=e.array,n=e.usage||i.STATIC_DRAW,o=e.isInterleavedBufferAttribute?e.data:e,a=s.get(o);let h,u=a.bufferGPU;if(void 0===u&&(u=this._createBuffer(i,t,r,n),a.bufferGPU=u,a.bufferType=t,a.version=o.version),r instanceof Float32Array)h=i.FLOAT;else if(r instanceof Uint16Array)h=e.isFloat16BufferAttribute?i.HALF_FLOAT:i.UNSIGNED_SHORT;else if(r instanceof Int16Array)h=i.SHORT;else if(r instanceof Uint32Array)h=i.UNSIGNED_INT;else if(r instanceof Int32Array)h=i.INT;else if(r instanceof Int8Array)h=i.BYTE;else if(r instanceof Uint8Array)h=i.UNSIGNED_BYTE;else{if(!(r instanceof Uint8ClampedArray))throw new Error("THREE.WebGLBackend: Unsupported buffer data format: "+r);h=i.UNSIGNED_BYTE}let l={bufferGPU:u,bufferType:t,type:h,byteLength:r.byteLength,bytesPerElement:r.BYTES_PER_ELEMENT,version:e.version,pbo:e.pbo,isInteger:h===i.INT||h===i.UNSIGNED_INT||e.gpuType===Ee,id:FP++};if(e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute){const e=this._createBuffer(i,t,r,n);l=new zP(l,e)}s.set(e,l)}updateAttribute(e){const t=this.backend,{gl:s}=t,i=e.array,r=e.isInterleavedBufferAttribute?e.data:e,n=t.get(r),o=n.bufferType,a=e.isInterleavedBufferAttribute?e.data.updateRanges:e.updateRanges;if(s.bindBuffer(o,n.bufferGPU),0===a.length)s.bufferSubData(o,0,i);else{for(let e=0,t=a.length;e1?this.enable(s.SAMPLE_ALPHA_TO_COVERAGE):this.disable(s.SAMPLE_ALPHA_TO_COVERAGE)}setPolygonOffset(e,t,s){const{gl:i}=this;e?(this.enable(i.POLYGON_OFFSET_FILL),this.currentPolygonOffsetFactor===t&&this.currentPolygonOffsetUnits===s||(i.polygonOffset(t,s),this.currentPolygonOffsetFactor=t,this.currentPolygonOffsetUnits=s)):this.disable(i.POLYGON_OFFSET_FILL)}useProgram(e){return this.currentProgram!==e&&(this.gl.useProgram(e),this.currentProgram=e,!0)}bindFramebuffer(e,t){const{gl:s,currentBoundFramebuffers:i}=this;return i[e]!==t&&(s.bindFramebuffer(e,t),i[e]=t,e===s.DRAW_FRAMEBUFFER&&(i[s.FRAMEBUFFER]=t),e===s.FRAMEBUFFER&&(i[s.DRAW_FRAMEBUFFER]=t),!0)}drawBuffers(e,t){const{gl:s}=this;let i=[],r=!1;if(null!==e.textures){i=this.currentDrawbuffers.get(t),void 0===i&&(i=[],this.currentDrawbuffers.set(t,i));const n=e.textures;if(i.length!==n.length||i[0]!==s.COLOR_ATTACHMENT0){for(let e=0,t=n.length;e{!function r(){const n=e.clientWaitSync(t,e.SYNC_FLUSH_COMMANDS_BIT,0);if(n===e.WAIT_FAILED)return e.deleteSync(t),void i();n!==e.TIMEOUT_EXPIRED?(e.deleteSync(t),s()):requestAnimationFrame(r)}()}))}}let GP,WP,jP,HP=!1;class qP{constructor(e){this.backend=e,this.gl=e.gl,this.extensions=e.extensions,this.defaultTextures={},!1===HP&&(this._init(this.gl),HP=!0)}_init(e){GP={[pe]:e.REPEAT,[me]:e.CLAMP_TO_EDGE,[ge]:e.MIRRORED_REPEAT},WP={[fe]:e.NEAREST,[ye]:e.NEAREST_MIPMAP_NEAREST,[be]:e.NEAREST_MIPMAP_LINEAR,[Te]:e.LINEAR,[_e]:e.LINEAR_MIPMAP_NEAREST,[Se]:e.LINEAR_MIPMAP_LINEAR},jP={512:e.NEVER,519:e.ALWAYS,[Ts]:e.LESS,515:e.LEQUAL,514:e.EQUAL,518:e.GEQUAL,516:e.GREATER,517:e.NOTEQUAL}}filterFallback(e){const{gl:t}=this;return e===fe||e===ye||e===be?t.NEAREST:t.LINEAR}getGLTextureType(e){const{gl:t}=this;let s;return s=!0===e.isCubeTexture?t.TEXTURE_CUBE_MAP:!0===e.isDataArrayTexture||!0===e.isCompressedArrayTexture?t.TEXTURE_2D_ARRAY:!0===e.isData3DTexture?t.TEXTURE_3D:t.TEXTURE_2D,s}getInternalFormat(e,t,s,i,r=!1){const{gl:n,extensions:o}=this;if(null!==e){if(void 0!==n[e])return n[e];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+e+"'")}let a=t;return t===n.RED&&(s===n.FLOAT&&(a=n.R32F),s===n.HALF_FLOAT&&(a=n.R16F),s===n.UNSIGNED_BYTE&&(a=n.R8),s===n.UNSIGNED_SHORT&&(a=n.R16),s===n.UNSIGNED_INT&&(a=n.R32UI),s===n.BYTE&&(a=n.R8I),s===n.SHORT&&(a=n.R16I),s===n.INT&&(a=n.R32I)),t===n.RED_INTEGER&&(s===n.UNSIGNED_BYTE&&(a=n.R8UI),s===n.UNSIGNED_SHORT&&(a=n.R16UI),s===n.UNSIGNED_INT&&(a=n.R32UI),s===n.BYTE&&(a=n.R8I),s===n.SHORT&&(a=n.R16I),s===n.INT&&(a=n.R32I)),t===n.RG&&(s===n.FLOAT&&(a=n.RG32F),s===n.HALF_FLOAT&&(a=n.RG16F),s===n.UNSIGNED_BYTE&&(a=n.RG8),s===n.UNSIGNED_SHORT&&(a=n.RG16),s===n.UNSIGNED_INT&&(a=n.RG32UI),s===n.BYTE&&(a=n.RG8I),s===n.SHORT&&(a=n.RG16I),s===n.INT&&(a=n.RG32I)),t===n.RG_INTEGER&&(s===n.UNSIGNED_BYTE&&(a=n.RG8UI),s===n.UNSIGNED_SHORT&&(a=n.RG16UI),s===n.UNSIGNED_INT&&(a=n.RG32UI),s===n.BYTE&&(a=n.RG8I),s===n.SHORT&&(a=n.RG16I),s===n.INT&&(a=n.RG32I)),t===n.RGB&&(s===n.FLOAT&&(a=n.RGB32F),s===n.HALF_FLOAT&&(a=n.RGB16F),s===n.UNSIGNED_BYTE&&(a=n.RGB8),s===n.UNSIGNED_SHORT&&(a=n.RGB16),s===n.UNSIGNED_INT&&(a=n.RGB32UI),s===n.BYTE&&(a=n.RGB8I),s===n.SHORT&&(a=n.RGB16I),s===n.INT&&(a=n.RGB32I),s===n.UNSIGNED_BYTE&&(a=i===Zt&&!1===r?n.SRGB8:n.RGB8),s===n.UNSIGNED_SHORT_5_6_5&&(a=n.RGB565),s===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1),s===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGB4),s===n.UNSIGNED_INT_5_9_9_9_REV&&(a=n.RGB9_E5)),t===n.RGB_INTEGER&&(s===n.UNSIGNED_BYTE&&(a=n.RGB8UI),s===n.UNSIGNED_SHORT&&(a=n.RGB16UI),s===n.UNSIGNED_INT&&(a=n.RGB32UI),s===n.BYTE&&(a=n.RGB8I),s===n.SHORT&&(a=n.RGB16I),s===n.INT&&(a=n.RGB32I)),t===n.RGBA&&(s===n.FLOAT&&(a=n.RGBA32F),s===n.HALF_FLOAT&&(a=n.RGBA16F),s===n.UNSIGNED_BYTE&&(a=n.RGBA8),s===n.UNSIGNED_SHORT&&(a=n.RGBA16),s===n.UNSIGNED_INT&&(a=n.RGBA32UI),s===n.BYTE&&(a=n.RGBA8I),s===n.SHORT&&(a=n.RGBA16I),s===n.INT&&(a=n.RGBA32I),s===n.UNSIGNED_BYTE&&(a=i===Zt&&!1===r?n.SRGB8_ALPHA8:n.RGBA8),s===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGBA4),s===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1)),t===n.RGBA_INTEGER&&(s===n.UNSIGNED_BYTE&&(a=n.RGBA8UI),s===n.UNSIGNED_SHORT&&(a=n.RGBA16UI),s===n.UNSIGNED_INT&&(a=n.RGBA32UI),s===n.BYTE&&(a=n.RGBA8I),s===n.SHORT&&(a=n.RGBA16I),s===n.INT&&(a=n.RGBA32I)),t===n.DEPTH_COMPONENT&&(s===n.UNSIGNED_INT&&(a=n.DEPTH24_STENCIL8),s===n.FLOAT&&(a=n.DEPTH_COMPONENT32F)),t===n.DEPTH_STENCIL&&s===n.UNSIGNED_INT_24_8&&(a=n.DEPTH24_STENCIL8),a!==n.R16F&&a!==n.R32F&&a!==n.RG16F&&a!==n.RG32F&&a!==n.RGBA16F&&a!==n.RGBA32F||o.get("EXT_color_buffer_float"),a}setTextureParameters(e,t){const{gl:s,extensions:i,backend:r}=this;s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL,t.flipY),s.pixelStorei(s.UNPACK_PREMULTIPLY_ALPHA_WEBGL,t.premultiplyAlpha),s.pixelStorei(s.UNPACK_ALIGNMENT,t.unpackAlignment),s.pixelStorei(s.UNPACK_COLORSPACE_CONVERSION_WEBGL,s.NONE),s.texParameteri(e,s.TEXTURE_WRAP_S,GP[t.wrapS]),s.texParameteri(e,s.TEXTURE_WRAP_T,GP[t.wrapT]),e!==s.TEXTURE_3D&&e!==s.TEXTURE_2D_ARRAY||s.texParameteri(e,s.TEXTURE_WRAP_R,GP[t.wrapR]),s.texParameteri(e,s.TEXTURE_MAG_FILTER,WP[t.magFilter]);const n=void 0!==t.mipmaps&&t.mipmaps.length>0,o=t.minFilter===Te&&n?Se:t.minFilter;if(s.texParameteri(e,s.TEXTURE_MIN_FILTER,WP[o]),t.compareFunction&&(s.texParameteri(e,s.TEXTURE_COMPARE_MODE,s.COMPARE_REF_TO_TEXTURE),s.texParameteri(e,s.TEXTURE_COMPARE_FUNC,jP[t.compareFunction])),!0===i.has("EXT_texture_filter_anisotropic")){if(t.magFilter===fe)return;if(t.minFilter!==be&&t.minFilter!==Se)return;if(t.type===Ie&&!1===i.has("OES_texture_float_linear"))return;if(t.anisotropy>1){const n=i.get("EXT_texture_filter_anisotropic");s.texParameterf(e,n.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(t.anisotropy,r.getMaxAnisotropy()))}}}createDefaultTexture(e){const{gl:t,backend:s,defaultTextures:i}=this,r=this.getGLTextureType(e);let n=i[r];void 0===n&&(n=t.createTexture(),s.state.bindTexture(r,n),t.texParameteri(r,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(r,t.TEXTURE_MAG_FILTER,t.NEAREST),i[r]=n),s.set(e,{textureGPU:n,glTextureType:r,isDefault:!0})}createTexture(e,t){const{gl:s,backend:i}=this,{levels:r,width:n,height:o,depth:a}=t,h=i.utils.convert(e.format,e.colorSpace),u=i.utils.convert(e.type),l=this.getInternalFormat(e.internalFormat,h,u,e.colorSpace,e.isVideoTexture),c=s.createTexture(),d=this.getGLTextureType(e);i.state.bindTexture(d,c),this.setTextureParameters(d,e),e.isDataArrayTexture||e.isCompressedArrayTexture?s.texStorage3D(s.TEXTURE_2D_ARRAY,r,l,n,o,a):e.isData3DTexture?s.texStorage3D(s.TEXTURE_3D,r,l,n,o,a):e.isVideoTexture||s.texStorage2D(d,r,l,n,o),i.set(e,{textureGPU:c,glTextureType:d,glFormat:h,glType:u,glInternalFormat:l})}copyBufferToTexture(e,t){const{gl:s,backend:i}=this,{textureGPU:r,glTextureType:n,glFormat:o,glType:a}=i.get(t),{width:h,height:u}=t.source.data;s.bindBuffer(s.PIXEL_UNPACK_BUFFER,e),i.state.bindTexture(n,r),s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL,!1),s.pixelStorei(s.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),s.texSubImage2D(n,0,0,0,h,u,o,a,0),s.bindBuffer(s.PIXEL_UNPACK_BUFFER,null),i.state.unbindTexture()}updateTexture(e,t){const{gl:s}=this,{width:i,height:r}=t,{textureGPU:n,glTextureType:o,glFormat:a,glType:h,glInternalFormat:u}=this.backend.get(e);if(e.isRenderTargetTexture||void 0===n)return;const l=e=>e.isDataTexture?e.image.data:e instanceof ImageBitmap||e instanceof OffscreenCanvas||e instanceof HTMLImageElement||e instanceof HTMLCanvasElement?e:e.data;if(this.backend.state.bindTexture(o,n),this.setTextureParameters(o,e),e.isCompressedTexture){const i=e.mipmaps,r=t.image;for(let t=0;t0,c=t.renderTarget?t.renderTarget.height:this.backend.gerDrawingBufferSize().y;if(l){const s=0!==o||0!==a;let l,d;if(!0===e.isDepthTexture?(l=i.DEPTH_BUFFER_BIT,d=i.DEPTH_ATTACHMENT,t.stencil&&(l|=i.STENCIL_BUFFER_BIT)):(l=i.COLOR_BUFFER_BIT,d=i.COLOR_ATTACHMENT0),s){const e=this.backend.get(t.renderTarget),s=e.framebuffers[t.getCacheKey()],d=e.msaaFrameBuffer;r.bindFramebuffer(i.DRAW_FRAMEBUFFER,s),r.bindFramebuffer(i.READ_FRAMEBUFFER,d);const p=c-a-u;i.blitFramebuffer(o,p,o+h,p+u,o,p,o+h,p+u,l,i.NEAREST),r.bindFramebuffer(i.READ_FRAMEBUFFER,s),r.bindTexture(i.TEXTURE_2D,n),i.copyTexSubImage2D(i.TEXTURE_2D,0,0,0,o,p,h,u),r.unbindTexture()}else{const e=i.createFramebuffer();r.bindFramebuffer(i.DRAW_FRAMEBUFFER,e),i.framebufferTexture2D(i.DRAW_FRAMEBUFFER,d,i.TEXTURE_2D,n,0),i.blitFramebuffer(0,0,h,u,0,0,h,u,l,i.NEAREST),i.deleteFramebuffer(e)}}else r.bindTexture(i.TEXTURE_2D,n),i.copyTexSubImage2D(i.TEXTURE_2D,0,0,0,o,c-u-a,h,u),r.unbindTexture();e.generateMipmaps&&this.generateMipmaps(e),this.backend._setFramebuffer(t)}setupRenderBufferStorage(e,t){const{gl:s}=this,i=t.renderTarget,{samples:r,depthTexture:n,depthBuffer:o,stencilBuffer:a,width:h,height:u}=i;if(s.bindRenderbuffer(s.RENDERBUFFER,e),o&&!a){let t=s.DEPTH_COMPONENT24;r>0?(n&&n.isDepthTexture&&n.type===s.FLOAT&&(t=s.DEPTH_COMPONENT32F),s.renderbufferStorageMultisample(s.RENDERBUFFER,r,t,h,u)):s.renderbufferStorage(s.RENDERBUFFER,t,h,u),s.framebufferRenderbuffer(s.FRAMEBUFFER,s.DEPTH_ATTACHMENT,s.RENDERBUFFER,e)}else o&&a&&(r>0?s.renderbufferStorageMultisample(s.RENDERBUFFER,r,s.DEPTH24_STENCIL8,h,u):s.renderbufferStorage(s.RENDERBUFFER,s.DEPTH_STENCIL,h,u),s.framebufferRenderbuffer(s.FRAMEBUFFER,s.DEPTH_STENCIL_ATTACHMENT,s.RENDERBUFFER,e))}async copyTextureToBuffer(e,t,s,i,r,n){const{backend:o,gl:a}=this,{textureGPU:h,glFormat:u,glType:l}=this.backend.get(e),c=a.createFramebuffer();a.bindFramebuffer(a.READ_FRAMEBUFFER,c);const d=e.isCubeTexture?a.TEXTURE_CUBE_MAP_POSITIVE_X+n:a.TEXTURE_2D;a.framebufferTexture2D(a.READ_FRAMEBUFFER,a.COLOR_ATTACHMENT0,d,h,0);const p=this._getTypedArrayType(l),m=i*r*this._getBytesPerTexel(l,u),g=a.createBuffer();a.bindBuffer(a.PIXEL_PACK_BUFFER,g),a.bufferData(a.PIXEL_PACK_BUFFER,m,a.STREAM_READ),a.readPixels(t,s,i,r,u,l,0),a.bindBuffer(a.PIXEL_PACK_BUFFER,null),await o.utils._clientWaitAsync();const f=new p(m/p.BYTES_PER_ELEMENT);return a.bindBuffer(a.PIXEL_PACK_BUFFER,g),a.getBufferSubData(a.PIXEL_PACK_BUFFER,0,f),a.bindBuffer(a.PIXEL_PACK_BUFFER,null),a.deleteFramebuffer(c),f}_getTypedArrayType(e){const{gl:t}=this;if(e===t.UNSIGNED_BYTE)return Uint8Array;if(e===t.UNSIGNED_SHORT_4_4_4_4)return Uint16Array;if(e===t.UNSIGNED_SHORT_5_5_5_1)return Uint16Array;if(e===t.UNSIGNED_SHORT_5_6_5)return Uint16Array;if(e===t.UNSIGNED_SHORT)return Uint16Array;if(e===t.UNSIGNED_INT)return Uint32Array;if(e===t.HALF_FLOAT)return Uint16Array;if(e===t.FLOAT)return Float32Array;throw new Error(`Unsupported WebGL type: ${e}`)}_getBytesPerTexel(e,t){const{gl:s}=this;let i=0;return e===s.UNSIGNED_BYTE&&(i=1),e!==s.UNSIGNED_SHORT_4_4_4_4&&e!==s.UNSIGNED_SHORT_5_5_5_1&&e!==s.UNSIGNED_SHORT_5_6_5&&e!==s.UNSIGNED_SHORT&&e!==s.HALF_FLOAT||(i=2),e!==s.UNSIGNED_INT&&e!==s.FLOAT||(i=4),t===s.RGBA?4*i:t===s.RGB?3*i:t===s.ALPHA?i:void 0}}class $P{constructor(e){this.backend=e,this.gl=this.backend.gl,this.availableExtensions=this.gl.getSupportedExtensions(),this.extensions={}}get(e){let t=this.extensions[e];return void 0===t&&(t=this.gl.getExtension(e),this.extensions[e]=t),t}has(e){return this.availableExtensions.includes(e)}}class XP{constructor(e){this.backend=e,this.maxAnisotropy=null}getMaxAnisotropy(){if(null!==this.maxAnisotropy)return this.maxAnisotropy;const e=this.backend.gl,t=this.backend.extensions;if(!0===t.has("EXT_texture_filter_anisotropic")){const s=t.get("EXT_texture_filter_anisotropic");this.maxAnisotropy=e.getParameter(s.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else this.maxAnisotropy=0;return this.maxAnisotropy}}const YP={WEBGL_multi_draw:"WEBGL_multi_draw",WEBGL_compressed_texture_astc:"texture-compression-astc",WEBGL_compressed_texture_etc:"texture-compression-etc2",WEBGL_compressed_texture_etc1:"texture-compression-etc1",WEBGL_compressed_texture_pvrtc:"texture-compression-pvrtc",WEBKIT_WEBGL_compressed_texture_pvrtc:"texture-compression-pvrtc",WEBGL_compressed_texture_s3tc:"texture-compression-bc",EXT_texture_compression_bptc:"texture-compression-bptc",EXT_disjoint_timer_query_webgl2:"timestamp-query"};class ZP{constructor(e){this.gl=e.gl,this.extensions=e.extensions,this.info=e.renderer.info,this.mode=null,this.index=0,this.type=null,this.object=null}render(e,t){const{gl:s,mode:i,object:r,type:n,info:o,index:a}=this;0!==a?s.drawElements(i,t,n,e):s.drawArrays(i,e,t),o.update(r,t,i,1)}renderInstances(e,t,s){const{gl:i,mode:r,type:n,index:o,object:a,info:h}=this;0!==s&&(0!==o?i.drawElementsInstanced(r,t,n,e,s):i.drawArraysInstanced(r,e,t,s),h.update(a,t,r,s))}renderMultiDraw(e,t,s){const{extensions:i,mode:r,object:n,info:o}=this;if(0===s)return;const a=i.get("WEBGL_multi_draw");if(null===a)for(let i=0;i0)){const e=t.queryQueue.shift();this.initTimestampQuery(e)}}async resolveTimestampAsync(e,t="render"){if(!this.disjoint||!this.trackTimestamp)return;const s=this.get(e);s.gpuQueries||(s.gpuQueries=[]);for(let e=0;e0&&(s.currentOcclusionQueries=s.occlusionQueries,s.currentOcclusionQueryObjects=s.occlusionQueryObjects,s.lastOcclusionObject=null,s.occlusionQueries=new Array(i),s.occlusionQueryObjects=new Array(i),s.occlusionQueryIndex=0)}finishRender(e){const{gl:t,state:s}=this,i=this.get(e),r=i.previousContext,n=e.occlusionQueryCount;n>0&&(n>i.occlusionQueryIndex&&t.endQuery(t.ANY_SAMPLES_PASSED),this.resolveOccludedAsync(e));const o=e.textures;if(null!==o)for(let e=0;e0){const r=i.framebuffers[e.getCacheKey()],n=t.COLOR_BUFFER_BIT,o=i.msaaFrameBuffer,a=e.textures;s.bindFramebuffer(t.READ_FRAMEBUFFER,o),s.bindFramebuffer(t.DRAW_FRAMEBUFFER,r);for(let s=0;s{let o=0;for(let t=0;t0&&e.add(i[t]),s[t]=null,r.deleteQuery(n),o++))}o1?m.renderInstances(y,g,f):m.render(y,g),o.bindVertexArray(null)}needsRenderUpdate(){return!1}getRenderCacheKey(){return""}createDefaultTexture(e){this.textureUtils.createDefaultTexture(e)}createTexture(e,t){this.textureUtils.createTexture(e,t)}updateTexture(e,t){this.textureUtils.updateTexture(e,t)}generateMipmaps(e){this.textureUtils.generateMipmaps(e)}destroyTexture(e){this.textureUtils.destroyTexture(e)}copyTextureToBuffer(e,t,s,i,r,n){return this.textureUtils.copyTextureToBuffer(e,t,s,i,r,n)}createSampler(){}destroySampler(){}createNodeBuilder(e,t){return new RP(e,t)}createProgram(e){const t=this.gl,{stage:s,code:i}=e,r="fragment"===s?t.createShader(t.FRAGMENT_SHADER):t.createShader(t.VERTEX_SHADER);t.shaderSource(r,i),t.compileShader(r),this.set(e,{shaderGPU:r})}destroyProgram(){console.warn("Abstract class.")}createRenderPipeline(e,t){const s=this.gl,i=e.pipeline,{fragmentProgram:r,vertexProgram:n}=i,o=s.createProgram(),a=this.get(r).shaderGPU,h=this.get(n).shaderGPU;if(s.attachShader(o,a),s.attachShader(o,h),s.linkProgram(o),this.set(i,{programGPU:o,fragmentShader:a,vertexShader:h}),null!==t&&this.parallel){const r=new Promise((t=>{const r=this.parallel,n=()=>{s.getProgramParameter(o,r.COMPLETION_STATUS_KHR)?(this._completeCompile(e,i),t()):requestAnimationFrame(n)};n()}));t.push(r)}else this._completeCompile(e,i)}_handleSource(e,t){const s=e.split("\n"),i=[],r=Math.max(t-6,0),n=Math.min(t+6,s.length);for(let e=r;e":" "} ${r}: ${s[e]}`)}return i.join("\n")}_getShaderErrors(e,t,s){const i=e.getShaderParameter(t,e.COMPILE_STATUS),r=e.getShaderInfoLog(t).trim();if(i&&""===r)return"";const n=/ERROR: 0:(\d+)/.exec(r);if(n){const i=parseInt(n[1]);return s.toUpperCase()+"\n\n"+r+"\n\n"+this._handleSource(e.getShaderSource(t),i)}return r}_logProgramError(e,t,s){if(this.renderer.debug.checkShaderErrors){const i=this.gl,r=i.getProgramInfoLog(e).trim();if(!1===i.getProgramParameter(e,i.LINK_STATUS))if("function"==typeof this.renderer.debug.onShaderError)this.renderer.debug.onShaderError(i,e,s,t);else{const n=this._getShaderErrors(i,s,"vertex"),o=this._getShaderErrors(i,t,"fragment");console.error("THREE.WebGLProgram: Shader Error "+i.getError()+" - VALIDATE_STATUS "+i.getProgramParameter(e,i.VALIDATE_STATUS)+"\n\nProgram Info Log: "+r+"\n"+n+"\n"+o)}else""!==r&&console.warn("THREE.WebGLProgram: Program Info Log:",r)}}_completeCompile(e,t){const{state:s,gl:i}=this,r=this.get(t),{programGPU:n,fragmentShader:o,vertexShader:a}=r;!1===i.getProgramParameter(n,i.LINK_STATUS)&&this._logProgramError(n,o,a),s.useProgram(n);const h=e.getBindings();this._setupBindings(h,n),this.set(t,{programGPU:n})}createComputePipeline(e,t){const{state:s,gl:i}=this,r={stage:"fragment",code:"#version 300 es\nprecision highp float;\nvoid main() {}"};this.createProgram(r);const{computeProgram:n}=e,o=i.createProgram(),a=this.get(r).shaderGPU,h=this.get(n).shaderGPU,u=n.transforms,l=[],c=[];for(let e=0;eYP[t]===e)),s=this.extensions;for(let e=0;e0){if(void 0===l){const i=[];l=t.createFramebuffer(),s.bindFramebuffer(t.FRAMEBUFFER,l);const r=[],u=e.textures;for(let s=0;s,\n\t@location( 0 ) vTex : vec2\n};\n\n@vertex\nfn main( @builtin( vertex_index ) vertexIndex : u32 ) -> VarysStruct {\n\n\tvar Varys : VarysStruct;\n\n\tvar pos = array< vec2, 4 >(\n\t\tvec2( -1.0, 1.0 ),\n\t\tvec2( 1.0, 1.0 ),\n\t\tvec2( -1.0, -1.0 ),\n\t\tvec2( 1.0, -1.0 )\n\t);\n\n\tvar tex = array< vec2, 4 >(\n\t\tvec2( 0.0, 0.0 ),\n\t\tvec2( 1.0, 0.0 ),\n\t\tvec2( 0.0, 1.0 ),\n\t\tvec2( 1.0, 1.0 )\n\t);\n\n\tVarys.vTex = tex[ vertexIndex ];\n\tVarys.Position = vec4( pos[ vertexIndex ], 0.0, 1.0 );\n\n\treturn Varys;\n\n}\n"}),this.mipmapFragmentShaderModule=e.createShaderModule({label:"mipmapFragment",code:"\n@group( 0 ) @binding( 0 )\nvar imgSampler : sampler;\n\n@group( 0 ) @binding( 1 )\nvar img : texture_2d;\n\n@fragment\nfn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 {\n\n\treturn textureSample( img, imgSampler, vTex );\n\n}\n"}),this.flipYFragmentShaderModule=e.createShaderModule({label:"flipYFragment",code:"\n@group( 0 ) @binding( 0 )\nvar imgSampler : sampler;\n\n@group( 0 ) @binding( 1 )\nvar img : texture_2d;\n\n@fragment\nfn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 {\n\n\treturn textureSample( img, imgSampler, vec2( vTex.x, 1.0 - vTex.y ) );\n\n}\n"})}getTransferPipeline(e){let t=this.transferPipelines[e];return void 0===t&&(t=this.device.createRenderPipeline({label:`mipmap-${e}`,vertex:{module:this.mipmapVertexShaderModule,entryPoint:"main"},fragment:{module:this.mipmapFragmentShaderModule,entryPoint:"main",targets:[{format:e}]},primitive:{topology:CN,stripIndexFormat:HN},layout:"auto"}),this.transferPipelines[e]=t),t}getFlipYPipeline(e){let t=this.flipYPipelines[e];return void 0===t&&(t=this.device.createRenderPipeline({label:`flipY-${e}`,vertex:{module:this.mipmapVertexShaderModule,entryPoint:"main"},fragment:{module:this.flipYFragmentShaderModule,entryPoint:"main",targets:[{format:e}]},primitive:{topology:CN,stripIndexFormat:HN},layout:"auto"}),this.flipYPipelines[e]=t),t}flipY(e,t,s=0){const i=t.format,{width:r,height:n}=t.size,o=this.getTransferPipeline(i),a=this.getFlipYPipeline(i),h=this.device.createTexture({size:{width:r,height:n,depthOrArrayLayers:1},format:i,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING}),u=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:OA,baseArrayLayer:s}),l=h.createView({baseMipLevel:0,mipLevelCount:1,dimension:OA,baseArrayLayer:0}),c=this.device.createCommandEncoder({}),d=(e,t,s)=>{const i=e.getBindGroupLayout(0),r=this.device.createBindGroup({layout:i,entries:[{binding:0,resource:this.flipYSampler},{binding:1,resource:t}]}),n=c.beginRenderPass({colorAttachments:[{view:s,loadOp:VN,storeOp:ON,clearValue:[0,0,0,0]}]});n.setPipeline(e),n.setBindGroup(0,r),n.draw(4,1,0,0),n.end()};d(o,u,l),d(a,l,u),this.device.queue.submit([c.finish()]),h.destroy()}generateMipmaps(e,t,s=0){const i=this.get(e);void 0===i.useCount&&(i.useCount=0,i.layers=[]);const r=i.layers[s]||this._mipmapCreateBundles(e,t,s),n=this.device.createCommandEncoder({});this._mipmapRunBundles(n,r),this.device.queue.submit([n.finish()]),0!==i.useCount&&(i.layers[s]=r),i.useCount++}_mipmapCreateBundles(e,t,s){const i=this.getTransferPipeline(t.format),r=i.getBindGroupLayout(0);let n=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:OA,baseArrayLayer:s});const o=[];for(let a=1;a1&&!e.isMultisampleRenderTargetTexture){const e=Object.assign({},p);e.label=e.label+"-msaa",e.sampleCount=l,i.msaaTexture=s.device.createTexture(e)}i.initialized=!0,i.textureDescriptorGPU=p}destroyTexture(e){const t=this.backend,s=t.get(e);s.texture.destroy(),void 0!==s.msaaTexture&&s.msaaTexture.destroy(),t.delete(e)}destroySampler(e){delete this.backend.get(e).sampler}generateMipmaps(e){const t=this.backend.get(e);if(e.isCubeTexture)for(let e=0;e<6;e++)this._generateMipmaps(t.texture,t.textureDescriptorGPU,e);else{const s=e.image.depth||1;for(let e=0;e1;for(let o=0;o]*\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/i,uF=/([a-z_0-9]+)\s*:\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/gi,lF={f32:"float",i32:"int",u32:"uint",bool:"bool","vec2":"vec2","vec2":"ivec2","vec2":"uvec2","vec2":"bvec2",vec2f:"vec2",vec2i:"ivec2",vec2u:"uvec2",vec2b:"bvec2","vec3":"vec3","vec3":"ivec3","vec3":"uvec3","vec3":"bvec3",vec3f:"vec3",vec3i:"ivec3",vec3u:"uvec3",vec3b:"bvec3","vec4":"vec4","vec4":"ivec4","vec4":"uvec4","vec4":"bvec4",vec4f:"vec4",vec4i:"ivec4",vec4u:"uvec4",vec4b:"bvec4","mat2x2":"mat2",mat2x2f:"mat2","mat3x3":"mat3",mat3x3f:"mat3","mat4x4":"mat4",mat4x4f:"mat4",sampler:"sampler",texture_1d:"texture",texture_2d:"texture",texture_2d_array:"texture",texture_multisampled_2d:"cubeTexture",texture_depth_2d:"depthTexture",texture_3d:"texture3D",texture_cube:"cubeTexture",texture_cube_array:"cubeTexture",texture_storage_1d:"storageTexture",texture_storage_2d:"storageTexture",texture_storage_2d_array:"storageTexture",texture_storage_3d:"storageTexture"};class cF extends FI{constructor(e){const{type:t,inputs:s,name:i,inputsCode:r,blockCode:n,outputType:o}=(e=>{const t=(e=e.trim()).match(hF);if(null!==t&&4===t.length){const s=t[2],i=[];let r=null;for(;null!==(r=uF.exec(s));)i.push({name:r[1],type:r[2]});const n=[];for(let e=0;e "+this.outputType:"";return`fn ${e} ( ${this.inputsCode.trim()} ) ${t}`+this.blockCode}}class dF extends PI{parseFunction(e){return new cF(e)}}const pF=self.GPUShaderStage,mF={vertex:pF?pF.VERTEX:1,fragment:pF?pF.FRAGMENT:2,compute:pF?pF.COMPUTE:4},gF={instance:!0,swizzleAssign:!1,storageBuffer:!0},fF={"^^":"tsl_xor"},yF={float:"f32",int:"i32",uint:"u32",bool:"bool",color:"vec3",vec2:"vec2",ivec2:"vec2",uvec2:"vec2",bvec2:"vec2",vec3:"vec3",ivec3:"vec3",uvec3:"vec3",bvec3:"vec3",vec4:"vec4",ivec4:"vec4",uvec4:"vec4",bvec4:"vec4",mat2:"mat2x2",imat2:"mat2x2",umat2:"mat2x2",bmat2:"mat2x2",mat3:"mat3x3",imat3:"mat3x3",umat3:"mat3x3",bmat3:"mat3x3",mat4:"mat4x4",imat4:"mat4x4",umat4:"mat4x4",bmat4:"mat4x4"},xF={tsl_xor:new vS("fn tsl_xor( a : bool, b : bool ) -> bool { return ( a || b ) && !( a && b ); }"),mod_float:new vS("fn tsl_mod_float( x : f32, y : f32 ) -> f32 { return x - y * floor( x / y ); }"),mod_vec2:new vS("fn tsl_mod_vec2( x : vec2f, y : vec2f ) -> vec2f { return x - y * floor( x / y ); }"),mod_vec3:new vS("fn tsl_mod_vec3( x : vec3f, y : vec3f ) -> vec3f { return x - y * floor( x / y ); }"),mod_vec4:new vS("fn tsl_mod_vec4( x : vec4f, y : vec4f ) -> vec4f { return x - y * floor( x / y ); }"),equals_bool:new vS("fn tsl_equals_bool( a : bool, b : bool ) -> bool { return a == b; }"),equals_bvec2:new vS("fn tsl_equals_bvec2( a : vec2f, b : vec2f ) -> vec2 { return vec2( a.x == b.x, a.y == b.y ); }"),equals_bvec3:new vS("fn tsl_equals_bvec3( a : vec3f, b : vec3f ) -> vec3 { return vec3( a.x == b.x, a.y == b.y, a.z == b.z ); }"),equals_bvec4:new vS("fn tsl_equals_bvec4( a : vec4f, b : vec4f ) -> vec4 { return vec4( a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w ); }"),repeatWrapping:new vS("\nfn tsl_repeatWrapping( uv : vec2, dimension : vec2 ) -> vec2 {\n\n\tlet uvScaled = vec2( uv * vec2( dimension ) );\n\n\treturn ( ( uvScaled % dimension ) + dimension ) % dimension;\n\n}\n"),biquadraticTexture:new vS("\nfn tsl_biquadraticTexture( map : texture_2d, coord : vec2f, level : i32 ) -> vec4f {\n\n\tlet iRes = vec2i( textureDimensions( map, level ) );\n\tlet res = vec2f( iRes );\n\n\tlet uvScaled = coord * res;\n\tlet uvWrapping = ( ( uvScaled % res ) + res ) % res;\n\n\t// https://www.shadertoy.com/view/WtyXRy\n\n\tlet uv = uvWrapping - 0.5;\n\tlet iuv = floor( uv );\n\tlet f = fract( uv );\n\n\tlet rg1 = textureLoad( map, vec2i( iuv + vec2( 0.5, 0.5 ) ) % iRes, level );\n\tlet rg2 = textureLoad( map, vec2i( iuv + vec2( 1.5, 0.5 ) ) % iRes, level );\n\tlet rg3 = textureLoad( map, vec2i( iuv + vec2( 0.5, 1.5 ) ) % iRes, level );\n\tlet rg4 = textureLoad( map, vec2i( iuv + vec2( 1.5, 1.5 ) ) % iRes, level );\n\n\treturn mix( mix( rg1, rg2, f.x ), mix( rg3, rg4, f.x ), f.y );\n\n}\n")},bF={dFdx:"dpdx",dFdy:"- dpdy",mod_float:"tsl_mod_float",mod_vec2:"tsl_mod_vec2",mod_vec3:"tsl_mod_vec3",mod_vec4:"tsl_mod_vec4",equals_bool:"tsl_equals_bool",equals_bvec2:"tsl_equals_bvec2",equals_bvec3:"tsl_equals_bvec3",equals_bvec4:"tsl_equals_bvec4",inversesqrt:"inverseSqrt",bitcast:"bitcast"};/Windows/g.test(navigator.userAgent)&&(xF.pow_float=new vS("fn tsl_pow_float( a : f32, b : f32 ) -> f32 { return select( -pow( -a, b ), pow( a, b ), a > 0.0 ); }"),xF.pow_vec2=new vS("fn tsl_pow_vec2( a : vec2f, b : vec2f ) -> vec2f { return vec2f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ) ); }",[xF.pow_float]),xF.pow_vec3=new vS("fn tsl_pow_vec3( a : vec3f, b : vec3f ) -> vec3f { return vec3f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ), tsl_pow_float( a.z, b.z ) ); }",[xF.pow_float]),xF.pow_vec4=new vS("fn tsl_pow_vec4( a : vec4f, b : vec4f ) -> vec4f { return vec4f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ), tsl_pow_float( a.z, b.z ), tsl_pow_float( a.w, b.w ) ); }",[xF.pow_float]),bF.pow_float="tsl_pow_float",bF.pow_vec2="tsl_pow_vec2",bF.pow_vec3="tsl_pow_vec3",bF.pow_vec4="tsl_pow_vec4");let vF="";!0!==/Firefox/g.test(navigator.userAgent)&&(vF+="diagnostic( off, derivative_uniformity );\n");class TF extends xM{constructor(e,t){super(e,t,new dF),this.uniformGroups={},this.builtins={},this.directives={},this.scopedArrays=new Map}needsToWorkingColorSpace(e){return!0===e.isVideoTexture&&e.colorSpace!==Yt}_generateTextureSample(e,t,s,i,r=this.shaderStage){return"fragment"===r?i?`textureSample( ${t}, ${t}_sampler, ${s}, ${i} )`:`textureSample( ${t}, ${t}_sampler, ${s} )`:this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,s):this.generateTextureLod(e,t,s,"0")}_generateVideoSample(e,t,s=this.shaderStage){if("fragment"===s)return`textureSampleBaseClampToEdge( ${e}, ${e}_sampler, vec2( ${t}.x, 1.0 - ${t}.y ) )`;console.error(`WebGPURenderer: THREE.VideoTexture does not support ${s} shader.`)}_generateTextureSampleLevel(e,t,s,i,r,n=this.shaderStage){return"fragment"===n&&!1===this.isUnfilterable(e)?`textureSampleLevel( ${t}, ${t}_sampler, ${s}, ${i} )`:this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,s,i):this.generateTextureLod(e,t,s,i)}generateFilteredTexture(e,t,s,i="0"){return this._include("biquadraticTexture"),`tsl_biquadraticTexture( ${t}, ${s}, i32( ${i} ) )`}generateTextureLod(e,t,s,i="0"){this._include("repeatWrapping");return`textureLoad( ${t}, tsl_repeatWrapping( ${s}, ${!0===e.isMultisampleRenderTargetTexture?`textureDimensions( ${t} )`:`textureDimensions( ${t}, 0 )`} ), i32( ${i} ) )`}generateTextureLoad(e,t,s,i,r="0u"){return i?`textureLoad( ${t}, ${s}, ${i}, ${r} )`:`textureLoad( ${t}, ${s}, ${r} )`}generateTextureStore(e,t,s,i){return`textureStore( ${t}, ${s}, ${i} )`}isUnfilterable(e){return"float"!==this.getComponentTypeFromTexture(e)||!this.isAvailable("float32Filterable")&&!0===e.isDataTexture&&e.type===Ie||!0===e.isMultisampleRenderTargetTexture}generateTexture(e,t,s,i,r=this.shaderStage){let n=null;return n=!0===e.isVideoTexture?this._generateVideoSample(t,s,r):this.isUnfilterable(e)?this.generateTextureLod(e,t,s,"0",i,r):this._generateTextureSample(e,t,s,i,r),n}generateTextureGrad(e,t,s,i,r,n=this.shaderStage){if("fragment"===n)return`textureSampleGrad( ${t}, ${t}_sampler, ${s}, ${i[0]}, ${i[1]} )`;console.error(`WebGPURenderer: THREE.TextureNode.gradient() does not support ${n} shader.`)}generateTextureCompare(e,t,s,i,r,n=this.shaderStage){if("fragment"===n)return`textureSampleCompare( ${t}, ${t}_sampler, ${s}, ${i} )`;console.error(`WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${n} shader.`)}generateTextureLevel(e,t,s,i,r,n=this.shaderStage){let o=null;return o=!0===e.isVideoTexture?this._generateVideoSample(t,s,n):this._generateTextureSampleLevel(e,t,s,i,r,n),o}generateTextureBias(e,t,s,i,r,n=this.shaderStage){if("fragment"===n)return`textureSampleBias( ${t}, ${t}_sampler, ${s}, ${i} )`;console.error(`WebGPURenderer: THREE.TextureNode.biasNode does not support ${n} shader.`)}getPropertyName(e,t=this.shaderStage){if(!0===e.isNodeVarying&&!0===e.needsInterpolation){if("vertex"===t)return`varyings.${e.name}`}else if(!0===e.isNodeUniform){const t=e.name,s=e.type;return"texture"===s||"cubeTexture"===s||"storageTexture"===s||"texture3D"===s?t:"buffer"===s||"storageBuffer"===s?`NodeBuffer_${e.id}.${t}`:e.groupNode.name+"."+t}return super.getPropertyName(e)}getOutputStructName(){return"output"}_getUniformGroupCount(e){return Object.keys(this.uniforms[e]).length}getFunctionOperator(e){const t=fF[e];return void 0!==t?(this._include(t),t):null}getStorageAccess(e){if(e.isStorageTextureNode)switch(e.access){case RA:return"read";case CA:return"write";default:return"read_write"}else switch(e.access){case NA:return"read_write";case AA:return"read";default:return"write"}}getUniformFromNode(e,t,s,i=null){const r=super.getUniformFromNode(e,t,s,i),n=this.getDataFromNode(e,s,this.globalCache);if(void 0===n.uniformGPU){let i;const o=e.groupNode,a=o.name,h=this.getBindGroupArray(a,s);if("texture"===t||"cubeTexture"===t||"storageTexture"===t||"texture3D"===t){let n=null;if("texture"===t||"storageTexture"===t?n=new _P(r.name,r.node,o,e.access?e.access:null):"cubeTexture"===t?n=new wP(r.name,r.node,o,e.access?e.access:null):"texture3D"===t&&(n=new SP(r.name,r.node,o,e.access?e.access:null)),n.store=!0===e.isStorageTextureNode,n.setVisibility(mF[s]),"fragment"===s&&!1===this.isUnfilterable(e.value)&&!1===n.store){const e=new QP(`${r.name}_sampler`,r.node,o);e.setVisibility(mF[s]),h.push(e,n),i=[e,n]}else h.push(n),i=[n]}else if("buffer"===t||"storageBuffer"===t){const r=new("storageBuffer"===t?sF:fP)(e,o);r.setVisibility(mF[s]),h.push(r),i=r}else{const e=this.uniformGroups[s]||(this.uniformGroups[s]={});let n=e[a];void 0===n&&(n=new bP(a,o),n.setVisibility(mF[s]),e[a]=n,h.push(n)),i=this.getNodeUniform(r,t),n.addUniform(i)}n.uniformGPU=i}return r}getBuiltin(e,t,s,i=this.shaderStage){const r=this.builtins[i]||(this.builtins[i]=new Map);return!1===r.has(e)&&r.set(e,{name:e,property:t,type:s}),t}hasBuiltin(e,t=this.shaderStage){return void 0!==this.builtins[t]&&this.builtins[t].has(e)}getVertexIndex(){return"vertex"===this.shaderStage?this.getBuiltin("vertex_index","vertexIndex","u32","attribute"):"vertexIndex"}buildFunctionCode(e){const t=e.layout,s=this.flowShaderNode(e),i=[];for(const e of t.inputs)i.push(e.name+" : "+this.getType(e.type));let r=`fn ${t.name}( ${i.join(", ")} ) -> ${this.getType(t.type)} {\n${s.vars}\n${s.code}\n`;return s.result&&(r+=`\treturn ${s.result};\n`),r+="\n}\n",r}getInstanceIndex(){return"vertex"===this.shaderStage?this.getBuiltin("instance_index","instanceIndex","u32","attribute"):"instanceIndex"}getInvocationLocalIndex(){return this.getBuiltin("local_invocation_index","invocationLocalIndex","u32","attribute")}getSubgroupSize(){return this.enableSubGroups(),this.getBuiltin("subgroup_size","subgroupSize","u32","attribute")}getInvocationSubgroupIndex(){return this.enableSubGroups(),this.getBuiltin("subgroup_invocation_id","invocationSubgroupIndex","u32","attribute")}getSubgroupIndex(){return this.enableSubGroups(),this.getBuiltin("subgroup_id","subgroupIndex","u32","attribute")}getDrawIndex(){return null}getFrontFacing(){return this.getBuiltin("front_facing","isFront","bool")}getFragCoord(){return this.getBuiltin("position","fragCoord","vec4")+".xy"}getFragDepth(){return"output."+this.getBuiltin("frag_depth","depth","f32","output")}isFlipY(){return!1}enableDirective(e,t=this.shaderStage){(this.directives[t]||(this.directives[t]=new Set)).add(e)}getDirectives(e){const t=[],s=this.directives[e];if(void 0!==s)for(const e of s)t.push(`enable ${e};`);return t.join("\n")}enableSubGroups(){this.enableDirective("subgroups")}enableSubgroupsF16(){this.enableDirective("subgroups-f16")}enableClipDistances(){this.enableDirective("clip_distances")}enableShaderF16(){this.enableDirective("f16")}enableDualSourceBlending(){this.enableDirective("dual_source_blending")}getBuiltins(e){const t=[],s=this.builtins[e];if(void 0!==s)for(const{name:e,property:i,type:r}of s.values())t.push(`@builtin( ${e} ) ${i} : ${r}`);return t.join(",\n\t")}getScopedArray(e,t,s,i){return!1===this.scopedArrays.has(e)&&this.scopedArrays.set(e,{name:e,scope:t,bufferType:s,bufferCount:i}),e}getScopedArrays(e){if("compute"!==e)return;const t=[];for(const{name:e,scope:s,bufferType:i,bufferCount:r}of this.scopedArrays.values()){const n=this.getType(i);t.push(`var<${s}> ${e}: array< ${n}, ${r} >;`)}return t.join("\n")}getAttributes(e){const t=[];if("compute"===e&&(this.getBuiltin("global_invocation_id","id","vec3","attribute"),this.getBuiltin("workgroup_id","workgroupId","vec3","attribute"),this.getBuiltin("local_invocation_id","localId","vec3","attribute"),this.getBuiltin("num_workgroups","numWorkgroups","vec3","attribute"),this.renderer.hasFeature("subgroups")&&(this.enableDirective("subgroups",e),this.getBuiltin("subgroup_size","subgroupSize","u32","attribute"))),"vertex"===e||"compute"===e){const e=this.getBuiltins("attribute");e&&t.push(e);const s=this.getAttributesArray();for(let e=0,i=s.length;e`)}const i=this.getBuiltins("output");return i&&t.push("\t"+i),t.join(",\n")}getStructs(e){const t=[],s=this.structs[e];for(let e=0,i=s.length;e output : ${r};\n\n`)}return t.join("\n\n")}getVar(e,t){return`var ${t} : ${this.getType(e)}`}getVars(e){const t=[],s=this.vars[e];if(void 0!==s)for(const e of s)t.push(`\t${this.getVar(e.type,e.name)};`);return`\n${t.join("\n")}\n`}getVaryings(e){const t=[];if("vertex"===e&&this.getBuiltin("position","Vertex","vec4","vertex"),"vertex"===e||"fragment"===e){const s=this.varyings,i=this.vars[e];for(let r=0;r";else if(!0===t.isDataArrayTexture||!0===t.isCompressedArrayTexture)i="texture_2d_array";else if(!0===t.isDepthTexture)i=`texture_depth${n}_2d`;else if(!0===t.isVideoTexture)i="texture_external";else if(!0===t.isData3DTexture)i="texture_3d";else if(!0===r.node.isStorageTextureNode){i=`texture_storage_2d<${aF(t)}, ${this.getStorageAccess(r.node)}>`}else{i=`texture${n}_2d<${this.getComponentTypeFromTexture(t).charAt(0)}32>`}s.push(`@binding( ${o.binding++} ) @group( ${o.group} ) var ${r.name} : ${i};`)}else if("buffer"===r.type||"storageBuffer"===r.type){const e=r.node,t=this.getType(e.bufferType),s=e.bufferCount,n=s>0?", "+s:"",a=e.isAtomic?`atomic<${t}>`:`${t}`,h=`\t${r.name} : array< ${a}${n} >\n`,u=e.isStorageBufferNode?`storage, ${this.getStorageAccess(e)}`:"uniform";i.push(this._getWGSLStructBinding("NodeBuffer_"+e.id,h,u,o.binding++,o.group))}else{const e=this.getType(this.getVectorType(r.type)),t=r.groupNode.name;(n[t]||(n[t]={index:o.binding++,id:o.group,snippets:[]})).snippets.push(`\t${r.name} : ${e}`)}}for(const e in n){const t=n[e];r.push(this._getWGSLStructBinding(e,t.snippets.join(",\n"),"uniform",t.index,t.id))}let o=s.join("\n");return o+=i.join("\n"),o+=r.join("\n"),o}buildCode(){const e=null!==this.material?{fragment:{},vertex:{}}:{compute:{}};this.sortBindingGroups();for(const t in e){const s=e[t];s.uniforms=this.getUniforms(t),s.attributes=this.getAttributes(t),s.varyings=this.getVaryings(t),s.structs=this.getStructs(t),s.vars=this.getVars(t),s.codes=this.getCodes(t),s.directives=this.getDirectives(t),s.scopedArrays=this.getScopedArrays(t);let i="// code\n\n";i+=this.flowCode[t];const r=this.flowNodes[t],n=r[r.length-1],o=n.outputNode,a=void 0!==o&&!0===o.isOutputStructNode;for(const e of r){const r=this.getFlowData(e),h=e.name;if(h&&(i.length>0&&(i+="\n"),i+=`\t// flow -> ${h}\n\t`),i+=`${r.code}\n\t`,e===n&&"compute"!==t)if(i+="// result\n\n\t","vertex"===t)i+=`varyings.Vertex = ${r.result};`;else if("fragment"===t)if(a)s.returnType=o.nodeType,i+=`return ${r.result};`;else{let e="\t@location(0) color: vec4";const t=this.getBuiltins("output");t&&(e+=",\n\t"+t),s.returnType="OutputStruct",s.structs+=this._getWGSLStruct("OutputStruct",e),s.structs+="\nvar output : OutputStruct;\n\n",i+=`output.color = ${r.result};\n\n\treturn output;`}}s.flow=i}null!==this.material?(this.vertexShader=this._getWGSLVertexCode(e.vertex),this.fragmentShader=this._getWGSLFragmentCode(e.fragment)):this.computeShader=this._getWGSLComputeCode(e.compute,(this.object.workgroupSize||[64]).join(", "))}getMethod(e,t=null){let s;return null!==t&&(s=this._getWGSLMethod(e+"_"+t)),void 0===s&&(s=this._getWGSLMethod(e)),s||e}getType(e){return yF[e]||e}isAvailable(e){let t=gF[e];return void 0===t&&("float32Filterable"===e&&(t=this.renderer.hasFeature("float32-filterable")),gF[e]=t),t}_getWGSLMethod(e){return void 0!==xF[e]&&this._include(e),bF[e]}_include(e){const t=xF[e];return t.build(this),null!==this.currentFunctionNode&&this.currentFunctionNode.includes.push(t),t}_getWGSLVertexCode(e){return`${this.getSignature()}\n// directives\n${e.directives}\n\n// uniforms\n${e.uniforms}\n\n// varyings\n${e.varyings}\nvar varyings : VaryingsStruct;\n\n// codes\n${e.codes}\n\n@vertex\nfn main( ${e.attributes} ) -> VaryingsStruct {\n\n\t// vars\n\t${e.vars}\n\n\t// flow\n\t${e.flow}\n\n\treturn varyings;\n\n}\n`}_getWGSLFragmentCode(e){return`${this.getSignature()}\n// global\n${vF}\n\n// uniforms\n${e.uniforms}\n\n// structs\n${e.structs}\n\n// codes\n${e.codes}\n\n@fragment\nfn main( ${e.varyings} ) -> ${e.returnType} {\n\n\t// vars\n\t${e.vars}\n\n\t// flow\n\t${e.flow}\n\n}\n`}_getWGSLComputeCode(e,t){return`${this.getSignature()}\n// directives\n${e.directives}\n\n// system\nvar instanceIndex : u32;\n\n// locals\n${e.scopedArrays}\n\n// uniforms\n${e.uniforms}\n\n// codes\n${e.codes}\n\n@compute @workgroup_size( ${t} )\nfn main( ${e.attributes} ) {\n\n\t// system\n\tinstanceIndex = id.x + id.y * numWorkgroups.x * u32(${t}) + id.z * numWorkgroups.x * numWorkgroups.y * u32(${t});\n\n\t// vars\n\t${e.vars}\n\n\t// flow\n\t${e.flow}\n\n}\n`}_getWGSLStruct(e,t){return`\nstruct ${e} {\n${t}\n};`}_getWGSLStructBinding(e,t,s,i=0,r=0){const n=e+"Struct";return`${this._getWGSLStruct(n,t)}\n@binding( ${i} ) @group( ${r} )\nvar<${s}> ${e} : ${n};`}}class _F{constructor(e){this.backend=e}getCurrentDepthStencilFormat(e){let t;return null!==e.depthTexture?t=this.getTextureFormatGPU(e.depthTexture):e.depth&&e.stencil?t=qN.Depth24PlusStencil8:e.depth&&(t=qN.Depth24Plus),t}getTextureFormatGPU(e){return this.backend.get(e).format}getCurrentColorFormat(e){let t;return t=null!==e.textures?this.getTextureFormatGPU(e.textures[0]):this.getPreferredCanvasFormat(),t}getCurrentColorSpace(e){return null!==e.textures?e.textures[0].colorSpace:this.backend.renderer.outputColorSpace}getPrimitiveTopology(e,t){return e.isPoints?SN:e.isLineSegments||e.isMesh&&!0===t.wireframe?MN:e.isLine?NN:e.isMesh?AN:void 0}getSampleCount(e){let t=1;return e>1&&(t=Math.pow(2,Math.floor(Math.log2(e))),2===t&&(t=4)),t}getSampleCountRenderContext(e){return null!==e.textures?this.getSampleCount(e.sampleCount):this.getSampleCount(this.backend.renderer.samples)}getPreferredCanvasFormat(){return navigator.userAgent.includes("Quest")?qN.BGRA8Unorm:navigator.gpu.getPreferredCanvasFormat()}}const wF=new Map([[Int8Array,["sint8","snorm8"]],[Uint8Array,["uint8","unorm8"]],[Int16Array,["sint16","snorm16"]],[Uint16Array,["uint16","unorm16"]],[Int32Array,["sint32","snorm32"]],[Uint32Array,["uint32","unorm32"]],[Float32Array,["float32"]]]),SF=new Map([[xn,["float16"]]]),MF=new Map([[Int32Array,"sint32"],[Int16Array,"sint32"],[Uint32Array,"uint32"],[Uint16Array,"uint32"],[Float32Array,"float32"]]);class NF{constructor(e){this.backend=e}createAttribute(e,t){const s=this._getBufferAttribute(e),i=this.backend,r=i.get(s);let n=r.buffer;if(void 0===n){const o=i.device;let a=s.array;if(!1===e.normalized&&(a.constructor===Int16Array||a.constructor===Uint16Array)){const e=new Uint32Array(a.length);for(let t=0;t1},layout:u.createPipelineLayout({bindGroupLayouts:d})};if(null===t)c.pipeline=u.createRenderPipeline(M);else{const e=new Promise((e=>{u.createRenderPipelineAsync(M).then((t=>{c.pipeline=t,e()}))}));t.push(e)}}createBundleEncoder(e){const t=this.backend,{utils:s,device:i}=t,r=s.getCurrentDepthStencilFormat(e),n={label:"renderBundleEncoder",colorFormats:[s.getCurrentColorFormat(e)],depthStencilFormat:r,sampleCount:this._getSampleCount(e)};return i.createRenderBundleEncoder(n)}createComputePipeline(e,t){const s=this.backend,i=s.device,r=s.get(e.computeProgram).module,n=s.get(e),o=[];for(const e of t){const t=s.get(e);o.push(t.layout)}n.pipeline=i.createComputePipeline({compute:r,layout:i.createPipelineLayout({bindGroupLayouts:o})})}_getBlending(e){let t,s;const i=e.blending,r=e.blendSrc,n=e.blendDst,o=e.blendEquation;if(5===i){const i=null!==e.blendSrcAlpha?e.blendSrcAlpha:r,a=null!==e.blendDstAlpha?e.blendDstAlpha:n,h=null!==e.blendEquationAlpha?e.blendEquationAlpha:o;t={srcFactor:this._getBlendFactor(r),dstFactor:this._getBlendFactor(n),operation:this._getBlendOperation(o)},s={srcFactor:this._getBlendFactor(i),dstFactor:this._getBlendFactor(a),operation:this._getBlendOperation(h)}}else{const r=(e,i,r,n)=>{t={srcFactor:e,dstFactor:i,operation:cA},s={srcFactor:r,dstFactor:n,operation:cA}};if(e.premultipliedAlpha)switch(i){case 1:r(QN,iA,QN,iA);break;case 2:r(QN,QN,QN,QN);break;case 3:r(KN,tA,KN,QN);break;case 4:r(KN,eA,KN,sA)}else switch(i){case 1:r(sA,iA,QN,iA);break;case 2:r(sA,QN,sA,QN);break;case 3:r(KN,tA,KN,QN);break;case 4:r(KN,eA,KN,eA)}}if(void 0!==t&&void 0!==s)return{color:t,alpha:s};console.error("THREE.WebGPURenderer: Invalid blending: ",i)}_getBlendFactor(e){let t;switch(e){case 200:t=KN;break;case 201:t=QN;break;case 202:t=eA;break;case 203:t=tA;break;case R:t=sA;break;case E:t=iA;break;case 208:t=rA;break;case 209:t=nA;break;case 206:t=oA;break;case 207:t=aA;break;case 210:t=hA;break;case 211:t=uA;break;case 212:t=lA;break;default:console.error("THREE.WebGPURenderer: Blend factor not supported.",e)}return t}_getStencilCompare(e){let t;const s=e.stencilFunc;switch(s){case 512:t=RN;break;case bs:t=UN;break;case 513:t=EN;break;case 515:t=IN;break;case 514:t=BN;break;case 518:t=zN;break;case 516:t=PN;break;case 517:t=FN;break;default:console.error("THREE.WebGPURenderer: Invalid stencil function.",s)}return t}_getStencilOperation(e){let t;switch(e){case ns:t=xA;break;case 0:t=bA;break;case 7681:t=vA;break;case 5386:t=TA;break;case 7682:t=_A;break;case 7683:t=wA;break;case 34055:t=SA;break;case 34056:t=MA;break;default:console.error("THREE.WebGPURenderer: Invalid stencil operation.",t)}return t}_getBlendOperation(e){let t;switch(e){case v:t=cA;break;case 101:t=dA;break;case 102:t=pA;break;case 103:t=mA;break;case 104:t=gA;break;default:console.error("THREE.WebGPUPipelineUtils: Blend equation not supported.",e)}return t}_getPrimitiveState(e,t,s){const i={},r=this.backend.utils;switch(i.topology=r.getPrimitiveTopology(e,s),null!==t.index&&!0===e.isLine&&!0!==e.isLineSegments&&(i.stripIndexFormat=t.index.array instanceof Uint16Array?jN:HN),s.side){case c:i.frontFace=DN,i.cullMode=WN;break;case d:i.frontFace=DN,i.cullMode=GN;break;case 2:i.frontFace=DN,i.cullMode=kN;break;default:console.error("THREE.WebGPUPipelineUtils: Unknown material.side value.",s.side)}return i}_getColorWriteMask(e){return!0===e.colorWrite?yA:fA}_getDepthCompare(e){let t;if(!1===e.depthTest)t=UN;else{const s=e.depthFunc;switch(s){case 0:t=RN;break;case 1:t=UN;break;case 2:t=EN;break;case 3:t=IN;break;case 4:t=BN;break;case 5:t=zN;break;case 6:t=PN;break;case 7:t=FN;break;default:console.error("THREE.WebGPUPipelineUtils: Invalid depth function.",s)}}return t}}class RF extends PP{constructor(e={}){super(e),this.isWebGPUBackend=!0,this.parameters.alpha=void 0===e.alpha||e.alpha,this.parameters.requiredLimits=void 0===e.requiredLimits?{}:e.requiredLimits,this.trackTimestamp=!0===e.trackTimestamp,this.device=null,this.context=null,this.colorBuffer=null,this.defaultRenderPassdescriptor=null,this.utils=new _F(this),this.attributeUtils=new NF(this),this.bindingUtils=new AF(this),this.pipelineUtils=new CF(this),this.textureUtils=new oF(this),this.occludedResolveCache=new Map}async init(e){await super.init(e);const t=this.parameters;let s;if(void 0===t.device){const e={powerPreference:t.powerPreference},i=await navigator.gpu.requestAdapter(e);if(null===i)throw new Error("WebGPUBackend: Unable to create WebGPU adapter.");const r=Object.values(jA),n=[];for(const e of r)i.features.has(e)&&n.push(e);const o={requiredFeatures:n,requiredLimits:t.requiredLimits};s=await i.requestDevice(o)}else s=t.device;const i=void 0!==t.context?t.context:e.domElement.getContext("webgpu");this.device=s,this.context=i;const r=t.alpha?"premultiplied":"opaque";this.trackTimestamp=this.trackTimestamp&&this.hasFeature(jA.TimestampQuery),this.context.configure({device:this.device,format:this.utils.getPreferredCanvasFormat(),usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC,alphaMode:r}),this.updateSize()}get coordinateSystem(){return Ds}async getArrayBufferAsync(e){return await this.attributeUtils.getArrayBufferAsync(e)}getContext(){return this.context}_getDefaultRenderPassDescriptor(){let e=this.defaultRenderPassdescriptor;if(null===e){const t=this.renderer;e={colorAttachments:[{view:null}],depthStencilAttachment:{view:this.textureUtils.getDepthBuffer(t.depth,t.stencil).createView()}};const s=e.colorAttachments[0];this.renderer.samples>0?s.view=this.colorBuffer.createView():s.resolveTarget=void 0,this.defaultRenderPassdescriptor=e}const t=e.colorAttachments[0];return this.renderer.samples>0?t.resolveTarget=this.context.getCurrentTexture().createView():t.view=this.context.getCurrentTexture().createView(),e}_getRenderPassDescriptor(e){const t=e.renderTarget,s=this.get(t);let i=s.descriptors;if(void 0===i||s.width!==t.width||s.height!==t.height||s.activeMipmapLevel!==t.activeMipmapLevel||s.samples!==t.samples){i={},s.descriptors=i;const e=()=>{t.removeEventListener("dispose",e),this.delete(t)};t.addEventListener("dispose",e)}const r=e.getCacheKey();let n=i[r];if(void 0===n){const o=e.textures,a=[];for(let t=0;t0&&(t.currentOcclusionQuerySet&&t.currentOcclusionQuerySet.destroy(),t.currentOcclusionQueryBuffer&&t.currentOcclusionQueryBuffer.destroy(),t.currentOcclusionQuerySet=t.occlusionQuerySet,t.currentOcclusionQueryBuffer=t.occlusionQueryBuffer,t.currentOcclusionQueryObjects=t.occlusionQueryObjects,r=s.createQuerySet({type:"occlusion",count:i}),t.occlusionQuerySet=r,t.occlusionQueryIndex=0,t.occlusionQueryObjects=new Array(i),t.lastOcclusionObject=null),n=null===e.textures?this._getDefaultRenderPassDescriptor():this._getRenderPassDescriptor(e),this.initTimestampQuery(e,n),n.occlusionQuerySet=r;const o=n.depthStencilAttachment;if(null!==e.textures){const t=n.colorAttachments;for(let s=0;s0&&t.currentPass.executeBundles(t.renderBundles),s>t.occlusionQueryIndex&&t.currentPass.endOcclusionQuery(),t.currentPass.end(),s>0){const i=8*s;let r=this.occludedResolveCache.get(i);void 0===r&&(r=this.device.createBuffer({size:i,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),this.occludedResolveCache.set(i,r));const n=this.device.createBuffer({size:i,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});t.encoder.resolveQuerySet(t.occlusionQuerySet,0,s,r,0),t.encoder.copyBufferToBuffer(r,0,n,0,i),t.occlusionQueryBuffer=n,this.resolveOccludedAsync(e)}if(this.prepareTimestampBuffer(e,t.encoder),this.device.queue.submit([t.encoder.finish()]),null!==e.textures){const t=e.textures;for(let e=0;eo?(h.x=Math.min(t.dispatchCount,o),h.y=Math.ceil(t.dispatchCount/o)):h.x=t.dispatchCount,r.dispatchWorkgroups(h.x,h.y,h.z)}finishCompute(e){const t=this.get(e);t.passEncoderGPU.end(),this.prepareTimestampBuffer(e,t.cmdEncoderGPU),this.device.queue.submit([t.cmdEncoderGPU.finish()])}draw(e,t){const{object:s,context:i,pipeline:r}=e,n=e.getBindings(),o=this.get(i),a=this.get(r).pipeline,h=o.currentSets,u=o.currentPass,l=e.getDrawParameters();if(null===l)return;h.pipeline!==a&&(u.setPipeline(a),h.pipeline=a);const c=h.bindingGroups;for(let e=0,t=n.length;e1?0:s;u.drawIndexed(t[s],i,e[s]/n,0,o)}}else if(!0===p){const{vertexCount:e,instanceCount:i,firstVertex:r}=l;u.drawIndexed(e,i,r,0,0),t.update(s,e,i)}else{const{vertexCount:e,instanceCount:i,firstVertex:r}=l;u.draw(e,i,r,0),t.update(s,e,i)}}needsRenderUpdate(e){const t=this.get(e),{object:s,material:i}=e,r=this.utils,n=r.getSampleCountRenderContext(e.context),o=r.getCurrentColorSpace(e.context),a=r.getCurrentColorFormat(e.context),h=r.getCurrentDepthStencilFormat(e.context),u=r.getPrimitiveTopology(s,i);let l=!1;return t.material===i&&t.materialVersion===i.version&&t.transparent===i.transparent&&t.blending===i.blending&&t.premultipliedAlpha===i.premultipliedAlpha&&t.blendSrc===i.blendSrc&&t.blendDst===i.blendDst&&t.blendEquation===i.blendEquation&&t.blendSrcAlpha===i.blendSrcAlpha&&t.blendDstAlpha===i.blendDstAlpha&&t.blendEquationAlpha===i.blendEquationAlpha&&t.colorWrite===i.colorWrite&&t.depthWrite===i.depthWrite&&t.depthTest===i.depthTest&&t.depthFunc===i.depthFunc&&t.stencilWrite===i.stencilWrite&&t.stencilFunc===i.stencilFunc&&t.stencilFail===i.stencilFail&&t.stencilZFail===i.stencilZFail&&t.stencilZPass===i.stencilZPass&&t.stencilFuncMask===i.stencilFuncMask&&t.stencilWriteMask===i.stencilWriteMask&&t.side===i.side&&t.alphaToCoverage===i.alphaToCoverage&&t.sampleCount===n&&t.colorSpace===o&&t.colorFormat===a&&t.depthStencilFormat===h&&t.primitiveTopology===u&&t.clippingContextCacheKey===e.clippingContext.cacheKey||(t.material=i,t.materialVersion=i.version,t.transparent=i.transparent,t.blending=i.blending,t.premultipliedAlpha=i.premultipliedAlpha,t.blendSrc=i.blendSrc,t.blendDst=i.blendDst,t.blendEquation=i.blendEquation,t.blendSrcAlpha=i.blendSrcAlpha,t.blendDstAlpha=i.blendDstAlpha,t.blendEquationAlpha=i.blendEquationAlpha,t.colorWrite=i.colorWrite,t.depthWrite=i.depthWrite,t.depthTest=i.depthTest,t.depthFunc=i.depthFunc,t.stencilWrite=i.stencilWrite,t.stencilFunc=i.stencilFunc,t.stencilFail=i.stencilFail,t.stencilZFail=i.stencilZFail,t.stencilZPass=i.stencilZPass,t.stencilFuncMask=i.stencilFuncMask,t.stencilWriteMask=i.stencilWriteMask,t.side=i.side,t.alphaToCoverage=i.alphaToCoverage,t.sampleCount=n,t.colorSpace=o,t.colorFormat=a,t.depthStencilFormat=h,t.primitiveTopology=u,t.clippingContextCacheKey=e.clippingContext.cacheKey,l=!0),l}getRenderCacheKey(e){const{object:t,material:s}=e,i=this.utils,r=e.context;return[s.transparent,s.blending,s.premultipliedAlpha,s.blendSrc,s.blendDst,s.blendEquation,s.blendSrcAlpha,s.blendDstAlpha,s.blendEquationAlpha,s.colorWrite,s.depthWrite,s.depthTest,s.depthFunc,s.stencilWrite,s.stencilFunc,s.stencilFail,s.stencilZFail,s.stencilZPass,s.stencilFuncMask,s.stencilWriteMask,s.side,i.getSampleCountRenderContext(r),i.getCurrentColorSpace(r),i.getCurrentColorFormat(r),i.getCurrentDepthStencilFormat(r),i.getPrimitiveTopology(t,s),e.clippingContext.cacheKey].join()}createSampler(e){this.textureUtils.createSampler(e)}destroySampler(e){this.textureUtils.destroySampler(e)}createDefaultTexture(e){this.textureUtils.createDefaultTexture(e)}createTexture(e,t){this.textureUtils.createTexture(e,t)}updateTexture(e,t){this.textureUtils.updateTexture(e,t)}generateMipmaps(e){this.textureUtils.generateMipmaps(e)}destroyTexture(e){this.textureUtils.destroyTexture(e)}copyTextureToBuffer(e,t,s,i,r,n){return this.textureUtils.copyTextureToBuffer(e,t,s,i,r,n)}initTimestampQuery(e,t){if(!this.trackTimestamp)return;const s=this.get(e);if(!s.timeStampQuerySet){const e=this.device.createQuerySet({type:"timestamp",count:2}),i={querySet:e,beginningOfPassWriteIndex:0,endOfPassWriteIndex:1};Object.assign(t,{timestampWrites:i}),s.timeStampQuerySet=e}}prepareTimestampBuffer(e,t){if(!this.trackTimestamp)return;const s=this.get(e),i=2*BigInt64Array.BYTES_PER_ELEMENT;void 0===s.currentTimestampQueryBuffers&&(s.currentTimestampQueryBuffers={resolveBuffer:this.device.createBuffer({label:"timestamp resolve buffer",size:i,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),resultBuffer:this.device.createBuffer({label:"timestamp result buffer",size:i,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),isMappingPending:!1});const{resolveBuffer:r,resultBuffer:n,isMappingPending:o}=s.currentTimestampQueryBuffers;!0!==o&&(t.resolveQuerySet(s.timeStampQuerySet,0,2,r,0),t.copyBufferToBuffer(r,0,n,0,i))}async resolveTimestampAsync(e,t="render"){if(!this.trackTimestamp)return;const s=this.get(e);if(void 0===s.currentTimestampQueryBuffers)return;const{resultBuffer:i,isMappingPending:r}=s.currentTimestampQueryBuffers;!0!==r&&(s.currentTimestampQueryBuffers.isMappingPending=!0,i.mapAsync(GPUMapMode.READ).then((()=>{const e=new BigUint64Array(i.getMappedRange()),r=Number(e[1]-e[0])/1e6;this.renderer.info.updateTimestamp(t,r),i.unmap(),s.currentTimestampQueryBuffers.isMappingPending=!1})))}createNodeBuilder(e,t){return new TF(e,t)}createProgram(e){this.get(e).module={module:this.device.createShaderModule({code:e.code,label:e.stage}),entryPoint:"main"}}destroyProgram(e){this.delete(e)}createRenderPipeline(e,t){this.pipelineUtils.createRenderPipeline(e,t)}createComputePipeline(e,t){this.pipelineUtils.createComputePipeline(e,t)}beginBundle(e){const t=this.get(e);t._currentPass=t.currentPass,t._currentSets=t.currentSets,t.currentSets={attributes:{},bindingGroups:[],pipeline:null,index:null},t.currentPass=this.pipelineUtils.createBundleEncoder(e)}finishBundle(e,t){const s=this.get(e),i=s.currentPass.finish();this.get(t).bundleGPU=i,s.currentSets=s._currentSets,s.currentPass=s._currentPass}addBundle(e,t){this.get(e).renderBundles.push(this.get(t).bundleGPU)}createBindings(e){this.bindingUtils.createBindings(e)}updateBindings(e){this.bindingUtils.createBindings(e)}updateBinding(e){this.bindingUtils.updateBinding(e)}createIndexAttribute(e){this.attributeUtils.createAttribute(e,GPUBufferUsage.INDEX|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST)}createAttribute(e){this.attributeUtils.createAttribute(e,GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST)}createStorageAttribute(e){this.attributeUtils.createAttribute(e,GPUBufferUsage.STORAGE|GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST)}updateAttribute(e){this.attributeUtils.updateAttribute(e)}destroyAttribute(e){this.attributeUtils.destroyAttribute(e)}updateSize(){this.colorBuffer=this.textureUtils.getColorBuffer(),this.defaultRenderPassdescriptor=null}getMaxAnisotropy(){return 16}hasFeature(e){return this.device.features.has(e)}copyTextureToTexture(e,t,s=null,i=null,r=0){let n=0,o=0,a=0,h=0,u=0,l=0,c=e.image.width,d=e.image.height;null!==s&&(h=s.x,u=s.y,l=s.z||0,c=s.width,d=s.height),null!==i&&(n=i.x,o=i.y,a=i.z||0);const p=this.device.createCommandEncoder({label:"copyTextureToTexture_"+e.id+"_"+t.id}),m=this.get(e).texture,g=this.get(t).texture;p.copyTextureToTexture({texture:m,mipLevel:r,origin:{x:h,y:u,z:l}},{texture:g,mipLevel:r,origin:{x:n,y:o,z:a}},[c,d,1]),this.device.queue.submit([p.finish()])}copyFramebufferToTexture(e,t,s){const i=this.get(t),{encoder:r,descriptor:n}=i;let o=null;o=t.renderTarget?e.isDepthTexture?this.get(t.depthTexture).texture:this.get(t.textures[0]).texture:e.isDepthTexture?this.textureUtils.getDepthBuffer(t.depth,t.stencil):this.context.getCurrentTexture();const a=this.get(e).texture;if(o.format===a.format){i.currentPass.end(),r.copyTextureToTexture({texture:o,origin:{x:s.x,y:s.y,z:0}},{texture:a},[s.z,s.w]),e.generateMipmaps&&this.textureUtils.generateMipmaps(e);for(let e=0;e(console.warn("THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend."),new JP(e)));super(new t(e),e),this.nodes.library=new BF,this.isWebGPURenderer=!0}}class PF extends Ga{constructor(){super(),this.isBundleGroup=!0,this.type="BundleGroup",this.static=!0,this.version=0}set needsUpdate(e){!0===e&&this.version++}}const FF=new pT,zF=new dN(FF);class UF{constructor(e,t=Xp(0,0,1,1)){this.renderer=e,this.outputNode=t,this.outputColorTransform=!0,this.needsUpdate=!0,FF.name="PostProcessing"}render(){this.update();const e=this.renderer,t=e.toneMapping,s=e.outputColorSpace;e.toneMapping=0,e.outputColorSpace=Jt,zF.render(e),e.toneMapping=t,e.outputColorSpace=s}update(){if(!0===this.needsUpdate){const e=this.renderer,t=e.toneMapping,s=e.outputColorSpace;zF.material.fragmentNode=!0===this.outputColorTransform?Ty(this.outputNode,t,s):this.outputNode.context({toneMapping:t,outputColorSpace:s}),zF.material.needsUpdate=!0,this.needsUpdate=!1}}async renderAsync(){this.update();const e=this.renderer,t=e.toneMapping,s=e.outputColorSpace;e.toneMapping=0,e.outputColorSpace=Jt,await zF.renderAsync(e),e.toneMapping=t,e.outputColorSpace=s}}class OF extends vi{constructor(e=1,t=1){super(),this.image={width:e,height:t},this.magFilter=Te,this.minFilter=Te,this.isStorageTexture=!0}}class LF extends ln{constructor(e,t,s=Float32Array){!1===ArrayBuffer.isView(e)&&(e=new s(e*t)),super(e,t),this.isStorageBufferAttribute=!0}}class VF extends Do{constructor(e,t,s=Float32Array){!1===ArrayBuffer.isView(e)&&(e=new s(e*t)),super(e,t),this.isStorageInstancedBufferAttribute=!0}}class DF extends tl{constructor(e){super(e),this.textures={},this.nodes={}}load(e,t,s,i){const r=new rl(this.manager);r.setPath(this.path),r.setRequestHeader(this.requestHeader),r.setWithCredentials(this.withCredentials),r.load(e,(s=>{try{t(this.parse(JSON.parse(s)))}catch(t){i?i(t):console.error(t),this.manager.itemError(e)}}),s,i)}parseNodes(e){const t={};if(void 0!==e){for(const s of e){const{uuid:e,type:i}=s;t[e]=this.createNodeFromType(i),t[e].uuid=e}const s={nodes:t,textures:this.textures};for(const i of e){i.meta=s;t[i.uuid].deserialize(i),delete i.meta}}return t}parse(e){const t=this.createNodeFromType(e.type);t.uuid=e.uuid;const s={nodes:this.parseNodes(e.nodes),textures:this.textures};return e.meta=s,t.deserialize(e),delete e.meta,t}setTextures(e){return this.textures=e,this}setNodes(e){return this.nodes=e,this}createNodeFromType(e){return void 0===this.nodes[e]?(console.error("THREE.NodeLoader: Node type not found:",e),Up()):Sp(new this.nodes[e])}}class kF extends Bl{constructor(e){super(e),this.nodes={},this.nodeMaterials={}}parse(e){const t=super.parse(e),s=this.nodes,i=e.inputNodes;for(const e in i){const r=i[e];t[e]=s[r]}return t}setNodes(e){return this.nodes=e,this}setNodeMaterials(e){return this.nodeMaterials=e,this}createMaterialFromType(e){const t=this.nodeMaterials[e];return void 0!==t?new t:super.createMaterialFromType(e)}}class GF extends zl{constructor(e){super(e),this.nodes={},this.nodeMaterials={},this._nodesJSON=null}setNodes(e){return this.nodes=e,this}setNodeMaterials(e){return this.nodeMaterials=e,this}parse(e,t){this._nodesJSON=e.nodes;const s=super.parse(e,t);return this._nodesJSON=null,s}parseNodes(e,t){if(void 0!==e){const s=new DF;return s.setNodes(this.nodes),s.setTextures(t),s.parseNodes(e)}return{}}parseMaterials(e,t){const s={};if(void 0!==e){const i=this.parseNodes(this._nodesJSON,t),r=new kF;r.setTextures(t),r.setNodes(i),r.setNodeMaterials(this.nodeMaterials);for(let t=0,i=e.length;t> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' + + _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' + + _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] + + _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ]; + + // .toLowerCase() here flattens concatenated strings to save heap memory space. + return uuid.toLowerCase(); + +} + +function clamp$1( value, min, max ) { + + return Math.max( min, Math.min( max, value ) ); + +} + +// compute euclidean modulo of m % n +// https://en.wikipedia.org/wiki/Modulo_operation +function euclideanModulo( n, m ) { + + return ( ( n % m ) + m ) % m; + +} + +// Linear mapping from range to range +function mapLinear( x, a1, a2, b1, b2 ) { + + return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); + +} + +// https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/ +function inverseLerp( x, y, value ) { + + if ( x !== y ) { + + return ( value - x ) / ( y - x ); + + } else { + + return 0; + + } + +} + +// https://en.wikipedia.org/wiki/Linear_interpolation +function lerp( x, y, t ) { + + return ( 1 - t ) * x + t * y; + +} + +// http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ +function damp( x, y, lambda, dt ) { + + return lerp( x, y, 1 - Math.exp( - lambda * dt ) ); + +} + +// https://www.desmos.com/calculator/vcsjnyz7x4 +function pingpong( x, length = 1 ) { + + return length - Math.abs( euclideanModulo( x, length * 2 ) - length ); + +} + +// http://en.wikipedia.org/wiki/Smoothstep +function smoothstep$1( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min ) / ( max - min ); + + return x * x * ( 3 - 2 * x ); + +} + +function smootherstep( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min ) / ( max - min ); + + return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); + +} + +// Random integer from interval +function randInt( low, high ) { + + return low + Math.floor( Math.random() * ( high - low + 1 ) ); + +} + +// Random float from interval +function randFloat( low, high ) { + + return low + Math.random() * ( high - low ); + +} + +// Random float from <-range/2, range/2> interval +function randFloatSpread( range ) { + + return range * ( 0.5 - Math.random() ); + +} + +// Deterministic pseudo-random float in the interval [ 0, 1 ] +function seededRandom( s ) { + + if ( s !== undefined ) _seed = s; + + // Mulberry32 generator + + let t = _seed += 0x6D2B79F5; + + t = Math.imul( t ^ t >>> 15, t | 1 ); + + t ^= t + Math.imul( t ^ t >>> 7, t | 61 ); + + return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296; + +} + +function degToRad( degrees ) { + + return degrees * DEG2RAD; + +} + +function radToDeg( radians ) { + + return radians * RAD2DEG; + +} + +function isPowerOfTwo( value ) { + + return ( value & ( value - 1 ) ) === 0 && value !== 0; + +} + +function ceilPowerOfTwo( value ) { + + return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); + +} + +function floorPowerOfTwo( value ) { + + return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); + +} + +function setQuaternionFromProperEuler( q, a, b, c, order ) { + + // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles + + // rotations are applied to the axes in the order specified by 'order' + // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c' + // angles are in radians + + const cos = Math.cos; + const sin = Math.sin; + + const c2 = cos( b / 2 ); + const s2 = sin( b / 2 ); + + const c13 = cos( ( a + c ) / 2 ); + const s13 = sin( ( a + c ) / 2 ); + + const c1_3 = cos( ( a - c ) / 2 ); + const s1_3 = sin( ( a - c ) / 2 ); + + const c3_1 = cos( ( c - a ) / 2 ); + const s3_1 = sin( ( c - a ) / 2 ); + + switch ( order ) { + + case 'XYX': + q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 ); + break; + + case 'YZY': + q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 ); + break; + + case 'ZXZ': + q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 ); + break; + + case 'XZX': + q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 ); + break; + + case 'YXY': + q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 ); + break; + + case 'ZYZ': + q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 ); + break; + + default: + console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order ); + + } + +} + +function denormalize( value, array ) { + + switch ( array.constructor ) { + + case Float32Array: + + return value; + + case Uint32Array: + + return value / 4294967295.0; + + case Uint16Array: + + return value / 65535.0; + + case Uint8Array: + + return value / 255.0; + + case Int32Array: + + return Math.max( value / 2147483647.0, - 1.0 ); + + case Int16Array: + + return Math.max( value / 32767.0, - 1.0 ); + + case Int8Array: + + return Math.max( value / 127.0, - 1.0 ); + + default: + + throw new Error( 'Invalid component type.' ); + + } + +} + +function normalize$1( value, array ) { + + switch ( array.constructor ) { + + case Float32Array: + + return value; + + case Uint32Array: + + return Math.round( value * 4294967295.0 ); + + case Uint16Array: + + return Math.round( value * 65535.0 ); + + case Uint8Array: + + return Math.round( value * 255.0 ); + + case Int32Array: + + return Math.round( value * 2147483647.0 ); + + case Int16Array: + + return Math.round( value * 32767.0 ); + + case Int8Array: + + return Math.round( value * 127.0 ); + + default: + + throw new Error( 'Invalid component type.' ); + + } + +} + +const MathUtils = { + DEG2RAD: DEG2RAD, + RAD2DEG: RAD2DEG, + generateUUID: generateUUID, + clamp: clamp$1, + euclideanModulo: euclideanModulo, + mapLinear: mapLinear, + inverseLerp: inverseLerp, + lerp: lerp, + damp: damp, + pingpong: pingpong, + smoothstep: smoothstep$1, + smootherstep: smootherstep, + randInt: randInt, + randFloat: randFloat, + randFloatSpread: randFloatSpread, + seededRandom: seededRandom, + degToRad: degToRad, + radToDeg: radToDeg, + isPowerOfTwo: isPowerOfTwo, + ceilPowerOfTwo: ceilPowerOfTwo, + floorPowerOfTwo: floorPowerOfTwo, + setQuaternionFromProperEuler: setQuaternionFromProperEuler, + normalize: normalize$1, + denormalize: denormalize +}; + +class Vector2 { + + constructor( x = 0, y = 0 ) { + + Vector2.prototype.isVector2 = true; + + this.x = x; + this.y = y; + + } + + get width() { + + return this.x; + + } + + set width( value ) { + + this.x = value; + + } + + get height() { + + return this.y; + + } + + set height( value ) { + + this.y = value; + + } + + set( x, y ) { + + this.x = x; + this.y = y; + + return this; + + } + + setScalar( scalar ) { + + this.x = scalar; + this.y = scalar; + + return this; + + } + + setX( x ) { + + this.x = x; + + return this; + + } + + setY( y ) { + + this.y = y; + + return this; + + } + + setComponent( index, value ) { + + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + default: throw new Error( 'index is out of range: ' + index ); + + } + + return this; + + } + + getComponent( index ) { + + switch ( index ) { + + case 0: return this.x; + case 1: return this.y; + default: throw new Error( 'index is out of range: ' + index ); + + } + + } + + clone() { + + return new this.constructor( this.x, this.y ); + + } + + copy( v ) { + + this.x = v.x; + this.y = v.y; + + return this; + + } + + add( v ) { + + this.x += v.x; + this.y += v.y; + + return this; + + } + + addScalar( s ) { + + this.x += s; + this.y += s; + + return this; + + } + + addVectors( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + + return this; + + } + + addScaledVector( v, s ) { + + this.x += v.x * s; + this.y += v.y * s; + + return this; + + } + + sub( v ) { + + this.x -= v.x; + this.y -= v.y; + + return this; + + } + + subScalar( s ) { + + this.x -= s; + this.y -= s; + + return this; + + } + + subVectors( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + + return this; + + } + + multiply( v ) { + + this.x *= v.x; + this.y *= v.y; + + return this; + + } + + multiplyScalar( scalar ) { + + this.x *= scalar; + this.y *= scalar; + + return this; + + } + + divide( v ) { + + this.x /= v.x; + this.y /= v.y; + + return this; + + } + + divideScalar( scalar ) { + + return this.multiplyScalar( 1 / scalar ); + + } + + applyMatrix3( m ) { + + const x = this.x, y = this.y; + const e = m.elements; + + this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ]; + this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ]; + + return this; + + } + + min( v ) { + + this.x = Math.min( this.x, v.x ); + this.y = Math.min( this.y, v.y ); + + return this; + + } + + max( v ) { + + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + + return this; + + } + + clamp( min, max ) { + + // assumes min < max, componentwise + + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + + return this; + + } + + clampScalar( minVal, maxVal ) { + + this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); + this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); + + return this; + + } + + clampLength( min, max ) { + + const length = this.length(); + + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + + } + + floor() { + + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + + return this; + + } + + ceil() { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + + return this; + + } + + round() { + + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + + return this; + + } + + roundToZero() { + + this.x = Math.trunc( this.x ); + this.y = Math.trunc( this.y ); + + return this; + + } + + negate() { + + this.x = - this.x; + this.y = - this.y; + + return this; + + } + + dot( v ) { + + return this.x * v.x + this.y * v.y; + + } + + cross( v ) { + + return this.x * v.y - this.y * v.x; + + } + + lengthSq() { + + return this.x * this.x + this.y * this.y; + + } + + length() { + + return Math.sqrt( this.x * this.x + this.y * this.y ); + + } + + manhattanLength() { + + return Math.abs( this.x ) + Math.abs( this.y ); + + } + + normalize() { + + return this.divideScalar( this.length() || 1 ); + + } + + angle() { + + // computes the angle in radians with respect to the positive x-axis + + const angle = Math.atan2( - this.y, - this.x ) + Math.PI; + + return angle; + + } + + angleTo( v ) { + + const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); + + if ( denominator === 0 ) return Math.PI / 2; + + const theta = this.dot( v ) / denominator; + + // clamp, to handle numerical problems + + return Math.acos( clamp$1( theta, - 1, 1 ) ); + + } + + distanceTo( v ) { + + return Math.sqrt( this.distanceToSquared( v ) ); + + } + + distanceToSquared( v ) { + + const dx = this.x - v.x, dy = this.y - v.y; + return dx * dx + dy * dy; + + } + + manhattanDistanceTo( v ) { + + return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ); + + } + + setLength( length ) { + + return this.normalize().multiplyScalar( length ); + + } + + lerp( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + + return this; + + } + + lerpVectors( v1, v2, alpha ) { + + this.x = v1.x + ( v2.x - v1.x ) * alpha; + this.y = v1.y + ( v2.y - v1.y ) * alpha; + + return this; + + } + + equals( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) ); + + } + + fromArray( array, offset = 0 ) { + + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + + return this; + + } + + toArray( array = [], offset = 0 ) { + + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + + return array; + + } + + fromBufferAttribute( attribute, index ) { + + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + + return this; + + } + + rotateAround( center, angle ) { + + const c = Math.cos( angle ), s = Math.sin( angle ); + + const x = this.x - center.x; + const y = this.y - center.y; + + this.x = x * c - y * s + center.x; + this.y = x * s + y * c + center.y; + + return this; + + } + + random() { + + this.x = Math.random(); + this.y = Math.random(); + + return this; + + } + + *[ Symbol.iterator ]() { + + yield this.x; + yield this.y; + + } + +} + +class Matrix3 { + + constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { + + Matrix3.prototype.isMatrix3 = true; + + this.elements = [ + + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + + ]; + + if ( n11 !== undefined ) { + + this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ); + + } + + } + + set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { + + const te = this.elements; + + te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31; + te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32; + te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33; + + return this; + + } + + identity() { + + this.set( + + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + + ); + + return this; + + } + + copy( m ) { + + const te = this.elements; + const me = m.elements; + + te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; + te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; + te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ]; + + return this; + + } + + extractBasis( xAxis, yAxis, zAxis ) { + + xAxis.setFromMatrix3Column( this, 0 ); + yAxis.setFromMatrix3Column( this, 1 ); + zAxis.setFromMatrix3Column( this, 2 ); + + return this; + + } + + setFromMatrix4( m ) { + + const me = m.elements; + + this.set( + + me[ 0 ], me[ 4 ], me[ 8 ], + me[ 1 ], me[ 5 ], me[ 9 ], + me[ 2 ], me[ 6 ], me[ 10 ] + + ); + + return this; + + } + + multiply( m ) { + + return this.multiplyMatrices( this, m ); + + } + + premultiply( m ) { + + return this.multiplyMatrices( m, this ); + + } + + multiplyMatrices( a, b ) { + + const ae = a.elements; + const be = b.elements; + const te = this.elements; + + const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ]; + const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ]; + const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ]; + + const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ]; + const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ]; + const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ]; + + te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31; + te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32; + te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33; + + te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31; + te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32; + te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33; + + te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31; + te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32; + te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33; + + return this; + + } + + multiplyScalar( s ) { + + const te = this.elements; + + te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; + te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; + te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; + + return this; + + } + + determinant() { + + const te = this.elements; + + const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], + d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], + g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; + + return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; + + } + + invert() { + + const te = this.elements, + + n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], + n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ], + n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ], + + t11 = n33 * n22 - n32 * n23, + t12 = n32 * n13 - n33 * n12, + t13 = n23 * n12 - n22 * n13, + + det = n11 * t11 + n21 * t12 + n31 * t13; + + if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + + const detInv = 1 / det; + + te[ 0 ] = t11 * detInv; + te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; + te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; + + te[ 3 ] = t12 * detInv; + te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv; + te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv; + + te[ 6 ] = t13 * detInv; + te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv; + te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv; + + return this; + + } + + transpose() { + + let tmp; + const m = this.elements; + + tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp; + tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp; + tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp; + + return this; + + } + + getNormalMatrix( matrix4 ) { + + return this.setFromMatrix4( matrix4 ).invert().transpose(); + + } + + transposeIntoArray( r ) { + + const m = this.elements; + + r[ 0 ] = m[ 0 ]; + r[ 1 ] = m[ 3 ]; + r[ 2 ] = m[ 6 ]; + r[ 3 ] = m[ 1 ]; + r[ 4 ] = m[ 4 ]; + r[ 5 ] = m[ 7 ]; + r[ 6 ] = m[ 2 ]; + r[ 7 ] = m[ 5 ]; + r[ 8 ] = m[ 8 ]; + + return this; + + } + + setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) { + + const c = Math.cos( rotation ); + const s = Math.sin( rotation ); + + this.set( + sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx, + - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty, + 0, 0, 1 + ); + + return this; + + } + + // + + scale( sx, sy ) { + + this.premultiply( _m3.makeScale( sx, sy ) ); + + return this; + + } + + rotate( theta ) { + + this.premultiply( _m3.makeRotation( - theta ) ); + + return this; + + } + + translate( tx, ty ) { + + this.premultiply( _m3.makeTranslation( tx, ty ) ); + + return this; + + } + + // for 2D Transforms + + makeTranslation( x, y ) { + + if ( x.isVector2 ) { + + this.set( + + 1, 0, x.x, + 0, 1, x.y, + 0, 0, 1 + + ); + + } else { + + this.set( + + 1, 0, x, + 0, 1, y, + 0, 0, 1 + + ); + + } + + return this; + + } + + makeRotation( theta ) { + + // counterclockwise + + const c = Math.cos( theta ); + const s = Math.sin( theta ); + + this.set( + + c, - s, 0, + s, c, 0, + 0, 0, 1 + + ); + + return this; + + } + + makeScale( x, y ) { + + this.set( + + x, 0, 0, + 0, y, 0, + 0, 0, 1 + + ); + + return this; + + } + + // + + equals( matrix ) { + + const te = this.elements; + const me = matrix.elements; + + for ( let i = 0; i < 9; i ++ ) { + + if ( te[ i ] !== me[ i ] ) return false; + + } + + return true; + + } + + fromArray( array, offset = 0 ) { + + for ( let i = 0; i < 9; i ++ ) { + + this.elements[ i ] = array[ i + offset ]; + + } + + return this; + + } + + toArray( array = [], offset = 0 ) { + + const te = this.elements; + + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; + + array[ offset + 3 ] = te[ 3 ]; + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; + + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; + array[ offset + 8 ] = te[ 8 ]; + + return array; + + } + + clone() { + + return new this.constructor().fromArray( this.elements ); + + } + +} + +const _m3 = /*@__PURE__*/ new Matrix3(); + +function arrayNeedsUint32$1( array ) { + + // assumes larger values usually on last + + for ( let i = array.length - 1; i >= 0; -- i ) { + + if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 + + } + + return false; + +} + +const TYPED_ARRAYS = { + Int8Array: Int8Array, + Uint8Array: Uint8Array, + Uint8ClampedArray: Uint8ClampedArray, + Int16Array: Int16Array, + Uint16Array: Uint16Array, + Int32Array: Int32Array, + Uint32Array: Uint32Array, + Float32Array: Float32Array, + Float64Array: Float64Array +}; + +function getTypedArray( type, buffer ) { + + return new TYPED_ARRAYS[ type ]( buffer ); + +} + +function createElementNS( name ) { + + return document.createElementNS( 'http://www.w3.org/1999/xhtml', name ); + +} + +function createCanvasElement() { + + const canvas = createElementNS( 'canvas' ); + canvas.style.display = 'block'; + return canvas; + +} + +const _cache$2 = {}; + +function warnOnce( message ) { + + if ( message in _cache$2 ) return; + + _cache$2[ message ] = true; + + console.warn( message ); + +} + +/** + * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping + * or clipping. Based on W3C specifications for sRGB and Display P3, + * and ICC specifications for the D50 connection space. Values in/out + * are _linear_ sRGB and _linear_ Display P3. + * + * Note that both sRGB and Display P3 use the sRGB transfer functions. + * + * Reference: + * - http://www.russellcottrell.com/photo/matrixCalculator.htm + */ + +const LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().set( + 0.8224621, 0.177538, 0.0, + 0.0331941, 0.9668058, 0.0, + 0.0170827, 0.0723974, 0.9105199, +); + +const LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = /*@__PURE__*/ new Matrix3().set( + 1.2249401, - 0.2249404, 0.0, + - 0.0420569, 1.0420571, 0.0, + - 0.0196376, - 0.0786361, 1.0982735 +); + +/** + * Defines supported color spaces by transfer function and primaries, + * and provides conversions to/from the Linear-sRGB reference space. + */ +const COLOR_SPACES = { + [ LinearSRGBColorSpace ]: { + transfer: LinearTransfer, + primaries: Rec709Primaries, + luminanceCoefficients: [ 0.2126, 0.7152, 0.0722 ], + toReference: ( color ) => color, + fromReference: ( color ) => color, + }, + [ SRGBColorSpace ]: { + transfer: SRGBTransfer, + primaries: Rec709Primaries, + luminanceCoefficients: [ 0.2126, 0.7152, 0.0722 ], + toReference: ( color ) => color.convertSRGBToLinear(), + fromReference: ( color ) => color.convertLinearToSRGB(), + }, + [ LinearDisplayP3ColorSpace ]: { + transfer: LinearTransfer, + primaries: P3Primaries, + luminanceCoefficients: [ 0.2289, 0.6917, 0.0793 ], + toReference: ( color ) => color.applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), + fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ), + }, + [ DisplayP3ColorSpace ]: { + transfer: SRGBTransfer, + primaries: P3Primaries, + luminanceCoefficients: [ 0.2289, 0.6917, 0.0793 ], + toReference: ( color ) => color.convertSRGBToLinear().applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), + fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ).convertLinearToSRGB(), + }, +}; + +const SUPPORTED_WORKING_COLOR_SPACES = new Set( [ LinearSRGBColorSpace, LinearDisplayP3ColorSpace ] ); + +const ColorManagement = { + + enabled: true, + + _workingColorSpace: LinearSRGBColorSpace, + + get workingColorSpace() { + + return this._workingColorSpace; + + }, + + set workingColorSpace( colorSpace ) { + + if ( ! SUPPORTED_WORKING_COLOR_SPACES.has( colorSpace ) ) { + + throw new Error( `Unsupported working color space, "${ colorSpace }".` ); + + } + + this._workingColorSpace = colorSpace; + + }, + + convert: function ( color, sourceColorSpace, targetColorSpace ) { + + if ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { + + return color; + + } + + const sourceToReference = COLOR_SPACES[ sourceColorSpace ].toReference; + const targetFromReference = COLOR_SPACES[ targetColorSpace ].fromReference; + + return targetFromReference( sourceToReference( color ) ); + + }, + + fromWorkingColorSpace: function ( color, targetColorSpace ) { + + return this.convert( color, this._workingColorSpace, targetColorSpace ); + + }, + + toWorkingColorSpace: function ( color, sourceColorSpace ) { + + return this.convert( color, sourceColorSpace, this._workingColorSpace ); + + }, + + getPrimaries: function ( colorSpace ) { + + return COLOR_SPACES[ colorSpace ].primaries; + + }, + + getTransfer: function ( colorSpace ) { + + if ( colorSpace === NoColorSpace ) return LinearTransfer; + + return COLOR_SPACES[ colorSpace ].transfer; + + }, + + getLuminanceCoefficients: function ( target, colorSpace = this._workingColorSpace ) { + + return target.fromArray( COLOR_SPACES[ colorSpace ].luminanceCoefficients ); + + }, + +}; + + +function SRGBToLinear( c ) { + + return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); + +} + +function LinearToSRGB( c ) { + + return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; + +} + +let _canvas; + +class ImageUtils { + + static getDataURL( image ) { + + if ( /^data:/i.test( image.src ) ) { + + return image.src; + + } + + if ( typeof HTMLCanvasElement === 'undefined' ) { + + return image.src; + + } + + let canvas; + + if ( image instanceof HTMLCanvasElement ) { + + canvas = image; + + } else { + + if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); + + _canvas.width = image.width; + _canvas.height = image.height; + + const context = _canvas.getContext( '2d' ); + + if ( image instanceof ImageData ) { + + context.putImageData( image, 0, 0 ); + + } else { + + context.drawImage( image, 0, 0, image.width, image.height ); + + } + + canvas = _canvas; + + } + + if ( canvas.width > 2048 || canvas.height > 2048 ) { + + console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image ); + + return canvas.toDataURL( 'image/jpeg', 0.6 ); + + } else { + + return canvas.toDataURL( 'image/png' ); + + } + + } + + static sRGBToLinear( image ) { + + if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || + ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || + ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { + + const canvas = createElementNS( 'canvas' ); + + canvas.width = image.width; + canvas.height = image.height; + + const context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, image.width, image.height ); + + const imageData = context.getImageData( 0, 0, image.width, image.height ); + const data = imageData.data; + + for ( let i = 0; i < data.length; i ++ ) { + + data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; + + } + + context.putImageData( imageData, 0, 0 ); + + return canvas; + + } else if ( image.data ) { + + const data = image.data.slice( 0 ); + + for ( let i = 0; i < data.length; i ++ ) { + + if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { + + data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); + + } else { + + // assuming float + + data[ i ] = SRGBToLinear( data[ i ] ); + + } + + } + + return { + data: data, + width: image.width, + height: image.height + }; + + } else { + + console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); + return image; + + } + + } + +} + +let _sourceId = 0; + +class Source { + + constructor( data = null ) { + + this.isSource = true; + + Object.defineProperty( this, 'id', { value: _sourceId ++ } ); + + this.uuid = generateUUID(); + + this.data = data; + this.dataReady = true; + + this.version = 0; + + } + + set needsUpdate( value ) { + + if ( value === true ) this.version ++; + + } + + toJSON( meta ) { + + const isRootObject = ( meta === undefined || typeof meta === 'string' ); + + if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { + + return meta.images[ this.uuid ]; + + } + + const output = { + uuid: this.uuid, + url: '' + }; + + const data = this.data; + + if ( data !== null ) { + + let url; + + if ( Array.isArray( data ) ) { + + // cube texture + + url = []; + + for ( let i = 0, l = data.length; i < l; i ++ ) { + + if ( data[ i ].isDataTexture ) { + + url.push( serializeImage( data[ i ].image ) ); + + } else { + + url.push( serializeImage( data[ i ] ) ); + + } + + } + + } else { + + // texture + + url = serializeImage( data ); + + } + + output.url = url; + + } + + if ( ! isRootObject ) { + + meta.images[ this.uuid ] = output; + + } + + return output; + + } + +} + +function serializeImage( image ) { + + if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || + ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || + ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { + + // default images + + return ImageUtils.getDataURL( image ); + + } else { + + if ( image.data ) { + + // images of DataTexture + + return { + data: Array.from( image.data ), + width: image.width, + height: image.height, + type: image.data.constructor.name + }; + + } else { + + console.warn( 'THREE.Texture: Unable to serialize Texture.' ); + return {}; + + } + + } + +} + +let _textureId = 0; + +class Texture extends EventDispatcher { + + constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, colorSpace = NoColorSpace ) { + + super(); + + this.isTexture = true; + + Object.defineProperty( this, 'id', { value: _textureId ++ } ); + + this.uuid = generateUUID(); + + this.name = ''; + + this.source = new Source( image ); + this.mipmaps = []; + + this.mapping = mapping; + this.channel = 0; + + this.wrapS = wrapS; + this.wrapT = wrapT; + + this.magFilter = magFilter; + this.minFilter = minFilter; + + this.anisotropy = anisotropy; + + this.format = format; + this.internalFormat = null; + this.type = type; + + this.offset = new Vector2( 0, 0 ); + this.repeat = new Vector2( 1, 1 ); + this.center = new Vector2( 0, 0 ); + this.rotation = 0; + + this.matrixAutoUpdate = true; + this.matrix = new Matrix3(); + + this.generateMipmaps = true; + this.premultiplyAlpha = false; + this.flipY = true; + this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) + + this.colorSpace = colorSpace; + + this.userData = {}; + + this.version = 0; + this.onUpdate = null; + + this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not + this.pmremVersion = 0; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures) + + } + + get image() { + + return this.source.data; + + } + + set image( value = null ) { + + this.source.data = value; + + } + + updateMatrix() { + + this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + copy( source ) { + + this.name = source.name; + + this.source = source.source; + this.mipmaps = source.mipmaps.slice( 0 ); + + this.mapping = source.mapping; + this.channel = source.channel; + + this.wrapS = source.wrapS; + this.wrapT = source.wrapT; + + this.magFilter = source.magFilter; + this.minFilter = source.minFilter; + + this.anisotropy = source.anisotropy; + + this.format = source.format; + this.internalFormat = source.internalFormat; + this.type = source.type; + + this.offset.copy( source.offset ); + this.repeat.copy( source.repeat ); + this.center.copy( source.center ); + this.rotation = source.rotation; + + this.matrixAutoUpdate = source.matrixAutoUpdate; + this.matrix.copy( source.matrix ); + + this.generateMipmaps = source.generateMipmaps; + this.premultiplyAlpha = source.premultiplyAlpha; + this.flipY = source.flipY; + this.unpackAlignment = source.unpackAlignment; + this.colorSpace = source.colorSpace; + + this.userData = JSON.parse( JSON.stringify( source.userData ) ); + + this.needsUpdate = true; + + return this; + + } + + toJSON( meta ) { + + const isRootObject = ( meta === undefined || typeof meta === 'string' ); + + if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { + + return meta.textures[ this.uuid ]; + + } + + const output = { + + metadata: { + version: 4.6, + type: 'Texture', + generator: 'Texture.toJSON' + }, + + uuid: this.uuid, + name: this.name, + + image: this.source.toJSON( meta ).uuid, + + mapping: this.mapping, + channel: this.channel, + + repeat: [ this.repeat.x, this.repeat.y ], + offset: [ this.offset.x, this.offset.y ], + center: [ this.center.x, this.center.y ], + rotation: this.rotation, + + wrap: [ this.wrapS, this.wrapT ], + + format: this.format, + internalFormat: this.internalFormat, + type: this.type, + colorSpace: this.colorSpace, + + minFilter: this.minFilter, + magFilter: this.magFilter, + anisotropy: this.anisotropy, + + flipY: this.flipY, + + generateMipmaps: this.generateMipmaps, + premultiplyAlpha: this.premultiplyAlpha, + unpackAlignment: this.unpackAlignment + + }; + + if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData; + + if ( ! isRootObject ) { + + meta.textures[ this.uuid ] = output; + + } + + return output; + + } + + dispose() { + + this.dispatchEvent( { type: 'dispose' } ); + + } + + transformUv( uv ) { + + if ( this.mapping !== UVMapping ) return uv; + + uv.applyMatrix3( this.matrix ); + + if ( uv.x < 0 || uv.x > 1 ) { + + switch ( this.wrapS ) { + + case RepeatWrapping: + + uv.x = uv.x - Math.floor( uv.x ); + break; + + case ClampToEdgeWrapping: + + uv.x = uv.x < 0 ? 0 : 1; + break; + + case MirroredRepeatWrapping: + + if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { + + uv.x = Math.ceil( uv.x ) - uv.x; + + } else { + + uv.x = uv.x - Math.floor( uv.x ); + + } + + break; + + } + + } + + if ( uv.y < 0 || uv.y > 1 ) { + + switch ( this.wrapT ) { + + case RepeatWrapping: + + uv.y = uv.y - Math.floor( uv.y ); + break; + + case ClampToEdgeWrapping: + + uv.y = uv.y < 0 ? 0 : 1; + break; + + case MirroredRepeatWrapping: + + if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { + + uv.y = Math.ceil( uv.y ) - uv.y; + + } else { + + uv.y = uv.y - Math.floor( uv.y ); + + } + + break; + + } + + } + + if ( this.flipY ) { + + uv.y = 1 - uv.y; + + } + + return uv; + + } + + set needsUpdate( value ) { + + if ( value === true ) { + + this.version ++; + this.source.needsUpdate = true; + + } + + } + + set needsPMREMUpdate( value ) { + + if ( value === true ) { + + this.pmremVersion ++; + + } + + } + +} + +Texture.DEFAULT_IMAGE = null; +Texture.DEFAULT_MAPPING = UVMapping; +Texture.DEFAULT_ANISOTROPY = 1; + +class Vector4 { + + constructor( x = 0, y = 0, z = 0, w = 1 ) { + + Vector4.prototype.isVector4 = true; + + this.x = x; + this.y = y; + this.z = z; + this.w = w; + + } + + get width() { + + return this.z; + + } + + set width( value ) { + + this.z = value; + + } + + get height() { + + return this.w; + + } + + set height( value ) { + + this.w = value; + + } + + set( x, y, z, w ) { + + this.x = x; + this.y = y; + this.z = z; + this.w = w; + + return this; + + } + + setScalar( scalar ) { + + this.x = scalar; + this.y = scalar; + this.z = scalar; + this.w = scalar; + + return this; + + } + + setX( x ) { + + this.x = x; + + return this; + + } + + setY( y ) { + + this.y = y; + + return this; + + } + + setZ( z ) { + + this.z = z; + + return this; + + } + + setW( w ) { + + this.w = w; + + return this; + + } + + setComponent( index, value ) { + + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + case 3: this.w = value; break; + default: throw new Error( 'index is out of range: ' + index ); + + } + + return this; + + } + + getComponent( index ) { + + switch ( index ) { + + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + case 3: return this.w; + default: throw new Error( 'index is out of range: ' + index ); + + } + + } + + clone() { + + return new this.constructor( this.x, this.y, this.z, this.w ); + + } + + copy( v ) { + + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.w = ( v.w !== undefined ) ? v.w : 1; + + return this; + + } + + add( v ) { + + this.x += v.x; + this.y += v.y; + this.z += v.z; + this.w += v.w; + + return this; + + } + + addScalar( s ) { + + this.x += s; + this.y += s; + this.z += s; + this.w += s; + + return this; + + } + + addVectors( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + this.w = a.w + b.w; + + return this; + + } + + addScaledVector( v, s ) { + + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; + this.w += v.w * s; + + return this; + + } + + sub( v ) { + + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + this.w -= v.w; + + return this; + + } + + subScalar( s ) { + + this.x -= s; + this.y -= s; + this.z -= s; + this.w -= s; + + return this; + + } + + subVectors( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + this.w = a.w - b.w; + + return this; + + } + + multiply( v ) { + + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; + this.w *= v.w; + + return this; + + } + + multiplyScalar( scalar ) { + + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + this.w *= scalar; + + return this; + + } + + applyMatrix4( m ) { + + const x = this.x, y = this.y, z = this.z, w = this.w; + const e = m.elements; + + this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; + this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; + this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; + this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; + + return this; + + } + + divideScalar( scalar ) { + + return this.multiplyScalar( 1 / scalar ); + + } + + setAxisAngleFromQuaternion( q ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm + + // q is assumed to be normalized + + this.w = 2 * Math.acos( q.w ); + + const s = Math.sqrt( 1 - q.w * q.w ); + + if ( s < 0.0001 ) { + + this.x = 1; + this.y = 0; + this.z = 0; + + } else { + + this.x = q.x / s; + this.y = q.y / s; + this.z = q.z / s; + + } + + return this; + + } + + setAxisAngleFromRotationMatrix( m ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + let angle, x, y, z; // variables for result + const epsilon = 0.01, // margin to allow for rounding errors + epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees + + te = m.elements, + + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; + + if ( ( Math.abs( m12 - m21 ) < epsilon ) && + ( Math.abs( m13 - m31 ) < epsilon ) && + ( Math.abs( m23 - m32 ) < epsilon ) ) { + + // singularity found + // first check for identity matrix which must have +1 for all terms + // in leading diagonal and zero in other terms + + if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && + ( Math.abs( m13 + m31 ) < epsilon2 ) && + ( Math.abs( m23 + m32 ) < epsilon2 ) && + ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { + + // this singularity is identity matrix so angle = 0 + + this.set( 1, 0, 0, 0 ); + + return this; // zero angle, arbitrary axis + + } + + // otherwise this singularity is angle = 180 + + angle = Math.PI; + + const xx = ( m11 + 1 ) / 2; + const yy = ( m22 + 1 ) / 2; + const zz = ( m33 + 1 ) / 2; + const xy = ( m12 + m21 ) / 4; + const xz = ( m13 + m31 ) / 4; + const yz = ( m23 + m32 ) / 4; + + if ( ( xx > yy ) && ( xx > zz ) ) { + + // m11 is the largest diagonal term + + if ( xx < epsilon ) { + + x = 0; + y = 0.707106781; + z = 0.707106781; + + } else { + + x = Math.sqrt( xx ); + y = xy / x; + z = xz / x; + + } + + } else if ( yy > zz ) { + + // m22 is the largest diagonal term + + if ( yy < epsilon ) { + + x = 0.707106781; + y = 0; + z = 0.707106781; + + } else { + + y = Math.sqrt( yy ); + x = xy / y; + z = yz / y; + + } + + } else { + + // m33 is the largest diagonal term so base result on this + + if ( zz < epsilon ) { + + x = 0.707106781; + y = 0.707106781; + z = 0; + + } else { + + z = Math.sqrt( zz ); + x = xz / z; + y = yz / z; + + } + + } + + this.set( x, y, z, angle ); + + return this; // return 180 deg rotation + + } + + // as we have reached here there are no singularities so we can handle normally + + let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + + ( m13 - m31 ) * ( m13 - m31 ) + + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize + + if ( Math.abs( s ) < 0.001 ) s = 1; + + // prevent divide by zero, should not happen if matrix is orthogonal and should be + // caught by singularity test above, but I've left it in just in case + + this.x = ( m32 - m23 ) / s; + this.y = ( m13 - m31 ) / s; + this.z = ( m21 - m12 ) / s; + this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); + + return this; + + } + + setFromMatrixPosition( m ) { + + const e = m.elements; + + this.x = e[ 12 ]; + this.y = e[ 13 ]; + this.z = e[ 14 ]; + this.w = e[ 15 ]; + + return this; + + } + + min( v ) { + + this.x = Math.min( this.x, v.x ); + this.y = Math.min( this.y, v.y ); + this.z = Math.min( this.z, v.z ); + this.w = Math.min( this.w, v.w ); + + return this; + + } + + max( v ) { + + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); + this.w = Math.max( this.w, v.w ); + + return this; + + } + + clamp( min, max ) { + + // assumes min < max, componentwise + + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); + this.w = Math.max( min.w, Math.min( max.w, this.w ) ); + + return this; + + } + + clampScalar( minVal, maxVal ) { + + this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); + this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); + this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); + this.w = Math.max( minVal, Math.min( maxVal, this.w ) ); + + return this; + + } + + clampLength( min, max ) { + + const length = this.length(); + + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + + } + + floor() { + + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + this.w = Math.floor( this.w ); + + return this; + + } + + ceil() { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + this.w = Math.ceil( this.w ); + + return this; + + } + + round() { + + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + this.w = Math.round( this.w ); + + return this; + + } + + roundToZero() { + + this.x = Math.trunc( this.x ); + this.y = Math.trunc( this.y ); + this.z = Math.trunc( this.z ); + this.w = Math.trunc( this.w ); + + return this; + + } + + negate() { + + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + this.w = - this.w; + + return this; + + } + + dot( v ) { + + return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; + + } + + lengthSq() { + + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + + } + + length() { + + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); + + } + + manhattanLength() { + + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); + + } + + normalize() { + + return this.divideScalar( this.length() || 1 ); + + } + + setLength( length ) { + + return this.normalize().multiplyScalar( length ); + + } + + lerp( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + this.w += ( v.w - this.w ) * alpha; + + return this; + + } + + lerpVectors( v1, v2, alpha ) { + + this.x = v1.x + ( v2.x - v1.x ) * alpha; + this.y = v1.y + ( v2.y - v1.y ) * alpha; + this.z = v1.z + ( v2.z - v1.z ) * alpha; + this.w = v1.w + ( v2.w - v1.w ) * alpha; + + return this; + + } + + equals( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); + + } + + fromArray( array, offset = 0 ) { + + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + this.w = array[ offset + 3 ]; + + return this; + + } + + toArray( array = [], offset = 0 ) { + + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; + array[ offset + 3 ] = this.w; + + return array; + + } + + fromBufferAttribute( attribute, index ) { + + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); + this.w = attribute.getW( index ); + + return this; + + } + + random() { + + this.x = Math.random(); + this.y = Math.random(); + this.z = Math.random(); + this.w = Math.random(); + + return this; + + } + + *[ Symbol.iterator ]() { + + yield this.x; + yield this.y; + yield this.z; + yield this.w; + + } + +} + +/* + In options, we can specify: + * Texture parameters for an auto-generated target texture + * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers +*/ +class RenderTarget extends EventDispatcher { + + constructor( width = 1, height = 1, options = {} ) { + + super(); + + this.isRenderTarget = true; + + this.width = width; + this.height = height; + this.depth = 1; + + this.scissor = new Vector4( 0, 0, width, height ); + this.scissorTest = false; + + this.viewport = new Vector4( 0, 0, width, height ); + + const image = { width: width, height: height, depth: 1 }; + + options = Object.assign( { + generateMipmaps: false, + internalFormat: null, + minFilter: LinearFilter, + depthBuffer: true, + stencilBuffer: false, + resolveDepthBuffer: true, + resolveStencilBuffer: true, + depthTexture: null, + samples: 0, + count: 1 + }, options ); + + const texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); + + texture.flipY = false; + texture.generateMipmaps = options.generateMipmaps; + texture.internalFormat = options.internalFormat; + + this.textures = []; + + const count = options.count; + for ( let i = 0; i < count; i ++ ) { + + this.textures[ i ] = texture.clone(); + this.textures[ i ].isRenderTargetTexture = true; + + } + + this.depthBuffer = options.depthBuffer; + this.stencilBuffer = options.stencilBuffer; + + this.resolveDepthBuffer = options.resolveDepthBuffer; + this.resolveStencilBuffer = options.resolveStencilBuffer; + + this.depthTexture = options.depthTexture; + + this.samples = options.samples; + + } + + get texture() { + + return this.textures[ 0 ]; + + } + + set texture( value ) { + + this.textures[ 0 ] = value; + + } + + setSize( width, height, depth = 1 ) { + + if ( this.width !== width || this.height !== height || this.depth !== depth ) { + + this.width = width; + this.height = height; + this.depth = depth; + + for ( let i = 0, il = this.textures.length; i < il; i ++ ) { + + this.textures[ i ].image.width = width; + this.textures[ i ].image.height = height; + this.textures[ i ].image.depth = depth; + + } + + this.dispose(); + + } + + this.viewport.set( 0, 0, width, height ); + this.scissor.set( 0, 0, width, height ); + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + copy( source ) { + + this.width = source.width; + this.height = source.height; + this.depth = source.depth; + + this.scissor.copy( source.scissor ); + this.scissorTest = source.scissorTest; + + this.viewport.copy( source.viewport ); + + this.textures.length = 0; + + for ( let i = 0, il = source.textures.length; i < il; i ++ ) { + + this.textures[ i ] = source.textures[ i ].clone(); + this.textures[ i ].isRenderTargetTexture = true; + + } + + // ensure image object is not shared, see #20328 + + const image = Object.assign( {}, source.texture.image ); + this.texture.source = new Source( image ); + + this.depthBuffer = source.depthBuffer; + this.stencilBuffer = source.stencilBuffer; + + this.resolveDepthBuffer = source.resolveDepthBuffer; + this.resolveStencilBuffer = source.resolveStencilBuffer; + + if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); + + this.samples = source.samples; + + return this; + + } + + dispose() { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +} + +class WebGLRenderTarget extends RenderTarget { + + constructor( width = 1, height = 1, options = {} ) { + + super( width, height, options ); + + this.isWebGLRenderTarget = true; + + } + +} + +class DataArrayTexture extends Texture { + + constructor( data = null, width = 1, height = 1, depth = 1 ) { + + super( null ); + + this.isDataArrayTexture = true; + + this.image = { data, width, height, depth }; + + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; + + this.wrapR = ClampToEdgeWrapping; + + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; + + this.layerUpdates = new Set(); + + } + + addLayerUpdate( layerIndex ) { + + this.layerUpdates.add( layerIndex ); + + } + + clearLayerUpdates() { + + this.layerUpdates.clear(); + + } + +} + +class WebGLArrayRenderTarget extends WebGLRenderTarget { + + constructor( width = 1, height = 1, depth = 1, options = {} ) { + + super( width, height, options ); + + this.isWebGLArrayRenderTarget = true; + + this.depth = depth; + + this.texture = new DataArrayTexture( null, width, height, depth ); + + this.texture.isRenderTargetTexture = true; + + } + +} + +class Data3DTexture extends Texture { + + constructor( data = null, width = 1, height = 1, depth = 1 ) { + + // We're going to add .setXXX() methods for setting properties later. + // Users can still set in DataTexture3D directly. + // + // const texture = new THREE.DataTexture3D( data, width, height, depth ); + // texture.anisotropy = 16; + // + // See #14839 + + super( null ); + + this.isData3DTexture = true; + + this.image = { data, width, height, depth }; + + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; + + this.wrapR = ClampToEdgeWrapping; + + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; + + } + +} + +class WebGL3DRenderTarget extends WebGLRenderTarget { + + constructor( width = 1, height = 1, depth = 1, options = {} ) { + + super( width, height, options ); + + this.isWebGL3DRenderTarget = true; + + this.depth = depth; + + this.texture = new Data3DTexture( null, width, height, depth ); + + this.texture.isRenderTargetTexture = true; + + } + +} + +class Quaternion { + + constructor( x = 0, y = 0, z = 0, w = 1 ) { + + this.isQuaternion = true; + + this._x = x; + this._y = y; + this._z = z; + this._w = w; + + } + + static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { + + // fuzz-free, array-based Quaternion SLERP operation + + let x0 = src0[ srcOffset0 + 0 ], + y0 = src0[ srcOffset0 + 1 ], + z0 = src0[ srcOffset0 + 2 ], + w0 = src0[ srcOffset0 + 3 ]; + + const x1 = src1[ srcOffset1 + 0 ], + y1 = src1[ srcOffset1 + 1 ], + z1 = src1[ srcOffset1 + 2 ], + w1 = src1[ srcOffset1 + 3 ]; + + if ( t === 0 ) { + + dst[ dstOffset + 0 ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; + return; + + } + + if ( t === 1 ) { + + dst[ dstOffset + 0 ] = x1; + dst[ dstOffset + 1 ] = y1; + dst[ dstOffset + 2 ] = z1; + dst[ dstOffset + 3 ] = w1; + return; + + } + + if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { + + let s = 1 - t; + const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, + dir = ( cos >= 0 ? 1 : - 1 ), + sqrSin = 1 - cos * cos; + + // Skip the Slerp for tiny steps to avoid numeric problems: + if ( sqrSin > Number.EPSILON ) { + + const sin = Math.sqrt( sqrSin ), + len = Math.atan2( sin, cos * dir ); + + s = Math.sin( s * len ) / sin; + t = Math.sin( t * len ) / sin; + + } + + const tDir = t * dir; + + x0 = x0 * s + x1 * tDir; + y0 = y0 * s + y1 * tDir; + z0 = z0 * s + z1 * tDir; + w0 = w0 * s + w1 * tDir; + + // Normalize in case we just did a lerp: + if ( s === 1 - t ) { + + const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); + + x0 *= f; + y0 *= f; + z0 *= f; + w0 *= f; + + } + + } + + dst[ dstOffset ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; + + } + + static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { + + const x0 = src0[ srcOffset0 ]; + const y0 = src0[ srcOffset0 + 1 ]; + const z0 = src0[ srcOffset0 + 2 ]; + const w0 = src0[ srcOffset0 + 3 ]; + + const x1 = src1[ srcOffset1 ]; + const y1 = src1[ srcOffset1 + 1 ]; + const z1 = src1[ srcOffset1 + 2 ]; + const w1 = src1[ srcOffset1 + 3 ]; + + dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; + dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; + dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; + dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; + + return dst; + + } + + get x() { + + return this._x; + + } + + set x( value ) { + + this._x = value; + this._onChangeCallback(); + + } + + get y() { + + return this._y; + + } + + set y( value ) { + + this._y = value; + this._onChangeCallback(); + + } + + get z() { + + return this._z; + + } + + set z( value ) { + + this._z = value; + this._onChangeCallback(); + + } + + get w() { + + return this._w; + + } + + set w( value ) { + + this._w = value; + this._onChangeCallback(); + + } + + set( x, y, z, w ) { + + this._x = x; + this._y = y; + this._z = z; + this._w = w; + + this._onChangeCallback(); + + return this; + + } + + clone() { + + return new this.constructor( this._x, this._y, this._z, this._w ); + + } + + copy( quaternion ) { + + this._x = quaternion.x; + this._y = quaternion.y; + this._z = quaternion.z; + this._w = quaternion.w; + + this._onChangeCallback(); + + return this; + + } + + setFromEuler( euler, update = true ) { + + const x = euler._x, y = euler._y, z = euler._z, order = euler._order; + + // http://www.mathworks.com/matlabcentral/fileexchange/ + // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ + // content/SpinCalc.m + + const cos = Math.cos; + const sin = Math.sin; + + const c1 = cos( x / 2 ); + const c2 = cos( y / 2 ); + const c3 = cos( z / 2 ); + + const s1 = sin( x / 2 ); + const s2 = sin( y / 2 ); + const s3 = sin( z / 2 ); + + switch ( order ) { + + case 'XYZ': + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + break; + + case 'YXZ': + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + break; + + case 'ZXY': + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + break; + + case 'ZYX': + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + break; + + case 'YZX': + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + break; + + case 'XZY': + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + break; + + default: + console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order ); + + } + + if ( update === true ) this._onChangeCallback(); + + return this; + + } + + setFromAxisAngle( axis, angle ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + + // assumes axis is normalized + + const halfAngle = angle / 2, s = Math.sin( halfAngle ); + + this._x = axis.x * s; + this._y = axis.y * s; + this._z = axis.z * s; + this._w = Math.cos( halfAngle ); + + this._onChangeCallback(); + + return this; + + } + + setFromRotationMatrix( m ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + const te = m.elements, + + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], + + trace = m11 + m22 + m33; + + if ( trace > 0 ) { + + const s = 0.5 / Math.sqrt( trace + 1.0 ); + + this._w = 0.25 / s; + this._x = ( m32 - m23 ) * s; + this._y = ( m13 - m31 ) * s; + this._z = ( m21 - m12 ) * s; + + } else if ( m11 > m22 && m11 > m33 ) { + + const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); + + this._w = ( m32 - m23 ) / s; + this._x = 0.25 * s; + this._y = ( m12 + m21 ) / s; + this._z = ( m13 + m31 ) / s; + + } else if ( m22 > m33 ) { + + const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); + + this._w = ( m13 - m31 ) / s; + this._x = ( m12 + m21 ) / s; + this._y = 0.25 * s; + this._z = ( m23 + m32 ) / s; + + } else { + + const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); + + this._w = ( m21 - m12 ) / s; + this._x = ( m13 + m31 ) / s; + this._y = ( m23 + m32 ) / s; + this._z = 0.25 * s; + + } + + this._onChangeCallback(); + + return this; + + } + + setFromUnitVectors( vFrom, vTo ) { + + // assumes direction vectors vFrom and vTo are normalized + + let r = vFrom.dot( vTo ) + 1; + + if ( r < Number.EPSILON ) { + + // vFrom and vTo point in opposite directions + + r = 0; + + if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { + + this._x = - vFrom.y; + this._y = vFrom.x; + this._z = 0; + this._w = r; + + } else { + + this._x = 0; + this._y = - vFrom.z; + this._z = vFrom.y; + this._w = r; + + } + + } else { + + // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 + + this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; + this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; + this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; + this._w = r; + + } + + return this.normalize(); + + } + + angleTo( q ) { + + return 2 * Math.acos( Math.abs( clamp$1( this.dot( q ), - 1, 1 ) ) ); + + } + + rotateTowards( q, step ) { + + const angle = this.angleTo( q ); + + if ( angle === 0 ) return this; + + const t = Math.min( 1, step / angle ); + + this.slerp( q, t ); + + return this; + + } + + identity() { + + return this.set( 0, 0, 0, 1 ); + + } + + invert() { + + // quaternion is assumed to have unit length + + return this.conjugate(); + + } + + conjugate() { + + this._x *= - 1; + this._y *= - 1; + this._z *= - 1; + + this._onChangeCallback(); + + return this; + + } + + dot( v ) { + + return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; + + } + + lengthSq() { + + return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; + + } + + length() { + + return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); + + } + + normalize() { + + let l = this.length(); + + if ( l === 0 ) { + + this._x = 0; + this._y = 0; + this._z = 0; + this._w = 1; + + } else { + + l = 1 / l; + + this._x = this._x * l; + this._y = this._y * l; + this._z = this._z * l; + this._w = this._w * l; + + } + + this._onChangeCallback(); + + return this; + + } + + multiply( q ) { + + return this.multiplyQuaternions( this, q ); + + } + + premultiply( q ) { + + return this.multiplyQuaternions( q, this ); + + } + + multiplyQuaternions( a, b ) { + + // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm + + const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; + const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; + + this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + + this._onChangeCallback(); + + return this; + + } + + slerp( qb, t ) { + + if ( t === 0 ) return this; + if ( t === 1 ) return this.copy( qb ); + + const x = this._x, y = this._y, z = this._z, w = this._w; + + // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ + + let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; + + if ( cosHalfTheta < 0 ) { + + this._w = - qb._w; + this._x = - qb._x; + this._y = - qb._y; + this._z = - qb._z; + + cosHalfTheta = - cosHalfTheta; + + } else { + + this.copy( qb ); + + } + + if ( cosHalfTheta >= 1.0 ) { + + this._w = w; + this._x = x; + this._y = y; + this._z = z; + + return this; + + } + + const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; + + if ( sqrSinHalfTheta <= Number.EPSILON ) { + + const s = 1 - t; + this._w = s * w + t * this._w; + this._x = s * x + t * this._x; + this._y = s * y + t * this._y; + this._z = s * z + t * this._z; + + this.normalize(); // normalize calls _onChangeCallback() + + return this; + + } + + const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); + const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); + const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, + ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; + + this._w = ( w * ratioA + this._w * ratioB ); + this._x = ( x * ratioA + this._x * ratioB ); + this._y = ( y * ratioA + this._y * ratioB ); + this._z = ( z * ratioA + this._z * ratioB ); + + this._onChangeCallback(); + + return this; + + } + + slerpQuaternions( qa, qb, t ) { + + return this.copy( qa ).slerp( qb, t ); + + } + + random() { + + // sets this quaternion to a uniform random unit quaternnion + + // Ken Shoemake + // Uniform random rotations + // D. Kirk, editor, Graphics Gems III, pages 124-132. Academic Press, New York, 1992. + + const theta1 = 2 * Math.PI * Math.random(); + const theta2 = 2 * Math.PI * Math.random(); + + const x0 = Math.random(); + const r1 = Math.sqrt( 1 - x0 ); + const r2 = Math.sqrt( x0 ); + + return this.set( + r1 * Math.sin( theta1 ), + r1 * Math.cos( theta1 ), + r2 * Math.sin( theta2 ), + r2 * Math.cos( theta2 ), + ); + + } + + equals( quaternion ) { + + return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); + + } + + fromArray( array, offset = 0 ) { + + this._x = array[ offset ]; + this._y = array[ offset + 1 ]; + this._z = array[ offset + 2 ]; + this._w = array[ offset + 3 ]; + + this._onChangeCallback(); + + return this; + + } + + toArray( array = [], offset = 0 ) { + + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._w; + + return array; + + } + + fromBufferAttribute( attribute, index ) { + + this._x = attribute.getX( index ); + this._y = attribute.getY( index ); + this._z = attribute.getZ( index ); + this._w = attribute.getW( index ); + + this._onChangeCallback(); + + return this; + + } + + toJSON() { + + return this.toArray(); + + } + + _onChange( callback ) { + + this._onChangeCallback = callback; + + return this; + + } + + _onChangeCallback() {} + + *[ Symbol.iterator ]() { + + yield this._x; + yield this._y; + yield this._z; + yield this._w; + + } + +} + +class Vector3 { + + constructor( x = 0, y = 0, z = 0 ) { + + Vector3.prototype.isVector3 = true; + + this.x = x; + this.y = y; + this.z = z; + + } + + set( x, y, z ) { + + if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) + + this.x = x; + this.y = y; + this.z = z; + + return this; + + } + + setScalar( scalar ) { + + this.x = scalar; + this.y = scalar; + this.z = scalar; + + return this; + + } + + setX( x ) { + + this.x = x; + + return this; + + } + + setY( y ) { + + this.y = y; + + return this; + + } + + setZ( z ) { + + this.z = z; + + return this; + + } + + setComponent( index, value ) { + + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + default: throw new Error( 'index is out of range: ' + index ); + + } + + return this; + + } + + getComponent( index ) { + + switch ( index ) { + + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + default: throw new Error( 'index is out of range: ' + index ); + + } + + } + + clone() { + + return new this.constructor( this.x, this.y, this.z ); + + } + + copy( v ) { + + this.x = v.x; + this.y = v.y; + this.z = v.z; + + return this; + + } + + add( v ) { + + this.x += v.x; + this.y += v.y; + this.z += v.z; + + return this; + + } + + addScalar( s ) { + + this.x += s; + this.y += s; + this.z += s; + + return this; + + } + + addVectors( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + + return this; + + } + + addScaledVector( v, s ) { + + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; + + return this; + + } + + sub( v ) { + + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + + return this; + + } + + subScalar( s ) { + + this.x -= s; + this.y -= s; + this.z -= s; + + return this; + + } + + subVectors( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + + return this; + + } + + multiply( v ) { + + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; + + return this; + + } + + multiplyScalar( scalar ) { + + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + + return this; + + } + + multiplyVectors( a, b ) { + + this.x = a.x * b.x; + this.y = a.y * b.y; + this.z = a.z * b.z; + + return this; + + } + + applyEuler( euler ) { + + return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); + + } + + applyAxisAngle( axis, angle ) { + + return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); + + } + + applyMatrix3( m ) { + + const x = this.x, y = this.y, z = this.z; + const e = m.elements; + + this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; + this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; + this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; + + return this; + + } + + applyNormalMatrix( m ) { + + return this.applyMatrix3( m ).normalize(); + + } + + applyMatrix4( m ) { + + const x = this.x, y = this.y, z = this.z; + const e = m.elements; + + const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); + + this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w; + this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w; + this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w; + + return this; + + } + + applyQuaternion( q ) { + + // quaternion q is assumed to have unit length + + const vx = this.x, vy = this.y, vz = this.z; + const qx = q.x, qy = q.y, qz = q.z, qw = q.w; + + // t = 2 * cross( q.xyz, v ); + const tx = 2 * ( qy * vz - qz * vy ); + const ty = 2 * ( qz * vx - qx * vz ); + const tz = 2 * ( qx * vy - qy * vx ); + + // v + q.w * t + cross( q.xyz, t ); + this.x = vx + qw * tx + qy * tz - qz * ty; + this.y = vy + qw * ty + qz * tx - qx * tz; + this.z = vz + qw * tz + qx * ty - qy * tx; + + return this; + + } + + project( camera ) { + + return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); + + } + + unproject( camera ) { + + return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); + + } + + transformDirection( m ) { + + // input: THREE.Matrix4 affine matrix + // vector interpreted as a direction + + const x = this.x, y = this.y, z = this.z; + const e = m.elements; + + this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; + this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; + this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; + + return this.normalize(); + + } + + divide( v ) { + + this.x /= v.x; + this.y /= v.y; + this.z /= v.z; + + return this; + + } + + divideScalar( scalar ) { + + return this.multiplyScalar( 1 / scalar ); + + } + + min( v ) { + + this.x = Math.min( this.x, v.x ); + this.y = Math.min( this.y, v.y ); + this.z = Math.min( this.z, v.z ); + + return this; + + } + + max( v ) { + + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); + + return this; + + } + + clamp( min, max ) { + + // assumes min < max, componentwise + + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); + + return this; + + } + + clampScalar( minVal, maxVal ) { + + this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); + this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); + this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); + + return this; + + } + + clampLength( min, max ) { + + const length = this.length(); + + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + + } + + floor() { + + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + + return this; + + } + + ceil() { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + + return this; + + } + + round() { + + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + + return this; + + } + + roundToZero() { + + this.x = Math.trunc( this.x ); + this.y = Math.trunc( this.y ); + this.z = Math.trunc( this.z ); + + return this; + + } + + negate() { + + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + + return this; + + } + + dot( v ) { + + return this.x * v.x + this.y * v.y + this.z * v.z; + + } + + // TODO lengthSquared? + + lengthSq() { + + return this.x * this.x + this.y * this.y + this.z * this.z; + + } + + length() { + + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); + + } + + manhattanLength() { + + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); + + } + + normalize() { + + return this.divideScalar( this.length() || 1 ); + + } + + setLength( length ) { + + return this.normalize().multiplyScalar( length ); + + } + + lerp( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + + return this; + + } + + lerpVectors( v1, v2, alpha ) { + + this.x = v1.x + ( v2.x - v1.x ) * alpha; + this.y = v1.y + ( v2.y - v1.y ) * alpha; + this.z = v1.z + ( v2.z - v1.z ) * alpha; + + return this; + + } + + cross( v ) { + + return this.crossVectors( this, v ); + + } + + crossVectors( a, b ) { + + const ax = a.x, ay = a.y, az = a.z; + const bx = b.x, by = b.y, bz = b.z; + + this.x = ay * bz - az * by; + this.y = az * bx - ax * bz; + this.z = ax * by - ay * bx; + + return this; + + } + + projectOnVector( v ) { + + const denominator = v.lengthSq(); + + if ( denominator === 0 ) return this.set( 0, 0, 0 ); + + const scalar = v.dot( this ) / denominator; + + return this.copy( v ).multiplyScalar( scalar ); + + } + + projectOnPlane( planeNormal ) { + + _vector$c.copy( this ).projectOnVector( planeNormal ); + + return this.sub( _vector$c ); + + } + + reflect( normal ) { + + // reflect incident vector off plane orthogonal to normal + // normal is assumed to have unit length + + return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); + + } + + angleTo( v ) { + + const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); + + if ( denominator === 0 ) return Math.PI / 2; + + const theta = this.dot( v ) / denominator; + + // clamp, to handle numerical problems + + return Math.acos( clamp$1( theta, - 1, 1 ) ); + + } + + distanceTo( v ) { + + return Math.sqrt( this.distanceToSquared( v ) ); + + } + + distanceToSquared( v ) { + + const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; + + return dx * dx + dy * dy + dz * dz; + + } + + manhattanDistanceTo( v ) { + + return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); + + } + + setFromSpherical( s ) { + + return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); + + } + + setFromSphericalCoords( radius, phi, theta ) { + + const sinPhiRadius = Math.sin( phi ) * radius; + + this.x = sinPhiRadius * Math.sin( theta ); + this.y = Math.cos( phi ) * radius; + this.z = sinPhiRadius * Math.cos( theta ); + + return this; + + } + + setFromCylindrical( c ) { + + return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); + + } + + setFromCylindricalCoords( radius, theta, y ) { + + this.x = radius * Math.sin( theta ); + this.y = y; + this.z = radius * Math.cos( theta ); + + return this; + + } + + setFromMatrixPosition( m ) { + + const e = m.elements; + + this.x = e[ 12 ]; + this.y = e[ 13 ]; + this.z = e[ 14 ]; + + return this; + + } + + setFromMatrixScale( m ) { + + const sx = this.setFromMatrixColumn( m, 0 ).length(); + const sy = this.setFromMatrixColumn( m, 1 ).length(); + const sz = this.setFromMatrixColumn( m, 2 ).length(); + + this.x = sx; + this.y = sy; + this.z = sz; + + return this; + + } + + setFromMatrixColumn( m, index ) { + + return this.fromArray( m.elements, index * 4 ); + + } + + setFromMatrix3Column( m, index ) { + + return this.fromArray( m.elements, index * 3 ); + + } + + setFromEuler( e ) { + + this.x = e._x; + this.y = e._y; + this.z = e._z; + + return this; + + } + + setFromColor( c ) { + + this.x = c.r; + this.y = c.g; + this.z = c.b; + + return this; + + } + + equals( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + + } + + fromArray( array, offset = 0 ) { + + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + + return this; + + } + + toArray( array = [], offset = 0 ) { + + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; + + return array; + + } + + fromBufferAttribute( attribute, index ) { + + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); + + return this; + + } + + random() { + + this.x = Math.random(); + this.y = Math.random(); + this.z = Math.random(); + + return this; + + } + + randomDirection() { + + // https://mathworld.wolfram.com/SpherePointPicking.html + + const theta = Math.random() * Math.PI * 2; + const u = Math.random() * 2 - 1; + const c = Math.sqrt( 1 - u * u ); + + this.x = c * Math.cos( theta ); + this.y = u; + this.z = c * Math.sin( theta ); + + return this; + + } + + *[ Symbol.iterator ]() { + + yield this.x; + yield this.y; + yield this.z; + + } + +} + +const _vector$c = /*@__PURE__*/ new Vector3(); +const _quaternion$4 = /*@__PURE__*/ new Quaternion(); + +class Box3 { + + constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { + + this.isBox3 = true; + + this.min = min; + this.max = max; + + } + + set( min, max ) { + + this.min.copy( min ); + this.max.copy( max ); + + return this; + + } + + setFromArray( array ) { + + this.makeEmpty(); + + for ( let i = 0, il = array.length; i < il; i += 3 ) { + + this.expandByPoint( _vector$b.fromArray( array, i ) ); + + } + + return this; + + } + + setFromBufferAttribute( attribute ) { + + this.makeEmpty(); + + for ( let i = 0, il = attribute.count; i < il; i ++ ) { + + this.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) ); + + } + + return this; + + } + + setFromPoints( points ) { + + this.makeEmpty(); + + for ( let i = 0, il = points.length; i < il; i ++ ) { + + this.expandByPoint( points[ i ] ); + + } + + return this; + + } + + setFromCenterAndSize( center, size ) { + + const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); + + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); + + return this; + + } + + setFromObject( object, precise = false ) { + + this.makeEmpty(); + + return this.expandByObject( object, precise ); + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + copy( box ) { + + this.min.copy( box.min ); + this.max.copy( box.max ); + + return this; + + } + + makeEmpty() { + + this.min.x = this.min.y = this.min.z = + Infinity; + this.max.x = this.max.y = this.max.z = - Infinity; + + return this; + + } + + isEmpty() { + + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); + + } + + getCenter( target ) { + + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + + } + + getSize( target ) { + + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); + + } + + expandByPoint( point ) { + + this.min.min( point ); + this.max.max( point ); + + return this; + + } + + expandByVector( vector ) { + + this.min.sub( vector ); + this.max.add( vector ); + + return this; + + } + + expandByScalar( scalar ) { + + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); + + return this; + + } + + expandByObject( object, precise = false ) { + + // Computes the world-axis-aligned bounding box of an object (including its children), + // accounting for both the object's, and children's, world transforms + + object.updateWorldMatrix( false, false ); + + const geometry = object.geometry; + + if ( geometry !== undefined ) { + + const positionAttribute = geometry.getAttribute( 'position' ); + + // precise AABB computation based on vertex data requires at least a position attribute. + // instancing isn't supported so far and uses the normal (conservative) code path. + + if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) { + + for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) { + + if ( object.isMesh === true ) { + + object.getVertexPosition( i, _vector$b ); + + } else { + + _vector$b.fromBufferAttribute( positionAttribute, i ); + + } + + _vector$b.applyMatrix4( object.matrixWorld ); + this.expandByPoint( _vector$b ); + + } + + } else { + + if ( object.boundingBox !== undefined ) { + + // object-level bounding box + + if ( object.boundingBox === null ) { + + object.computeBoundingBox(); + + } + + _box$4.copy( object.boundingBox ); + + + } else { + + // geometry-level bounding box + + if ( geometry.boundingBox === null ) { + + geometry.computeBoundingBox(); + + } + + _box$4.copy( geometry.boundingBox ); + + } + + _box$4.applyMatrix4( object.matrixWorld ); + + this.union( _box$4 ); + + } + + } + + const children = object.children; + + for ( let i = 0, l = children.length; i < l; i ++ ) { + + this.expandByObject( children[ i ], precise ); + + } + + return this; + + } + + containsPoint( point ) { + + return point.x >= this.min.x && point.x <= this.max.x && + point.y >= this.min.y && point.y <= this.max.y && + point.z >= this.min.z && point.z <= this.max.z; + + } + + containsBox( box ) { + + return this.min.x <= box.min.x && box.max.x <= this.max.x && + this.min.y <= box.min.y && box.max.y <= this.max.y && + this.min.z <= box.min.z && box.max.z <= this.max.z; + + } + + getParameter( point, target ) { + + // This can potentially have a divide by zero if the box + // has a size dimension of 0. + + return target.set( + ( point.x - this.min.x ) / ( this.max.x - this.min.x ), + ( point.y - this.min.y ) / ( this.max.y - this.min.y ), + ( point.z - this.min.z ) / ( this.max.z - this.min.z ) + ); + + } + + intersectsBox( box ) { + + // using 6 splitting planes to rule out intersections. + return box.max.x >= this.min.x && box.min.x <= this.max.x && + box.max.y >= this.min.y && box.min.y <= this.max.y && + box.max.z >= this.min.z && box.min.z <= this.max.z; + + } + + intersectsSphere( sphere ) { + + // Find the point on the AABB closest to the sphere center. + this.clampPoint( sphere.center, _vector$b ); + + // If that point is inside the sphere, the AABB and sphere intersect. + return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); + + } + + intersectsPlane( plane ) { + + // We compute the minimum and maximum dot product values. If those values + // are on the same side (back or front) of the plane, then there is no intersection. + + let min, max; + + if ( plane.normal.x > 0 ) { + + min = plane.normal.x * this.min.x; + max = plane.normal.x * this.max.x; + + } else { + + min = plane.normal.x * this.max.x; + max = plane.normal.x * this.min.x; + + } + + if ( plane.normal.y > 0 ) { + + min += plane.normal.y * this.min.y; + max += plane.normal.y * this.max.y; + + } else { + + min += plane.normal.y * this.max.y; + max += plane.normal.y * this.min.y; + + } + + if ( plane.normal.z > 0 ) { + + min += plane.normal.z * this.min.z; + max += plane.normal.z * this.max.z; + + } else { + + min += plane.normal.z * this.max.z; + max += plane.normal.z * this.min.z; + + } + + return ( min <= - plane.constant && max >= - plane.constant ); + + } + + intersectsTriangle( triangle ) { + + if ( this.isEmpty() ) { + + return false; + + } + + // compute box center and extents + this.getCenter( _center ); + _extents.subVectors( this.max, _center ); + + // translate triangle to aabb origin + _v0$2.subVectors( triangle.a, _center ); + _v1$7.subVectors( triangle.b, _center ); + _v2$4.subVectors( triangle.c, _center ); + + // compute edge vectors for triangle + _f0.subVectors( _v1$7, _v0$2 ); + _f1.subVectors( _v2$4, _v1$7 ); + _f2.subVectors( _v0$2, _v2$4 ); + + // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb + // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation + // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) + let axes = [ + 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, + _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, + - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 + ]; + if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { + + return false; + + } + + // test 3 face normals from the aabb + axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; + if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { + + return false; + + } + + // finally testing the face normal of the triangle + // use already existing triangle edge vectors here + _triangleNormal.crossVectors( _f0, _f1 ); + axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; + + return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ); + + } + + clampPoint( point, target ) { + + return target.copy( point ).clamp( this.min, this.max ); + + } + + distanceToPoint( point ) { + + return this.clampPoint( point, _vector$b ).distanceTo( point ); + + } + + getBoundingSphere( target ) { + + if ( this.isEmpty() ) { + + target.makeEmpty(); + + } else { + + this.getCenter( target.center ); + + target.radius = this.getSize( _vector$b ).length() * 0.5; + + } + + return target; + + } + + intersect( box ) { + + this.min.max( box.min ); + this.max.min( box.max ); + + // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. + if ( this.isEmpty() ) this.makeEmpty(); + + return this; + + } + + union( box ) { + + this.min.min( box.min ); + this.max.max( box.max ); + + return this; + + } + + applyMatrix4( matrix ) { + + // transform of empty box is an empty box. + if ( this.isEmpty() ) return this; + + // NOTE: I am using a binary pattern to specify all 2^3 combinations below + _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 + _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 + _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 + _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 + _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 + _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 + _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 + _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 + + this.setFromPoints( _points ); + + return this; + + } + + translate( offset ) { + + this.min.add( offset ); + this.max.add( offset ); + + return this; + + } + + equals( box ) { + + return box.min.equals( this.min ) && box.max.equals( this.max ); + + } + +} + +const _points = [ + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3() +]; + +const _vector$b = /*@__PURE__*/ new Vector3(); + +const _box$4 = /*@__PURE__*/ new Box3(); + +// triangle centered vertices + +const _v0$2 = /*@__PURE__*/ new Vector3(); +const _v1$7 = /*@__PURE__*/ new Vector3(); +const _v2$4 = /*@__PURE__*/ new Vector3(); + +// triangle edge vectors + +const _f0 = /*@__PURE__*/ new Vector3(); +const _f1 = /*@__PURE__*/ new Vector3(); +const _f2 = /*@__PURE__*/ new Vector3(); + +const _center = /*@__PURE__*/ new Vector3(); +const _extents = /*@__PURE__*/ new Vector3(); +const _triangleNormal = /*@__PURE__*/ new Vector3(); +const _testAxis = /*@__PURE__*/ new Vector3(); + +function satForAxes( axes, v0, v1, v2, extents ) { + + for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { + + _testAxis.fromArray( axes, i ); + // project the aabb onto the separating axis + const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z ); + // project all 3 vertices of the triangle onto the separating axis + const p0 = v0.dot( _testAxis ); + const p1 = v1.dot( _testAxis ); + const p2 = v2.dot( _testAxis ); + // actual test, basically see if either of the most extreme of the triangle points intersects r + if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) { + + // points of the projected triangle are outside the projected half-length of the aabb + // the axis is separating and we can exit + return false; + + } + + } + + return true; + +} + +const _box$3 = /*@__PURE__*/ new Box3(); +const _v1$6 = /*@__PURE__*/ new Vector3(); +const _v2$3 = /*@__PURE__*/ new Vector3(); + +class Sphere { + + constructor( center = new Vector3(), radius = - 1 ) { + + this.isSphere = true; + + this.center = center; + this.radius = radius; + + } + + set( center, radius ) { + + this.center.copy( center ); + this.radius = radius; + + return this; + + } + + setFromPoints( points, optionalCenter ) { + + const center = this.center; + + if ( optionalCenter !== undefined ) { + + center.copy( optionalCenter ); + + } else { + + _box$3.setFromPoints( points ).getCenter( center ); + + } + + let maxRadiusSq = 0; + + for ( let i = 0, il = points.length; i < il; i ++ ) { + + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); + + } + + this.radius = Math.sqrt( maxRadiusSq ); + + return this; + + } + + copy( sphere ) { + + this.center.copy( sphere.center ); + this.radius = sphere.radius; + + return this; + + } + + isEmpty() { + + return ( this.radius < 0 ); + + } + + makeEmpty() { + + this.center.set( 0, 0, 0 ); + this.radius = - 1; + + return this; + + } + + containsPoint( point ) { + + return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); + + } + + distanceToPoint( point ) { + + return ( point.distanceTo( this.center ) - this.radius ); + + } + + intersectsSphere( sphere ) { + + const radiusSum = this.radius + sphere.radius; + + return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); + + } + + intersectsBox( box ) { + + return box.intersectsSphere( this ); + + } + + intersectsPlane( plane ) { + + return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; + + } + + clampPoint( point, target ) { + + const deltaLengthSq = this.center.distanceToSquared( point ); + + target.copy( point ); + + if ( deltaLengthSq > ( this.radius * this.radius ) ) { + + target.sub( this.center ).normalize(); + target.multiplyScalar( this.radius ).add( this.center ); + + } + + return target; + + } + + getBoundingBox( target ) { + + if ( this.isEmpty() ) { + + // Empty sphere produces empty bounding box + target.makeEmpty(); + return target; + + } + + target.set( this.center, this.center ); + target.expandByScalar( this.radius ); + + return target; + + } + + applyMatrix4( matrix ) { + + this.center.applyMatrix4( matrix ); + this.radius = this.radius * matrix.getMaxScaleOnAxis(); + + return this; + + } + + translate( offset ) { + + this.center.add( offset ); + + return this; + + } + + expandByPoint( point ) { + + if ( this.isEmpty() ) { + + this.center.copy( point ); + + this.radius = 0; + + return this; + + } + + _v1$6.subVectors( point, this.center ); + + const lengthSq = _v1$6.lengthSq(); + + if ( lengthSq > ( this.radius * this.radius ) ) { + + // calculate the minimal sphere + + const length = Math.sqrt( lengthSq ); + + const delta = ( length - this.radius ) * 0.5; + + this.center.addScaledVector( _v1$6, delta / length ); + + this.radius += delta; + + } + + return this; + + } + + union( sphere ) { + + if ( sphere.isEmpty() ) { + + return this; + + } + + if ( this.isEmpty() ) { + + this.copy( sphere ); + + return this; + + } + + if ( this.center.equals( sphere.center ) === true ) { + + this.radius = Math.max( this.radius, sphere.radius ); + + } else { + + _v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius ); + + this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) ); + + this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) ); + + } + + return this; + + } + + equals( sphere ) { + + return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); + + } + + clone() { + + return new this.constructor().copy( this ); + + } + +} + +const _vector$a = /*@__PURE__*/ new Vector3(); +const _segCenter = /*@__PURE__*/ new Vector3(); +const _segDir = /*@__PURE__*/ new Vector3(); +const _diff = /*@__PURE__*/ new Vector3(); + +const _edge1 = /*@__PURE__*/ new Vector3(); +const _edge2 = /*@__PURE__*/ new Vector3(); +const _normal$2 = /*@__PURE__*/ new Vector3(); + +class Ray { + + constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { + + this.origin = origin; + this.direction = direction; + + } + + set( origin, direction ) { + + this.origin.copy( origin ); + this.direction.copy( direction ); + + return this; + + } + + copy( ray ) { + + this.origin.copy( ray.origin ); + this.direction.copy( ray.direction ); + + return this; + + } + + at( t, target ) { + + return target.copy( this.origin ).addScaledVector( this.direction, t ); + + } + + lookAt( v ) { + + this.direction.copy( v ).sub( this.origin ).normalize(); + + return this; + + } + + recast( t ) { + + this.origin.copy( this.at( t, _vector$a ) ); + + return this; + + } + + closestPointToPoint( point, target ) { + + target.subVectors( point, this.origin ); + + const directionDistance = target.dot( this.direction ); + + if ( directionDistance < 0 ) { + + return target.copy( this.origin ); + + } + + return target.copy( this.origin ).addScaledVector( this.direction, directionDistance ); + + } + + distanceToPoint( point ) { + + return Math.sqrt( this.distanceSqToPoint( point ) ); + + } + + distanceSqToPoint( point ) { + + const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); + + // point behind the ray + + if ( directionDistance < 0 ) { + + return this.origin.distanceToSquared( point ); + + } + + _vector$a.copy( this.origin ).addScaledVector( this.direction, directionDistance ); + + return _vector$a.distanceToSquared( point ); + + } + + distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { + + // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h + // It returns the min distance between the ray and the segment + // defined by v0 and v1 + // It can also set two optional targets : + // - The closest point on the ray + // - The closest point on the segment + + _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); + _segDir.copy( v1 ).sub( v0 ).normalize(); + _diff.copy( this.origin ).sub( _segCenter ); + + const segExtent = v0.distanceTo( v1 ) * 0.5; + const a01 = - this.direction.dot( _segDir ); + const b0 = _diff.dot( this.direction ); + const b1 = - _diff.dot( _segDir ); + const c = _diff.lengthSq(); + const det = Math.abs( 1 - a01 * a01 ); + let s0, s1, sqrDist, extDet; + + if ( det > 0 ) { + + // The ray and segment are not parallel. + + s0 = a01 * b1 - b0; + s1 = a01 * b0 - b1; + extDet = segExtent * det; + + if ( s0 >= 0 ) { + + if ( s1 >= - extDet ) { + + if ( s1 <= extDet ) { + + // region 0 + // Minimum at interior points of ray and segment. + + const invDet = 1 / det; + s0 *= invDet; + s1 *= invDet; + sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; + + } else { + + // region 1 + + s1 = segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } + + } else { + + // region 5 + + s1 = - segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } + + } else { + + if ( s1 <= - extDet ) { + + // region 4 + + s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } else if ( s1 <= extDet ) { + + // region 3 + + s0 = 0; + s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = s1 * ( s1 + 2 * b1 ) + c; + + } else { + + // region 2 + + s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } + + } + + } else { + + // Ray and segment are parallel. + + s1 = ( a01 > 0 ) ? - segExtent : segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } + + if ( optionalPointOnRay ) { + + optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 ); + + } + + if ( optionalPointOnSegment ) { + + optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 ); + + } + + return sqrDist; + + } + + intersectSphere( sphere, target ) { + + _vector$a.subVectors( sphere.center, this.origin ); + const tca = _vector$a.dot( this.direction ); + const d2 = _vector$a.dot( _vector$a ) - tca * tca; + const radius2 = sphere.radius * sphere.radius; + + if ( d2 > radius2 ) return null; + + const thc = Math.sqrt( radius2 - d2 ); + + // t0 = first intersect point - entrance on front of sphere + const t0 = tca - thc; + + // t1 = second intersect point - exit point on back of sphere + const t1 = tca + thc; + + // test to see if t1 is behind the ray - if so, return null + if ( t1 < 0 ) return null; + + // test to see if t0 is behind the ray: + // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, + // in order to always return an intersect point that is in front of the ray. + if ( t0 < 0 ) return this.at( t1, target ); + + // else t0 is in front of the ray, so return the first collision point scaled by t0 + return this.at( t0, target ); + + } + + intersectsSphere( sphere ) { + + return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); + + } + + distanceToPlane( plane ) { + + const denominator = plane.normal.dot( this.direction ); + + if ( denominator === 0 ) { + + // line is coplanar, return origin + if ( plane.distanceToPoint( this.origin ) === 0 ) { + + return 0; + + } + + // Null is preferable to undefined since undefined means.... it is undefined + + return null; + + } + + const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; + + // Return if the ray never intersects the plane + + return t >= 0 ? t : null; + + } + + intersectPlane( plane, target ) { + + const t = this.distanceToPlane( plane ); + + if ( t === null ) { + + return null; + + } + + return this.at( t, target ); + + } + + intersectsPlane( plane ) { + + // check if the ray lies on the plane first + + const distToPoint = plane.distanceToPoint( this.origin ); + + if ( distToPoint === 0 ) { + + return true; + + } + + const denominator = plane.normal.dot( this.direction ); + + if ( denominator * distToPoint < 0 ) { + + return true; + + } + + // ray origin is behind the plane (and is pointing behind it) + + return false; + + } + + intersectBox( box, target ) { + + let tmin, tmax, tymin, tymax, tzmin, tzmax; + + const invdirx = 1 / this.direction.x, + invdiry = 1 / this.direction.y, + invdirz = 1 / this.direction.z; + + const origin = this.origin; + + if ( invdirx >= 0 ) { + + tmin = ( box.min.x - origin.x ) * invdirx; + tmax = ( box.max.x - origin.x ) * invdirx; + + } else { + + tmin = ( box.max.x - origin.x ) * invdirx; + tmax = ( box.min.x - origin.x ) * invdirx; + + } + + if ( invdiry >= 0 ) { + + tymin = ( box.min.y - origin.y ) * invdiry; + tymax = ( box.max.y - origin.y ) * invdiry; + + } else { + + tymin = ( box.max.y - origin.y ) * invdiry; + tymax = ( box.min.y - origin.y ) * invdiry; + + } + + if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; + + if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin; + + if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax; + + if ( invdirz >= 0 ) { + + tzmin = ( box.min.z - origin.z ) * invdirz; + tzmax = ( box.max.z - origin.z ) * invdirz; + + } else { + + tzmin = ( box.max.z - origin.z ) * invdirz; + tzmax = ( box.min.z - origin.z ) * invdirz; + + } + + if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; + + if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; + + if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; + + //return point closest to the ray (positive side) + + if ( tmax < 0 ) return null; + + return this.at( tmin >= 0 ? tmin : tmax, target ); + + } + + intersectsBox( box ) { + + return this.intersectBox( box, _vector$a ) !== null; + + } + + intersectTriangle( a, b, c, backfaceCulling, target ) { + + // Compute the offset origin, edges, and normal. + + // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h + + _edge1.subVectors( b, a ); + _edge2.subVectors( c, a ); + _normal$2.crossVectors( _edge1, _edge2 ); + + // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, + // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by + // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) + // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) + // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) + let DdN = this.direction.dot( _normal$2 ); + let sign; + + if ( DdN > 0 ) { + + if ( backfaceCulling ) return null; + sign = 1; + + } else if ( DdN < 0 ) { + + sign = - 1; + DdN = - DdN; + + } else { + + return null; + + } + + _diff.subVectors( this.origin, a ); + const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); + + // b1 < 0, no intersection + if ( DdQxE2 < 0 ) { + + return null; + + } + + const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); + + // b2 < 0, no intersection + if ( DdE1xQ < 0 ) { + + return null; + + } + + // b1+b2 > 1, no intersection + if ( DdQxE2 + DdE1xQ > DdN ) { + + return null; + + } + + // Line intersects triangle, check if ray does. + const QdN = - sign * _diff.dot( _normal$2 ); + + // t < 0, no intersection + if ( QdN < 0 ) { + + return null; + + } + + // Ray intersects triangle. + return this.at( QdN / DdN, target ); + + } + + applyMatrix4( matrix4 ) { + + this.origin.applyMatrix4( matrix4 ); + this.direction.transformDirection( matrix4 ); + + return this; + + } + + equals( ray ) { + + return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); + + } + + clone() { + + return new this.constructor().copy( this ); + + } + +} + +class Matrix4 { + + constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + + Matrix4.prototype.isMatrix4 = true; + + this.elements = [ + + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + + ]; + + if ( n11 !== undefined ) { + + this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ); + + } + + } + + set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + + const te = this.elements; + + te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; + te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; + te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; + te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; + + return this; + + } + + identity() { + + this.set( + + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + + ); + + return this; + + } + + clone() { + + return new Matrix4().fromArray( this.elements ); + + } + + copy( m ) { + + const te = this.elements; + const me = m.elements; + + te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; + te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; + te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; + te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; + + return this; + + } + + copyPosition( m ) { + + const te = this.elements, me = m.elements; + + te[ 12 ] = me[ 12 ]; + te[ 13 ] = me[ 13 ]; + te[ 14 ] = me[ 14 ]; + + return this; + + } + + setFromMatrix3( m ) { + + const me = m.elements; + + this.set( + + me[ 0 ], me[ 3 ], me[ 6 ], 0, + me[ 1 ], me[ 4 ], me[ 7 ], 0, + me[ 2 ], me[ 5 ], me[ 8 ], 0, + 0, 0, 0, 1 + + ); + + return this; + + } + + extractBasis( xAxis, yAxis, zAxis ) { + + xAxis.setFromMatrixColumn( this, 0 ); + yAxis.setFromMatrixColumn( this, 1 ); + zAxis.setFromMatrixColumn( this, 2 ); + + return this; + + } + + makeBasis( xAxis, yAxis, zAxis ) { + + this.set( + xAxis.x, yAxis.x, zAxis.x, 0, + xAxis.y, yAxis.y, zAxis.y, 0, + xAxis.z, yAxis.z, zAxis.z, 0, + 0, 0, 0, 1 + ); + + return this; + + } + + extractRotation( m ) { + + // this method does not support reflection matrices + + const te = this.elements; + const me = m.elements; + + const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); + const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); + const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); + + te[ 0 ] = me[ 0 ] * scaleX; + te[ 1 ] = me[ 1 ] * scaleX; + te[ 2 ] = me[ 2 ] * scaleX; + te[ 3 ] = 0; + + te[ 4 ] = me[ 4 ] * scaleY; + te[ 5 ] = me[ 5 ] * scaleY; + te[ 6 ] = me[ 6 ] * scaleY; + te[ 7 ] = 0; + + te[ 8 ] = me[ 8 ] * scaleZ; + te[ 9 ] = me[ 9 ] * scaleZ; + te[ 10 ] = me[ 10 ] * scaleZ; + te[ 11 ] = 0; + + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; + + return this; + + } + + makeRotationFromEuler( euler ) { + + const te = this.elements; + + const x = euler.x, y = euler.y, z = euler.z; + const a = Math.cos( x ), b = Math.sin( x ); + const c = Math.cos( y ), d = Math.sin( y ); + const e = Math.cos( z ), f = Math.sin( z ); + + if ( euler.order === 'XYZ' ) { + + const ae = a * e, af = a * f, be = b * e, bf = b * f; + + te[ 0 ] = c * e; + te[ 4 ] = - c * f; + te[ 8 ] = d; + + te[ 1 ] = af + be * d; + te[ 5 ] = ae - bf * d; + te[ 9 ] = - b * c; + + te[ 2 ] = bf - ae * d; + te[ 6 ] = be + af * d; + te[ 10 ] = a * c; + + } else if ( euler.order === 'YXZ' ) { + + const ce = c * e, cf = c * f, de = d * e, df = d * f; + + te[ 0 ] = ce + df * b; + te[ 4 ] = de * b - cf; + te[ 8 ] = a * d; + + te[ 1 ] = a * f; + te[ 5 ] = a * e; + te[ 9 ] = - b; + + te[ 2 ] = cf * b - de; + te[ 6 ] = df + ce * b; + te[ 10 ] = a * c; + + } else if ( euler.order === 'ZXY' ) { + + const ce = c * e, cf = c * f, de = d * e, df = d * f; + + te[ 0 ] = ce - df * b; + te[ 4 ] = - a * f; + te[ 8 ] = de + cf * b; + + te[ 1 ] = cf + de * b; + te[ 5 ] = a * e; + te[ 9 ] = df - ce * b; + + te[ 2 ] = - a * d; + te[ 6 ] = b; + te[ 10 ] = a * c; + + } else if ( euler.order === 'ZYX' ) { + + const ae = a * e, af = a * f, be = b * e, bf = b * f; + + te[ 0 ] = c * e; + te[ 4 ] = be * d - af; + te[ 8 ] = ae * d + bf; + + te[ 1 ] = c * f; + te[ 5 ] = bf * d + ae; + te[ 9 ] = af * d - be; + + te[ 2 ] = - d; + te[ 6 ] = b * c; + te[ 10 ] = a * c; + + } else if ( euler.order === 'YZX' ) { + + const ac = a * c, ad = a * d, bc = b * c, bd = b * d; + + te[ 0 ] = c * e; + te[ 4 ] = bd - ac * f; + te[ 8 ] = bc * f + ad; + + te[ 1 ] = f; + te[ 5 ] = a * e; + te[ 9 ] = - b * e; + + te[ 2 ] = - d * e; + te[ 6 ] = ad * f + bc; + te[ 10 ] = ac - bd * f; + + } else if ( euler.order === 'XZY' ) { + + const ac = a * c, ad = a * d, bc = b * c, bd = b * d; + + te[ 0 ] = c * e; + te[ 4 ] = - f; + te[ 8 ] = d * e; + + te[ 1 ] = ac * f + bd; + te[ 5 ] = a * e; + te[ 9 ] = ad * f - bc; + + te[ 2 ] = bc * f - ad; + te[ 6 ] = b * e; + te[ 10 ] = bd * f + ac; + + } + + // bottom row + te[ 3 ] = 0; + te[ 7 ] = 0; + te[ 11 ] = 0; + + // last column + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; + + return this; + + } + + makeRotationFromQuaternion( q ) { + + return this.compose( _zero, q, _one ); + + } + + lookAt( eye, target, up ) { + + const te = this.elements; + + _z.subVectors( eye, target ); + + if ( _z.lengthSq() === 0 ) { + + // eye and target are in the same position + + _z.z = 1; + + } + + _z.normalize(); + _x.crossVectors( up, _z ); + + if ( _x.lengthSq() === 0 ) { + + // up and z are parallel + + if ( Math.abs( up.z ) === 1 ) { + + _z.x += 0.0001; + + } else { + + _z.z += 0.0001; + + } + + _z.normalize(); + _x.crossVectors( up, _z ); + + } + + _x.normalize(); + _y.crossVectors( _z, _x ); + + te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; + te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; + te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; + + return this; + + } + + multiply( m ) { + + return this.multiplyMatrices( this, m ); + + } + + premultiply( m ) { + + return this.multiplyMatrices( m, this ); + + } + + multiplyMatrices( a, b ) { + + const ae = a.elements; + const be = b.elements; + const te = this.elements; + + const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; + const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; + const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; + const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; + + const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; + const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; + const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; + const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; + + te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; + te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; + te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; + te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; + + te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; + te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; + te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; + te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; + + te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; + te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; + te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; + te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; + + te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; + te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; + te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; + te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; + + return this; + + } + + multiplyScalar( s ) { + + const te = this.elements; + + te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; + te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; + te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; + te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; + + return this; + + } + + determinant() { + + const te = this.elements; + + const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; + const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; + const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; + const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; + + //TODO: make this more efficient + //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) + + return ( + n41 * ( + + n14 * n23 * n32 + - n13 * n24 * n32 + - n14 * n22 * n33 + + n12 * n24 * n33 + + n13 * n22 * n34 + - n12 * n23 * n34 + ) + + n42 * ( + + n11 * n23 * n34 + - n11 * n24 * n33 + + n14 * n21 * n33 + - n13 * n21 * n34 + + n13 * n24 * n31 + - n14 * n23 * n31 + ) + + n43 * ( + + n11 * n24 * n32 + - n11 * n22 * n34 + - n14 * n21 * n32 + + n12 * n21 * n34 + + n14 * n22 * n31 + - n12 * n24 * n31 + ) + + n44 * ( + - n13 * n22 * n31 + - n11 * n23 * n32 + + n11 * n22 * n33 + + n13 * n21 * n32 + - n12 * n21 * n33 + + n12 * n23 * n31 + ) + + ); + + } + + transpose() { + + const te = this.elements; + let tmp; + + tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; + tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; + tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; + + tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; + tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; + tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; + + return this; + + } + + setPosition( x, y, z ) { + + const te = this.elements; + + if ( x.isVector3 ) { + + te[ 12 ] = x.x; + te[ 13 ] = x.y; + te[ 14 ] = x.z; + + } else { + + te[ 12 ] = x; + te[ 13 ] = y; + te[ 14 ] = z; + + } + + return this; + + } + + invert() { + + // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm + const te = this.elements, + + n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], + n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], + n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], + n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], + + t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, + t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, + t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, + t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; + + const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; + + if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + + const detInv = 1 / det; + + te[ 0 ] = t11 * detInv; + te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; + te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; + te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; + + te[ 4 ] = t12 * detInv; + te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; + te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; + te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; + + te[ 8 ] = t13 * detInv; + te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; + te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; + te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; + + te[ 12 ] = t14 * detInv; + te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; + te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; + te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; + + return this; + + } + + scale( v ) { + + const te = this.elements; + const x = v.x, y = v.y, z = v.z; + + te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; + te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; + te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; + te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; + + return this; + + } + + getMaxScaleOnAxis() { + + const te = this.elements; + + const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; + const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; + const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; + + return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); + + } + + makeTranslation( x, y, z ) { + + if ( x.isVector3 ) { + + this.set( + + 1, 0, 0, x.x, + 0, 1, 0, x.y, + 0, 0, 1, x.z, + 0, 0, 0, 1 + + ); + + } else { + + this.set( + + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1 + + ); + + } + + return this; + + } + + makeRotationX( theta ) { + + const c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + 1, 0, 0, 0, + 0, c, - s, 0, + 0, s, c, 0, + 0, 0, 0, 1 + + ); + + return this; + + } + + makeRotationY( theta ) { + + const c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + c, 0, s, 0, + 0, 1, 0, 0, + - s, 0, c, 0, + 0, 0, 0, 1 + + ); + + return this; + + } + + makeRotationZ( theta ) { + + const c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + c, - s, 0, 0, + s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + + ); + + return this; + + } + + makeRotationAxis( axis, angle ) { + + // Based on http://www.gamedev.net/reference/articles/article1199.asp + + const c = Math.cos( angle ); + const s = Math.sin( angle ); + const t = 1 - c; + const x = axis.x, y = axis.y, z = axis.z; + const tx = t * x, ty = t * y; + + this.set( + + tx * x + c, tx * y - s * z, tx * z + s * y, 0, + tx * y + s * z, ty * y + c, ty * z - s * x, 0, + tx * z - s * y, ty * z + s * x, t * z * z + c, 0, + 0, 0, 0, 1 + + ); + + return this; + + } + + makeScale( x, y, z ) { + + this.set( + + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1 + + ); + + return this; + + } + + makeShear( xy, xz, yx, yz, zx, zy ) { + + this.set( + + 1, yx, zx, 0, + xy, 1, zy, 0, + xz, yz, 1, 0, + 0, 0, 0, 1 + + ); + + return this; + + } + + compose( position, quaternion, scale ) { + + const te = this.elements; + + const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; + const x2 = x + x, y2 = y + y, z2 = z + z; + const xx = x * x2, xy = x * y2, xz = x * z2; + const yy = y * y2, yz = y * z2, zz = z * z2; + const wx = w * x2, wy = w * y2, wz = w * z2; + + const sx = scale.x, sy = scale.y, sz = scale.z; + + te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; + te[ 1 ] = ( xy + wz ) * sx; + te[ 2 ] = ( xz - wy ) * sx; + te[ 3 ] = 0; + + te[ 4 ] = ( xy - wz ) * sy; + te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; + te[ 6 ] = ( yz + wx ) * sy; + te[ 7 ] = 0; + + te[ 8 ] = ( xz + wy ) * sz; + te[ 9 ] = ( yz - wx ) * sz; + te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; + te[ 11 ] = 0; + + te[ 12 ] = position.x; + te[ 13 ] = position.y; + te[ 14 ] = position.z; + te[ 15 ] = 1; + + return this; + + } + + decompose( position, quaternion, scale ) { + + const te = this.elements; + + let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); + const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); + const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); + + // if determine is negative, we need to invert one scale + const det = this.determinant(); + if ( det < 0 ) sx = - sx; + + position.x = te[ 12 ]; + position.y = te[ 13 ]; + position.z = te[ 14 ]; + + // scale the rotation part + _m1$2.copy( this ); + + const invSX = 1 / sx; + const invSY = 1 / sy; + const invSZ = 1 / sz; + + _m1$2.elements[ 0 ] *= invSX; + _m1$2.elements[ 1 ] *= invSX; + _m1$2.elements[ 2 ] *= invSX; + + _m1$2.elements[ 4 ] *= invSY; + _m1$2.elements[ 5 ] *= invSY; + _m1$2.elements[ 6 ] *= invSY; + + _m1$2.elements[ 8 ] *= invSZ; + _m1$2.elements[ 9 ] *= invSZ; + _m1$2.elements[ 10 ] *= invSZ; + + quaternion.setFromRotationMatrix( _m1$2 ); + + scale.x = sx; + scale.y = sy; + scale.z = sz; + + return this; + + } + + makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { + + const te = this.elements; + const x = 2 * near / ( right - left ); + const y = 2 * near / ( top - bottom ); + + const a = ( right + left ) / ( right - left ); + const b = ( top + bottom ) / ( top - bottom ); + + let c, d; + + if ( coordinateSystem === WebGLCoordinateSystem ) { + + c = - ( far + near ) / ( far - near ); + d = ( - 2 * far * near ) / ( far - near ); + + } else if ( coordinateSystem === WebGPUCoordinateSystem ) { + + c = - far / ( far - near ); + d = ( - far * near ) / ( far - near ); + + } else { + + throw new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem ); + + } + + te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; + te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; + + return this; + + } + + makeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { + + const te = this.elements; + const w = 1.0 / ( right - left ); + const h = 1.0 / ( top - bottom ); + const p = 1.0 / ( far - near ); + + const x = ( right + left ) * w; + const y = ( top + bottom ) * h; + + let z, zInv; + + if ( coordinateSystem === WebGLCoordinateSystem ) { + + z = ( far + near ) * p; + zInv = - 2 * p; + + } else if ( coordinateSystem === WebGPUCoordinateSystem ) { + + z = near * p; + zInv = - 1 * p; + + } else { + + throw new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem ); + + } + + te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; + te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = zInv; te[ 14 ] = - z; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; + + return this; + + } + + equals( matrix ) { + + const te = this.elements; + const me = matrix.elements; + + for ( let i = 0; i < 16; i ++ ) { + + if ( te[ i ] !== me[ i ] ) return false; + + } + + return true; + + } + + fromArray( array, offset = 0 ) { + + for ( let i = 0; i < 16; i ++ ) { + + this.elements[ i ] = array[ i + offset ]; + + } + + return this; + + } + + toArray( array = [], offset = 0 ) { + + const te = this.elements; + + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; + array[ offset + 3 ] = te[ 3 ]; + + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; + + array[ offset + 8 ] = te[ 8 ]; + array[ offset + 9 ] = te[ 9 ]; + array[ offset + 10 ] = te[ 10 ]; + array[ offset + 11 ] = te[ 11 ]; + + array[ offset + 12 ] = te[ 12 ]; + array[ offset + 13 ] = te[ 13 ]; + array[ offset + 14 ] = te[ 14 ]; + array[ offset + 15 ] = te[ 15 ]; + + return array; + + } + +} + +const _v1$5 = /*@__PURE__*/ new Vector3(); +const _m1$2 = /*@__PURE__*/ new Matrix4(); +const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); +const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); +const _x = /*@__PURE__*/ new Vector3(); +const _y = /*@__PURE__*/ new Vector3(); +const _z = /*@__PURE__*/ new Vector3(); + +const _matrix$2 = /*@__PURE__*/ new Matrix4(); +const _quaternion$3 = /*@__PURE__*/ new Quaternion(); + +class Euler { + + constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) { + + this.isEuler = true; + + this._x = x; + this._y = y; + this._z = z; + this._order = order; + + } + + get x() { + + return this._x; + + } + + set x( value ) { + + this._x = value; + this._onChangeCallback(); + + } + + get y() { + + return this._y; + + } + + set y( value ) { + + this._y = value; + this._onChangeCallback(); + + } + + get z() { + + return this._z; + + } + + set z( value ) { + + this._z = value; + this._onChangeCallback(); + + } + + get order() { + + return this._order; + + } + + set order( value ) { + + this._order = value; + this._onChangeCallback(); + + } + + set( x, y, z, order = this._order ) { + + this._x = x; + this._y = y; + this._z = z; + this._order = order; + + this._onChangeCallback(); + + return this; + + } + + clone() { + + return new this.constructor( this._x, this._y, this._z, this._order ); + + } + + copy( euler ) { + + this._x = euler._x; + this._y = euler._y; + this._z = euler._z; + this._order = euler._order; + + this._onChangeCallback(); + + return this; + + } + + setFromRotationMatrix( m, order = this._order, update = true ) { + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + const te = m.elements; + const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; + const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; + const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; + + switch ( order ) { + + case 'XYZ': + + this._y = Math.asin( clamp$1( m13, - 1, 1 ) ); + + if ( Math.abs( m13 ) < 0.9999999 ) { + + this._x = Math.atan2( - m23, m33 ); + this._z = Math.atan2( - m12, m11 ); + + } else { + + this._x = Math.atan2( m32, m22 ); + this._z = 0; + + } + + break; + + case 'YXZ': + + this._x = Math.asin( - clamp$1( m23, - 1, 1 ) ); + + if ( Math.abs( m23 ) < 0.9999999 ) { + + this._y = Math.atan2( m13, m33 ); + this._z = Math.atan2( m21, m22 ); + + } else { + + this._y = Math.atan2( - m31, m11 ); + this._z = 0; + + } + + break; + + case 'ZXY': + + this._x = Math.asin( clamp$1( m32, - 1, 1 ) ); + + if ( Math.abs( m32 ) < 0.9999999 ) { + + this._y = Math.atan2( - m31, m33 ); + this._z = Math.atan2( - m12, m22 ); + + } else { + + this._y = 0; + this._z = Math.atan2( m21, m11 ); + + } + + break; + + case 'ZYX': + + this._y = Math.asin( - clamp$1( m31, - 1, 1 ) ); + + if ( Math.abs( m31 ) < 0.9999999 ) { + + this._x = Math.atan2( m32, m33 ); + this._z = Math.atan2( m21, m11 ); + + } else { + + this._x = 0; + this._z = Math.atan2( - m12, m22 ); + + } + + break; + + case 'YZX': + + this._z = Math.asin( clamp$1( m21, - 1, 1 ) ); + + if ( Math.abs( m21 ) < 0.9999999 ) { + + this._x = Math.atan2( - m23, m22 ); + this._y = Math.atan2( - m31, m11 ); + + } else { + + this._x = 0; + this._y = Math.atan2( m13, m33 ); + + } + + break; + + case 'XZY': + + this._z = Math.asin( - clamp$1( m12, - 1, 1 ) ); + + if ( Math.abs( m12 ) < 0.9999999 ) { + + this._x = Math.atan2( m32, m22 ); + this._y = Math.atan2( m13, m11 ); + + } else { + + this._x = Math.atan2( - m23, m33 ); + this._y = 0; + + } + + break; + + default: + + console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); + + } + + this._order = order; + + if ( update === true ) this._onChangeCallback(); + + return this; + + } + + setFromQuaternion( q, order, update ) { + + _matrix$2.makeRotationFromQuaternion( q ); + + return this.setFromRotationMatrix( _matrix$2, order, update ); + + } + + setFromVector3( v, order = this._order ) { + + return this.set( v.x, v.y, v.z, order ); + + } + + reorder( newOrder ) { + + // WARNING: this discards revolution information -bhouston + + _quaternion$3.setFromEuler( this ); + + return this.setFromQuaternion( _quaternion$3, newOrder ); + + } + + equals( euler ) { + + return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + + } + + fromArray( array ) { + + this._x = array[ 0 ]; + this._y = array[ 1 ]; + this._z = array[ 2 ]; + if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; + + this._onChangeCallback(); + + return this; + + } + + toArray( array = [], offset = 0 ) { + + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._order; + + return array; + + } + + _onChange( callback ) { + + this._onChangeCallback = callback; + + return this; + + } + + _onChangeCallback() {} + + *[ Symbol.iterator ]() { + + yield this._x; + yield this._y; + yield this._z; + yield this._order; + + } + +} + +Euler.DEFAULT_ORDER = 'XYZ'; + +class Layers { + + constructor() { + + this.mask = 1 | 0; + + } + + set( channel ) { + + this.mask = ( 1 << channel | 0 ) >>> 0; + + } + + enable( channel ) { + + this.mask |= 1 << channel | 0; + + } + + enableAll() { + + this.mask = 0xffffffff | 0; + + } + + toggle( channel ) { + + this.mask ^= 1 << channel | 0; + + } + + disable( channel ) { + + this.mask &= ~ ( 1 << channel | 0 ); + + } + + disableAll() { + + this.mask = 0; + + } + + test( layers ) { + + return ( this.mask & layers.mask ) !== 0; + + } + + isEnabled( channel ) { + + return ( this.mask & ( 1 << channel | 0 ) ) !== 0; + + } + +} + +let _object3DId = 0; + +const _v1$4 = /*@__PURE__*/ new Vector3(); +const _q1 = /*@__PURE__*/ new Quaternion(); +const _m1$1 = /*@__PURE__*/ new Matrix4(); +const _target$1 = /*@__PURE__*/ new Vector3(); + +const _position$3 = /*@__PURE__*/ new Vector3(); +const _scale$2 = /*@__PURE__*/ new Vector3(); +const _quaternion$2 = /*@__PURE__*/ new Quaternion(); + +const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); +const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); +const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); + +const _addedEvent = { type: 'added' }; +const _removedEvent = { type: 'removed' }; + +const _childaddedEvent = { type: 'childadded', child: null }; +const _childremovedEvent = { type: 'childremoved', child: null }; + +class Object3D extends EventDispatcher { + + constructor() { + + super(); + + this.isObject3D = true; + + Object.defineProperty( this, 'id', { value: _object3DId ++ } ); + + this.uuid = generateUUID(); + + this.name = ''; + this.type = 'Object3D'; + + this.parent = null; + this.children = []; + + this.up = Object3D.DEFAULT_UP.clone(); + + const position = new Vector3(); + const rotation = new Euler(); + const quaternion = new Quaternion(); + const scale = new Vector3( 1, 1, 1 ); + + function onRotationChange() { + + quaternion.setFromEuler( rotation, false ); + + } + + function onQuaternionChange() { + + rotation.setFromQuaternion( quaternion, undefined, false ); + + } + + rotation._onChange( onRotationChange ); + quaternion._onChange( onQuaternionChange ); + + Object.defineProperties( this, { + position: { + configurable: true, + enumerable: true, + value: position + }, + rotation: { + configurable: true, + enumerable: true, + value: rotation + }, + quaternion: { + configurable: true, + enumerable: true, + value: quaternion + }, + scale: { + configurable: true, + enumerable: true, + value: scale + }, + modelViewMatrix: { + value: new Matrix4() + }, + normalMatrix: { + value: new Matrix3() + } + } ); + + this.matrix = new Matrix4(); + this.matrixWorld = new Matrix4(); + + this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE; + + this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer + this.matrixWorldNeedsUpdate = false; + + this.layers = new Layers(); + this.visible = true; + + this.castShadow = false; + this.receiveShadow = false; + + this.frustumCulled = true; + this.renderOrder = 0; + + this.animations = []; + + this.userData = {}; + + } + + onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} + + onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} + + onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} + + onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} + + applyMatrix4( matrix ) { + + if ( this.matrixAutoUpdate ) this.updateMatrix(); + + this.matrix.premultiply( matrix ); + + this.matrix.decompose( this.position, this.quaternion, this.scale ); + + } + + applyQuaternion( q ) { + + this.quaternion.premultiply( q ); + + return this; + + } + + setRotationFromAxisAngle( axis, angle ) { + + // assumes axis is normalized + + this.quaternion.setFromAxisAngle( axis, angle ); + + } + + setRotationFromEuler( euler ) { + + this.quaternion.setFromEuler( euler, true ); + + } + + setRotationFromMatrix( m ) { + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + this.quaternion.setFromRotationMatrix( m ); + + } + + setRotationFromQuaternion( q ) { + + // assumes q is normalized + + this.quaternion.copy( q ); + + } + + rotateOnAxis( axis, angle ) { + + // rotate object on axis in object space + // axis is assumed to be normalized + + _q1.setFromAxisAngle( axis, angle ); + + this.quaternion.multiply( _q1 ); + + return this; + + } + + rotateOnWorldAxis( axis, angle ) { + + // rotate object on axis in world space + // axis is assumed to be normalized + // method assumes no rotated parent + + _q1.setFromAxisAngle( axis, angle ); + + this.quaternion.premultiply( _q1 ); + + return this; + + } + + rotateX( angle ) { + + return this.rotateOnAxis( _xAxis, angle ); + + } + + rotateY( angle ) { + + return this.rotateOnAxis( _yAxis, angle ); + + } + + rotateZ( angle ) { + + return this.rotateOnAxis( _zAxis, angle ); + + } + + translateOnAxis( axis, distance ) { + + // translate object by distance along axis in object space + // axis is assumed to be normalized + + _v1$4.copy( axis ).applyQuaternion( this.quaternion ); + + this.position.add( _v1$4.multiplyScalar( distance ) ); + + return this; + + } + + translateX( distance ) { + + return this.translateOnAxis( _xAxis, distance ); + + } + + translateY( distance ) { + + return this.translateOnAxis( _yAxis, distance ); + + } + + translateZ( distance ) { + + return this.translateOnAxis( _zAxis, distance ); + + } + + localToWorld( vector ) { + + this.updateWorldMatrix( true, false ); + + return vector.applyMatrix4( this.matrixWorld ); + + } + + worldToLocal( vector ) { + + this.updateWorldMatrix( true, false ); + + return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); + + } + + lookAt( x, y, z ) { + + // This method does not support objects having non-uniformly-scaled parent(s) + + if ( x.isVector3 ) { + + _target$1.copy( x ); + + } else { + + _target$1.set( x, y, z ); + + } + + const parent = this.parent; + + this.updateWorldMatrix( true, false ); + + _position$3.setFromMatrixPosition( this.matrixWorld ); + + if ( this.isCamera || this.isLight ) { + + _m1$1.lookAt( _position$3, _target$1, this.up ); + + } else { + + _m1$1.lookAt( _target$1, _position$3, this.up ); + + } + + this.quaternion.setFromRotationMatrix( _m1$1 ); + + if ( parent ) { + + _m1$1.extractRotation( parent.matrixWorld ); + _q1.setFromRotationMatrix( _m1$1 ); + this.quaternion.premultiply( _q1.invert() ); + + } + + } + + add( object ) { + + if ( arguments.length > 1 ) { + + for ( let i = 0; i < arguments.length; i ++ ) { + + this.add( arguments[ i ] ); + + } + + return this; + + } + + if ( object === this ) { + + console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); + return this; + + } + + if ( object && object.isObject3D ) { + + object.removeFromParent(); + object.parent = this; + this.children.push( object ); + + object.dispatchEvent( _addedEvent ); + + _childaddedEvent.child = object; + this.dispatchEvent( _childaddedEvent ); + _childaddedEvent.child = null; + + } else { + + console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); + + } + + return this; + + } + + remove( object ) { + + if ( arguments.length > 1 ) { + + for ( let i = 0; i < arguments.length; i ++ ) { + + this.remove( arguments[ i ] ); + + } + + return this; + + } + + const index = this.children.indexOf( object ); + + if ( index !== - 1 ) { + + object.parent = null; + this.children.splice( index, 1 ); + + object.dispatchEvent( _removedEvent ); + + _childremovedEvent.child = object; + this.dispatchEvent( _childremovedEvent ); + _childremovedEvent.child = null; + + } + + return this; + + } + + removeFromParent() { + + const parent = this.parent; + + if ( parent !== null ) { + + parent.remove( this ); + + } + + return this; + + } + + clear() { + + return this.remove( ... this.children ); + + } + + attach( object ) { + + // adds object as a child of this, while maintaining the object's world transform + + // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) + + this.updateWorldMatrix( true, false ); + + _m1$1.copy( this.matrixWorld ).invert(); + + if ( object.parent !== null ) { + + object.parent.updateWorldMatrix( true, false ); + + _m1$1.multiply( object.parent.matrixWorld ); + + } + + object.applyMatrix4( _m1$1 ); + + object.removeFromParent(); + object.parent = this; + this.children.push( object ); + + object.updateWorldMatrix( false, true ); + + object.dispatchEvent( _addedEvent ); + + _childaddedEvent.child = object; + this.dispatchEvent( _childaddedEvent ); + _childaddedEvent.child = null; + + return this; + + } + + getObjectById( id ) { + + return this.getObjectByProperty( 'id', id ); + + } + + getObjectByName( name ) { + + return this.getObjectByProperty( 'name', name ); + + } + + getObjectByProperty( name, value ) { + + if ( this[ name ] === value ) return this; + + for ( let i = 0, l = this.children.length; i < l; i ++ ) { + + const child = this.children[ i ]; + const object = child.getObjectByProperty( name, value ); + + if ( object !== undefined ) { + + return object; + + } + + } + + return undefined; + + } + + getObjectsByProperty( name, value, result = [] ) { + + if ( this[ name ] === value ) result.push( this ); + + const children = this.children; + + for ( let i = 0, l = children.length; i < l; i ++ ) { + + children[ i ].getObjectsByProperty( name, value, result ); + + } + + return result; + + } + + getWorldPosition( target ) { + + this.updateWorldMatrix( true, false ); + + return target.setFromMatrixPosition( this.matrixWorld ); + + } + + getWorldQuaternion( target ) { + + this.updateWorldMatrix( true, false ); + + this.matrixWorld.decompose( _position$3, target, _scale$2 ); + + return target; + + } + + getWorldScale( target ) { + + this.updateWorldMatrix( true, false ); + + this.matrixWorld.decompose( _position$3, _quaternion$2, target ); + + return target; + + } + + getWorldDirection( target ) { + + this.updateWorldMatrix( true, false ); + + const e = this.matrixWorld.elements; + + return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); + + } + + raycast( /* raycaster, intersects */ ) {} + + traverse( callback ) { + + callback( this ); + + const children = this.children; + + for ( let i = 0, l = children.length; i < l; i ++ ) { + + children[ i ].traverse( callback ); + + } + + } + + traverseVisible( callback ) { + + if ( this.visible === false ) return; + + callback( this ); + + const children = this.children; + + for ( let i = 0, l = children.length; i < l; i ++ ) { + + children[ i ].traverseVisible( callback ); + + } + + } + + traverseAncestors( callback ) { + + const parent = this.parent; + + if ( parent !== null ) { + + callback( parent ); + + parent.traverseAncestors( callback ); + + } + + } + + updateMatrix() { + + this.matrix.compose( this.position, this.quaternion, this.scale ); + + this.matrixWorldNeedsUpdate = true; + + } + + updateMatrixWorld( force ) { + + if ( this.matrixAutoUpdate ) this.updateMatrix(); + + if ( this.matrixWorldNeedsUpdate || force ) { + + if ( this.matrixWorldAutoUpdate === true ) { + + if ( this.parent === null ) { + + this.matrixWorld.copy( this.matrix ); + + } else { + + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + + } + + } + + this.matrixWorldNeedsUpdate = false; + + force = true; + + } + + // make sure descendants are updated if required + + const children = this.children; + + for ( let i = 0, l = children.length; i < l; i ++ ) { + + const child = children[ i ]; + + child.updateMatrixWorld( force ); + + } + + } + + updateWorldMatrix( updateParents, updateChildren ) { + + const parent = this.parent; + + if ( updateParents === true && parent !== null ) { + + parent.updateWorldMatrix( true, false ); + + } + + if ( this.matrixAutoUpdate ) this.updateMatrix(); + + if ( this.matrixWorldAutoUpdate === true ) { + + if ( this.parent === null ) { + + this.matrixWorld.copy( this.matrix ); + + } else { + + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + + } + + } + + // make sure descendants are updated + + if ( updateChildren === true ) { + + const children = this.children; + + for ( let i = 0, l = children.length; i < l; i ++ ) { + + const child = children[ i ]; + + child.updateWorldMatrix( false, true ); + + } + + } + + } + + toJSON( meta ) { + + // meta is a string when called from JSON.stringify + const isRootObject = ( meta === undefined || typeof meta === 'string' ); + + const output = {}; + + // meta is a hash used to collect geometries, materials. + // not providing it implies that this is the root object + // being serialized. + if ( isRootObject ) { + + // initialize meta obj + meta = { + geometries: {}, + materials: {}, + textures: {}, + images: {}, + shapes: {}, + skeletons: {}, + animations: {}, + nodes: {} + }; + + output.metadata = { + version: 4.6, + type: 'Object', + generator: 'Object3D.toJSON' + }; + + } + + // standard Object3D serialization + + const object = {}; + + object.uuid = this.uuid; + object.type = this.type; + + if ( this.name !== '' ) object.name = this.name; + if ( this.castShadow === true ) object.castShadow = true; + if ( this.receiveShadow === true ) object.receiveShadow = true; + if ( this.visible === false ) object.visible = false; + if ( this.frustumCulled === false ) object.frustumCulled = false; + if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; + if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData; + + object.layers = this.layers.mask; + object.matrix = this.matrix.toArray(); + object.up = this.up.toArray(); + + if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; + + // object specific properties + + if ( this.isInstancedMesh ) { + + object.type = 'InstancedMesh'; + object.count = this.count; + object.instanceMatrix = this.instanceMatrix.toJSON(); + if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); + + } + + if ( this.isBatchedMesh ) { + + object.type = 'BatchedMesh'; + object.perObjectFrustumCulled = this.perObjectFrustumCulled; + object.sortObjects = this.sortObjects; + + object.drawRanges = this._drawRanges; + object.reservedRanges = this._reservedRanges; + + object.visibility = this._visibility; + object.active = this._active; + object.bounds = this._bounds.map( bound => ( { + boxInitialized: bound.boxInitialized, + boxMin: bound.box.min.toArray(), + boxMax: bound.box.max.toArray(), + + sphereInitialized: bound.sphereInitialized, + sphereRadius: bound.sphere.radius, + sphereCenter: bound.sphere.center.toArray() + } ) ); + + object.maxInstanceCount = this._maxInstanceCount; + object.maxVertexCount = this._maxVertexCount; + object.maxIndexCount = this._maxIndexCount; + + object.geometryInitialized = this._geometryInitialized; + object.geometryCount = this._geometryCount; + + object.matricesTexture = this._matricesTexture.toJSON( meta ); + + if ( this._colorsTexture !== null ) object.colorsTexture = this._colorsTexture.toJSON( meta ); + + if ( this.boundingSphere !== null ) { + + object.boundingSphere = { + center: object.boundingSphere.center.toArray(), + radius: object.boundingSphere.radius + }; + + } + + if ( this.boundingBox !== null ) { + + object.boundingBox = { + min: object.boundingBox.min.toArray(), + max: object.boundingBox.max.toArray() + }; + + } + + } + + // + + function serialize( library, element ) { + + if ( library[ element.uuid ] === undefined ) { + + library[ element.uuid ] = element.toJSON( meta ); + + } + + return element.uuid; + + } + + if ( this.isScene ) { + + if ( this.background ) { + + if ( this.background.isColor ) { + + object.background = this.background.toJSON(); + + } else if ( this.background.isTexture ) { + + object.background = this.background.toJSON( meta ).uuid; + + } + + } + + if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { + + object.environment = this.environment.toJSON( meta ).uuid; + + } + + } else if ( this.isMesh || this.isLine || this.isPoints ) { + + object.geometry = serialize( meta.geometries, this.geometry ); + + const parameters = this.geometry.parameters; + + if ( parameters !== undefined && parameters.shapes !== undefined ) { + + const shapes = parameters.shapes; + + if ( Array.isArray( shapes ) ) { + + for ( let i = 0, l = shapes.length; i < l; i ++ ) { + + const shape = shapes[ i ]; + + serialize( meta.shapes, shape ); + + } + + } else { + + serialize( meta.shapes, shapes ); + + } + + } + + } + + if ( this.isSkinnedMesh ) { + + object.bindMode = this.bindMode; + object.bindMatrix = this.bindMatrix.toArray(); + + if ( this.skeleton !== undefined ) { + + serialize( meta.skeletons, this.skeleton ); + + object.skeleton = this.skeleton.uuid; + + } + + } + + if ( this.material !== undefined ) { + + if ( Array.isArray( this.material ) ) { + + const uuids = []; + + for ( let i = 0, l = this.material.length; i < l; i ++ ) { + + uuids.push( serialize( meta.materials, this.material[ i ] ) ); + + } + + object.material = uuids; + + } else { + + object.material = serialize( meta.materials, this.material ); + + } + + } + + // + + if ( this.children.length > 0 ) { + + object.children = []; + + for ( let i = 0; i < this.children.length; i ++ ) { + + object.children.push( this.children[ i ].toJSON( meta ).object ); + + } + + } + + // + + if ( this.animations.length > 0 ) { + + object.animations = []; + + for ( let i = 0; i < this.animations.length; i ++ ) { + + const animation = this.animations[ i ]; + + object.animations.push( serialize( meta.animations, animation ) ); + + } + + } + + if ( isRootObject ) { + + const geometries = extractFromCache( meta.geometries ); + const materials = extractFromCache( meta.materials ); + const textures = extractFromCache( meta.textures ); + const images = extractFromCache( meta.images ); + const shapes = extractFromCache( meta.shapes ); + const skeletons = extractFromCache( meta.skeletons ); + const animations = extractFromCache( meta.animations ); + const nodes = extractFromCache( meta.nodes ); + + if ( geometries.length > 0 ) output.geometries = geometries; + if ( materials.length > 0 ) output.materials = materials; + if ( textures.length > 0 ) output.textures = textures; + if ( images.length > 0 ) output.images = images; + if ( shapes.length > 0 ) output.shapes = shapes; + if ( skeletons.length > 0 ) output.skeletons = skeletons; + if ( animations.length > 0 ) output.animations = animations; + if ( nodes.length > 0 ) output.nodes = nodes; + + } + + output.object = object; + + return output; + + // extract data from the cache hash + // remove metadata on each item + // and return as array + function extractFromCache( cache ) { + + const values = []; + for ( const key in cache ) { + + const data = cache[ key ]; + delete data.metadata; + values.push( data ); + + } + + return values; + + } + + } + + clone( recursive ) { + + return new this.constructor().copy( this, recursive ); + + } + + copy( source, recursive = true ) { + + this.name = source.name; + + this.up.copy( source.up ); + + this.position.copy( source.position ); + this.rotation.order = source.rotation.order; + this.quaternion.copy( source.quaternion ); + this.scale.copy( source.scale ); + + this.matrix.copy( source.matrix ); + this.matrixWorld.copy( source.matrixWorld ); + + this.matrixAutoUpdate = source.matrixAutoUpdate; + + this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; + this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; + + this.layers.mask = source.layers.mask; + this.visible = source.visible; + + this.castShadow = source.castShadow; + this.receiveShadow = source.receiveShadow; + + this.frustumCulled = source.frustumCulled; + this.renderOrder = source.renderOrder; + + this.animations = source.animations.slice(); + + this.userData = JSON.parse( JSON.stringify( source.userData ) ); + + if ( recursive === true ) { + + for ( let i = 0; i < source.children.length; i ++ ) { + + const child = source.children[ i ]; + this.add( child.clone() ); + + } + + } + + return this; + + } + +} + +Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 ); +Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true; +Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true; + +const _v0$1 = /*@__PURE__*/ new Vector3(); +const _v1$3 = /*@__PURE__*/ new Vector3(); +const _v2$2 = /*@__PURE__*/ new Vector3(); +const _v3$2 = /*@__PURE__*/ new Vector3(); + +const _vab = /*@__PURE__*/ new Vector3(); +const _vac = /*@__PURE__*/ new Vector3(); +const _vbc = /*@__PURE__*/ new Vector3(); +const _vap = /*@__PURE__*/ new Vector3(); +const _vbp = /*@__PURE__*/ new Vector3(); +const _vcp = /*@__PURE__*/ new Vector3(); + +const _v40 = /*@__PURE__*/ new Vector4(); +const _v41 = /*@__PURE__*/ new Vector4(); +const _v42 = /*@__PURE__*/ new Vector4(); + +class Triangle { + + constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { + + this.a = a; + this.b = b; + this.c = c; + + } + + static getNormal( a, b, c, target ) { + + target.subVectors( c, b ); + _v0$1.subVectors( a, b ); + target.cross( _v0$1 ); + + const targetLengthSq = target.lengthSq(); + if ( targetLengthSq > 0 ) { + + return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); + + } + + return target.set( 0, 0, 0 ); + + } + + // static/instance method to calculate barycentric coordinates + // based on: http://www.blackpawn.com/texts/pointinpoly/default.html + static getBarycoord( point, a, b, c, target ) { + + _v0$1.subVectors( c, a ); + _v1$3.subVectors( b, a ); + _v2$2.subVectors( point, a ); + + const dot00 = _v0$1.dot( _v0$1 ); + const dot01 = _v0$1.dot( _v1$3 ); + const dot02 = _v0$1.dot( _v2$2 ); + const dot11 = _v1$3.dot( _v1$3 ); + const dot12 = _v1$3.dot( _v2$2 ); + + const denom = ( dot00 * dot11 - dot01 * dot01 ); + + // collinear or singular triangle + if ( denom === 0 ) { + + target.set( 0, 0, 0 ); + return null; + + } + + const invDenom = 1 / denom; + const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; + const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; + + // barycentric coordinates must always sum to 1 + return target.set( 1 - u - v, v, u ); + + } + + static containsPoint( point, a, b, c ) { + + // if the triangle is degenerate then we can't contain a point + if ( this.getBarycoord( point, a, b, c, _v3$2 ) === null ) { + + return false; + + } + + return ( _v3$2.x >= 0 ) && ( _v3$2.y >= 0 ) && ( ( _v3$2.x + _v3$2.y ) <= 1 ); + + } + + static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) { + + if ( this.getBarycoord( point, p1, p2, p3, _v3$2 ) === null ) { + + target.x = 0; + target.y = 0; + if ( 'z' in target ) target.z = 0; + if ( 'w' in target ) target.w = 0; + return null; + + } + + target.setScalar( 0 ); + target.addScaledVector( v1, _v3$2.x ); + target.addScaledVector( v2, _v3$2.y ); + target.addScaledVector( v3, _v3$2.z ); + + return target; + + } + + static getInterpolatedAttribute( attr, i1, i2, i3, barycoord, target ) { + + _v40.setScalar( 0 ); + _v41.setScalar( 0 ); + _v42.setScalar( 0 ); + + _v40.fromBufferAttribute( attr, i1 ); + _v41.fromBufferAttribute( attr, i2 ); + _v42.fromBufferAttribute( attr, i3 ); + + target.setScalar( 0 ); + target.addScaledVector( _v40, barycoord.x ); + target.addScaledVector( _v41, barycoord.y ); + target.addScaledVector( _v42, barycoord.z ); + + return target; + + } + + static isFrontFacing( a, b, c, direction ) { + + _v0$1.subVectors( c, b ); + _v1$3.subVectors( a, b ); + + // strictly front facing + return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; + + } + + set( a, b, c ) { + + this.a.copy( a ); + this.b.copy( b ); + this.c.copy( c ); + + return this; + + } + + setFromPointsAndIndices( points, i0, i1, i2 ) { + + this.a.copy( points[ i0 ] ); + this.b.copy( points[ i1 ] ); + this.c.copy( points[ i2 ] ); + + return this; + + } + + setFromAttributeAndIndices( attribute, i0, i1, i2 ) { + + this.a.fromBufferAttribute( attribute, i0 ); + this.b.fromBufferAttribute( attribute, i1 ); + this.c.fromBufferAttribute( attribute, i2 ); + + return this; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + copy( triangle ) { + + this.a.copy( triangle.a ); + this.b.copy( triangle.b ); + this.c.copy( triangle.c ); + + return this; + + } + + getArea() { + + _v0$1.subVectors( this.c, this.b ); + _v1$3.subVectors( this.a, this.b ); + + return _v0$1.cross( _v1$3 ).length() * 0.5; + + } + + getMidpoint( target ) { + + return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); + + } + + getNormal( target ) { + + return Triangle.getNormal( this.a, this.b, this.c, target ); + + } + + getPlane( target ) { + + return target.setFromCoplanarPoints( this.a, this.b, this.c ); + + } + + getBarycoord( point, target ) { + + return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); + + } + + getInterpolation( point, v1, v2, v3, target ) { + + return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target ); + + } + + containsPoint( point ) { + + return Triangle.containsPoint( point, this.a, this.b, this.c ); + + } + + isFrontFacing( direction ) { + + return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); + + } + + intersectsBox( box ) { + + return box.intersectsTriangle( this ); + + } + + closestPointToPoint( p, target ) { + + const a = this.a, b = this.b, c = this.c; + let v, w; + + // algorithm thanks to Real-Time Collision Detection by Christer Ericson, + // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., + // under the accompanying license; see chapter 5.1.5 for detailed explanation. + // basically, we're distinguishing which of the voronoi regions of the triangle + // the point lies in with the minimum amount of redundant computation. + + _vab.subVectors( b, a ); + _vac.subVectors( c, a ); + _vap.subVectors( p, a ); + const d1 = _vab.dot( _vap ); + const d2 = _vac.dot( _vap ); + if ( d1 <= 0 && d2 <= 0 ) { + + // vertex region of A; barycentric coords (1, 0, 0) + return target.copy( a ); + + } + + _vbp.subVectors( p, b ); + const d3 = _vab.dot( _vbp ); + const d4 = _vac.dot( _vbp ); + if ( d3 >= 0 && d4 <= d3 ) { + + // vertex region of B; barycentric coords (0, 1, 0) + return target.copy( b ); + + } + + const vc = d1 * d4 - d3 * d2; + if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { + + v = d1 / ( d1 - d3 ); + // edge region of AB; barycentric coords (1-v, v, 0) + return target.copy( a ).addScaledVector( _vab, v ); + + } + + _vcp.subVectors( p, c ); + const d5 = _vab.dot( _vcp ); + const d6 = _vac.dot( _vcp ); + if ( d6 >= 0 && d5 <= d6 ) { + + // vertex region of C; barycentric coords (0, 0, 1) + return target.copy( c ); + + } + + const vb = d5 * d2 - d1 * d6; + if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { + + w = d2 / ( d2 - d6 ); + // edge region of AC; barycentric coords (1-w, 0, w) + return target.copy( a ).addScaledVector( _vac, w ); + + } + + const va = d3 * d6 - d5 * d4; + if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { + + _vbc.subVectors( c, b ); + w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) ); + // edge region of BC; barycentric coords (0, 1-w, w) + return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC + + } + + // face region + const denom = 1 / ( va + vb + vc ); + // u = va * denom + v = vb * denom; + w = vc * denom; + + return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); + + } + + equals( triangle ) { + + return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); + + } + +} + +const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, + 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, + 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, + 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, + 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, + 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, + 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, + 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, + 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, + 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, + 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, + 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, + 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, + 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, + 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, + 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, + 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, + 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, + 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, + 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, + 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, + 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, + 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, + 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; + +const _hslA = { h: 0, s: 0, l: 0 }; +const _hslB = { h: 0, s: 0, l: 0 }; + +function hue2rgb( p, q, t ) { + + if ( t < 0 ) t += 1; + if ( t > 1 ) t -= 1; + if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; + if ( t < 1 / 2 ) return q; + if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); + return p; + +} + +class Color { + + constructor( r, g, b ) { + + this.isColor = true; + + this.r = 1; + this.g = 1; + this.b = 1; + + return this.set( r, g, b ); + + } + + set( r, g, b ) { + + if ( g === undefined && b === undefined ) { + + // r is THREE.Color, hex or string + + const value = r; + + if ( value && value.isColor ) { + + this.copy( value ); + + } else if ( typeof value === 'number' ) { + + this.setHex( value ); + + } else if ( typeof value === 'string' ) { + + this.setStyle( value ); + + } + + } else { + + this.setRGB( r, g, b ); + + } + + return this; + + } + + setScalar( scalar ) { + + this.r = scalar; + this.g = scalar; + this.b = scalar; + + return this; + + } + + setHex( hex, colorSpace = SRGBColorSpace ) { + + hex = Math.floor( hex ); + + this.r = ( hex >> 16 & 255 ) / 255; + this.g = ( hex >> 8 & 255 ) / 255; + this.b = ( hex & 255 ) / 255; + + ColorManagement.toWorkingColorSpace( this, colorSpace ); + + return this; + + } + + setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) { + + this.r = r; + this.g = g; + this.b = b; + + ColorManagement.toWorkingColorSpace( this, colorSpace ); + + return this; + + } + + setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) { + + // h,s,l ranges are in 0.0 - 1.0 + h = euclideanModulo( h, 1 ); + s = clamp$1( s, 0, 1 ); + l = clamp$1( l, 0, 1 ); + + if ( s === 0 ) { + + this.r = this.g = this.b = l; + + } else { + + const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); + const q = ( 2 * l ) - p; + + this.r = hue2rgb( q, p, h + 1 / 3 ); + this.g = hue2rgb( q, p, h ); + this.b = hue2rgb( q, p, h - 1 / 3 ); + + } + + ColorManagement.toWorkingColorSpace( this, colorSpace ); + + return this; + + } + + setStyle( style, colorSpace = SRGBColorSpace ) { + + function handleAlpha( string ) { + + if ( string === undefined ) return; + + if ( parseFloat( string ) < 1 ) { + + console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); + + } + + } + + + let m; + + if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) { + + // rgb / hsl + + let color; + const name = m[ 1 ]; + const components = m[ 2 ]; + + switch ( name ) { + + case 'rgb': + case 'rgba': + + if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { + + // rgb(255,0,0) rgba(255,0,0,0.5) + + handleAlpha( color[ 4 ] ); + + return this.setRGB( + Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255, + Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255, + Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255, + colorSpace + ); + + } + + if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { + + // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) + + handleAlpha( color[ 4 ] ); + + return this.setRGB( + Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100, + Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100, + Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100, + colorSpace + ); + + } + + break; + + case 'hsl': + case 'hsla': + + if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { + + // hsl(120,50%,50%) hsla(120,50%,50%,0.5) + + handleAlpha( color[ 4 ] ); + + return this.setHSL( + parseFloat( color[ 1 ] ) / 360, + parseFloat( color[ 2 ] ) / 100, + parseFloat( color[ 3 ] ) / 100, + colorSpace + ); + + } + + break; + + default: + + console.warn( 'THREE.Color: Unknown color model ' + style ); + + } + + } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { + + // hex color + + const hex = m[ 1 ]; + const size = hex.length; + + if ( size === 3 ) { + + // #ff0 + return this.setRGB( + parseInt( hex.charAt( 0 ), 16 ) / 15, + parseInt( hex.charAt( 1 ), 16 ) / 15, + parseInt( hex.charAt( 2 ), 16 ) / 15, + colorSpace + ); + + } else if ( size === 6 ) { + + // #ff0000 + return this.setHex( parseInt( hex, 16 ), colorSpace ); + + } else { + + console.warn( 'THREE.Color: Invalid hex color ' + style ); + + } + + } else if ( style && style.length > 0 ) { + + return this.setColorName( style, colorSpace ); + + } + + return this; + + } + + setColorName( style, colorSpace = SRGBColorSpace ) { + + // color keywords + const hex = _colorKeywords[ style.toLowerCase() ]; + + if ( hex !== undefined ) { + + // red + this.setHex( hex, colorSpace ); + + } else { + + // unknown color + console.warn( 'THREE.Color: Unknown color ' + style ); + + } + + return this; + + } + + clone() { + + return new this.constructor( this.r, this.g, this.b ); + + } + + copy( color ) { + + this.r = color.r; + this.g = color.g; + this.b = color.b; + + return this; + + } + + copySRGBToLinear( color ) { + + this.r = SRGBToLinear( color.r ); + this.g = SRGBToLinear( color.g ); + this.b = SRGBToLinear( color.b ); + + return this; + + } + + copyLinearToSRGB( color ) { + + this.r = LinearToSRGB( color.r ); + this.g = LinearToSRGB( color.g ); + this.b = LinearToSRGB( color.b ); + + return this; + + } + + convertSRGBToLinear() { + + this.copySRGBToLinear( this ); + + return this; + + } + + convertLinearToSRGB() { + + this.copyLinearToSRGB( this ); + + return this; + + } + + getHex( colorSpace = SRGBColorSpace ) { + + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); + + return Math.round( clamp$1( _color.r * 255, 0, 255 ) ) * 65536 + Math.round( clamp$1( _color.g * 255, 0, 255 ) ) * 256 + Math.round( clamp$1( _color.b * 255, 0, 255 ) ); + + } + + getHexString( colorSpace = SRGBColorSpace ) { + + return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 ); + + } + + getHSL( target, colorSpace = ColorManagement.workingColorSpace ) { + + // h,s,l ranges are in 0.0 - 1.0 + + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); + + const r = _color.r, g = _color.g, b = _color.b; + + const max = Math.max( r, g, b ); + const min = Math.min( r, g, b ); + + let hue, saturation; + const lightness = ( min + max ) / 2.0; + + if ( min === max ) { + + hue = 0; + saturation = 0; + + } else { + + const delta = max - min; + + saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); + + switch ( max ) { + + case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; + case g: hue = ( b - r ) / delta + 2; break; + case b: hue = ( r - g ) / delta + 4; break; + + } + + hue /= 6; + + } + + target.h = hue; + target.s = saturation; + target.l = lightness; + + return target; + + } + + getRGB( target, colorSpace = ColorManagement.workingColorSpace ) { + + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); + + target.r = _color.r; + target.g = _color.g; + target.b = _color.b; + + return target; + + } + + getStyle( colorSpace = SRGBColorSpace ) { + + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); + + const r = _color.r, g = _color.g, b = _color.b; + + if ( colorSpace !== SRGBColorSpace ) { + + // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). + return `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`; + + } + + return `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`; + + } + + offsetHSL( h, s, l ) { + + this.getHSL( _hslA ); + + return this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l ); + + } + + add( color ) { + + this.r += color.r; + this.g += color.g; + this.b += color.b; + + return this; + + } + + addColors( color1, color2 ) { + + this.r = color1.r + color2.r; + this.g = color1.g + color2.g; + this.b = color1.b + color2.b; + + return this; + + } + + addScalar( s ) { + + this.r += s; + this.g += s; + this.b += s; + + return this; + + } + + sub( color ) { + + this.r = Math.max( 0, this.r - color.r ); + this.g = Math.max( 0, this.g - color.g ); + this.b = Math.max( 0, this.b - color.b ); + + return this; + + } + + multiply( color ) { + + this.r *= color.r; + this.g *= color.g; + this.b *= color.b; + + return this; + + } + + multiplyScalar( s ) { + + this.r *= s; + this.g *= s; + this.b *= s; + + return this; + + } + + lerp( color, alpha ) { + + this.r += ( color.r - this.r ) * alpha; + this.g += ( color.g - this.g ) * alpha; + this.b += ( color.b - this.b ) * alpha; + + return this; + + } + + lerpColors( color1, color2, alpha ) { + + this.r = color1.r + ( color2.r - color1.r ) * alpha; + this.g = color1.g + ( color2.g - color1.g ) * alpha; + this.b = color1.b + ( color2.b - color1.b ) * alpha; + + return this; + + } + + lerpHSL( color, alpha ) { + + this.getHSL( _hslA ); + color.getHSL( _hslB ); + + const h = lerp( _hslA.h, _hslB.h, alpha ); + const s = lerp( _hslA.s, _hslB.s, alpha ); + const l = lerp( _hslA.l, _hslB.l, alpha ); + + this.setHSL( h, s, l ); + + return this; + + } + + setFromVector3( v ) { + + this.r = v.x; + this.g = v.y; + this.b = v.z; + + return this; + + } + + applyMatrix3( m ) { + + const r = this.r, g = this.g, b = this.b; + const e = m.elements; + + this.r = e[ 0 ] * r + e[ 3 ] * g + e[ 6 ] * b; + this.g = e[ 1 ] * r + e[ 4 ] * g + e[ 7 ] * b; + this.b = e[ 2 ] * r + e[ 5 ] * g + e[ 8 ] * b; + + return this; + + } + + equals( c ) { + + return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); + + } + + fromArray( array, offset = 0 ) { + + this.r = array[ offset ]; + this.g = array[ offset + 1 ]; + this.b = array[ offset + 2 ]; + + return this; + + } + + toArray( array = [], offset = 0 ) { + + array[ offset ] = this.r; + array[ offset + 1 ] = this.g; + array[ offset + 2 ] = this.b; + + return array; + + } + + fromBufferAttribute( attribute, index ) { + + this.r = attribute.getX( index ); + this.g = attribute.getY( index ); + this.b = attribute.getZ( index ); + + return this; + + } + + toJSON() { + + return this.getHex(); + + } + + *[ Symbol.iterator ]() { + + yield this.r; + yield this.g; + yield this.b; + + } + +} + +const _color = /*@__PURE__*/ new Color(); + +Color.NAMES = _colorKeywords; + +let _materialId = 0; + +class Material extends EventDispatcher { + + constructor() { + + super(); + + this.isMaterial = true; + + Object.defineProperty( this, 'id', { value: _materialId ++ } ); + + this.uuid = generateUUID(); + + this.name = ''; + this.type = 'Material'; + + this.blending = NormalBlending; + this.side = FrontSide; + this.vertexColors = false; + + this.opacity = 1; + this.transparent = false; + this.alphaHash = false; + + this.blendSrc = SrcAlphaFactor; + this.blendDst = OneMinusSrcAlphaFactor; + this.blendEquation = AddEquation; + this.blendSrcAlpha = null; + this.blendDstAlpha = null; + this.blendEquationAlpha = null; + this.blendColor = new Color( 0, 0, 0 ); + this.blendAlpha = 0; + + this.depthFunc = LessEqualDepth; + this.depthTest = true; + this.depthWrite = true; + + this.stencilWriteMask = 0xff; + this.stencilFunc = AlwaysStencilFunc; + this.stencilRef = 0; + this.stencilFuncMask = 0xff; + this.stencilFail = KeepStencilOp; + this.stencilZFail = KeepStencilOp; + this.stencilZPass = KeepStencilOp; + this.stencilWrite = false; + + this.clippingPlanes = null; + this.clipIntersection = false; + this.clipShadows = false; + + this.shadowSide = null; + + this.colorWrite = true; + + this.precision = null; // override the renderer's default precision for this material + + this.polygonOffset = false; + this.polygonOffsetFactor = 0; + this.polygonOffsetUnits = 0; + + this.dithering = false; + + this.alphaToCoverage = false; + this.premultipliedAlpha = false; + this.forceSinglePass = false; + + this.visible = true; + + this.toneMapped = true; + + this.userData = {}; + + this.version = 0; + + this._alphaTest = 0; + + } + + get alphaTest() { + + return this._alphaTest; + + } + + set alphaTest( value ) { + + if ( this._alphaTest > 0 !== value > 0 ) { + + this.version ++; + + } + + this._alphaTest = value; + + } + + // onBeforeRender and onBeforeCompile only supported in WebGLRenderer + + onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {} + + onBeforeCompile( /* shaderobject, renderer */ ) {} + + customProgramCacheKey() { + + return this.onBeforeCompile.toString(); + + } + + setValues( values ) { + + if ( values === undefined ) return; + + for ( const key in values ) { + + const newValue = values[ key ]; + + if ( newValue === undefined ) { + + console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` ); + continue; + + } + + const currentValue = this[ key ]; + + if ( currentValue === undefined ) { + + console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` ); + continue; + + } + + if ( currentValue && currentValue.isColor ) { + + currentValue.set( newValue ); + + } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { + + currentValue.copy( newValue ); + + } else { + + this[ key ] = newValue; + + } + + } + + } + + toJSON( meta ) { + + const isRootObject = ( meta === undefined || typeof meta === 'string' ); + + if ( isRootObject ) { + + meta = { + textures: {}, + images: {} + }; + + } + + const data = { + metadata: { + version: 4.6, + type: 'Material', + generator: 'Material.toJSON' + } + }; + + // standard Material serialization + data.uuid = this.uuid; + data.type = this.type; + + if ( this.name !== '' ) data.name = this.name; + + if ( this.color && this.color.isColor ) data.color = this.color.getHex(); + + if ( this.roughness !== undefined ) data.roughness = this.roughness; + if ( this.metalness !== undefined ) data.metalness = this.metalness; + + if ( this.sheen !== undefined ) data.sheen = this.sheen; + if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex(); + if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness; + if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); + if ( this.emissiveIntensity !== undefined && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity; + + if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex(); + if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity; + if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex(); + if ( this.shininess !== undefined ) data.shininess = this.shininess; + if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat; + if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness; + + if ( this.clearcoatMap && this.clearcoatMap.isTexture ) { + + data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid; + + } + + if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) { + + data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid; + + } + + if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) { + + data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid; + data.clearcoatNormalScale = this.clearcoatNormalScale.toArray(); + + } + + if ( this.dispersion !== undefined ) data.dispersion = this.dispersion; + + if ( this.iridescence !== undefined ) data.iridescence = this.iridescence; + if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR; + if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange; + + if ( this.iridescenceMap && this.iridescenceMap.isTexture ) { + + data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid; + + } + + if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) { + + data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid; + + } + + if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy; + if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation; + + if ( this.anisotropyMap && this.anisotropyMap.isTexture ) { + + data.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid; + + } + + if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid; + if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid; + if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; + + if ( this.lightMap && this.lightMap.isTexture ) { + + data.lightMap = this.lightMap.toJSON( meta ).uuid; + data.lightMapIntensity = this.lightMapIntensity; + + } + + if ( this.aoMap && this.aoMap.isTexture ) { + + data.aoMap = this.aoMap.toJSON( meta ).uuid; + data.aoMapIntensity = this.aoMapIntensity; + + } + + if ( this.bumpMap && this.bumpMap.isTexture ) { + + data.bumpMap = this.bumpMap.toJSON( meta ).uuid; + data.bumpScale = this.bumpScale; + + } + + if ( this.normalMap && this.normalMap.isTexture ) { + + data.normalMap = this.normalMap.toJSON( meta ).uuid; + data.normalMapType = this.normalMapType; + data.normalScale = this.normalScale.toArray(); + + } + + if ( this.displacementMap && this.displacementMap.isTexture ) { + + data.displacementMap = this.displacementMap.toJSON( meta ).uuid; + data.displacementScale = this.displacementScale; + data.displacementBias = this.displacementBias; + + } + + if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid; + if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid; + + if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; + if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; + if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid; + if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid; + + if ( this.envMap && this.envMap.isTexture ) { + + data.envMap = this.envMap.toJSON( meta ).uuid; + + if ( this.combine !== undefined ) data.combine = this.combine; + + } + + if ( this.envMapRotation !== undefined ) data.envMapRotation = this.envMapRotation.toArray(); + if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity; + if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity; + if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio; + + if ( this.gradientMap && this.gradientMap.isTexture ) { + + data.gradientMap = this.gradientMap.toJSON( meta ).uuid; + + } + + if ( this.transmission !== undefined ) data.transmission = this.transmission; + if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid; + if ( this.thickness !== undefined ) data.thickness = this.thickness; + if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid; + if ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance; + if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex(); + + if ( this.size !== undefined ) data.size = this.size; + if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide; + if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; + + if ( this.blending !== NormalBlending ) data.blending = this.blending; + if ( this.side !== FrontSide ) data.side = this.side; + if ( this.vertexColors === true ) data.vertexColors = true; + + if ( this.opacity < 1 ) data.opacity = this.opacity; + if ( this.transparent === true ) data.transparent = true; + + if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc; + if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst; + if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation; + if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha; + if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha; + if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha; + if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex(); + if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha; + + if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc; + if ( this.depthTest === false ) data.depthTest = this.depthTest; + if ( this.depthWrite === false ) data.depthWrite = this.depthWrite; + if ( this.colorWrite === false ) data.colorWrite = this.colorWrite; + + if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask; + if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc; + if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef; + if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask; + if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail; + if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail; + if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass; + if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite; + + // rotation (SpriteMaterial) + if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation; + + if ( this.polygonOffset === true ) data.polygonOffset = true; + if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor; + if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits; + + if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth; + if ( this.dashSize !== undefined ) data.dashSize = this.dashSize; + if ( this.gapSize !== undefined ) data.gapSize = this.gapSize; + if ( this.scale !== undefined ) data.scale = this.scale; + + if ( this.dithering === true ) data.dithering = true; + + if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; + if ( this.alphaHash === true ) data.alphaHash = true; + if ( this.alphaToCoverage === true ) data.alphaToCoverage = true; + if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true; + if ( this.forceSinglePass === true ) data.forceSinglePass = true; + + if ( this.wireframe === true ) data.wireframe = true; + if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; + if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; + if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; + + if ( this.flatShading === true ) data.flatShading = true; + + if ( this.visible === false ) data.visible = false; + + if ( this.toneMapped === false ) data.toneMapped = false; + + if ( this.fog === false ) data.fog = false; + + if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; + + // TODO: Copied from Object3D.toJSON + + function extractFromCache( cache ) { + + const values = []; + + for ( const key in cache ) { + + const data = cache[ key ]; + delete data.metadata; + values.push( data ); + + } + + return values; + + } + + if ( isRootObject ) { + + const textures = extractFromCache( meta.textures ); + const images = extractFromCache( meta.images ); + + if ( textures.length > 0 ) data.textures = textures; + if ( images.length > 0 ) data.images = images; + + } + + return data; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + copy( source ) { + + this.name = source.name; + + this.blending = source.blending; + this.side = source.side; + this.vertexColors = source.vertexColors; + + this.opacity = source.opacity; + this.transparent = source.transparent; + + this.blendSrc = source.blendSrc; + this.blendDst = source.blendDst; + this.blendEquation = source.blendEquation; + this.blendSrcAlpha = source.blendSrcAlpha; + this.blendDstAlpha = source.blendDstAlpha; + this.blendEquationAlpha = source.blendEquationAlpha; + this.blendColor.copy( source.blendColor ); + this.blendAlpha = source.blendAlpha; + + this.depthFunc = source.depthFunc; + this.depthTest = source.depthTest; + this.depthWrite = source.depthWrite; + + this.stencilWriteMask = source.stencilWriteMask; + this.stencilFunc = source.stencilFunc; + this.stencilRef = source.stencilRef; + this.stencilFuncMask = source.stencilFuncMask; + this.stencilFail = source.stencilFail; + this.stencilZFail = source.stencilZFail; + this.stencilZPass = source.stencilZPass; + this.stencilWrite = source.stencilWrite; + + const srcPlanes = source.clippingPlanes; + let dstPlanes = null; + + if ( srcPlanes !== null ) { + + const n = srcPlanes.length; + dstPlanes = new Array( n ); + + for ( let i = 0; i !== n; ++ i ) { + + dstPlanes[ i ] = srcPlanes[ i ].clone(); + + } + + } + + this.clippingPlanes = dstPlanes; + this.clipIntersection = source.clipIntersection; + this.clipShadows = source.clipShadows; + + this.shadowSide = source.shadowSide; + + this.colorWrite = source.colorWrite; + + this.precision = source.precision; + + this.polygonOffset = source.polygonOffset; + this.polygonOffsetFactor = source.polygonOffsetFactor; + this.polygonOffsetUnits = source.polygonOffsetUnits; + + this.dithering = source.dithering; + + this.alphaTest = source.alphaTest; + this.alphaHash = source.alphaHash; + this.alphaToCoverage = source.alphaToCoverage; + this.premultipliedAlpha = source.premultipliedAlpha; + this.forceSinglePass = source.forceSinglePass; + + this.visible = source.visible; + + this.toneMapped = source.toneMapped; + + this.userData = JSON.parse( JSON.stringify( source.userData ) ); + + return this; + + } + + dispose() { + + this.dispatchEvent( { type: 'dispose' } ); + + } + + set needsUpdate( value ) { + + if ( value === true ) this.version ++; + + } + + onBuild( /* shaderobject, renderer */ ) { + + console.warn( 'Material: onBuild() has been removed.' ); // @deprecated, r166 + + } + +} + +class MeshBasicMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isMeshBasicMaterial = true; + + this.type = 'MeshBasicMaterial'; + + this.color = new Color( 0xffffff ); // emissive + + this.map = null; + + this.lightMap = null; + this.lightMapIntensity = 1.0; + + this.aoMap = null; + this.aoMapIntensity = 1.0; + + this.specularMap = null; + + this.alphaMap = null; + + this.envMap = null; + this.envMapRotation = new Euler(); + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.fog = true; + + this.setValues( parameters ); + + } + + copy( source ) { + + super.copy( source ); + + this.color.copy( source.color ); + + this.map = source.map; + + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; + + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; + + this.specularMap = source.specularMap; + + this.alphaMap = source.alphaMap; + + this.envMap = source.envMap; + this.envMapRotation.copy( source.envMapRotation ); + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; + + this.fog = source.fog; + + return this; + + } + +} + +// Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf + +const _tables = /*@__PURE__*/ _generateTables(); + +function _generateTables() { + + // float32 to float16 helpers + + const buffer = new ArrayBuffer( 4 ); + const floatView = new Float32Array( buffer ); + const uint32View = new Uint32Array( buffer ); + + const baseTable = new Uint32Array( 512 ); + const shiftTable = new Uint32Array( 512 ); + + for ( let i = 0; i < 256; ++ i ) { + + const e = i - 127; + + // very small number (0, -0) + + if ( e < - 27 ) { + + baseTable[ i ] = 0x0000; + baseTable[ i | 0x100 ] = 0x8000; + shiftTable[ i ] = 24; + shiftTable[ i | 0x100 ] = 24; + + // small number (denorm) + + } else if ( e < - 14 ) { + + baseTable[ i ] = 0x0400 >> ( - e - 14 ); + baseTable[ i | 0x100 ] = ( 0x0400 >> ( - e - 14 ) ) | 0x8000; + shiftTable[ i ] = - e - 1; + shiftTable[ i | 0x100 ] = - e - 1; + + // normal number + + } else if ( e <= 15 ) { + + baseTable[ i ] = ( e + 15 ) << 10; + baseTable[ i | 0x100 ] = ( ( e + 15 ) << 10 ) | 0x8000; + shiftTable[ i ] = 13; + shiftTable[ i | 0x100 ] = 13; + + // large number (Infinity, -Infinity) + + } else if ( e < 128 ) { + + baseTable[ i ] = 0x7c00; + baseTable[ i | 0x100 ] = 0xfc00; + shiftTable[ i ] = 24; + shiftTable[ i | 0x100 ] = 24; + + // stay (NaN, Infinity, -Infinity) + + } else { + + baseTable[ i ] = 0x7c00; + baseTable[ i | 0x100 ] = 0xfc00; + shiftTable[ i ] = 13; + shiftTable[ i | 0x100 ] = 13; + + } + + } + + // float16 to float32 helpers + + const mantissaTable = new Uint32Array( 2048 ); + const exponentTable = new Uint32Array( 64 ); + const offsetTable = new Uint32Array( 64 ); + + for ( let i = 1; i < 1024; ++ i ) { + + let m = i << 13; // zero pad mantissa bits + let e = 0; // zero exponent + + // normalized + while ( ( m & 0x00800000 ) === 0 ) { + + m <<= 1; + e -= 0x00800000; // decrement exponent + + } + + m &= ~ 0x00800000; // clear leading 1 bit + e += 0x38800000; // adjust bias + + mantissaTable[ i ] = m | e; + + } + + for ( let i = 1024; i < 2048; ++ i ) { + + mantissaTable[ i ] = 0x38000000 + ( ( i - 1024 ) << 13 ); + + } + + for ( let i = 1; i < 31; ++ i ) { + + exponentTable[ i ] = i << 23; + + } + + exponentTable[ 31 ] = 0x47800000; + exponentTable[ 32 ] = 0x80000000; + + for ( let i = 33; i < 63; ++ i ) { + + exponentTable[ i ] = 0x80000000 + ( ( i - 32 ) << 23 ); + + } + + exponentTable[ 63 ] = 0xc7800000; + + for ( let i = 1; i < 64; ++ i ) { + + if ( i !== 32 ) { + + offsetTable[ i ] = 1024; + + } + + } + + return { + floatView: floatView, + uint32View: uint32View, + baseTable: baseTable, + shiftTable: shiftTable, + mantissaTable: mantissaTable, + exponentTable: exponentTable, + offsetTable: offsetTable + }; + +} + +// float32 to float16 + +function toHalfFloat( val ) { + + if ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' ); + + val = clamp$1( val, - 65504, 65504 ); + + _tables.floatView[ 0 ] = val; + const f = _tables.uint32View[ 0 ]; + const e = ( f >> 23 ) & 0x1ff; + return _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] ); + +} + +// float16 to float32 + +function fromHalfFloat( val ) { + + const m = val >> 10; + _tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ]; + return _tables.floatView[ 0 ]; + +} + +const DataUtils = { + toHalfFloat: toHalfFloat, + fromHalfFloat: fromHalfFloat, +}; + +const _vector$9 = /*@__PURE__*/ new Vector3(); +const _vector2$1 = /*@__PURE__*/ new Vector2(); + +class BufferAttribute { + + constructor( array, itemSize, normalized = false ) { + + if ( Array.isArray( array ) ) { + + throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); + + } + + this.isBufferAttribute = true; + + this.name = ''; + + this.array = array; + this.itemSize = itemSize; + this.count = array !== undefined ? array.length / itemSize : 0; + this.normalized = normalized; + + this.usage = StaticDrawUsage; + this.updateRanges = []; + this.gpuType = FloatType; + + this.version = 0; + + } + + onUploadCallback() {} + + set needsUpdate( value ) { + + if ( value === true ) this.version ++; + + } + + setUsage( value ) { + + this.usage = value; + + return this; + + } + + addUpdateRange( start, count ) { + + this.updateRanges.push( { start, count } ); + + } + + clearUpdateRanges() { + + this.updateRanges.length = 0; + + } + + copy( source ) { + + this.name = source.name; + this.array = new source.array.constructor( source.array ); + this.itemSize = source.itemSize; + this.count = source.count; + this.normalized = source.normalized; + + this.usage = source.usage; + this.gpuType = source.gpuType; + + return this; + + } + + copyAt( index1, attribute, index2 ) { + + index1 *= this.itemSize; + index2 *= attribute.itemSize; + + for ( let i = 0, l = this.itemSize; i < l; i ++ ) { + + this.array[ index1 + i ] = attribute.array[ index2 + i ]; + + } + + return this; + + } + + copyArray( array ) { + + this.array.set( array ); + + return this; + + } + + applyMatrix3( m ) { + + if ( this.itemSize === 2 ) { + + for ( let i = 0, l = this.count; i < l; i ++ ) { + + _vector2$1.fromBufferAttribute( this, i ); + _vector2$1.applyMatrix3( m ); + + this.setXY( i, _vector2$1.x, _vector2$1.y ); + + } + + } else if ( this.itemSize === 3 ) { + + for ( let i = 0, l = this.count; i < l; i ++ ) { + + _vector$9.fromBufferAttribute( this, i ); + _vector$9.applyMatrix3( m ); + + this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); + + } + + } + + return this; + + } + + applyMatrix4( m ) { + + for ( let i = 0, l = this.count; i < l; i ++ ) { + + _vector$9.fromBufferAttribute( this, i ); + + _vector$9.applyMatrix4( m ); + + this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); + + } + + return this; + + } + + applyNormalMatrix( m ) { + + for ( let i = 0, l = this.count; i < l; i ++ ) { + + _vector$9.fromBufferAttribute( this, i ); + + _vector$9.applyNormalMatrix( m ); + + this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); + + } + + return this; + + } + + transformDirection( m ) { + + for ( let i = 0, l = this.count; i < l; i ++ ) { + + _vector$9.fromBufferAttribute( this, i ); + + _vector$9.transformDirection( m ); + + this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); + + } + + return this; + + } + + set( value, offset = 0 ) { + + // Matching BufferAttribute constructor, do not normalize the array. + this.array.set( value, offset ); + + return this; + + } + + getComponent( index, component ) { + + let value = this.array[ index * this.itemSize + component ]; + + if ( this.normalized ) value = denormalize( value, this.array ); + + return value; + + } + + setComponent( index, component, value ) { + + if ( this.normalized ) value = normalize$1( value, this.array ); + + this.array[ index * this.itemSize + component ] = value; + + return this; + + } + + getX( index ) { + + let x = this.array[ index * this.itemSize ]; + + if ( this.normalized ) x = denormalize( x, this.array ); + + return x; + + } + + setX( index, x ) { + + if ( this.normalized ) x = normalize$1( x, this.array ); + + this.array[ index * this.itemSize ] = x; + + return this; + + } + + getY( index ) { + + let y = this.array[ index * this.itemSize + 1 ]; + + if ( this.normalized ) y = denormalize( y, this.array ); + + return y; + + } + + setY( index, y ) { + + if ( this.normalized ) y = normalize$1( y, this.array ); + + this.array[ index * this.itemSize + 1 ] = y; + + return this; + + } + + getZ( index ) { + + let z = this.array[ index * this.itemSize + 2 ]; + + if ( this.normalized ) z = denormalize( z, this.array ); + + return z; + + } + + setZ( index, z ) { + + if ( this.normalized ) z = normalize$1( z, this.array ); + + this.array[ index * this.itemSize + 2 ] = z; + + return this; + + } + + getW( index ) { + + let w = this.array[ index * this.itemSize + 3 ]; + + if ( this.normalized ) w = denormalize( w, this.array ); + + return w; + + } + + setW( index, w ) { + + if ( this.normalized ) w = normalize$1( w, this.array ); + + this.array[ index * this.itemSize + 3 ] = w; + + return this; + + } + + setXY( index, x, y ) { + + index *= this.itemSize; + + if ( this.normalized ) { + + x = normalize$1( x, this.array ); + y = normalize$1( y, this.array ); + + } + + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + + return this; + + } + + setXYZ( index, x, y, z ) { + + index *= this.itemSize; + + if ( this.normalized ) { + + x = normalize$1( x, this.array ); + y = normalize$1( y, this.array ); + z = normalize$1( z, this.array ); + + } + + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; + + return this; + + } + + setXYZW( index, x, y, z, w ) { + + index *= this.itemSize; + + if ( this.normalized ) { + + x = normalize$1( x, this.array ); + y = normalize$1( y, this.array ); + z = normalize$1( z, this.array ); + w = normalize$1( w, this.array ); + + } + + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; + this.array[ index + 3 ] = w; + + return this; + + } + + onUpload( callback ) { + + this.onUploadCallback = callback; + + return this; + + } + + clone() { + + return new this.constructor( this.array, this.itemSize ).copy( this ); + + } + + toJSON() { + + const data = { + itemSize: this.itemSize, + type: this.array.constructor.name, + array: Array.from( this.array ), + normalized: this.normalized + }; + + if ( this.name !== '' ) data.name = this.name; + if ( this.usage !== StaticDrawUsage ) data.usage = this.usage; + + return data; + + } + +} + +// + +class Int8BufferAttribute extends BufferAttribute { + + constructor( array, itemSize, normalized ) { + + super( new Int8Array( array ), itemSize, normalized ); + + } + +} + +class Uint8BufferAttribute extends BufferAttribute { + + constructor( array, itemSize, normalized ) { + + super( new Uint8Array( array ), itemSize, normalized ); + + } + +} + +class Uint8ClampedBufferAttribute extends BufferAttribute { + + constructor( array, itemSize, normalized ) { + + super( new Uint8ClampedArray( array ), itemSize, normalized ); + + } + +} + +class Int16BufferAttribute extends BufferAttribute { + + constructor( array, itemSize, normalized ) { + + super( new Int16Array( array ), itemSize, normalized ); + + } + +} + +class Uint16BufferAttribute extends BufferAttribute { + + constructor( array, itemSize, normalized ) { + + super( new Uint16Array( array ), itemSize, normalized ); + + } + +} + +class Int32BufferAttribute extends BufferAttribute { + + constructor( array, itemSize, normalized ) { + + super( new Int32Array( array ), itemSize, normalized ); + + } + +} + +class Uint32BufferAttribute extends BufferAttribute { + + constructor( array, itemSize, normalized ) { + + super( new Uint32Array( array ), itemSize, normalized ); + + } + +} + +class Float16BufferAttribute extends BufferAttribute { + + constructor( array, itemSize, normalized ) { + + super( new Uint16Array( array ), itemSize, normalized ); + + this.isFloat16BufferAttribute = true; + + } + + getX( index ) { + + let x = fromHalfFloat( this.array[ index * this.itemSize ] ); + + if ( this.normalized ) x = denormalize( x, this.array ); + + return x; + + } + + setX( index, x ) { + + if ( this.normalized ) x = normalize$1( x, this.array ); + + this.array[ index * this.itemSize ] = toHalfFloat( x ); + + return this; + + } + + getY( index ) { + + let y = fromHalfFloat( this.array[ index * this.itemSize + 1 ] ); + + if ( this.normalized ) y = denormalize( y, this.array ); + + return y; + + } + + setY( index, y ) { + + if ( this.normalized ) y = normalize$1( y, this.array ); + + this.array[ index * this.itemSize + 1 ] = toHalfFloat( y ); + + return this; + + } + + getZ( index ) { + + let z = fromHalfFloat( this.array[ index * this.itemSize + 2 ] ); + + if ( this.normalized ) z = denormalize( z, this.array ); + + return z; + + } + + setZ( index, z ) { + + if ( this.normalized ) z = normalize$1( z, this.array ); + + this.array[ index * this.itemSize + 2 ] = toHalfFloat( z ); + + return this; + + } + + getW( index ) { + + let w = fromHalfFloat( this.array[ index * this.itemSize + 3 ] ); + + if ( this.normalized ) w = denormalize( w, this.array ); + + return w; + + } + + setW( index, w ) { + + if ( this.normalized ) w = normalize$1( w, this.array ); + + this.array[ index * this.itemSize + 3 ] = toHalfFloat( w ); + + return this; + + } + + setXY( index, x, y ) { + + index *= this.itemSize; + + if ( this.normalized ) { + + x = normalize$1( x, this.array ); + y = normalize$1( y, this.array ); + + } + + this.array[ index + 0 ] = toHalfFloat( x ); + this.array[ index + 1 ] = toHalfFloat( y ); + + return this; + + } + + setXYZ( index, x, y, z ) { + + index *= this.itemSize; + + if ( this.normalized ) { + + x = normalize$1( x, this.array ); + y = normalize$1( y, this.array ); + z = normalize$1( z, this.array ); + + } + + this.array[ index + 0 ] = toHalfFloat( x ); + this.array[ index + 1 ] = toHalfFloat( y ); + this.array[ index + 2 ] = toHalfFloat( z ); + + return this; + + } + + setXYZW( index, x, y, z, w ) { + + index *= this.itemSize; + + if ( this.normalized ) { + + x = normalize$1( x, this.array ); + y = normalize$1( y, this.array ); + z = normalize$1( z, this.array ); + w = normalize$1( w, this.array ); + + } + + this.array[ index + 0 ] = toHalfFloat( x ); + this.array[ index + 1 ] = toHalfFloat( y ); + this.array[ index + 2 ] = toHalfFloat( z ); + this.array[ index + 3 ] = toHalfFloat( w ); + + return this; + + } + +} + + +class Float32BufferAttribute extends BufferAttribute { + + constructor( array, itemSize, normalized ) { + + super( new Float32Array( array ), itemSize, normalized ); + + } + +} + +let _id$9 = 0; + +const _m1 = /*@__PURE__*/ new Matrix4(); +const _obj = /*@__PURE__*/ new Object3D(); +const _offset = /*@__PURE__*/ new Vector3(); +const _box$2 = /*@__PURE__*/ new Box3(); +const _boxMorphTargets = /*@__PURE__*/ new Box3(); +const _vector$8 = /*@__PURE__*/ new Vector3(); + +class BufferGeometry extends EventDispatcher { + + constructor() { + + super(); + + this.isBufferGeometry = true; + + Object.defineProperty( this, 'id', { value: _id$9 ++ } ); + + this.uuid = generateUUID(); + + this.name = ''; + this.type = 'BufferGeometry'; + + this.index = null; + this.attributes = {}; + + this.morphAttributes = {}; + this.morphTargetsRelative = false; + + this.groups = []; + + this.boundingBox = null; + this.boundingSphere = null; + + this.drawRange = { start: 0, count: Infinity }; + + this.userData = {}; + + } + + getIndex() { + + return this.index; + + } + + setIndex( index ) { + + if ( Array.isArray( index ) ) { + + this.index = new ( arrayNeedsUint32$1( index ) ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); + + } else { + + this.index = index; + + } + + return this; + + } + + getAttribute( name ) { + + return this.attributes[ name ]; + + } + + setAttribute( name, attribute ) { + + this.attributes[ name ] = attribute; + + return this; + + } + + deleteAttribute( name ) { + + delete this.attributes[ name ]; + + return this; + + } + + hasAttribute( name ) { + + return this.attributes[ name ] !== undefined; + + } + + addGroup( start, count, materialIndex = 0 ) { + + this.groups.push( { + + start: start, + count: count, + materialIndex: materialIndex + + } ); + + } + + clearGroups() { + + this.groups = []; + + } + + setDrawRange( start, count ) { + + this.drawRange.start = start; + this.drawRange.count = count; + + } + + applyMatrix4( matrix ) { + + const position = this.attributes.position; + + if ( position !== undefined ) { + + position.applyMatrix4( matrix ); + + position.needsUpdate = true; + + } + + const normal = this.attributes.normal; + + if ( normal !== undefined ) { + + const normalMatrix = new Matrix3().getNormalMatrix( matrix ); + + normal.applyNormalMatrix( normalMatrix ); + + normal.needsUpdate = true; + + } + + const tangent = this.attributes.tangent; + + if ( tangent !== undefined ) { + + tangent.transformDirection( matrix ); + + tangent.needsUpdate = true; + + } + + if ( this.boundingBox !== null ) { + + this.computeBoundingBox(); + + } + + if ( this.boundingSphere !== null ) { + + this.computeBoundingSphere(); + + } + + return this; + + } + + applyQuaternion( q ) { + + _m1.makeRotationFromQuaternion( q ); + + this.applyMatrix4( _m1 ); + + return this; + + } + + rotateX( angle ) { + + // rotate geometry around world x-axis + + _m1.makeRotationX( angle ); + + this.applyMatrix4( _m1 ); + + return this; + + } + + rotateY( angle ) { + + // rotate geometry around world y-axis + + _m1.makeRotationY( angle ); + + this.applyMatrix4( _m1 ); + + return this; + + } + + rotateZ( angle ) { + + // rotate geometry around world z-axis + + _m1.makeRotationZ( angle ); + + this.applyMatrix4( _m1 ); + + return this; + + } + + translate( x, y, z ) { + + // translate geometry + + _m1.makeTranslation( x, y, z ); + + this.applyMatrix4( _m1 ); + + return this; + + } + + scale( x, y, z ) { + + // scale geometry + + _m1.makeScale( x, y, z ); + + this.applyMatrix4( _m1 ); + + return this; + + } + + lookAt( vector ) { + + _obj.lookAt( vector ); + + _obj.updateMatrix(); + + this.applyMatrix4( _obj.matrix ); + + return this; + + } + + center() { + + this.computeBoundingBox(); + + this.boundingBox.getCenter( _offset ).negate(); + + this.translate( _offset.x, _offset.y, _offset.z ); + + return this; + + } + + setFromPoints( points ) { + + const position = []; + + for ( let i = 0, l = points.length; i < l; i ++ ) { + + const point = points[ i ]; + position.push( point.x, point.y, point.z || 0 ); + + } + + this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) ); + + return this; + + } + + computeBoundingBox() { + + if ( this.boundingBox === null ) { + + this.boundingBox = new Box3(); + + } + + const position = this.attributes.position; + const morphAttributesPosition = this.morphAttributes.position; + + if ( position && position.isGLBufferAttribute ) { + + console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.', this ); + + this.boundingBox.set( + new Vector3( - Infinity, - Infinity, - Infinity ), + new Vector3( + Infinity, + Infinity, + Infinity ) + ); + + return; + + } + + if ( position !== undefined ) { + + this.boundingBox.setFromBufferAttribute( position ); + + // process morph attributes if present + + if ( morphAttributesPosition ) { + + for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { + + const morphAttribute = morphAttributesPosition[ i ]; + _box$2.setFromBufferAttribute( morphAttribute ); + + if ( this.morphTargetsRelative ) { + + _vector$8.addVectors( this.boundingBox.min, _box$2.min ); + this.boundingBox.expandByPoint( _vector$8 ); + + _vector$8.addVectors( this.boundingBox.max, _box$2.max ); + this.boundingBox.expandByPoint( _vector$8 ); + + } else { + + this.boundingBox.expandByPoint( _box$2.min ); + this.boundingBox.expandByPoint( _box$2.max ); + + } + + } + + } + + } else { + + this.boundingBox.makeEmpty(); + + } + + if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { + + console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); + + } + + } + + computeBoundingSphere() { + + if ( this.boundingSphere === null ) { + + this.boundingSphere = new Sphere(); + + } + + const position = this.attributes.position; + const morphAttributesPosition = this.morphAttributes.position; + + if ( position && position.isGLBufferAttribute ) { + + console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere.', this ); + + this.boundingSphere.set( new Vector3(), Infinity ); + + return; + + } + + if ( position ) { + + // first, find the center of the bounding sphere + + const center = this.boundingSphere.center; + + _box$2.setFromBufferAttribute( position ); + + // process morph attributes if present + + if ( morphAttributesPosition ) { + + for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { + + const morphAttribute = morphAttributesPosition[ i ]; + _boxMorphTargets.setFromBufferAttribute( morphAttribute ); + + if ( this.morphTargetsRelative ) { + + _vector$8.addVectors( _box$2.min, _boxMorphTargets.min ); + _box$2.expandByPoint( _vector$8 ); + + _vector$8.addVectors( _box$2.max, _boxMorphTargets.max ); + _box$2.expandByPoint( _vector$8 ); + + } else { + + _box$2.expandByPoint( _boxMorphTargets.min ); + _box$2.expandByPoint( _boxMorphTargets.max ); + + } + + } + + } + + _box$2.getCenter( center ); + + // second, try to find a boundingSphere with a radius smaller than the + // boundingSphere of the boundingBox: sqrt(3) smaller in the best case + + let maxRadiusSq = 0; + + for ( let i = 0, il = position.count; i < il; i ++ ) { + + _vector$8.fromBufferAttribute( position, i ); + + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); + + } + + // process morph attributes if present + + if ( morphAttributesPosition ) { + + for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { + + const morphAttribute = morphAttributesPosition[ i ]; + const morphTargetsRelative = this.morphTargetsRelative; + + for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) { + + _vector$8.fromBufferAttribute( morphAttribute, j ); + + if ( morphTargetsRelative ) { + + _offset.fromBufferAttribute( position, j ); + _vector$8.add( _offset ); + + } + + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); + + } + + } + + } + + this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); + + if ( isNaN( this.boundingSphere.radius ) ) { + + console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); + + } + + } + + } + + computeTangents() { + + const index = this.index; + const attributes = this.attributes; + + // based on http://www.terathon.com/code/tangent.html + // (per vertex tangents) + + if ( index === null || + attributes.position === undefined || + attributes.normal === undefined || + attributes.uv === undefined ) { + + console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' ); + return; + + } + + const positionAttribute = attributes.position; + const normalAttribute = attributes.normal; + const uvAttribute = attributes.uv; + + if ( this.hasAttribute( 'tangent' ) === false ) { + + this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * positionAttribute.count ), 4 ) ); + + } + + const tangentAttribute = this.getAttribute( 'tangent' ); + + const tan1 = [], tan2 = []; + + for ( let i = 0; i < positionAttribute.count; i ++ ) { + + tan1[ i ] = new Vector3(); + tan2[ i ] = new Vector3(); + + } + + const vA = new Vector3(), + vB = new Vector3(), + vC = new Vector3(), + + uvA = new Vector2(), + uvB = new Vector2(), + uvC = new Vector2(), + + sdir = new Vector3(), + tdir = new Vector3(); + + function handleTriangle( a, b, c ) { + + vA.fromBufferAttribute( positionAttribute, a ); + vB.fromBufferAttribute( positionAttribute, b ); + vC.fromBufferAttribute( positionAttribute, c ); + + uvA.fromBufferAttribute( uvAttribute, a ); + uvB.fromBufferAttribute( uvAttribute, b ); + uvC.fromBufferAttribute( uvAttribute, c ); + + vB.sub( vA ); + vC.sub( vA ); + + uvB.sub( uvA ); + uvC.sub( uvA ); + + const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y ); + + // silently ignore degenerate uv triangles having coincident or colinear vertices + + if ( ! isFinite( r ) ) return; + + sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r ); + tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r ); + + tan1[ a ].add( sdir ); + tan1[ b ].add( sdir ); + tan1[ c ].add( sdir ); + + tan2[ a ].add( tdir ); + tan2[ b ].add( tdir ); + tan2[ c ].add( tdir ); + + } + + let groups = this.groups; + + if ( groups.length === 0 ) { + + groups = [ { + start: 0, + count: index.count + } ]; + + } + + for ( let i = 0, il = groups.length; i < il; ++ i ) { + + const group = groups[ i ]; + + const start = group.start; + const count = group.count; + + for ( let j = start, jl = start + count; j < jl; j += 3 ) { + + handleTriangle( + index.getX( j + 0 ), + index.getX( j + 1 ), + index.getX( j + 2 ) + ); + + } + + } + + const tmp = new Vector3(), tmp2 = new Vector3(); + const n = new Vector3(), n2 = new Vector3(); + + function handleVertex( v ) { + + n.fromBufferAttribute( normalAttribute, v ); + n2.copy( n ); + + const t = tan1[ v ]; + + // Gram-Schmidt orthogonalize + + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + + // Calculate handedness + + tmp2.crossVectors( n2, t ); + const test = tmp2.dot( tan2[ v ] ); + const w = ( test < 0.0 ) ? - 1.0 : 1.0; + + tangentAttribute.setXYZW( v, tmp.x, tmp.y, tmp.z, w ); + + } + + for ( let i = 0, il = groups.length; i < il; ++ i ) { + + const group = groups[ i ]; + + const start = group.start; + const count = group.count; + + for ( let j = start, jl = start + count; j < jl; j += 3 ) { + + handleVertex( index.getX( j + 0 ) ); + handleVertex( index.getX( j + 1 ) ); + handleVertex( index.getX( j + 2 ) ); + + } + + } + + } + + computeVertexNormals() { + + const index = this.index; + const positionAttribute = this.getAttribute( 'position' ); + + if ( positionAttribute !== undefined ) { + + let normalAttribute = this.getAttribute( 'normal' ); + + if ( normalAttribute === undefined ) { + + normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 ); + this.setAttribute( 'normal', normalAttribute ); + + } else { + + // reset existing normals to zero + + for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) { + + normalAttribute.setXYZ( i, 0, 0, 0 ); + + } + + } + + const pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); + const nA = new Vector3(), nB = new Vector3(), nC = new Vector3(); + const cb = new Vector3(), ab = new Vector3(); + + // indexed elements + + if ( index ) { + + for ( let i = 0, il = index.count; i < il; i += 3 ) { + + const vA = index.getX( i + 0 ); + const vB = index.getX( i + 1 ); + const vC = index.getX( i + 2 ); + + pA.fromBufferAttribute( positionAttribute, vA ); + pB.fromBufferAttribute( positionAttribute, vB ); + pC.fromBufferAttribute( positionAttribute, vC ); + + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); + + nA.fromBufferAttribute( normalAttribute, vA ); + nB.fromBufferAttribute( normalAttribute, vB ); + nC.fromBufferAttribute( normalAttribute, vC ); + + nA.add( cb ); + nB.add( cb ); + nC.add( cb ); + + normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z ); + normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z ); + normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z ); + + } + + } else { + + // non-indexed elements (unconnected triangle soup) + + for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) { + + pA.fromBufferAttribute( positionAttribute, i + 0 ); + pB.fromBufferAttribute( positionAttribute, i + 1 ); + pC.fromBufferAttribute( positionAttribute, i + 2 ); + + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); + + normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z ); + normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z ); + normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z ); + + } + + } + + this.normalizeNormals(); + + normalAttribute.needsUpdate = true; + + } + + } + + normalizeNormals() { + + const normals = this.attributes.normal; + + for ( let i = 0, il = normals.count; i < il; i ++ ) { + + _vector$8.fromBufferAttribute( normals, i ); + + _vector$8.normalize(); + + normals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z ); + + } + + } + + toNonIndexed() { + + function convertBufferAttribute( attribute, indices ) { + + const array = attribute.array; + const itemSize = attribute.itemSize; + const normalized = attribute.normalized; + + const array2 = new array.constructor( indices.length * itemSize ); + + let index = 0, index2 = 0; + + for ( let i = 0, l = indices.length; i < l; i ++ ) { + + if ( attribute.isInterleavedBufferAttribute ) { + + index = indices[ i ] * attribute.data.stride + attribute.offset; + + } else { + + index = indices[ i ] * itemSize; + + } + + for ( let j = 0; j < itemSize; j ++ ) { + + array2[ index2 ++ ] = array[ index ++ ]; + + } + + } + + return new BufferAttribute( array2, itemSize, normalized ); + + } + + // + + if ( this.index === null ) { + + console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' ); + return this; + + } + + const geometry2 = new BufferGeometry(); + + const indices = this.index.array; + const attributes = this.attributes; + + // attributes + + for ( const name in attributes ) { + + const attribute = attributes[ name ]; + + const newAttribute = convertBufferAttribute( attribute, indices ); + + geometry2.setAttribute( name, newAttribute ); + + } + + // morph attributes + + const morphAttributes = this.morphAttributes; + + for ( const name in morphAttributes ) { + + const morphArray = []; + const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes + + for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) { + + const attribute = morphAttribute[ i ]; + + const newAttribute = convertBufferAttribute( attribute, indices ); + + morphArray.push( newAttribute ); + + } + + geometry2.morphAttributes[ name ] = morphArray; + + } + + geometry2.morphTargetsRelative = this.morphTargetsRelative; + + // groups + + const groups = this.groups; + + for ( let i = 0, l = groups.length; i < l; i ++ ) { + + const group = groups[ i ]; + geometry2.addGroup( group.start, group.count, group.materialIndex ); + + } + + return geometry2; + + } + + toJSON() { + + const data = { + metadata: { + version: 4.6, + type: 'BufferGeometry', + generator: 'BufferGeometry.toJSON' + } + }; + + // standard BufferGeometry serialization + + data.uuid = this.uuid; + data.type = this.type; + if ( this.name !== '' ) data.name = this.name; + if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; + + if ( this.parameters !== undefined ) { + + const parameters = this.parameters; + + for ( const key in parameters ) { + + if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; + + } + + return data; + + } + + // for simplicity the code assumes attributes are not shared across geometries, see #15811 + + data.data = { attributes: {} }; + + const index = this.index; + + if ( index !== null ) { + + data.data.index = { + type: index.array.constructor.name, + array: Array.prototype.slice.call( index.array ) + }; + + } + + const attributes = this.attributes; + + for ( const key in attributes ) { + + const attribute = attributes[ key ]; + + data.data.attributes[ key ] = attribute.toJSON( data.data ); + + } + + const morphAttributes = {}; + let hasMorphAttributes = false; + + for ( const key in this.morphAttributes ) { + + const attributeArray = this.morphAttributes[ key ]; + + const array = []; + + for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { + + const attribute = attributeArray[ i ]; + + array.push( attribute.toJSON( data.data ) ); + + } + + if ( array.length > 0 ) { + + morphAttributes[ key ] = array; + + hasMorphAttributes = true; + + } + + } + + if ( hasMorphAttributes ) { + + data.data.morphAttributes = morphAttributes; + data.data.morphTargetsRelative = this.morphTargetsRelative; + + } + + const groups = this.groups; + + if ( groups.length > 0 ) { + + data.data.groups = JSON.parse( JSON.stringify( groups ) ); + + } + + const boundingSphere = this.boundingSphere; + + if ( boundingSphere !== null ) { + + data.data.boundingSphere = { + center: boundingSphere.center.toArray(), + radius: boundingSphere.radius + }; + + } + + return data; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + copy( source ) { + + // reset + + this.index = null; + this.attributes = {}; + this.morphAttributes = {}; + this.groups = []; + this.boundingBox = null; + this.boundingSphere = null; + + // used for storing cloned, shared data + + const data = {}; + + // name + + this.name = source.name; + + // index + + const index = source.index; + + if ( index !== null ) { + + this.setIndex( index.clone( data ) ); + + } + + // attributes + + const attributes = source.attributes; + + for ( const name in attributes ) { + + const attribute = attributes[ name ]; + this.setAttribute( name, attribute.clone( data ) ); + + } + + // morph attributes + + const morphAttributes = source.morphAttributes; + + for ( const name in morphAttributes ) { + + const array = []; + const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes + + for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) { + + array.push( morphAttribute[ i ].clone( data ) ); + + } + + this.morphAttributes[ name ] = array; + + } + + this.morphTargetsRelative = source.morphTargetsRelative; + + // groups + + const groups = source.groups; + + for ( let i = 0, l = groups.length; i < l; i ++ ) { + + const group = groups[ i ]; + this.addGroup( group.start, group.count, group.materialIndex ); + + } + + // bounding box + + const boundingBox = source.boundingBox; + + if ( boundingBox !== null ) { + + this.boundingBox = boundingBox.clone(); + + } + + // bounding sphere + + const boundingSphere = source.boundingSphere; + + if ( boundingSphere !== null ) { + + this.boundingSphere = boundingSphere.clone(); + + } + + // draw range + + this.drawRange.start = source.drawRange.start; + this.drawRange.count = source.drawRange.count; + + // user data + + this.userData = source.userData; + + return this; + + } + + dispose() { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +} + +const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4(); +const _ray$3 = /*@__PURE__*/ new Ray(); +const _sphere$6 = /*@__PURE__*/ new Sphere(); +const _sphereHitAt = /*@__PURE__*/ new Vector3(); + +const _vA$1 = /*@__PURE__*/ new Vector3(); +const _vB$1 = /*@__PURE__*/ new Vector3(); +const _vC$1 = /*@__PURE__*/ new Vector3(); + +const _tempA = /*@__PURE__*/ new Vector3(); +const _morphA = /*@__PURE__*/ new Vector3(); + +const _intersectionPoint = /*@__PURE__*/ new Vector3(); +const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); + +class Mesh extends Object3D { + + constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) { + + super(); + + this.isMesh = true; + + this.type = 'Mesh'; + + this.geometry = geometry; + this.material = material; + + this.updateMorphTargets(); + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + if ( source.morphTargetInfluences !== undefined ) { + + this.morphTargetInfluences = source.morphTargetInfluences.slice(); + + } + + if ( source.morphTargetDictionary !== undefined ) { + + this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); + + } + + this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; + this.geometry = source.geometry; + + return this; + + } + + updateMorphTargets() { + + const geometry = this.geometry; + + const morphAttributes = geometry.morphAttributes; + const keys = Object.keys( morphAttributes ); + + if ( keys.length > 0 ) { + + const morphAttribute = morphAttributes[ keys[ 0 ] ]; + + if ( morphAttribute !== undefined ) { + + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; + + for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { + + const name = morphAttribute[ m ].name || String( m ); + + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ name ] = m; + + } + + } + + } + + } + + getVertexPosition( index, target ) { + + const geometry = this.geometry; + const position = geometry.attributes.position; + const morphPosition = geometry.morphAttributes.position; + const morphTargetsRelative = geometry.morphTargetsRelative; + + target.fromBufferAttribute( position, index ); + + const morphInfluences = this.morphTargetInfluences; + + if ( morphPosition && morphInfluences ) { + + _morphA.set( 0, 0, 0 ); + + for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { + + const influence = morphInfluences[ i ]; + const morphAttribute = morphPosition[ i ]; + + if ( influence === 0 ) continue; + + _tempA.fromBufferAttribute( morphAttribute, index ); + + if ( morphTargetsRelative ) { + + _morphA.addScaledVector( _tempA, influence ); + + } else { + + _morphA.addScaledVector( _tempA.sub( target ), influence ); + + } + + } + + target.add( _morphA ); + + } + + return target; + + } + + raycast( raycaster, intersects ) { + + const geometry = this.geometry; + const material = this.material; + const matrixWorld = this.matrixWorld; + + if ( material === undefined ) return; + + // test with bounding sphere in world space + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + _sphere$6.copy( geometry.boundingSphere ); + _sphere$6.applyMatrix4( matrixWorld ); + + // check distance from ray origin to bounding sphere + + _ray$3.copy( raycaster.ray ).recast( raycaster.near ); + + if ( _sphere$6.containsPoint( _ray$3.origin ) === false ) { + + if ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return; + + if ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return; + + } + + // convert ray to local space of mesh + + _inverseMatrix$3.copy( matrixWorld ).invert(); + _ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 ); + + // test with bounding box in local space + + if ( geometry.boundingBox !== null ) { + + if ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return; + + } + + // test for intersections with geometry + + this._computeIntersections( raycaster, intersects, _ray$3 ); + + } + + _computeIntersections( raycaster, intersects, rayLocalSpace ) { + + let intersection; + + const geometry = this.geometry; + const material = this.material; + + const index = geometry.index; + const position = geometry.attributes.position; + const uv = geometry.attributes.uv; + const uv1 = geometry.attributes.uv1; + const normal = geometry.attributes.normal; + const groups = geometry.groups; + const drawRange = geometry.drawRange; + + if ( index !== null ) { + + // indexed buffer geometry + + if ( Array.isArray( material ) ) { + + for ( let i = 0, il = groups.length; i < il; i ++ ) { + + const group = groups[ i ]; + const groupMaterial = material[ group.materialIndex ]; + + const start = Math.max( group.start, drawRange.start ); + const end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); + + for ( let j = start, jl = end; j < jl; j += 3 ) { + + const a = index.getX( j ); + const b = index.getX( j + 1 ); + const c = index.getX( j + 2 ); + + intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); + + if ( intersection ) { + + intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics + intersection.face.materialIndex = group.materialIndex; + intersects.push( intersection ); + + } + + } + + } + + } else { + + const start = Math.max( 0, drawRange.start ); + const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); + + for ( let i = start, il = end; i < il; i += 3 ) { + + const a = index.getX( i ); + const b = index.getX( i + 1 ); + const c = index.getX( i + 2 ); + + intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); + + if ( intersection ) { + + intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics + intersects.push( intersection ); + + } + + } + + } + + } else if ( position !== undefined ) { + + // non-indexed buffer geometry + + if ( Array.isArray( material ) ) { + + for ( let i = 0, il = groups.length; i < il; i ++ ) { + + const group = groups[ i ]; + const groupMaterial = material[ group.materialIndex ]; + + const start = Math.max( group.start, drawRange.start ); + const end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); + + for ( let j = start, jl = end; j < jl; j += 3 ) { + + const a = j; + const b = j + 1; + const c = j + 2; + + intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); + + if ( intersection ) { + + intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics + intersection.face.materialIndex = group.materialIndex; + intersects.push( intersection ); + + } + + } + + } + + } else { + + const start = Math.max( 0, drawRange.start ); + const end = Math.min( position.count, ( drawRange.start + drawRange.count ) ); + + for ( let i = start, il = end; i < il; i += 3 ) { + + const a = i; + const b = i + 1; + const c = i + 2; + + intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); + + if ( intersection ) { + + intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics + intersects.push( intersection ); + + } + + } + + } + + } + + } + +} + +function checkIntersection$1( object, material, raycaster, ray, pA, pB, pC, point ) { + + let intersect; + + if ( material.side === BackSide ) { + + intersect = ray.intersectTriangle( pC, pB, pA, true, point ); + + } else { + + intersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point ); + + } + + if ( intersect === null ) return null; + + _intersectionPointWorld.copy( point ); + _intersectionPointWorld.applyMatrix4( object.matrixWorld ); + + const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld ); + + if ( distance < raycaster.near || distance > raycaster.far ) return null; + + return { + distance: distance, + point: _intersectionPointWorld.clone(), + object: object + }; + +} + +function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) { + + object.getVertexPosition( a, _vA$1 ); + object.getVertexPosition( b, _vB$1 ); + object.getVertexPosition( c, _vC$1 ); + + const intersection = checkIntersection$1( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint ); + + if ( intersection ) { + + const barycoord = new Vector3(); + Triangle.getBarycoord( _intersectionPoint, _vA$1, _vB$1, _vC$1, barycoord ); + + if ( uv ) { + + intersection.uv = Triangle.getInterpolatedAttribute( uv, a, b, c, barycoord, new Vector2() ); + + } + + if ( uv1 ) { + + intersection.uv1 = Triangle.getInterpolatedAttribute( uv1, a, b, c, barycoord, new Vector2() ); + + } + + if ( normal ) { + + intersection.normal = Triangle.getInterpolatedAttribute( normal, a, b, c, barycoord, new Vector3() ); + + if ( intersection.normal.dot( ray.direction ) > 0 ) { + + intersection.normal.multiplyScalar( - 1 ); + + } + + } + + const face = { + a: a, + b: b, + c: c, + normal: new Vector3(), + materialIndex: 0 + }; + + Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal ); + + intersection.face = face; + intersection.barycoord = barycoord; + + } + + return intersection; + +} + +class BoxGeometry extends BufferGeometry { + + constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) { + + super(); + + this.type = 'BoxGeometry'; + + this.parameters = { + width: width, + height: height, + depth: depth, + widthSegments: widthSegments, + heightSegments: heightSegments, + depthSegments: depthSegments + }; + + const scope = this; + + // segments + + widthSegments = Math.floor( widthSegments ); + heightSegments = Math.floor( heightSegments ); + depthSegments = Math.floor( depthSegments ); + + // buffers + + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; + + // helper variables + + let numberOfVertices = 0; + let groupStart = 0; + + // build each side of the box geometry + + buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px + buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx + buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py + buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny + buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz + buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz + + // build geometry + + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) { + + const segmentWidth = width / gridX; + const segmentHeight = height / gridY; + + const widthHalf = width / 2; + const heightHalf = height / 2; + const depthHalf = depth / 2; + + const gridX1 = gridX + 1; + const gridY1 = gridY + 1; + + let vertexCounter = 0; + let groupCount = 0; + + const vector = new Vector3(); + + // generate vertices, normals and uvs + + for ( let iy = 0; iy < gridY1; iy ++ ) { + + const y = iy * segmentHeight - heightHalf; + + for ( let ix = 0; ix < gridX1; ix ++ ) { + + const x = ix * segmentWidth - widthHalf; + + // set values to correct vector component + + vector[ u ] = x * udir; + vector[ v ] = y * vdir; + vector[ w ] = depthHalf; + + // now apply vector to vertex buffer + + vertices.push( vector.x, vector.y, vector.z ); + + // set values to correct vector component + + vector[ u ] = 0; + vector[ v ] = 0; + vector[ w ] = depth > 0 ? 1 : - 1; + + // now apply vector to normal buffer + + normals.push( vector.x, vector.y, vector.z ); + + // uvs + + uvs.push( ix / gridX ); + uvs.push( 1 - ( iy / gridY ) ); + + // counters + + vertexCounter += 1; + + } + + } + + // indices + + // 1. you need three indices to draw a single face + // 2. a single segment consists of two faces + // 3. so we need to generate six (2*3) indices per segment + + for ( let iy = 0; iy < gridY; iy ++ ) { + + for ( let ix = 0; ix < gridX; ix ++ ) { + + const a = numberOfVertices + ix + gridX1 * iy; + const b = numberOfVertices + ix + gridX1 * ( iy + 1 ); + const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 ); + const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + // increase counter + + groupCount += 6; + + } + + } + + // add a group to the geometry. this will ensure multi material support + + scope.addGroup( groupStart, groupCount, materialIndex ); + + // calculate new start value for groups + + groupStart += groupCount; + + // update total number of vertices + + numberOfVertices += vertexCounter; + + } + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + + static fromJSON( data ) { + + return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ); + + } + +} + +/** + * Uniform Utilities + */ + +function cloneUniforms( src ) { + + const dst = {}; + + for ( const u in src ) { + + dst[ u ] = {}; + + for ( const p in src[ u ] ) { + + const property = src[ u ][ p ]; + + if ( property && ( property.isColor || + property.isMatrix3 || property.isMatrix4 || + property.isVector2 || property.isVector3 || property.isVector4 || + property.isTexture || property.isQuaternion ) ) { + + if ( property.isRenderTargetTexture ) { + + console.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' ); + dst[ u ][ p ] = null; + + } else { + + dst[ u ][ p ] = property.clone(); + + } + + } else if ( Array.isArray( property ) ) { + + dst[ u ][ p ] = property.slice(); + + } else { + + dst[ u ][ p ] = property; + + } + + } + + } + + return dst; + +} + +function cloneUniformsGroups( src ) { + + const dst = []; + + for ( let u = 0; u < src.length; u ++ ) { + + dst.push( src[ u ].clone() ); + + } + + return dst; + +} + +var default_vertex = /* glsl */` +void main() { + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); +} +`; + +var default_fragment = /* glsl */` +void main() { + gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 ); +} +`; + +class ShaderMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isShaderMaterial = true; + + this.type = 'ShaderMaterial'; + + this.defines = {}; + this.uniforms = {}; + this.uniformsGroups = []; + + this.vertexShader = default_vertex; + this.fragmentShader = default_fragment; + + this.linewidth = 1; + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.fog = false; // set to use scene fog + this.lights = false; // set to use scene lights + this.clipping = false; // set to use user-defined clipping planes + + this.forceSinglePass = true; + + this.extensions = { + clipCullDistance: false, // set to use vertex shader clipping + multiDraw: false // set to use vertex shader multi_draw / enable gl_DrawID + }; + + // When rendered geometry doesn't include these attributes but the material does, + // use these default values in WebGL. This avoids errors when buffer data is missing. + this.defaultAttributeValues = { + 'color': [ 1, 1, 1 ], + 'uv': [ 0, 0 ], + 'uv1': [ 0, 0 ] + }; + + this.index0AttributeName = undefined; + this.uniformsNeedUpdate = false; + + this.glslVersion = null; + + if ( parameters !== undefined ) { + + this.setValues( parameters ); + + } + + } + + copy( source ) { + + super.copy( source ); + + this.fragmentShader = source.fragmentShader; + this.vertexShader = source.vertexShader; + + this.uniforms = cloneUniforms( source.uniforms ); + this.uniformsGroups = cloneUniformsGroups( source.uniformsGroups ); + + this.defines = Object.assign( {}, source.defines ); + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + + this.fog = source.fog; + this.lights = source.lights; + this.clipping = source.clipping; + + this.extensions = Object.assign( {}, source.extensions ); + + this.glslVersion = source.glslVersion; + + return this; + + } + + toJSON( meta ) { + + const data = super.toJSON( meta ); + + data.glslVersion = this.glslVersion; + data.uniforms = {}; + + for ( const name in this.uniforms ) { + + const uniform = this.uniforms[ name ]; + const value = uniform.value; + + if ( value && value.isTexture ) { + + data.uniforms[ name ] = { + type: 't', + value: value.toJSON( meta ).uuid + }; + + } else if ( value && value.isColor ) { + + data.uniforms[ name ] = { + type: 'c', + value: value.getHex() + }; + + } else if ( value && value.isVector2 ) { + + data.uniforms[ name ] = { + type: 'v2', + value: value.toArray() + }; + + } else if ( value && value.isVector3 ) { + + data.uniforms[ name ] = { + type: 'v3', + value: value.toArray() + }; + + } else if ( value && value.isVector4 ) { + + data.uniforms[ name ] = { + type: 'v4', + value: value.toArray() + }; + + } else if ( value && value.isMatrix3 ) { + + data.uniforms[ name ] = { + type: 'm3', + value: value.toArray() + }; + + } else if ( value && value.isMatrix4 ) { + + data.uniforms[ name ] = { + type: 'm4', + value: value.toArray() + }; + + } else { + + data.uniforms[ name ] = { + value: value + }; + + // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far + + } + + } + + if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines; + + data.vertexShader = this.vertexShader; + data.fragmentShader = this.fragmentShader; + + data.lights = this.lights; + data.clipping = this.clipping; + + const extensions = {}; + + for ( const key in this.extensions ) { + + if ( this.extensions[ key ] === true ) extensions[ key ] = true; + + } + + if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions; + + return data; + + } + +} + +class Camera extends Object3D { + + constructor() { + + super(); + + this.isCamera = true; + + this.type = 'Camera'; + + this.matrixWorldInverse = new Matrix4(); + + this.projectionMatrix = new Matrix4(); + this.projectionMatrixInverse = new Matrix4(); + + this.coordinateSystem = WebGLCoordinateSystem; + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.matrixWorldInverse.copy( source.matrixWorldInverse ); + + this.projectionMatrix.copy( source.projectionMatrix ); + this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); + + this.coordinateSystem = source.coordinateSystem; + + return this; + + } + + getWorldDirection( target ) { + + return super.getWorldDirection( target ).negate(); + + } + + updateMatrixWorld( force ) { + + super.updateMatrixWorld( force ); + + this.matrixWorldInverse.copy( this.matrixWorld ).invert(); + + } + + updateWorldMatrix( updateParents, updateChildren ) { + + super.updateWorldMatrix( updateParents, updateChildren ); + + this.matrixWorldInverse.copy( this.matrixWorld ).invert(); + + } + + clone() { + + return new this.constructor().copy( this ); + + } + +} + +const _v3$1 = /*@__PURE__*/ new Vector3(); +const _minTarget = /*@__PURE__*/ new Vector2(); +const _maxTarget = /*@__PURE__*/ new Vector2(); + + +class PerspectiveCamera extends Camera { + + constructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) { + + super(); + + this.isPerspectiveCamera = true; + + this.type = 'PerspectiveCamera'; + + this.fov = fov; + this.zoom = 1; + + this.near = near; + this.far = far; + this.focus = 10; + + this.aspect = aspect; + this.view = null; + + this.filmGauge = 35; // width of the film (default in millimeters) + this.filmOffset = 0; // horizontal film offset (same unit as gauge) + + this.updateProjectionMatrix(); + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.fov = source.fov; + this.zoom = source.zoom; + + this.near = source.near; + this.far = source.far; + this.focus = source.focus; + + this.aspect = source.aspect; + this.view = source.view === null ? null : Object.assign( {}, source.view ); + + this.filmGauge = source.filmGauge; + this.filmOffset = source.filmOffset; + + return this; + + } + + /** + * Sets the FOV by focal length in respect to the current .filmGauge. + * + * The default film gauge is 35, so that the focal length can be specified for + * a 35mm (full frame) camera. + * + * Values for focal length and film gauge must have the same unit. + */ + setFocalLength( focalLength ) { + + /** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */ + const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; + + this.fov = RAD2DEG * 2 * Math.atan( vExtentSlope ); + this.updateProjectionMatrix(); + + } + + /** + * Calculates the focal length from the current .fov and .filmGauge. + */ + getFocalLength() { + + const vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov ); + + return 0.5 * this.getFilmHeight() / vExtentSlope; + + } + + getEffectiveFOV() { + + return RAD2DEG * 2 * Math.atan( + Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom ); + + } + + getFilmWidth() { + + // film not completely covered in portrait format (aspect < 1) + return this.filmGauge * Math.min( this.aspect, 1 ); + + } + + getFilmHeight() { + + // film not completely covered in landscape format (aspect > 1) + return this.filmGauge / Math.max( this.aspect, 1 ); + + } + + /** + * Computes the 2D bounds of the camera's viewable rectangle at a given distance along the viewing direction. + * Sets minTarget and maxTarget to the coordinates of the lower-left and upper-right corners of the view rectangle. + */ + getViewBounds( distance, minTarget, maxTarget ) { + + _v3$1.set( - 1, - 1, 0.5 ).applyMatrix4( this.projectionMatrixInverse ); + + minTarget.set( _v3$1.x, _v3$1.y ).multiplyScalar( - distance / _v3$1.z ); + + _v3$1.set( 1, 1, 0.5 ).applyMatrix4( this.projectionMatrixInverse ); + + maxTarget.set( _v3$1.x, _v3$1.y ).multiplyScalar( - distance / _v3$1.z ); + + } + + /** + * Computes the width and height of the camera's viewable rectangle at a given distance along the viewing direction. + * Copies the result into the target Vector2, where x is width and y is height. + */ + getViewSize( distance, target ) { + + this.getViewBounds( distance, _minTarget, _maxTarget ); + + return target.subVectors( _maxTarget, _minTarget ); + + } + + /** + * Sets an offset in a larger frustum. This is useful for multi-window or + * multi-monitor/multi-machine setups. + * + * For example, if you have 3x2 monitors and each monitor is 1920x1080 and + * the monitors are in grid like this + * + * +---+---+---+ + * | A | B | C | + * +---+---+---+ + * | D | E | F | + * +---+---+---+ + * + * then for each monitor you would call it like this + * + * const w = 1920; + * const h = 1080; + * const fullWidth = w * 3; + * const fullHeight = h * 2; + * + * --A-- + * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); + * --B-- + * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); + * --C-- + * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); + * --D-- + * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); + * --E-- + * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); + * --F-- + * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); + * + * Note there is no reason monitors have to be the same size or in a grid. + */ + setViewOffset( fullWidth, fullHeight, x, y, width, height ) { + + this.aspect = fullWidth / fullHeight; + + if ( this.view === null ) { + + this.view = { + enabled: true, + fullWidth: 1, + fullHeight: 1, + offsetX: 0, + offsetY: 0, + width: 1, + height: 1 + }; + + } + + this.view.enabled = true; + this.view.fullWidth = fullWidth; + this.view.fullHeight = fullHeight; + this.view.offsetX = x; + this.view.offsetY = y; + this.view.width = width; + this.view.height = height; + + this.updateProjectionMatrix(); + + } + + clearViewOffset() { + + if ( this.view !== null ) { + + this.view.enabled = false; + + } + + this.updateProjectionMatrix(); + + } + + updateProjectionMatrix() { + + const near = this.near; + let top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom; + let height = 2 * top; + let width = this.aspect * height; + let left = - 0.5 * width; + const view = this.view; + + if ( this.view !== null && this.view.enabled ) { + + const fullWidth = view.fullWidth, + fullHeight = view.fullHeight; + + left += view.offsetX * width / fullWidth; + top -= view.offsetY * height / fullHeight; + width *= view.width / fullWidth; + height *= view.height / fullHeight; + + } + + const skew = this.filmOffset; + if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); + + this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem ); + + this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); + + } + + toJSON( meta ) { + + const data = super.toJSON( meta ); + + data.object.fov = this.fov; + data.object.zoom = this.zoom; + + data.object.near = this.near; + data.object.far = this.far; + data.object.focus = this.focus; + + data.object.aspect = this.aspect; + + if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); + + data.object.filmGauge = this.filmGauge; + data.object.filmOffset = this.filmOffset; + + return data; + + } + +} + +const fov = - 90; // negative fov is not an error +const aspect = 1; + +class CubeCamera extends Object3D { + + constructor( near, far, renderTarget ) { + + super(); + + this.type = 'CubeCamera'; + + this.renderTarget = renderTarget; + this.coordinateSystem = null; + this.activeMipmapLevel = 0; + + const cameraPX = new PerspectiveCamera( fov, aspect, near, far ); + cameraPX.layers = this.layers; + this.add( cameraPX ); + + const cameraNX = new PerspectiveCamera( fov, aspect, near, far ); + cameraNX.layers = this.layers; + this.add( cameraNX ); + + const cameraPY = new PerspectiveCamera( fov, aspect, near, far ); + cameraPY.layers = this.layers; + this.add( cameraPY ); + + const cameraNY = new PerspectiveCamera( fov, aspect, near, far ); + cameraNY.layers = this.layers; + this.add( cameraNY ); + + const cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); + cameraPZ.layers = this.layers; + this.add( cameraPZ ); + + const cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); + cameraNZ.layers = this.layers; + this.add( cameraNZ ); + + } + + updateCoordinateSystem() { + + const coordinateSystem = this.coordinateSystem; + + const cameras = this.children.concat(); + + const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = cameras; + + for ( const camera of cameras ) this.remove( camera ); + + if ( coordinateSystem === WebGLCoordinateSystem ) { + + cameraPX.up.set( 0, 1, 0 ); + cameraPX.lookAt( 1, 0, 0 ); + + cameraNX.up.set( 0, 1, 0 ); + cameraNX.lookAt( - 1, 0, 0 ); + + cameraPY.up.set( 0, 0, - 1 ); + cameraPY.lookAt( 0, 1, 0 ); + + cameraNY.up.set( 0, 0, 1 ); + cameraNY.lookAt( 0, - 1, 0 ); + + cameraPZ.up.set( 0, 1, 0 ); + cameraPZ.lookAt( 0, 0, 1 ); + + cameraNZ.up.set( 0, 1, 0 ); + cameraNZ.lookAt( 0, 0, - 1 ); + + } else if ( coordinateSystem === WebGPUCoordinateSystem ) { + + cameraPX.up.set( 0, - 1, 0 ); + cameraPX.lookAt( - 1, 0, 0 ); + + cameraNX.up.set( 0, - 1, 0 ); + cameraNX.lookAt( 1, 0, 0 ); + + cameraPY.up.set( 0, 0, 1 ); + cameraPY.lookAt( 0, 1, 0 ); + + cameraNY.up.set( 0, 0, - 1 ); + cameraNY.lookAt( 0, - 1, 0 ); + + cameraPZ.up.set( 0, - 1, 0 ); + cameraPZ.lookAt( 0, 0, 1 ); + + cameraNZ.up.set( 0, - 1, 0 ); + cameraNZ.lookAt( 0, 0, - 1 ); + + } else { + + throw new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem ); + + } + + for ( const camera of cameras ) { + + this.add( camera ); + + camera.updateMatrixWorld(); + + } + + } + + update( renderer, scene ) { + + if ( this.parent === null ) this.updateMatrixWorld(); + + const { renderTarget, activeMipmapLevel } = this; + + if ( this.coordinateSystem !== renderer.coordinateSystem ) { + + this.coordinateSystem = renderer.coordinateSystem; + + this.updateCoordinateSystem(); + + } + + const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children; + + const currentRenderTarget = renderer.getRenderTarget(); + const currentActiveCubeFace = renderer.getActiveCubeFace(); + const currentActiveMipmapLevel = renderer.getActiveMipmapLevel(); + + const currentXrEnabled = renderer.xr.enabled; + + renderer.xr.enabled = false; + + const generateMipmaps = renderTarget.texture.generateMipmaps; + + renderTarget.texture.generateMipmaps = false; + + renderer.setRenderTarget( renderTarget, 0, activeMipmapLevel ); + renderer.render( scene, cameraPX ); + + renderer.setRenderTarget( renderTarget, 1, activeMipmapLevel ); + renderer.render( scene, cameraNX ); + + renderer.setRenderTarget( renderTarget, 2, activeMipmapLevel ); + renderer.render( scene, cameraPY ); + + renderer.setRenderTarget( renderTarget, 3, activeMipmapLevel ); + renderer.render( scene, cameraNY ); + + renderer.setRenderTarget( renderTarget, 4, activeMipmapLevel ); + renderer.render( scene, cameraPZ ); + + // mipmaps are generated during the last call of render() + // at this point, all sides of the cube render target are defined + + renderTarget.texture.generateMipmaps = generateMipmaps; + + renderer.setRenderTarget( renderTarget, 5, activeMipmapLevel ); + renderer.render( scene, cameraNZ ); + + renderer.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel ); + + renderer.xr.enabled = currentXrEnabled; + + renderTarget.texture.needsPMREMUpdate = true; + + } + +} + +class CubeTexture extends Texture { + + constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ) { + + images = images !== undefined ? images : []; + mapping = mapping !== undefined ? mapping : CubeReflectionMapping; + + super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); + + this.isCubeTexture = true; + + this.flipY = false; + + } + + get images() { + + return this.image; + + } + + set images( value ) { + + this.image = value; + + } + +} + +class WebGLCubeRenderTarget extends WebGLRenderTarget { + + constructor( size = 1, options = {} ) { + + super( size, size, options ); + + this.isWebGLCubeRenderTarget = true; + + const image = { width: size, height: size, depth: 1 }; + const images = [ image, image, image, image, image, image ]; + + this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); + + // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js) + // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words, + // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly. + + // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped + // and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture + // as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures). + + this.texture.isRenderTargetTexture = true; + + this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; + this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; + + } + + fromEquirectangularTexture( renderer, texture ) { + + this.texture.type = texture.type; + this.texture.colorSpace = texture.colorSpace; + + this.texture.generateMipmaps = texture.generateMipmaps; + this.texture.minFilter = texture.minFilter; + this.texture.magFilter = texture.magFilter; + + const shader = { + + uniforms: { + tEquirect: { value: null }, + }, + + vertexShader: /* glsl */` + + varying vec3 vWorldDirection; + + vec3 transformDirection( in vec3 dir, in mat4 matrix ) { + + return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); + + } + + void main() { + + vWorldDirection = transformDirection( position, modelMatrix ); + + #include + #include + + } + `, + + fragmentShader: /* glsl */` + + uniform sampler2D tEquirect; + + varying vec3 vWorldDirection; + + #include + + void main() { + + vec3 direction = normalize( vWorldDirection ); + + vec2 sampleUV = equirectUv( direction ); + + gl_FragColor = texture2D( tEquirect, sampleUV ); + + } + ` + }; + + const geometry = new BoxGeometry( 5, 5, 5 ); + + const material = new ShaderMaterial( { + + name: 'CubemapFromEquirect', + + uniforms: cloneUniforms( shader.uniforms ), + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader, + side: BackSide, + blending: NoBlending + + } ); + + material.uniforms.tEquirect.value = texture; + + const mesh = new Mesh( geometry, material ); + + const currentMinFilter = texture.minFilter; + + // Avoid blurred poles + if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter; + + const camera = new CubeCamera( 1, 10, this ); + camera.update( renderer, mesh ); + + texture.minFilter = currentMinFilter; + + mesh.geometry.dispose(); + mesh.material.dispose(); + + return this; + + } + + clear( renderer, color, depth, stencil ) { + + const currentRenderTarget = renderer.getRenderTarget(); + + for ( let i = 0; i < 6; i ++ ) { + + renderer.setRenderTarget( this, i ); + + renderer.clear( color, depth, stencil ); + + } + + renderer.setRenderTarget( currentRenderTarget ); + + } + +} + +class FogExp2 { + + constructor( color, density = 0.00025 ) { + + this.isFogExp2 = true; + + this.name = ''; + + this.color = new Color( color ); + this.density = density; + + } + + clone() { + + return new FogExp2( this.color, this.density ); + + } + + toJSON( /* meta */ ) { + + return { + type: 'FogExp2', + name: this.name, + color: this.color.getHex(), + density: this.density + }; + + } + +} + +class Fog { + + constructor( color, near = 1, far = 1000 ) { + + this.isFog = true; + + this.name = ''; + + this.color = new Color( color ); + + this.near = near; + this.far = far; + + } + + clone() { + + return new Fog( this.color, this.near, this.far ); + + } + + toJSON( /* meta */ ) { + + return { + type: 'Fog', + name: this.name, + color: this.color.getHex(), + near: this.near, + far: this.far + }; + + } + +} + +class Scene extends Object3D { + + constructor() { + + super(); + + this.isScene = true; + + this.type = 'Scene'; + + this.background = null; + this.environment = null; + this.fog = null; + + this.backgroundBlurriness = 0; + this.backgroundIntensity = 1; + this.backgroundRotation = new Euler(); + + this.environmentIntensity = 1; + this.environmentRotation = new Euler(); + + this.overrideMaterial = null; + + if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { + + __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); + + } + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + if ( source.background !== null ) this.background = source.background.clone(); + if ( source.environment !== null ) this.environment = source.environment.clone(); + if ( source.fog !== null ) this.fog = source.fog.clone(); + + this.backgroundBlurriness = source.backgroundBlurriness; + this.backgroundIntensity = source.backgroundIntensity; + this.backgroundRotation.copy( source.backgroundRotation ); + + this.environmentIntensity = source.environmentIntensity; + this.environmentRotation.copy( source.environmentRotation ); + + if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); + + this.matrixAutoUpdate = source.matrixAutoUpdate; + + return this; + + } + + toJSON( meta ) { + + const data = super.toJSON( meta ); + + if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); + + if ( this.backgroundBlurriness > 0 ) data.object.backgroundBlurriness = this.backgroundBlurriness; + if ( this.backgroundIntensity !== 1 ) data.object.backgroundIntensity = this.backgroundIntensity; + data.object.backgroundRotation = this.backgroundRotation.toArray(); + + if ( this.environmentIntensity !== 1 ) data.object.environmentIntensity = this.environmentIntensity; + data.object.environmentRotation = this.environmentRotation.toArray(); + + return data; + + } + +} + +class InterleavedBuffer { + + constructor( array, stride ) { + + this.isInterleavedBuffer = true; + + this.array = array; + this.stride = stride; + this.count = array !== undefined ? array.length / stride : 0; + + this.usage = StaticDrawUsage; + this.updateRanges = []; + + this.version = 0; + + this.uuid = generateUUID(); + + } + + onUploadCallback() {} + + set needsUpdate( value ) { + + if ( value === true ) this.version ++; + + } + + setUsage( value ) { + + this.usage = value; + + return this; + + } + + addUpdateRange( start, count ) { + + this.updateRanges.push( { start, count } ); + + } + + clearUpdateRanges() { + + this.updateRanges.length = 0; + + } + + copy( source ) { + + this.array = new source.array.constructor( source.array ); + this.count = source.count; + this.stride = source.stride; + this.usage = source.usage; + + return this; + + } + + copyAt( index1, attribute, index2 ) { + + index1 *= this.stride; + index2 *= attribute.stride; + + for ( let i = 0, l = this.stride; i < l; i ++ ) { + + this.array[ index1 + i ] = attribute.array[ index2 + i ]; + + } + + return this; + + } + + set( value, offset = 0 ) { + + this.array.set( value, offset ); + + return this; + + } + + clone( data ) { + + if ( data.arrayBuffers === undefined ) { + + data.arrayBuffers = {}; + + } + + if ( this.array.buffer._uuid === undefined ) { + + this.array.buffer._uuid = generateUUID(); + + } + + if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { + + data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer; + + } + + const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] ); + + const ib = new this.constructor( array, this.stride ); + ib.setUsage( this.usage ); + + return ib; + + } + + onUpload( callback ) { + + this.onUploadCallback = callback; + + return this; + + } + + toJSON( data ) { + + if ( data.arrayBuffers === undefined ) { + + data.arrayBuffers = {}; + + } + + // generate UUID for array buffer if necessary + + if ( this.array.buffer._uuid === undefined ) { + + this.array.buffer._uuid = generateUUID(); + + } + + if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { + + data.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) ); + + } + + // + + return { + uuid: this.uuid, + buffer: this.array.buffer._uuid, + type: this.array.constructor.name, + stride: this.stride + }; + + } + +} + +const _vector$7 = /*@__PURE__*/ new Vector3(); + +class InterleavedBufferAttribute { + + constructor( interleavedBuffer, itemSize, offset, normalized = false ) { + + this.isInterleavedBufferAttribute = true; + + this.name = ''; + + this.data = interleavedBuffer; + this.itemSize = itemSize; + this.offset = offset; + + this.normalized = normalized; + + } + + get count() { + + return this.data.count; + + } + + get array() { + + return this.data.array; + + } + + set needsUpdate( value ) { + + this.data.needsUpdate = value; + + } + + applyMatrix4( m ) { + + for ( let i = 0, l = this.data.count; i < l; i ++ ) { + + _vector$7.fromBufferAttribute( this, i ); + + _vector$7.applyMatrix4( m ); + + this.setXYZ( i, _vector$7.x, _vector$7.y, _vector$7.z ); + + } + + return this; + + } + + applyNormalMatrix( m ) { + + for ( let i = 0, l = this.count; i < l; i ++ ) { + + _vector$7.fromBufferAttribute( this, i ); + + _vector$7.applyNormalMatrix( m ); + + this.setXYZ( i, _vector$7.x, _vector$7.y, _vector$7.z ); + + } + + return this; + + } + + transformDirection( m ) { + + for ( let i = 0, l = this.count; i < l; i ++ ) { + + _vector$7.fromBufferAttribute( this, i ); + + _vector$7.transformDirection( m ); + + this.setXYZ( i, _vector$7.x, _vector$7.y, _vector$7.z ); + + } + + return this; + + } + + getComponent( index, component ) { + + let value = this.array[ index * this.data.stride + this.offset + component ]; + + if ( this.normalized ) value = denormalize( value, this.array ); + + return value; + + } + + setComponent( index, component, value ) { + + if ( this.normalized ) value = normalize$1( value, this.array ); + + this.data.array[ index * this.data.stride + this.offset + component ] = value; + + return this; + + } + + setX( index, x ) { + + if ( this.normalized ) x = normalize$1( x, this.array ); + + this.data.array[ index * this.data.stride + this.offset ] = x; + + return this; + + } + + setY( index, y ) { + + if ( this.normalized ) y = normalize$1( y, this.array ); + + this.data.array[ index * this.data.stride + this.offset + 1 ] = y; + + return this; + + } + + setZ( index, z ) { + + if ( this.normalized ) z = normalize$1( z, this.array ); + + this.data.array[ index * this.data.stride + this.offset + 2 ] = z; + + return this; + + } + + setW( index, w ) { + + if ( this.normalized ) w = normalize$1( w, this.array ); + + this.data.array[ index * this.data.stride + this.offset + 3 ] = w; + + return this; + + } + + getX( index ) { + + let x = this.data.array[ index * this.data.stride + this.offset ]; + + if ( this.normalized ) x = denormalize( x, this.array ); + + return x; + + } + + getY( index ) { + + let y = this.data.array[ index * this.data.stride + this.offset + 1 ]; + + if ( this.normalized ) y = denormalize( y, this.array ); + + return y; + + } + + getZ( index ) { + + let z = this.data.array[ index * this.data.stride + this.offset + 2 ]; + + if ( this.normalized ) z = denormalize( z, this.array ); + + return z; + + } + + getW( index ) { + + let w = this.data.array[ index * this.data.stride + this.offset + 3 ]; + + if ( this.normalized ) w = denormalize( w, this.array ); + + return w; + + } + + setXY( index, x, y ) { + + index = index * this.data.stride + this.offset; + + if ( this.normalized ) { + + x = normalize$1( x, this.array ); + y = normalize$1( y, this.array ); + + } + + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; + + return this; + + } + + setXYZ( index, x, y, z ) { + + index = index * this.data.stride + this.offset; + + if ( this.normalized ) { + + x = normalize$1( x, this.array ); + y = normalize$1( y, this.array ); + z = normalize$1( z, this.array ); + + } + + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; + this.data.array[ index + 2 ] = z; + + return this; + + } + + setXYZW( index, x, y, z, w ) { + + index = index * this.data.stride + this.offset; + + if ( this.normalized ) { + + x = normalize$1( x, this.array ); + y = normalize$1( y, this.array ); + z = normalize$1( z, this.array ); + w = normalize$1( w, this.array ); + + } + + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; + this.data.array[ index + 2 ] = z; + this.data.array[ index + 3 ] = w; + + return this; + + } + + clone( data ) { + + if ( data === undefined ) { + + console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' ); + + const array = []; + + for ( let i = 0; i < this.count; i ++ ) { + + const index = i * this.data.stride + this.offset; + + for ( let j = 0; j < this.itemSize; j ++ ) { + + array.push( this.data.array[ index + j ] ); + + } + + } + + return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized ); + + } else { + + if ( data.interleavedBuffers === undefined ) { + + data.interleavedBuffers = {}; + + } + + if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { + + data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data ); + + } + + return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized ); + + } + + } + + toJSON( data ) { + + if ( data === undefined ) { + + console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' ); + + const array = []; + + for ( let i = 0; i < this.count; i ++ ) { + + const index = i * this.data.stride + this.offset; + + for ( let j = 0; j < this.itemSize; j ++ ) { + + array.push( this.data.array[ index + j ] ); + + } + + } + + // de-interleave data and save it as an ordinary buffer attribute for now + + return { + itemSize: this.itemSize, + type: this.array.constructor.name, + array: array, + normalized: this.normalized + }; + + } else { + + // save as true interleaved attribute + + if ( data.interleavedBuffers === undefined ) { + + data.interleavedBuffers = {}; + + } + + if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { + + data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data ); + + } + + return { + isInterleavedBufferAttribute: true, + itemSize: this.itemSize, + data: this.data.uuid, + offset: this.offset, + normalized: this.normalized + }; + + } + + } + +} + +class SpriteMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isSpriteMaterial = true; + + this.type = 'SpriteMaterial'; + + this.color = new Color( 0xffffff ); + + this.map = null; + + this.alphaMap = null; + + this.rotation = 0; + + this.sizeAttenuation = true; + + this.transparent = true; + + this.fog = true; + + this.setValues( parameters ); + + } + + copy( source ) { + + super.copy( source ); + + this.color.copy( source.color ); + + this.map = source.map; + + this.alphaMap = source.alphaMap; + + this.rotation = source.rotation; + + this.sizeAttenuation = source.sizeAttenuation; + + this.fog = source.fog; + + return this; + + } + +} + +let _geometry$1; + +const _intersectPoint = /*@__PURE__*/ new Vector3(); +const _worldScale = /*@__PURE__*/ new Vector3(); +const _mvPosition = /*@__PURE__*/ new Vector3(); + +const _alignedPosition = /*@__PURE__*/ new Vector2(); +const _rotatedPosition = /*@__PURE__*/ new Vector2(); +const _viewWorldMatrix = /*@__PURE__*/ new Matrix4(); + +const _vA = /*@__PURE__*/ new Vector3(); +const _vB = /*@__PURE__*/ new Vector3(); +const _vC = /*@__PURE__*/ new Vector3(); + +const _uvA = /*@__PURE__*/ new Vector2(); +const _uvB = /*@__PURE__*/ new Vector2(); +const _uvC = /*@__PURE__*/ new Vector2(); + +class Sprite extends Object3D { + + constructor( material = new SpriteMaterial() ) { + + super(); + + this.isSprite = true; + + this.type = 'Sprite'; + + if ( _geometry$1 === undefined ) { + + _geometry$1 = new BufferGeometry(); + + const float32Array = new Float32Array( [ + - 0.5, - 0.5, 0, 0, 0, + 0.5, - 0.5, 0, 1, 0, + 0.5, 0.5, 0, 1, 1, + - 0.5, 0.5, 0, 0, 1 + ] ); + + const interleavedBuffer = new InterleavedBuffer( float32Array, 5 ); + + _geometry$1.setIndex( [ 0, 1, 2, 0, 2, 3 ] ); + _geometry$1.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) ); + _geometry$1.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) ); + + } + + this.geometry = _geometry$1; + this.material = material; + + this.center = new Vector2( 0.5, 0.5 ); + + } + + raycast( raycaster, intersects ) { + + if ( raycaster.camera === null ) { + + console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' ); + + } + + _worldScale.setFromMatrixScale( this.matrixWorld ); + + _viewWorldMatrix.copy( raycaster.camera.matrixWorld ); + this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld ); + + _mvPosition.setFromMatrixPosition( this.modelViewMatrix ); + + if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) { + + _worldScale.multiplyScalar( - _mvPosition.z ); + + } + + const rotation = this.material.rotation; + let sin, cos; + + if ( rotation !== 0 ) { + + cos = Math.cos( rotation ); + sin = Math.sin( rotation ); + + } + + const center = this.center; + + transformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); + transformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); + transformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); + + _uvA.set( 0, 0 ); + _uvB.set( 1, 0 ); + _uvC.set( 1, 1 ); + + // check first triangle + let intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint ); + + if ( intersect === null ) { + + // check second triangle + transformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); + _uvB.set( 0, 1 ); + + intersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint ); + if ( intersect === null ) { + + return; + + } + + } + + const distance = raycaster.ray.origin.distanceTo( _intersectPoint ); + + if ( distance < raycaster.near || distance > raycaster.far ) return; + + intersects.push( { + + distance: distance, + point: _intersectPoint.clone(), + uv: Triangle.getInterpolation( _intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ), + face: null, + object: this + + } ); + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + if ( source.center !== undefined ) this.center.copy( source.center ); + + this.material = source.material; + + return this; + + } + +} + +function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) { + + // compute position in camera space + _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale ); + + // to check if rotation is not zero + if ( sin !== undefined ) { + + _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y ); + _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y ); + + } else { + + _rotatedPosition.copy( _alignedPosition ); + + } + + + vertexPosition.copy( mvPosition ); + vertexPosition.x += _rotatedPosition.x; + vertexPosition.y += _rotatedPosition.y; + + // transform to world space + vertexPosition.applyMatrix4( _viewWorldMatrix ); + +} + +const _v1$2 = /*@__PURE__*/ new Vector3(); +const _v2$1 = /*@__PURE__*/ new Vector3(); + +class LOD extends Object3D { + + constructor() { + + super(); + + this._currentLevel = 0; + + this.type = 'LOD'; + + Object.defineProperties( this, { + levels: { + enumerable: true, + value: [] + }, + isLOD: { + value: true, + } + } ); + + this.autoUpdate = true; + + } + + copy( source ) { + + super.copy( source, false ); + + const levels = source.levels; + + for ( let i = 0, l = levels.length; i < l; i ++ ) { + + const level = levels[ i ]; + + this.addLevel( level.object.clone(), level.distance, level.hysteresis ); + + } + + this.autoUpdate = source.autoUpdate; + + return this; + + } + + addLevel( object, distance = 0, hysteresis = 0 ) { + + distance = Math.abs( distance ); + + const levels = this.levels; + + let l; + + for ( l = 0; l < levels.length; l ++ ) { + + if ( distance < levels[ l ].distance ) { + + break; + + } + + } + + levels.splice( l, 0, { distance: distance, hysteresis: hysteresis, object: object } ); + + this.add( object ); + + return this; + + } + + removeLevel( distance ) { + + const levels = this.levels; + + for ( let i = 0; i < levels.length; i ++ ) { + + if ( levels[ i ].distance === distance ) { + + const removedElements = levels.splice( i, 1 ); + this.remove( removedElements[ 0 ].object ); + + return true; + + } + + } + + return false; + + } + + getCurrentLevel() { + + return this._currentLevel; + + } + + + + getObjectForDistance( distance ) { + + const levels = this.levels; + + if ( levels.length > 0 ) { + + let i, l; + + for ( i = 1, l = levels.length; i < l; i ++ ) { + + let levelDistance = levels[ i ].distance; + + if ( levels[ i ].object.visible ) { + + levelDistance -= levelDistance * levels[ i ].hysteresis; + + } + + if ( distance < levelDistance ) { + + break; + + } + + } + + return levels[ i - 1 ].object; + + } + + return null; + + } + + raycast( raycaster, intersects ) { + + const levels = this.levels; + + if ( levels.length > 0 ) { + + _v1$2.setFromMatrixPosition( this.matrixWorld ); + + const distance = raycaster.ray.origin.distanceTo( _v1$2 ); + + this.getObjectForDistance( distance ).raycast( raycaster, intersects ); + + } + + } + + update( camera ) { + + const levels = this.levels; + + if ( levels.length > 1 ) { + + _v1$2.setFromMatrixPosition( camera.matrixWorld ); + _v2$1.setFromMatrixPosition( this.matrixWorld ); + + const distance = _v1$2.distanceTo( _v2$1 ) / camera.zoom; + + levels[ 0 ].object.visible = true; + + let i, l; + + for ( i = 1, l = levels.length; i < l; i ++ ) { + + let levelDistance = levels[ i ].distance; + + if ( levels[ i ].object.visible ) { + + levelDistance -= levelDistance * levels[ i ].hysteresis; + + } + + if ( distance >= levelDistance ) { + + levels[ i - 1 ].object.visible = false; + levels[ i ].object.visible = true; + + } else { + + break; + + } + + } + + this._currentLevel = i - 1; + + for ( ; i < l; i ++ ) { + + levels[ i ].object.visible = false; + + } + + } + + } + + toJSON( meta ) { + + const data = super.toJSON( meta ); + + if ( this.autoUpdate === false ) data.object.autoUpdate = false; + + data.object.levels = []; + + const levels = this.levels; + + for ( let i = 0, l = levels.length; i < l; i ++ ) { + + const level = levels[ i ]; + + data.object.levels.push( { + object: level.object.uuid, + distance: level.distance, + hysteresis: level.hysteresis + } ); + + } + + return data; + + } + +} + +const _basePosition = /*@__PURE__*/ new Vector3(); + +const _skinIndex = /*@__PURE__*/ new Vector4(); +const _skinWeight = /*@__PURE__*/ new Vector4(); + +const _vector3 = /*@__PURE__*/ new Vector3(); +const _matrix4 = /*@__PURE__*/ new Matrix4(); +const _vertex = /*@__PURE__*/ new Vector3(); + +const _sphere$5 = /*@__PURE__*/ new Sphere(); +const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4(); +const _ray$2 = /*@__PURE__*/ new Ray(); + +class SkinnedMesh extends Mesh { + + constructor( geometry, material ) { + + super( geometry, material ); + + this.isSkinnedMesh = true; + + this.type = 'SkinnedMesh'; + + this.bindMode = AttachedBindMode; + this.bindMatrix = new Matrix4(); + this.bindMatrixInverse = new Matrix4(); + + this.boundingBox = null; + this.boundingSphere = null; + + } + + computeBoundingBox() { + + const geometry = this.geometry; + + if ( this.boundingBox === null ) { + + this.boundingBox = new Box3(); + + } + + this.boundingBox.makeEmpty(); + + const positionAttribute = geometry.getAttribute( 'position' ); + + for ( let i = 0; i < positionAttribute.count; i ++ ) { + + this.getVertexPosition( i, _vertex ); + this.boundingBox.expandByPoint( _vertex ); + + } + + } + + computeBoundingSphere() { + + const geometry = this.geometry; + + if ( this.boundingSphere === null ) { + + this.boundingSphere = new Sphere(); + + } + + this.boundingSphere.makeEmpty(); + + const positionAttribute = geometry.getAttribute( 'position' ); + + for ( let i = 0; i < positionAttribute.count; i ++ ) { + + this.getVertexPosition( i, _vertex ); + this.boundingSphere.expandByPoint( _vertex ); + + } + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.bindMode = source.bindMode; + this.bindMatrix.copy( source.bindMatrix ); + this.bindMatrixInverse.copy( source.bindMatrixInverse ); + + this.skeleton = source.skeleton; + + if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone(); + if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone(); + + return this; + + } + + raycast( raycaster, intersects ) { + + const material = this.material; + const matrixWorld = this.matrixWorld; + + if ( material === undefined ) return; + + // test with bounding sphere in world space + + if ( this.boundingSphere === null ) this.computeBoundingSphere(); + + _sphere$5.copy( this.boundingSphere ); + _sphere$5.applyMatrix4( matrixWorld ); + + if ( raycaster.ray.intersectsSphere( _sphere$5 ) === false ) return; + + // convert ray to local space of skinned mesh + + _inverseMatrix$2.copy( matrixWorld ).invert(); + _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 ); + + // test with bounding box in local space + + if ( this.boundingBox !== null ) { + + if ( _ray$2.intersectsBox( this.boundingBox ) === false ) return; + + } + + // test for intersections with geometry + + this._computeIntersections( raycaster, intersects, _ray$2 ); + + } + + getVertexPosition( index, target ) { + + super.getVertexPosition( index, target ); + + this.applyBoneTransform( index, target ); + + return target; + + } + + bind( skeleton, bindMatrix ) { + + this.skeleton = skeleton; + + if ( bindMatrix === undefined ) { + + this.updateMatrixWorld( true ); + + this.skeleton.calculateInverses(); + + bindMatrix = this.matrixWorld; + + } + + this.bindMatrix.copy( bindMatrix ); + this.bindMatrixInverse.copy( bindMatrix ).invert(); + + } + + pose() { + + this.skeleton.pose(); + + } + + normalizeSkinWeights() { + + const vector = new Vector4(); + + const skinWeight = this.geometry.attributes.skinWeight; + + for ( let i = 0, l = skinWeight.count; i < l; i ++ ) { + + vector.fromBufferAttribute( skinWeight, i ); + + const scale = 1.0 / vector.manhattanLength(); + + if ( scale !== Infinity ) { + + vector.multiplyScalar( scale ); + + } else { + + vector.set( 1, 0, 0, 0 ); // do something reasonable + + } + + skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w ); + + } + + } + + updateMatrixWorld( force ) { + + super.updateMatrixWorld( force ); + + if ( this.bindMode === AttachedBindMode ) { + + this.bindMatrixInverse.copy( this.matrixWorld ).invert(); + + } else if ( this.bindMode === DetachedBindMode ) { + + this.bindMatrixInverse.copy( this.bindMatrix ).invert(); + + } else { + + console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); + + } + + } + + applyBoneTransform( index, vector ) { + + const skeleton = this.skeleton; + const geometry = this.geometry; + + _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index ); + _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index ); + + _basePosition.copy( vector ).applyMatrix4( this.bindMatrix ); + + vector.set( 0, 0, 0 ); + + for ( let i = 0; i < 4; i ++ ) { + + const weight = _skinWeight.getComponent( i ); + + if ( weight !== 0 ) { + + const boneIndex = _skinIndex.getComponent( i ); + + _matrix4.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] ); + + vector.addScaledVector( _vector3.copy( _basePosition ).applyMatrix4( _matrix4 ), weight ); + + } + + } + + return vector.applyMatrix4( this.bindMatrixInverse ); + + } + +} + +class Bone extends Object3D { + + constructor() { + + super(); + + this.isBone = true; + + this.type = 'Bone'; + + } + +} + +class DataTexture extends Texture { + + constructor( data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, colorSpace ) { + + super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); + + this.isDataTexture = true; + + this.image = { data: data, width: width, height: height }; + + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; + + } + +} + +const _offsetMatrix = /*@__PURE__*/ new Matrix4(); +const _identityMatrix$1 = /*@__PURE__*/ new Matrix4(); + +class Skeleton { + + constructor( bones = [], boneInverses = [] ) { + + this.uuid = generateUUID(); + + this.bones = bones.slice( 0 ); + this.boneInverses = boneInverses; + this.boneMatrices = null; + + this.boneTexture = null; + + this.init(); + + } + + init() { + + const bones = this.bones; + const boneInverses = this.boneInverses; + + this.boneMatrices = new Float32Array( bones.length * 16 ); + + // calculate inverse bone matrices if necessary + + if ( boneInverses.length === 0 ) { + + this.calculateInverses(); + + } else { + + // handle special case + + if ( bones.length !== boneInverses.length ) { + + console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' ); + + this.boneInverses = []; + + for ( let i = 0, il = this.bones.length; i < il; i ++ ) { + + this.boneInverses.push( new Matrix4() ); + + } + + } + + } + + } + + calculateInverses() { + + this.boneInverses.length = 0; + + for ( let i = 0, il = this.bones.length; i < il; i ++ ) { + + const inverse = new Matrix4(); + + if ( this.bones[ i ] ) { + + inverse.copy( this.bones[ i ].matrixWorld ).invert(); + + } + + this.boneInverses.push( inverse ); + + } + + } + + pose() { + + // recover the bind-time world matrices + + for ( let i = 0, il = this.bones.length; i < il; i ++ ) { + + const bone = this.bones[ i ]; + + if ( bone ) { + + bone.matrixWorld.copy( this.boneInverses[ i ] ).invert(); + + } + + } + + // compute the local matrices, positions, rotations and scales + + for ( let i = 0, il = this.bones.length; i < il; i ++ ) { + + const bone = this.bones[ i ]; + + if ( bone ) { + + if ( bone.parent && bone.parent.isBone ) { + + bone.matrix.copy( bone.parent.matrixWorld ).invert(); + bone.matrix.multiply( bone.matrixWorld ); + + } else { + + bone.matrix.copy( bone.matrixWorld ); + + } + + bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); + + } + + } + + } + + update() { + + const bones = this.bones; + const boneInverses = this.boneInverses; + const boneMatrices = this.boneMatrices; + const boneTexture = this.boneTexture; + + // flatten bone matrices to array + + for ( let i = 0, il = bones.length; i < il; i ++ ) { + + // compute the offset between the current and the original transform + + const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix$1; + + _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); + _offsetMatrix.toArray( boneMatrices, i * 16 ); + + } + + if ( boneTexture !== null ) { + + boneTexture.needsUpdate = true; + + } + + } + + clone() { + + return new Skeleton( this.bones, this.boneInverses ); + + } + + computeBoneTexture() { + + // layout (1 matrix = 4 pixels) + // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) + // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) + // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) + // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) + // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) + + let size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix + size = Math.ceil( size / 4 ) * 4; + size = Math.max( size, 4 ); + + const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel + boneMatrices.set( this.boneMatrices ); // copy current values + + const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); + boneTexture.needsUpdate = true; + + this.boneMatrices = boneMatrices; + this.boneTexture = boneTexture; + + return this; + + } + + getBoneByName( name ) { + + for ( let i = 0, il = this.bones.length; i < il; i ++ ) { + + const bone = this.bones[ i ]; + + if ( bone.name === name ) { + + return bone; + + } + + } + + return undefined; + + } + + dispose( ) { + + if ( this.boneTexture !== null ) { + + this.boneTexture.dispose(); + + this.boneTexture = null; + + } + + } + + fromJSON( json, bones ) { + + this.uuid = json.uuid; + + for ( let i = 0, l = json.bones.length; i < l; i ++ ) { + + const uuid = json.bones[ i ]; + let bone = bones[ uuid ]; + + if ( bone === undefined ) { + + console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid ); + bone = new Bone(); + + } + + this.bones.push( bone ); + this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) ); + + } + + this.init(); + + return this; + + } + + toJSON() { + + const data = { + metadata: { + version: 4.6, + type: 'Skeleton', + generator: 'Skeleton.toJSON' + }, + bones: [], + boneInverses: [] + }; + + data.uuid = this.uuid; + + const bones = this.bones; + const boneInverses = this.boneInverses; + + for ( let i = 0, l = bones.length; i < l; i ++ ) { + + const bone = bones[ i ]; + data.bones.push( bone.uuid ); + + const boneInverse = boneInverses[ i ]; + data.boneInverses.push( boneInverse.toArray() ); + + } + + return data; + + } + +} + +class InstancedBufferAttribute extends BufferAttribute { + + constructor( array, itemSize, normalized, meshPerAttribute = 1 ) { + + super( array, itemSize, normalized ); + + this.isInstancedBufferAttribute = true; + + this.meshPerAttribute = meshPerAttribute; + + } + + copy( source ) { + + super.copy( source ); + + this.meshPerAttribute = source.meshPerAttribute; + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.meshPerAttribute = this.meshPerAttribute; + + data.isInstancedBufferAttribute = true; + + return data; + + } + +} + +const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4(); +const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4(); + +const _instanceIntersects = []; + +const _box3 = /*@__PURE__*/ new Box3(); +const _identity = /*@__PURE__*/ new Matrix4(); +const _mesh$1 = /*@__PURE__*/ new Mesh(); +const _sphere$4 = /*@__PURE__*/ new Sphere(); + +class InstancedMesh extends Mesh { + + constructor( geometry, material, count ) { + + super( geometry, material ); + + this.isInstancedMesh = true; + + this.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 ); + this.instanceColor = null; + this.morphTexture = null; + + this.count = count; + + this.boundingBox = null; + this.boundingSphere = null; + + for ( let i = 0; i < count; i ++ ) { + + this.setMatrixAt( i, _identity ); + + } + + } + + computeBoundingBox() { + + const geometry = this.geometry; + const count = this.count; + + if ( this.boundingBox === null ) { + + this.boundingBox = new Box3(); + + } + + if ( geometry.boundingBox === null ) { + + geometry.computeBoundingBox(); + + } + + this.boundingBox.makeEmpty(); + + for ( let i = 0; i < count; i ++ ) { + + this.getMatrixAt( i, _instanceLocalMatrix ); + + _box3.copy( geometry.boundingBox ).applyMatrix4( _instanceLocalMatrix ); + + this.boundingBox.union( _box3 ); + + } + + } + + computeBoundingSphere() { + + const geometry = this.geometry; + const count = this.count; + + if ( this.boundingSphere === null ) { + + this.boundingSphere = new Sphere(); + + } + + if ( geometry.boundingSphere === null ) { + + geometry.computeBoundingSphere(); + + } + + this.boundingSphere.makeEmpty(); + + for ( let i = 0; i < count; i ++ ) { + + this.getMatrixAt( i, _instanceLocalMatrix ); + + _sphere$4.copy( geometry.boundingSphere ).applyMatrix4( _instanceLocalMatrix ); + + this.boundingSphere.union( _sphere$4 ); + + } + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.instanceMatrix.copy( source.instanceMatrix ); + + if ( source.morphTexture !== null ) this.morphTexture = source.morphTexture.clone(); + if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone(); + + this.count = source.count; + + if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone(); + if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone(); + + return this; + + } + + getColorAt( index, color ) { + + color.fromArray( this.instanceColor.array, index * 3 ); + + } + + getMatrixAt( index, matrix ) { + + matrix.fromArray( this.instanceMatrix.array, index * 16 ); + + } + + getMorphAt( index, object ) { + + const objectInfluences = object.morphTargetInfluences; + + const array = this.morphTexture.source.data.data; + + const len = objectInfluences.length + 1; // All influences + the baseInfluenceSum + + const dataIndex = index * len + 1; // Skip the baseInfluenceSum at the beginning + + for ( let i = 0; i < objectInfluences.length; i ++ ) { + + objectInfluences[ i ] = array[ dataIndex + i ]; + + } + + } + + raycast( raycaster, intersects ) { + + const matrixWorld = this.matrixWorld; + const raycastTimes = this.count; + + _mesh$1.geometry = this.geometry; + _mesh$1.material = this.material; + + if ( _mesh$1.material === undefined ) return; + + // test with bounding sphere first + + if ( this.boundingSphere === null ) this.computeBoundingSphere(); + + _sphere$4.copy( this.boundingSphere ); + _sphere$4.applyMatrix4( matrixWorld ); + + if ( raycaster.ray.intersectsSphere( _sphere$4 ) === false ) return; + + // now test each instance + + for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) { + + // calculate the world matrix for each instance + + this.getMatrixAt( instanceId, _instanceLocalMatrix ); + + _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix ); + + // the mesh represents this single instance + + _mesh$1.matrixWorld = _instanceWorldMatrix; + + _mesh$1.raycast( raycaster, _instanceIntersects ); + + // process the result of raycast + + for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) { + + const intersect = _instanceIntersects[ i ]; + intersect.instanceId = instanceId; + intersect.object = this; + intersects.push( intersect ); + + } + + _instanceIntersects.length = 0; + + } + + } + + setColorAt( index, color ) { + + if ( this.instanceColor === null ) { + + this.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ).fill( 1 ), 3 ); + + } + + color.toArray( this.instanceColor.array, index * 3 ); + + } + + setMatrixAt( index, matrix ) { + + matrix.toArray( this.instanceMatrix.array, index * 16 ); + + } + + setMorphAt( index, object ) { + + const objectInfluences = object.morphTargetInfluences; + + const len = objectInfluences.length + 1; // morphBaseInfluence + all influences + + if ( this.morphTexture === null ) { + + this.morphTexture = new DataTexture( new Float32Array( len * this.count ), len, this.count, RedFormat, FloatType ); + + } + + const array = this.morphTexture.source.data.data; + + let morphInfluencesSum = 0; + + for ( let i = 0; i < objectInfluences.length; i ++ ) { + + morphInfluencesSum += objectInfluences[ i ]; + + } + + const morphBaseInfluence = this.geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; + + const dataIndex = len * index; + + array[ dataIndex ] = morphBaseInfluence; + + array.set( objectInfluences, dataIndex + 1 ); + + } + + updateMorphTargets() { + + } + + dispose() { + + this.dispatchEvent( { type: 'dispose' } ); + + if ( this.morphTexture !== null ) { + + this.morphTexture.dispose(); + this.morphTexture = null; + + } + + return this; + + } + +} + +const _vector1 = /*@__PURE__*/ new Vector3(); +const _vector2 = /*@__PURE__*/ new Vector3(); +const _normalMatrix = /*@__PURE__*/ new Matrix3(); + +class Plane { + + constructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) { + + this.isPlane = true; + + // normal is assumed to be normalized + + this.normal = normal; + this.constant = constant; + + } + + set( normal, constant ) { + + this.normal.copy( normal ); + this.constant = constant; + + return this; + + } + + setComponents( x, y, z, w ) { + + this.normal.set( x, y, z ); + this.constant = w; + + return this; + + } + + setFromNormalAndCoplanarPoint( normal, point ) { + + this.normal.copy( normal ); + this.constant = - point.dot( this.normal ); + + return this; + + } + + setFromCoplanarPoints( a, b, c ) { + + const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize(); + + // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? + + this.setFromNormalAndCoplanarPoint( normal, a ); + + return this; + + } + + copy( plane ) { + + this.normal.copy( plane.normal ); + this.constant = plane.constant; + + return this; + + } + + normalize() { + + // Note: will lead to a divide by zero if the plane is invalid. + + const inverseNormalLength = 1.0 / this.normal.length(); + this.normal.multiplyScalar( inverseNormalLength ); + this.constant *= inverseNormalLength; + + return this; + + } + + negate() { + + this.constant *= - 1; + this.normal.negate(); + + return this; + + } + + distanceToPoint( point ) { + + return this.normal.dot( point ) + this.constant; + + } + + distanceToSphere( sphere ) { + + return this.distanceToPoint( sphere.center ) - sphere.radius; + + } + + projectPoint( point, target ) { + + return target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) ); + + } + + intersectLine( line, target ) { + + const direction = line.delta( _vector1 ); + + const denominator = this.normal.dot( direction ); + + if ( denominator === 0 ) { + + // line is coplanar, return origin + if ( this.distanceToPoint( line.start ) === 0 ) { + + return target.copy( line.start ); + + } + + // Unsure if this is the correct method to handle this case. + return null; + + } + + const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; + + if ( t < 0 || t > 1 ) { + + return null; + + } + + return target.copy( line.start ).addScaledVector( direction, t ); + + } + + intersectsLine( line ) { + + // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. + + const startSign = this.distanceToPoint( line.start ); + const endSign = this.distanceToPoint( line.end ); + + return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); + + } + + intersectsBox( box ) { + + return box.intersectsPlane( this ); + + } + + intersectsSphere( sphere ) { + + return sphere.intersectsPlane( this ); + + } + + coplanarPoint( target ) { + + return target.copy( this.normal ).multiplyScalar( - this.constant ); + + } + + applyMatrix4( matrix, optionalNormalMatrix ) { + + const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix ); + + const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix ); + + const normal = this.normal.applyMatrix3( normalMatrix ).normalize(); + + this.constant = - referencePoint.dot( normal ); + + return this; + + } + + translate( offset ) { + + this.constant -= offset.dot( this.normal ); + + return this; + + } + + equals( plane ) { + + return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); + + } + + clone() { + + return new this.constructor().copy( this ); + + } + +} + +const _sphere$3 = /*@__PURE__*/ new Sphere(); +const _vector$6 = /*@__PURE__*/ new Vector3(); + +class Frustum { + + constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) { + + this.planes = [ p0, p1, p2, p3, p4, p5 ]; + + } + + set( p0, p1, p2, p3, p4, p5 ) { + + const planes = this.planes; + + planes[ 0 ].copy( p0 ); + planes[ 1 ].copy( p1 ); + planes[ 2 ].copy( p2 ); + planes[ 3 ].copy( p3 ); + planes[ 4 ].copy( p4 ); + planes[ 5 ].copy( p5 ); + + return this; + + } + + copy( frustum ) { + + const planes = this.planes; + + for ( let i = 0; i < 6; i ++ ) { + + planes[ i ].copy( frustum.planes[ i ] ); + + } + + return this; + + } + + setFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem ) { + + const planes = this.planes; + const me = m.elements; + const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; + const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; + const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; + const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; + + planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); + planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); + planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); + planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); + planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); + + if ( coordinateSystem === WebGLCoordinateSystem ) { + + planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); + + } else if ( coordinateSystem === WebGPUCoordinateSystem ) { + + planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize(); + + } else { + + throw new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem ); + + } + + return this; + + } + + intersectsObject( object ) { + + if ( object.boundingSphere !== undefined ) { + + if ( object.boundingSphere === null ) object.computeBoundingSphere(); + + _sphere$3.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld ); + + } else { + + const geometry = object.geometry; + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + _sphere$3.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); + + } + + return this.intersectsSphere( _sphere$3 ); + + } + + intersectsSprite( sprite ) { + + _sphere$3.center.set( 0, 0, 0 ); + _sphere$3.radius = 0.7071067811865476; + _sphere$3.applyMatrix4( sprite.matrixWorld ); + + return this.intersectsSphere( _sphere$3 ); + + } + + intersectsSphere( sphere ) { + + const planes = this.planes; + const center = sphere.center; + const negRadius = - sphere.radius; + + for ( let i = 0; i < 6; i ++ ) { + + const distance = planes[ i ].distanceToPoint( center ); + + if ( distance < negRadius ) { + + return false; + + } + + } + + return true; + + } + + intersectsBox( box ) { + + const planes = this.planes; + + for ( let i = 0; i < 6; i ++ ) { + + const plane = planes[ i ]; + + // corner at max distance + + _vector$6.x = plane.normal.x > 0 ? box.max.x : box.min.x; + _vector$6.y = plane.normal.y > 0 ? box.max.y : box.min.y; + _vector$6.z = plane.normal.z > 0 ? box.max.z : box.min.z; + + if ( plane.distanceToPoint( _vector$6 ) < 0 ) { + + return false; + + } + + } + + return true; + + } + + containsPoint( point ) { + + const planes = this.planes; + + for ( let i = 0; i < 6; i ++ ) { + + if ( planes[ i ].distanceToPoint( point ) < 0 ) { + + return false; + + } + + } + + return true; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + +} + +function sortOpaque( a, b ) { + + return a.z - b.z; + +} + +function sortTransparent( a, b ) { + + return b.z - a.z; + +} + +class MultiDrawRenderList { + + constructor() { + + this.index = 0; + this.pool = []; + this.list = []; + + } + + push( drawRange, z, index ) { + + const pool = this.pool; + const list = this.list; + if ( this.index >= pool.length ) { + + pool.push( { + + start: - 1, + count: - 1, + z: - 1, + index: - 1, + + } ); + + } + + const item = pool[ this.index ]; + list.push( item ); + this.index ++; + + item.start = drawRange.start; + item.count = drawRange.count; + item.z = z; + item.index = index; + + } + + reset() { + + this.list.length = 0; + this.index = 0; + + } + +} + +const _matrix$1 = /*@__PURE__*/ new Matrix4(); +const _invMatrixWorld = /*@__PURE__*/ new Matrix4(); +const _identityMatrix = /*@__PURE__*/ new Matrix4(); +const _whiteColor = /*@__PURE__*/ new Color( 1, 1, 1 ); +const _projScreenMatrix$3 = /*@__PURE__*/ new Matrix4(); +const _frustum$1 = /*@__PURE__*/ new Frustum(); +const _box$1 = /*@__PURE__*/ new Box3(); +const _sphere$2 = /*@__PURE__*/ new Sphere(); +const _vector$5 = /*@__PURE__*/ new Vector3(); +const _forward = /*@__PURE__*/ new Vector3(); +const _temp = /*@__PURE__*/ new Vector3(); +const _renderList = /*@__PURE__*/ new MultiDrawRenderList(); +const _mesh = /*@__PURE__*/ new Mesh(); +const _batchIntersects = []; + +// @TODO: SkinnedMesh support? +// @TODO: geometry.groups support? +// @TODO: geometry.drawRange support? +// @TODO: geometry.morphAttributes support? +// @TODO: Support uniform parameter per geometry +// @TODO: Add an "optimize" function to pack geometry and remove data gaps + +// copies data from attribute "src" into "target" starting at "targetOffset" +function copyAttributeData( src, target, targetOffset = 0 ) { + + const itemSize = target.itemSize; + if ( src.isInterleavedBufferAttribute || src.array.constructor !== target.array.constructor ) { + + // use the component getters and setters if the array data cannot + // be copied directly + const vertexCount = src.count; + for ( let i = 0; i < vertexCount; i ++ ) { + + for ( let c = 0; c < itemSize; c ++ ) { + + target.setComponent( i + targetOffset, c, src.getComponent( i, c ) ); + + } + + } + + } else { + + // faster copy approach using typed array set function + target.array.set( src.array, targetOffset * itemSize ); + + } + + target.needsUpdate = true; + +} + +class BatchedMesh extends Mesh { + + get maxInstanceCount() { + + return this._maxInstanceCount; + + } + + constructor( maxInstanceCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material ) { + + super( new BufferGeometry(), material ); + + this.isBatchedMesh = true; + this.perObjectFrustumCulled = true; + this.sortObjects = true; + this.boundingBox = null; + this.boundingSphere = null; + this.customSort = null; + + // stores visible, active, and geometry id per object + this._drawInfo = []; + + // instance ids that have been set as inactive, and are available to be overwritten + this._availableInstanceIds = []; + + // geometry information + this._drawRanges = []; + this._reservedRanges = []; + this._bounds = []; + + this._maxInstanceCount = maxInstanceCount; + this._maxVertexCount = maxVertexCount; + this._maxIndexCount = maxIndexCount; + + this._geometryInitialized = false; + this._geometryCount = 0; + this._multiDrawCounts = new Int32Array( maxInstanceCount ); + this._multiDrawStarts = new Int32Array( maxInstanceCount ); + this._multiDrawCount = 0; + this._multiDrawInstances = null; + this._visibilityChanged = true; + + // Local matrix per geometry by using data texture + this._matricesTexture = null; + this._indirectTexture = null; + this._colorsTexture = null; + + this._initMatricesTexture(); + this._initIndirectTexture(); + + } + + _initMatricesTexture() { + + // layout (1 matrix = 4 pixels) + // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) + // with 8x8 pixel texture max 16 matrices * 4 pixels = (8 * 8) + // 16x16 pixel texture max 64 matrices * 4 pixels = (16 * 16) + // 32x32 pixel texture max 256 matrices * 4 pixels = (32 * 32) + // 64x64 pixel texture max 1024 matrices * 4 pixels = (64 * 64) + + let size = Math.sqrt( this._maxInstanceCount * 4 ); // 4 pixels needed for 1 matrix + size = Math.ceil( size / 4 ) * 4; + size = Math.max( size, 4 ); + + const matricesArray = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel + const matricesTexture = new DataTexture( matricesArray, size, size, RGBAFormat, FloatType ); + + this._matricesTexture = matricesTexture; + + } + + _initIndirectTexture() { + + let size = Math.sqrt( this._maxInstanceCount ); + size = Math.ceil( size ); + + const indirectArray = new Uint32Array( size * size ); + const indirectTexture = new DataTexture( indirectArray, size, size, RedIntegerFormat, UnsignedIntType ); + + this._indirectTexture = indirectTexture; + + } + + _initColorsTexture() { + + let size = Math.sqrt( this._maxInstanceCount ); + size = Math.ceil( size ); + + // 4 floats per RGBA pixel initialized to white + const colorsArray = new Float32Array( size * size * 4 ).fill( 1 ); + const colorsTexture = new DataTexture( colorsArray, size, size, RGBAFormat, FloatType ); + colorsTexture.colorSpace = ColorManagement.workingColorSpace; + + this._colorsTexture = colorsTexture; + + } + + _initializeGeometry( reference ) { + + const geometry = this.geometry; + const maxVertexCount = this._maxVertexCount; + const maxIndexCount = this._maxIndexCount; + if ( this._geometryInitialized === false ) { + + for ( const attributeName in reference.attributes ) { + + const srcAttribute = reference.getAttribute( attributeName ); + const { array, itemSize, normalized } = srcAttribute; + + const dstArray = new array.constructor( maxVertexCount * itemSize ); + const dstAttribute = new BufferAttribute( dstArray, itemSize, normalized ); + + geometry.setAttribute( attributeName, dstAttribute ); + + } + + if ( reference.getIndex() !== null ) { + + // Reserve last u16 index for primitive restart. + const indexArray = maxVertexCount > 65535 + ? new Uint32Array( maxIndexCount ) + : new Uint16Array( maxIndexCount ); + + geometry.setIndex( new BufferAttribute( indexArray, 1 ) ); + + } + + this._geometryInitialized = true; + + } + + } + + // Make sure the geometry is compatible with the existing combined geometry attributes + _validateGeometry( geometry ) { + + // check to ensure the geometries are using consistent attributes and indices + const batchGeometry = this.geometry; + if ( Boolean( geometry.getIndex() ) !== Boolean( batchGeometry.getIndex() ) ) { + + throw new Error( 'BatchedMesh: All geometries must consistently have "index".' ); + + } + + for ( const attributeName in batchGeometry.attributes ) { + + if ( ! geometry.hasAttribute( attributeName ) ) { + + throw new Error( `BatchedMesh: Added geometry missing "${ attributeName }". All geometries must have consistent attributes.` ); + + } + + const srcAttribute = geometry.getAttribute( attributeName ); + const dstAttribute = batchGeometry.getAttribute( attributeName ); + if ( srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized ) { + + throw new Error( 'BatchedMesh: All attributes must have a consistent itemSize and normalized value.' ); + + } + + } + + } + + setCustomSort( func ) { + + this.customSort = func; + return this; + + } + + computeBoundingBox() { + + if ( this.boundingBox === null ) { + + this.boundingBox = new Box3(); + + } + + const boundingBox = this.boundingBox; + const drawInfo = this._drawInfo; + + boundingBox.makeEmpty(); + for ( let i = 0, l = drawInfo.length; i < l; i ++ ) { + + if ( drawInfo[ i ].active === false ) continue; + + const geometryId = drawInfo[ i ].geometryIndex; + this.getMatrixAt( i, _matrix$1 ); + this.getBoundingBoxAt( geometryId, _box$1 ).applyMatrix4( _matrix$1 ); + boundingBox.union( _box$1 ); + + } + + } + + computeBoundingSphere() { + + if ( this.boundingSphere === null ) { + + this.boundingSphere = new Sphere(); + + } + + const boundingSphere = this.boundingSphere; + const drawInfo = this._drawInfo; + + boundingSphere.makeEmpty(); + for ( let i = 0, l = drawInfo.length; i < l; i ++ ) { + + if ( drawInfo[ i ].active === false ) continue; + + const geometryId = drawInfo[ i ].geometryIndex; + this.getMatrixAt( i, _matrix$1 ); + this.getBoundingSphereAt( geometryId, _sphere$2 ).applyMatrix4( _matrix$1 ); + boundingSphere.union( _sphere$2 ); + + } + + } + + addInstance( geometryId ) { + + const atCapacity = this._drawInfo.length >= this.maxInstanceCount; + + // ensure we're not over geometry + if ( atCapacity && this._availableInstanceIds.length === 0 ) { + + throw new Error( 'BatchedMesh: Maximum item count reached.' ); + + } + + const instanceDrawInfo = { + visible: true, + active: true, + geometryIndex: geometryId, + }; + + let drawId = null; + + // Prioritize using previously freed instance ids + if ( this._availableInstanceIds.length > 0 ) { + + drawId = this._availableInstanceIds.pop(); + this._drawInfo[ drawId ] = instanceDrawInfo; + + } else { + + drawId = this._drawInfo.length; + this._drawInfo.push( instanceDrawInfo ); + + } + + const matricesTexture = this._matricesTexture; + const matricesArray = matricesTexture.image.data; + _identityMatrix.toArray( matricesArray, drawId * 16 ); + matricesTexture.needsUpdate = true; + + const colorsTexture = this._colorsTexture; + if ( colorsTexture ) { + + _whiteColor.toArray( colorsTexture.image.data, drawId * 4 ); + colorsTexture.needsUpdate = true; + + } + + return drawId; + + } + + addGeometry( geometry, vertexCount = - 1, indexCount = - 1 ) { + + this._initializeGeometry( geometry ); + + this._validateGeometry( geometry ); + + // ensure we're not over geometry + if ( this._drawInfo.length >= this._maxInstanceCount ) { + + throw new Error( 'BatchedMesh: Maximum item count reached.' ); + + } + + // get the necessary range fo the geometry + const reservedRange = { + vertexStart: - 1, + vertexCount: - 1, + indexStart: - 1, + indexCount: - 1, + }; + + let lastRange = null; + const reservedRanges = this._reservedRanges; + const drawRanges = this._drawRanges; + const bounds = this._bounds; + if ( this._geometryCount !== 0 ) { + + lastRange = reservedRanges[ reservedRanges.length - 1 ]; + + } + + if ( vertexCount === - 1 ) { + + reservedRange.vertexCount = geometry.getAttribute( 'position' ).count; + + } else { + + reservedRange.vertexCount = vertexCount; + + } + + if ( lastRange === null ) { + + reservedRange.vertexStart = 0; + + } else { + + reservedRange.vertexStart = lastRange.vertexStart + lastRange.vertexCount; + + } + + const index = geometry.getIndex(); + const hasIndex = index !== null; + if ( hasIndex ) { + + if ( indexCount === - 1 ) { + + reservedRange.indexCount = index.count; + + } else { + + reservedRange.indexCount = indexCount; + + } + + if ( lastRange === null ) { + + reservedRange.indexStart = 0; + + } else { + + reservedRange.indexStart = lastRange.indexStart + lastRange.indexCount; + + } + + } + + if ( + reservedRange.indexStart !== - 1 && + reservedRange.indexStart + reservedRange.indexCount > this._maxIndexCount || + reservedRange.vertexStart + reservedRange.vertexCount > this._maxVertexCount + ) { + + throw new Error( 'BatchedMesh: Reserved space request exceeds the maximum buffer size.' ); + + } + + // update id + const geometryId = this._geometryCount; + this._geometryCount ++; + + // add the reserved range and draw range objects + reservedRanges.push( reservedRange ); + drawRanges.push( { + start: hasIndex ? reservedRange.indexStart : reservedRange.vertexStart, + count: - 1 + } ); + bounds.push( { + boxInitialized: false, + box: new Box3(), + + sphereInitialized: false, + sphere: new Sphere() + } ); + + // update the geometry + this.setGeometryAt( geometryId, geometry ); + + return geometryId; + + } + + setGeometryAt( geometryId, geometry ) { + + if ( geometryId >= this._geometryCount ) { + + throw new Error( 'BatchedMesh: Maximum geometry count reached.' ); + + } + + this._validateGeometry( geometry ); + + const batchGeometry = this.geometry; + const hasIndex = batchGeometry.getIndex() !== null; + const dstIndex = batchGeometry.getIndex(); + const srcIndex = geometry.getIndex(); + const reservedRange = this._reservedRanges[ geometryId ]; + if ( + hasIndex && + srcIndex.count > reservedRange.indexCount || + geometry.attributes.position.count > reservedRange.vertexCount + ) { + + throw new Error( 'BatchedMesh: Reserved space not large enough for provided geometry.' ); + + } + + // copy geometry over + const vertexStart = reservedRange.vertexStart; + const vertexCount = reservedRange.vertexCount; + for ( const attributeName in batchGeometry.attributes ) { + + // copy attribute data + const srcAttribute = geometry.getAttribute( attributeName ); + const dstAttribute = batchGeometry.getAttribute( attributeName ); + copyAttributeData( srcAttribute, dstAttribute, vertexStart ); + + // fill the rest in with zeroes + const itemSize = srcAttribute.itemSize; + for ( let i = srcAttribute.count, l = vertexCount; i < l; i ++ ) { + + const index = vertexStart + i; + for ( let c = 0; c < itemSize; c ++ ) { + + dstAttribute.setComponent( index, c, 0 ); + + } + + } + + dstAttribute.needsUpdate = true; + dstAttribute.addUpdateRange( vertexStart * itemSize, vertexCount * itemSize ); + + } + + // copy index + if ( hasIndex ) { + + const indexStart = reservedRange.indexStart; + + // copy index data over + for ( let i = 0; i < srcIndex.count; i ++ ) { + + dstIndex.setX( indexStart + i, vertexStart + srcIndex.getX( i ) ); + + } + + // fill the rest in with zeroes + for ( let i = srcIndex.count, l = reservedRange.indexCount; i < l; i ++ ) { + + dstIndex.setX( indexStart + i, vertexStart ); + + } + + dstIndex.needsUpdate = true; + dstIndex.addUpdateRange( indexStart, reservedRange.indexCount ); + + } + + // store the bounding boxes + const bound = this._bounds[ geometryId ]; + if ( geometry.boundingBox !== null ) { + + bound.box.copy( geometry.boundingBox ); + bound.boxInitialized = true; + + } else { + + bound.boxInitialized = false; + + } + + if ( geometry.boundingSphere !== null ) { + + bound.sphere.copy( geometry.boundingSphere ); + bound.sphereInitialized = true; + + } else { + + bound.sphereInitialized = false; + + } + + // set drawRange count + const drawRange = this._drawRanges[ geometryId ]; + const posAttr = geometry.getAttribute( 'position' ); + drawRange.count = hasIndex ? srcIndex.count : posAttr.count; + this._visibilityChanged = true; + + return geometryId; + + } + + /* + deleteGeometry( geometryId ) { + + // TODO: delete geometry and associated instances + + } + */ + + deleteInstance( instanceId ) { + + const drawInfo = this._drawInfo; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return this; + + } + + drawInfo[ instanceId ].active = false; + this._availableInstanceIds.push( instanceId ); + this._visibilityChanged = true; + + return this; + + } + + // get bounding box and compute it if it doesn't exist + getBoundingBoxAt( geometryId, target ) { + + if ( geometryId >= this._geometryCount ) { + + return null; + + } + + // compute bounding box + const bound = this._bounds[ geometryId ]; + const box = bound.box; + const geometry = this.geometry; + if ( bound.boxInitialized === false ) { + + box.makeEmpty(); + + const index = geometry.index; + const position = geometry.attributes.position; + const drawRange = this._drawRanges[ geometryId ]; + for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) { + + let iv = i; + if ( index ) { + + iv = index.getX( iv ); + + } + + box.expandByPoint( _vector$5.fromBufferAttribute( position, iv ) ); + + } + + bound.boxInitialized = true; + + } + + target.copy( box ); + return target; + + } + + // get bounding sphere and compute it if it doesn't exist + getBoundingSphereAt( geometryId, target ) { + + if ( geometryId >= this._geometryCount ) { + + return null; + + } + + // compute bounding sphere + const bound = this._bounds[ geometryId ]; + const sphere = bound.sphere; + const geometry = this.geometry; + if ( bound.sphereInitialized === false ) { + + sphere.makeEmpty(); + + this.getBoundingBoxAt( geometryId, _box$1 ); + _box$1.getCenter( sphere.center ); + + const index = geometry.index; + const position = geometry.attributes.position; + const drawRange = this._drawRanges[ geometryId ]; + + let maxRadiusSq = 0; + for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) { + + let iv = i; + if ( index ) { + + iv = index.getX( iv ); + + } + + _vector$5.fromBufferAttribute( position, iv ); + maxRadiusSq = Math.max( maxRadiusSq, sphere.center.distanceToSquared( _vector$5 ) ); + + } + + sphere.radius = Math.sqrt( maxRadiusSq ); + bound.sphereInitialized = true; + + } + + target.copy( sphere ); + return target; + + } + + setMatrixAt( instanceId, matrix ) { + + // @TODO: Map geometryId to index of the arrays because + // optimize() can make geometryId mismatch the index + + const drawInfo = this._drawInfo; + const matricesTexture = this._matricesTexture; + const matricesArray = this._matricesTexture.image.data; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return this; + + } + + matrix.toArray( matricesArray, instanceId * 16 ); + matricesTexture.needsUpdate = true; + + return this; + + } + + getMatrixAt( instanceId, matrix ) { + + const drawInfo = this._drawInfo; + const matricesArray = this._matricesTexture.image.data; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return null; + + } + + return matrix.fromArray( matricesArray, instanceId * 16 ); + + } + + setColorAt( instanceId, color ) { + + if ( this._colorsTexture === null ) { + + this._initColorsTexture(); + + } + + // @TODO: Map id to index of the arrays because + // optimize() can make id mismatch the index + + const colorsTexture = this._colorsTexture; + const colorsArray = this._colorsTexture.image.data; + const drawInfo = this._drawInfo; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return this; + + } + + color.toArray( colorsArray, instanceId * 4 ); + colorsTexture.needsUpdate = true; + + return this; + + } + + getColorAt( instanceId, color ) { + + const colorsArray = this._colorsTexture.image.data; + const drawInfo = this._drawInfo; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return null; + + } + + return color.fromArray( colorsArray, instanceId * 4 ); + + } + + setVisibleAt( instanceId, value ) { + + // if the geometry is out of range, not active, or visibility state + // does not change then return early + const drawInfo = this._drawInfo; + if ( + instanceId >= drawInfo.length || + drawInfo[ instanceId ].active === false || + drawInfo[ instanceId ].visible === value + ) { + + return this; + + } + + drawInfo[ instanceId ].visible = value; + this._visibilityChanged = true; + + return this; + + } + + getVisibleAt( instanceId ) { + + // return early if the geometry is out of range or not active + const drawInfo = this._drawInfo; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return false; + + } + + return drawInfo[ instanceId ].visible; + + } + + setGeometryIdAt( instanceId, geometryId ) { + + // return early if the geometry is out of range or not active + const drawInfo = this._drawInfo; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return null; + + } + + // check if the provided geometryId is within the valid range + if ( geometryId < 0 || geometryId >= this._geometryCount ) { + + return null; + + } + + drawInfo[ instanceId ].geometryIndex = geometryId; + + return this; + + } + + getGeometryIdAt( instanceId ) { + + const drawInfo = this._drawInfo; + if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) { + + return - 1; + + } + + return drawInfo[ instanceId ].geometryIndex; + + } + + getGeometryRangeAt( geometryId, target = {} ) { + + if ( geometryId < 0 || geometryId >= this._geometryCount ) { + + return null; + + } + + const drawRange = this._drawRanges[ geometryId ]; + + target.start = drawRange.start; + target.count = drawRange.count; + + return target; + + } + + raycast( raycaster, intersects ) { + + const drawInfo = this._drawInfo; + const drawRanges = this._drawRanges; + const matrixWorld = this.matrixWorld; + const batchGeometry = this.geometry; + + // iterate over each geometry + _mesh.material = this.material; + _mesh.geometry.index = batchGeometry.index; + _mesh.geometry.attributes = batchGeometry.attributes; + if ( _mesh.geometry.boundingBox === null ) { + + _mesh.geometry.boundingBox = new Box3(); + + } + + if ( _mesh.geometry.boundingSphere === null ) { + + _mesh.geometry.boundingSphere = new Sphere(); + + } + + for ( let i = 0, l = drawInfo.length; i < l; i ++ ) { + + if ( ! drawInfo[ i ].visible || ! drawInfo[ i ].active ) { + + continue; + + } + + const geometryId = drawInfo[ i ].geometryIndex; + const drawRange = drawRanges[ geometryId ]; + _mesh.geometry.setDrawRange( drawRange.start, drawRange.count ); + + // ge the intersects + this.getMatrixAt( i, _mesh.matrixWorld ).premultiply( matrixWorld ); + this.getBoundingBoxAt( geometryId, _mesh.geometry.boundingBox ); + this.getBoundingSphereAt( geometryId, _mesh.geometry.boundingSphere ); + _mesh.raycast( raycaster, _batchIntersects ); + + // add batch id to the intersects + for ( let j = 0, l = _batchIntersects.length; j < l; j ++ ) { + + const intersect = _batchIntersects[ j ]; + intersect.object = this; + intersect.batchId = i; + intersects.push( intersect ); + + } + + _batchIntersects.length = 0; + + } + + _mesh.material = null; + _mesh.geometry.index = null; + _mesh.geometry.attributes = {}; + _mesh.geometry.setDrawRange( 0, Infinity ); + + } + + copy( source ) { + + super.copy( source ); + + this.geometry = source.geometry.clone(); + this.perObjectFrustumCulled = source.perObjectFrustumCulled; + this.sortObjects = source.sortObjects; + this.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null; + this.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null; + + this._drawRanges = source._drawRanges.map( range => ( { ...range } ) ); + this._reservedRanges = source._reservedRanges.map( range => ( { ...range } ) ); + + this._drawInfo = source._drawInfo.map( inf => ( { ...inf } ) ); + this._bounds = source._bounds.map( bound => ( { + boxInitialized: bound.boxInitialized, + box: bound.box.clone(), + + sphereInitialized: bound.sphereInitialized, + sphere: bound.sphere.clone() + } ) ); + + this._maxInstanceCount = source._maxInstanceCount; + this._maxVertexCount = source._maxVertexCount; + this._maxIndexCount = source._maxIndexCount; + + this._geometryInitialized = source._geometryInitialized; + this._geometryCount = source._geometryCount; + this._multiDrawCounts = source._multiDrawCounts.slice(); + this._multiDrawStarts = source._multiDrawStarts.slice(); + + this._matricesTexture = source._matricesTexture.clone(); + this._matricesTexture.image.data = this._matricesTexture.image.data.slice(); + + if ( this._colorsTexture !== null ) { + + this._colorsTexture = source._colorsTexture.clone(); + this._colorsTexture.image.data = this._colorsTexture.image.data.slice(); + + } + + return this; + + } + + dispose() { + + // Assuming the geometry is not shared with other meshes + this.geometry.dispose(); + + this._matricesTexture.dispose(); + this._matricesTexture = null; + + this._indirectTexture.dispose(); + this._indirectTexture = null; + + if ( this._colorsTexture !== null ) { + + this._colorsTexture.dispose(); + this._colorsTexture = null; + + } + + return this; + + } + + onBeforeRender( renderer, scene, camera, geometry, material/*, _group*/ ) { + + // if visibility has not changed and frustum culling and object sorting is not required + // then skip iterating over all items + if ( ! this._visibilityChanged && ! this.perObjectFrustumCulled && ! this.sortObjects ) { + + return; + + } + + // the indexed version of the multi draw function requires specifying the start + // offset in bytes. + const index = geometry.getIndex(); + const bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT; + + const drawInfo = this._drawInfo; + const multiDrawStarts = this._multiDrawStarts; + const multiDrawCounts = this._multiDrawCounts; + const drawRanges = this._drawRanges; + const perObjectFrustumCulled = this.perObjectFrustumCulled; + const indirectTexture = this._indirectTexture; + const indirectArray = indirectTexture.image.data; + + // prepare the frustum in the local frame + if ( perObjectFrustumCulled ) { + + _projScreenMatrix$3 + .multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ) + .multiply( this.matrixWorld ); + _frustum$1.setFromProjectionMatrix( + _projScreenMatrix$3, + renderer.coordinateSystem + ); + + } + + let count = 0; + if ( this.sortObjects ) { + + // get the camera position in the local frame + _invMatrixWorld.copy( this.matrixWorld ).invert(); + _vector$5.setFromMatrixPosition( camera.matrixWorld ).applyMatrix4( _invMatrixWorld ); + _forward.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ).transformDirection( _invMatrixWorld ); + + for ( let i = 0, l = drawInfo.length; i < l; i ++ ) { + + if ( drawInfo[ i ].visible && drawInfo[ i ].active ) { + + const geometryId = drawInfo[ i ].geometryIndex; + + // get the bounds in world space + this.getMatrixAt( i, _matrix$1 ); + this.getBoundingSphereAt( geometryId, _sphere$2 ).applyMatrix4( _matrix$1 ); + + // determine whether the batched geometry is within the frustum + let culled = false; + if ( perObjectFrustumCulled ) { + + culled = ! _frustum$1.intersectsSphere( _sphere$2 ); + + } + + if ( ! culled ) { + + // get the distance from camera used for sorting + const z = _temp.subVectors( _sphere$2.center, _vector$5 ).dot( _forward ); + _renderList.push( drawRanges[ geometryId ], z, i ); + + } + + } + + } + + // Sort the draw ranges and prep for rendering + const list = _renderList.list; + const customSort = this.customSort; + if ( customSort === null ) { + + list.sort( material.transparent ? sortTransparent : sortOpaque ); + + } else { + + customSort.call( this, list, camera ); + + } + + for ( let i = 0, l = list.length; i < l; i ++ ) { + + const item = list[ i ]; + multiDrawStarts[ count ] = item.start * bytesPerElement; + multiDrawCounts[ count ] = item.count; + indirectArray[ count ] = item.index; + count ++; + + } + + _renderList.reset(); + + } else { + + for ( let i = 0, l = drawInfo.length; i < l; i ++ ) { + + if ( drawInfo[ i ].visible && drawInfo[ i ].active ) { + + const geometryId = drawInfo[ i ].geometryIndex; + + // determine whether the batched geometry is within the frustum + let culled = false; + if ( perObjectFrustumCulled ) { + + // get the bounds in world space + this.getMatrixAt( i, _matrix$1 ); + this.getBoundingSphereAt( geometryId, _sphere$2 ).applyMatrix4( _matrix$1 ); + culled = ! _frustum$1.intersectsSphere( _sphere$2 ); + + } + + if ( ! culled ) { + + const range = drawRanges[ geometryId ]; + multiDrawStarts[ count ] = range.start * bytesPerElement; + multiDrawCounts[ count ] = range.count; + indirectArray[ count ] = i; + count ++; + + } + + } + + } + + } + + indirectTexture.needsUpdate = true; + this._multiDrawCount = count; + this._visibilityChanged = false; + + } + + onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial/* , group */ ) { + + this.onBeforeRender( renderer, null, shadowCamera, geometry, depthMaterial ); + + } + +} + +class LineBasicMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isLineBasicMaterial = true; + + this.type = 'LineBasicMaterial'; + + this.color = new Color( 0xffffff ); + + this.map = null; + + this.linewidth = 1; + this.linecap = 'round'; + this.linejoin = 'round'; + + this.fog = true; + + this.setValues( parameters ); + + } + + + copy( source ) { + + super.copy( source ); + + this.color.copy( source.color ); + + this.map = source.map; + + this.linewidth = source.linewidth; + this.linecap = source.linecap; + this.linejoin = source.linejoin; + + this.fog = source.fog; + + return this; + + } + +} + +const _vStart = /*@__PURE__*/ new Vector3(); +const _vEnd = /*@__PURE__*/ new Vector3(); + +const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4(); +const _ray$1 = /*@__PURE__*/ new Ray(); +const _sphere$1 = /*@__PURE__*/ new Sphere(); + +const _intersectPointOnRay = /*@__PURE__*/ new Vector3(); +const _intersectPointOnSegment = /*@__PURE__*/ new Vector3(); + +class Line extends Object3D { + + constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) { + + super(); + + this.isLine = true; + + this.type = 'Line'; + + this.geometry = geometry; + this.material = material; + + this.updateMorphTargets(); + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; + this.geometry = source.geometry; + + return this; + + } + + computeLineDistances() { + + const geometry = this.geometry; + + // we assume non-indexed geometry + + if ( geometry.index === null ) { + + const positionAttribute = geometry.attributes.position; + const lineDistances = [ 0 ]; + + for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) { + + _vStart.fromBufferAttribute( positionAttribute, i - 1 ); + _vEnd.fromBufferAttribute( positionAttribute, i ); + + lineDistances[ i ] = lineDistances[ i - 1 ]; + lineDistances[ i ] += _vStart.distanceTo( _vEnd ); + + } + + geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); + + } else { + + console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); + + } + + return this; + + } + + raycast( raycaster, intersects ) { + + const geometry = this.geometry; + const matrixWorld = this.matrixWorld; + const threshold = raycaster.params.Line.threshold; + const drawRange = geometry.drawRange; + + // Checking boundingSphere distance to ray + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + _sphere$1.copy( geometry.boundingSphere ); + _sphere$1.applyMatrix4( matrixWorld ); + _sphere$1.radius += threshold; + + if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return; + + // + + _inverseMatrix$1.copy( matrixWorld ).invert(); + _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 ); + + const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); + const localThresholdSq = localThreshold * localThreshold; + + const step = this.isLineSegments ? 2 : 1; + + const index = geometry.index; + const attributes = geometry.attributes; + const positionAttribute = attributes.position; + + if ( index !== null ) { + + const start = Math.max( 0, drawRange.start ); + const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); + + for ( let i = start, l = end - 1; i < l; i += step ) { + + const a = index.getX( i ); + const b = index.getX( i + 1 ); + + const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, a, b ); + + if ( intersect ) { + + intersects.push( intersect ); + + } + + } + + if ( this.isLineLoop ) { + + const a = index.getX( end - 1 ); + const b = index.getX( start ); + + const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, a, b ); + + if ( intersect ) { + + intersects.push( intersect ); + + } + + } + + } else { + + const start = Math.max( 0, drawRange.start ); + const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); + + for ( let i = start, l = end - 1; i < l; i += step ) { + + const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, i, i + 1 ); + + if ( intersect ) { + + intersects.push( intersect ); + + } + + } + + if ( this.isLineLoop ) { + + const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, end - 1, start ); + + if ( intersect ) { + + intersects.push( intersect ); + + } + + } + + } + + } + + updateMorphTargets() { + + const geometry = this.geometry; + + const morphAttributes = geometry.morphAttributes; + const keys = Object.keys( morphAttributes ); + + if ( keys.length > 0 ) { + + const morphAttribute = morphAttributes[ keys[ 0 ] ]; + + if ( morphAttribute !== undefined ) { + + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; + + for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { + + const name = morphAttribute[ m ].name || String( m ); + + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ name ] = m; + + } + + } + + } + + } + +} + +function checkIntersection( object, raycaster, ray, thresholdSq, a, b ) { + + const positionAttribute = object.geometry.attributes.position; + + _vStart.fromBufferAttribute( positionAttribute, a ); + _vEnd.fromBufferAttribute( positionAttribute, b ); + + const distSq = ray.distanceSqToSegment( _vStart, _vEnd, _intersectPointOnRay, _intersectPointOnSegment ); + + if ( distSq > thresholdSq ) return; + + _intersectPointOnRay.applyMatrix4( object.matrixWorld ); // Move back to world space for distance calculation + + const distance = raycaster.ray.origin.distanceTo( _intersectPointOnRay ); + + if ( distance < raycaster.near || distance > raycaster.far ) return; + + return { + + distance: distance, + // What do we want? intersection point on the ray or on the segment?? + // point: raycaster.ray.at( distance ), + point: _intersectPointOnSegment.clone().applyMatrix4( object.matrixWorld ), + index: a, + face: null, + faceIndex: null, + barycoord: null, + object: object + + }; + +} + +const _start = /*@__PURE__*/ new Vector3(); +const _end = /*@__PURE__*/ new Vector3(); + +class LineSegments extends Line { + + constructor( geometry, material ) { + + super( geometry, material ); + + this.isLineSegments = true; + + this.type = 'LineSegments'; + + } + + computeLineDistances() { + + const geometry = this.geometry; + + // we assume non-indexed geometry + + if ( geometry.index === null ) { + + const positionAttribute = geometry.attributes.position; + const lineDistances = []; + + for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) { + + _start.fromBufferAttribute( positionAttribute, i ); + _end.fromBufferAttribute( positionAttribute, i + 1 ); + + lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; + lineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end ); + + } + + geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); + + } else { + + console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); + + } + + return this; + + } + +} + +class LineLoop extends Line { + + constructor( geometry, material ) { + + super( geometry, material ); + + this.isLineLoop = true; + + this.type = 'LineLoop'; + + } + +} + +class PointsMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isPointsMaterial = true; + + this.type = 'PointsMaterial'; + + this.color = new Color( 0xffffff ); + + this.map = null; + + this.alphaMap = null; + + this.size = 1; + this.sizeAttenuation = true; + + this.fog = true; + + this.setValues( parameters ); + + } + + copy( source ) { + + super.copy( source ); + + this.color.copy( source.color ); + + this.map = source.map; + + this.alphaMap = source.alphaMap; + + this.size = source.size; + this.sizeAttenuation = source.sizeAttenuation; + + this.fog = source.fog; + + return this; + + } + +} + +const _inverseMatrix = /*@__PURE__*/ new Matrix4(); +const _ray = /*@__PURE__*/ new Ray(); +const _sphere = /*@__PURE__*/ new Sphere(); +const _position$2 = /*@__PURE__*/ new Vector3(); + +class Points extends Object3D { + + constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) { + + super(); + + this.isPoints = true; + + this.type = 'Points'; + + this.geometry = geometry; + this.material = material; + + this.updateMorphTargets(); + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; + this.geometry = source.geometry; + + return this; + + } + + raycast( raycaster, intersects ) { + + const geometry = this.geometry; + const matrixWorld = this.matrixWorld; + const threshold = raycaster.params.Points.threshold; + const drawRange = geometry.drawRange; + + // Checking boundingSphere distance to ray + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + _sphere.copy( geometry.boundingSphere ); + _sphere.applyMatrix4( matrixWorld ); + _sphere.radius += threshold; + + if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return; + + // + + _inverseMatrix.copy( matrixWorld ).invert(); + _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix ); + + const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); + const localThresholdSq = localThreshold * localThreshold; + + const index = geometry.index; + const attributes = geometry.attributes; + const positionAttribute = attributes.position; + + if ( index !== null ) { + + const start = Math.max( 0, drawRange.start ); + const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); + + for ( let i = start, il = end; i < il; i ++ ) { + + const a = index.getX( i ); + + _position$2.fromBufferAttribute( positionAttribute, a ); + + testPoint( _position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this ); + + } + + } else { + + const start = Math.max( 0, drawRange.start ); + const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); + + for ( let i = start, l = end; i < l; i ++ ) { + + _position$2.fromBufferAttribute( positionAttribute, i ); + + testPoint( _position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this ); + + } + + } + + } + + updateMorphTargets() { + + const geometry = this.geometry; + + const morphAttributes = geometry.morphAttributes; + const keys = Object.keys( morphAttributes ); + + if ( keys.length > 0 ) { + + const morphAttribute = morphAttributes[ keys[ 0 ] ]; + + if ( morphAttribute !== undefined ) { + + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; + + for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { + + const name = morphAttribute[ m ].name || String( m ); + + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ name ] = m; + + } + + } + + } + + } + +} + +function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) { + + const rayPointDistanceSq = _ray.distanceSqToPoint( point ); + + if ( rayPointDistanceSq < localThresholdSq ) { + + const intersectPoint = new Vector3(); + + _ray.closestPointToPoint( point, intersectPoint ); + intersectPoint.applyMatrix4( matrixWorld ); + + const distance = raycaster.ray.origin.distanceTo( intersectPoint ); + + if ( distance < raycaster.near || distance > raycaster.far ) return; + + intersects.push( { + + distance: distance, + distanceToRay: Math.sqrt( rayPointDistanceSq ), + point: intersectPoint, + index: index, + face: null, + faceIndex: null, + barycoord: null, + object: object + + } ); + + } + +} + +class Group extends Object3D { + + constructor() { + + super(); + + this.isGroup = true; + + this.type = 'Group'; + + } + +} + +class VideoTexture extends Texture { + + constructor( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + + super( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.isVideoTexture = true; + + this.minFilter = minFilter !== undefined ? minFilter : LinearFilter; + this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; + + this.generateMipmaps = false; + + const scope = this; + + function updateVideo() { + + scope.needsUpdate = true; + video.requestVideoFrameCallback( updateVideo ); + + } + + if ( 'requestVideoFrameCallback' in video ) { + + video.requestVideoFrameCallback( updateVideo ); + + } + + } + + clone() { + + return new this.constructor( this.image ).copy( this ); + + } + + update() { + + const video = this.image; + const hasVideoFrameCallback = 'requestVideoFrameCallback' in video; + + if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) { + + this.needsUpdate = true; + + } + + } + +} + +class FramebufferTexture extends Texture { + + constructor( width, height ) { + + super( { width, height } ); + + this.isFramebufferTexture = true; + + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; + + this.generateMipmaps = false; + + this.needsUpdate = true; + + } + +} + +class CompressedTexture extends Texture { + + constructor( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, colorSpace ) { + + super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); + + this.isCompressedTexture = true; + + this.image = { width: width, height: height }; + this.mipmaps = mipmaps; + + // no flipping for cube textures + // (also flipping doesn't work for compressed textures ) + + this.flipY = false; + + // can't generate mipmaps for compressed textures + // mips must be embedded in DDS files + + this.generateMipmaps = false; + + } + +} + +class CompressedArrayTexture extends CompressedTexture { + + constructor( mipmaps, width, height, depth, format, type ) { + + super( mipmaps, width, height, format, type ); + + this.isCompressedArrayTexture = true; + this.image.depth = depth; + this.wrapR = ClampToEdgeWrapping; + + this.layerUpdates = new Set(); + + } + + addLayerUpdate( layerIndex ) { + + this.layerUpdates.add( layerIndex ); + + } + + clearLayerUpdates() { + + this.layerUpdates.clear(); + + } + +} + +class CompressedCubeTexture extends CompressedTexture { + + constructor( images, format, type ) { + + super( undefined, images[ 0 ].width, images[ 0 ].height, format, type, CubeReflectionMapping ); + + this.isCompressedCubeTexture = true; + this.isCubeTexture = true; + + this.image = images; + + } + +} + +class CanvasTexture extends Texture { + + constructor( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + + super( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.isCanvasTexture = true; + + this.needsUpdate = true; + + } + +} + +class DepthTexture extends Texture { + + constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format = DepthFormat ) { + + if ( format !== DepthFormat && format !== DepthStencilFormat ) { + + throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); + + } + + if ( type === undefined && format === DepthFormat ) type = UnsignedIntType; + if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; + + super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.isDepthTexture = true; + + this.image = { width: width, height: height }; + + this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; + this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; + + this.flipY = false; + this.generateMipmaps = false; + + this.compareFunction = null; + + } + + + copy( source ) { + + super.copy( source ); + + this.compareFunction = source.compareFunction; + + return this; + + } + + toJSON( meta ) { + + const data = super.toJSON( meta ); + + if ( this.compareFunction !== null ) data.compareFunction = this.compareFunction; + + return data; + + } + +} + +/** + * Extensible curve object. + * + * Some common of curve methods: + * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget ) + * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget ) + * .getPoints(), .getSpacedPoints() + * .getLength() + * .updateArcLengths() + * + * This following curves inherit from THREE.Curve: + * + * -- 2D curves -- + * THREE.ArcCurve + * THREE.CubicBezierCurve + * THREE.EllipseCurve + * THREE.LineCurve + * THREE.QuadraticBezierCurve + * THREE.SplineCurve + * + * -- 3D curves -- + * THREE.CatmullRomCurve3 + * THREE.CubicBezierCurve3 + * THREE.LineCurve3 + * THREE.QuadraticBezierCurve3 + * + * A series of curves can be represented as a THREE.CurvePath. + * + **/ + +class Curve { + + constructor() { + + this.type = 'Curve'; + + this.arcLengthDivisions = 200; + + } + + // Virtual base class method to overwrite and implement in subclasses + // - t [0 .. 1] + + getPoint( /* t, optionalTarget */ ) { + + console.warn( 'THREE.Curve: .getPoint() not implemented.' ); + return null; + + } + + // Get point at relative position in curve according to arc length + // - u [0 .. 1] + + getPointAt( u, optionalTarget ) { + + const t = this.getUtoTmapping( u ); + return this.getPoint( t, optionalTarget ); + + } + + // Get sequence of points using getPoint( t ) + + getPoints( divisions = 5 ) { + + const points = []; + + for ( let d = 0; d <= divisions; d ++ ) { + + points.push( this.getPoint( d / divisions ) ); + + } + + return points; + + } + + // Get sequence of points using getPointAt( u ) + + getSpacedPoints( divisions = 5 ) { + + const points = []; + + for ( let d = 0; d <= divisions; d ++ ) { + + points.push( this.getPointAt( d / divisions ) ); + + } + + return points; + + } + + // Get total curve arc length + + getLength() { + + const lengths = this.getLengths(); + return lengths[ lengths.length - 1 ]; + + } + + // Get list of cumulative segment lengths + + getLengths( divisions = this.arcLengthDivisions ) { + + if ( this.cacheArcLengths && + ( this.cacheArcLengths.length === divisions + 1 ) && + ! this.needsUpdate ) { + + return this.cacheArcLengths; + + } + + this.needsUpdate = false; + + const cache = []; + let current, last = this.getPoint( 0 ); + let sum = 0; + + cache.push( 0 ); + + for ( let p = 1; p <= divisions; p ++ ) { + + current = this.getPoint( p / divisions ); + sum += current.distanceTo( last ); + cache.push( sum ); + last = current; + + } + + this.cacheArcLengths = cache; + + return cache; // { sums: cache, sum: sum }; Sum is in the last element. + + } + + updateArcLengths() { + + this.needsUpdate = true; + this.getLengths(); + + } + + // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant + + getUtoTmapping( u, distance ) { + + const arcLengths = this.getLengths(); + + let i = 0; + const il = arcLengths.length; + + let targetArcLength; // The targeted u distance value to get + + if ( distance ) { + + targetArcLength = distance; + + } else { + + targetArcLength = u * arcLengths[ il - 1 ]; + + } + + // binary search for the index with largest value smaller than target u distance + + let low = 0, high = il - 1, comparison; + + while ( low <= high ) { + + i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats + + comparison = arcLengths[ i ] - targetArcLength; + + if ( comparison < 0 ) { + + low = i + 1; + + } else if ( comparison > 0 ) { + + high = i - 1; + + } else { + + high = i; + break; + + // DONE + + } + + } + + i = high; + + if ( arcLengths[ i ] === targetArcLength ) { + + return i / ( il - 1 ); + + } + + // we could get finer grain at lengths, or use simple interpolation between two points + + const lengthBefore = arcLengths[ i ]; + const lengthAfter = arcLengths[ i + 1 ]; + + const segmentLength = lengthAfter - lengthBefore; + + // determine where we are between the 'before' and 'after' points + + const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + + // add that fractional amount to t + + const t = ( i + segmentFraction ) / ( il - 1 ); + + return t; + + } + + // Returns a unit vector tangent at t + // In case any sub curve does not implement its tangent derivation, + // 2 points a small delta apart will be used to find its gradient + // which seems to give a reasonable approximation + + getTangent( t, optionalTarget ) { + + const delta = 0.0001; + let t1 = t - delta; + let t2 = t + delta; + + // Capping in case of danger + + if ( t1 < 0 ) t1 = 0; + if ( t2 > 1 ) t2 = 1; + + const pt1 = this.getPoint( t1 ); + const pt2 = this.getPoint( t2 ); + + const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() ); + + tangent.copy( pt2 ).sub( pt1 ).normalize(); + + return tangent; + + } + + getTangentAt( u, optionalTarget ) { + + const t = this.getUtoTmapping( u ); + return this.getTangent( t, optionalTarget ); + + } + + computeFrenetFrames( segments, closed ) { + + // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf + + const normal = new Vector3(); + + const tangents = []; + const normals = []; + const binormals = []; + + const vec = new Vector3(); + const mat = new Matrix4(); + + // compute the tangent vectors for each segment on the curve + + for ( let i = 0; i <= segments; i ++ ) { + + const u = i / segments; + + tangents[ i ] = this.getTangentAt( u, new Vector3() ); + + } + + // select an initial normal vector perpendicular to the first tangent vector, + // and in the direction of the minimum tangent xyz component + + normals[ 0 ] = new Vector3(); + binormals[ 0 ] = new Vector3(); + let min = Number.MAX_VALUE; + const tx = Math.abs( tangents[ 0 ].x ); + const ty = Math.abs( tangents[ 0 ].y ); + const tz = Math.abs( tangents[ 0 ].z ); + + if ( tx <= min ) { + + min = tx; + normal.set( 1, 0, 0 ); + + } + + if ( ty <= min ) { + + min = ty; + normal.set( 0, 1, 0 ); + + } + + if ( tz <= min ) { + + normal.set( 0, 0, 1 ); + + } + + vec.crossVectors( tangents[ 0 ], normal ).normalize(); + + normals[ 0 ].crossVectors( tangents[ 0 ], vec ); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); + + + // compute the slowly-varying normal and binormal vectors for each segment on the curve + + for ( let i = 1; i <= segments; i ++ ) { + + normals[ i ] = normals[ i - 1 ].clone(); + + binormals[ i ] = binormals[ i - 1 ].clone(); + + vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); + + if ( vec.length() > Number.EPSILON ) { + + vec.normalize(); + + const theta = Math.acos( clamp$1( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors + + normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); + + } + + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + + } + + // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same + + if ( closed === true ) { + + let theta = Math.acos( clamp$1( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); + theta /= segments; + + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { + + theta = - theta; + + } + + for ( let i = 1; i <= segments; i ++ ) { + + // twist a little... + normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + + } + + } + + return { + tangents: tangents, + normals: normals, + binormals: binormals + }; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + copy( source ) { + + this.arcLengthDivisions = source.arcLengthDivisions; + + return this; + + } + + toJSON() { + + const data = { + metadata: { + version: 4.6, + type: 'Curve', + generator: 'Curve.toJSON' + } + }; + + data.arcLengthDivisions = this.arcLengthDivisions; + data.type = this.type; + + return data; + + } + + fromJSON( json ) { + + this.arcLengthDivisions = json.arcLengthDivisions; + + return this; + + } + +} + +class EllipseCurve extends Curve { + + constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) { + + super(); + + this.isEllipseCurve = true; + + this.type = 'EllipseCurve'; + + this.aX = aX; + this.aY = aY; + + this.xRadius = xRadius; + this.yRadius = yRadius; + + this.aStartAngle = aStartAngle; + this.aEndAngle = aEndAngle; + + this.aClockwise = aClockwise; + + this.aRotation = aRotation; + + } + + getPoint( t, optionalTarget = new Vector2() ) { + + const point = optionalTarget; + + const twoPi = Math.PI * 2; + let deltaAngle = this.aEndAngle - this.aStartAngle; + const samePoints = Math.abs( deltaAngle ) < Number.EPSILON; + + // ensures that deltaAngle is 0 .. 2 PI + while ( deltaAngle < 0 ) deltaAngle += twoPi; + while ( deltaAngle > twoPi ) deltaAngle -= twoPi; + + if ( deltaAngle < Number.EPSILON ) { + + if ( samePoints ) { + + deltaAngle = 0; + + } else { + + deltaAngle = twoPi; + + } + + } + + if ( this.aClockwise === true && ! samePoints ) { + + if ( deltaAngle === twoPi ) { + + deltaAngle = - twoPi; + + } else { + + deltaAngle = deltaAngle - twoPi; + + } + + } + + const angle = this.aStartAngle + t * deltaAngle; + let x = this.aX + this.xRadius * Math.cos( angle ); + let y = this.aY + this.yRadius * Math.sin( angle ); + + if ( this.aRotation !== 0 ) { + + const cos = Math.cos( this.aRotation ); + const sin = Math.sin( this.aRotation ); + + const tx = x - this.aX; + const ty = y - this.aY; + + // Rotate the point about the center of the ellipse. + x = tx * cos - ty * sin + this.aX; + y = tx * sin + ty * cos + this.aY; + + } + + return point.set( x, y ); + + } + + copy( source ) { + + super.copy( source ); + + this.aX = source.aX; + this.aY = source.aY; + + this.xRadius = source.xRadius; + this.yRadius = source.yRadius; + + this.aStartAngle = source.aStartAngle; + this.aEndAngle = source.aEndAngle; + + this.aClockwise = source.aClockwise; + + this.aRotation = source.aRotation; + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.aX = this.aX; + data.aY = this.aY; + + data.xRadius = this.xRadius; + data.yRadius = this.yRadius; + + data.aStartAngle = this.aStartAngle; + data.aEndAngle = this.aEndAngle; + + data.aClockwise = this.aClockwise; + + data.aRotation = this.aRotation; + + return data; + + } + + fromJSON( json ) { + + super.fromJSON( json ); + + this.aX = json.aX; + this.aY = json.aY; + + this.xRadius = json.xRadius; + this.yRadius = json.yRadius; + + this.aStartAngle = json.aStartAngle; + this.aEndAngle = json.aEndAngle; + + this.aClockwise = json.aClockwise; + + this.aRotation = json.aRotation; + + return this; + + } + +} + +class ArcCurve extends EllipseCurve { + + constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + + super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); + + this.isArcCurve = true; + + this.type = 'ArcCurve'; + + } + +} + +/** + * Centripetal CatmullRom Curve - which is useful for avoiding + * cusps and self-intersections in non-uniform catmull rom curves. + * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf + * + * curve.type accepts centripetal(default), chordal and catmullrom + * curve.tension is used for catmullrom which defaults to 0.5 + */ + + +/* +Based on an optimized c++ solution in + - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ + - http://ideone.com/NoEbVM + +This CubicPoly class could be used for reusing some variables and calculations, +but for three.js curve use, it could be possible inlined and flatten into a single function call +which can be placed in CurveUtils. +*/ + +function CubicPoly() { + + let c0 = 0, c1 = 0, c2 = 0, c3 = 0; + + /* + * Compute coefficients for a cubic polynomial + * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 + * such that + * p(0) = x0, p(1) = x1 + * and + * p'(0) = t0, p'(1) = t1. + */ + function init( x0, x1, t0, t1 ) { + + c0 = x0; + c1 = t0; + c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; + c3 = 2 * x0 - 2 * x1 + t0 + t1; + + } + + return { + + initCatmullRom: function ( x0, x1, x2, x3, tension ) { + + init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); + + }, + + initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { + + // compute tangents when parameterized in [t1,t2] + let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; + let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; + + // rescale tangents for parametrization in [0,1] + t1 *= dt1; + t2 *= dt1; + + init( x1, x2, t1, t2 ); + + }, + + calc: function ( t ) { + + const t2 = t * t; + const t3 = t2 * t; + return c0 + c1 * t + c2 * t2 + c3 * t3; + + } + + }; + +} + +// + +const tmp = /*@__PURE__*/ new Vector3(); +const px = /*@__PURE__*/ new CubicPoly(); +const py = /*@__PURE__*/ new CubicPoly(); +const pz = /*@__PURE__*/ new CubicPoly(); + +class CatmullRomCurve3 extends Curve { + + constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) { + + super(); + + this.isCatmullRomCurve3 = true; + + this.type = 'CatmullRomCurve3'; + + this.points = points; + this.closed = closed; + this.curveType = curveType; + this.tension = tension; + + } + + getPoint( t, optionalTarget = new Vector3() ) { + + const point = optionalTarget; + + const points = this.points; + const l = points.length; + + const p = ( l - ( this.closed ? 0 : 1 ) ) * t; + let intPoint = Math.floor( p ); + let weight = p - intPoint; + + if ( this.closed ) { + + intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l; + + } else if ( weight === 0 && intPoint === l - 1 ) { + + intPoint = l - 2; + weight = 1; + + } + + let p0, p3; // 4 points (p1 & p2 defined below) + + if ( this.closed || intPoint > 0 ) { + + p0 = points[ ( intPoint - 1 ) % l ]; + + } else { + + // extrapolate first point + tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); + p0 = tmp; + + } + + const p1 = points[ intPoint % l ]; + const p2 = points[ ( intPoint + 1 ) % l ]; + + if ( this.closed || intPoint + 2 < l ) { + + p3 = points[ ( intPoint + 2 ) % l ]; + + } else { + + // extrapolate last point + tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); + p3 = tmp; + + } + + if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { + + // init Centripetal / Chordal Catmull-Rom + const pow = this.curveType === 'chordal' ? 0.5 : 0.25; + let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); + let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); + let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); + + // safety check for repeated points + if ( dt1 < 1e-4 ) dt1 = 1.0; + if ( dt0 < 1e-4 ) dt0 = dt1; + if ( dt2 < 1e-4 ) dt2 = dt1; + + px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); + py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); + pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); + + } else if ( this.curveType === 'catmullrom' ) { + + px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension ); + py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension ); + pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension ); + + } + + point.set( + px.calc( weight ), + py.calc( weight ), + pz.calc( weight ) + ); + + return point; + + } + + copy( source ) { + + super.copy( source ); + + this.points = []; + + for ( let i = 0, l = source.points.length; i < l; i ++ ) { + + const point = source.points[ i ]; + + this.points.push( point.clone() ); + + } + + this.closed = source.closed; + this.curveType = source.curveType; + this.tension = source.tension; + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.points = []; + + for ( let i = 0, l = this.points.length; i < l; i ++ ) { + + const point = this.points[ i ]; + data.points.push( point.toArray() ); + + } + + data.closed = this.closed; + data.curveType = this.curveType; + data.tension = this.tension; + + return data; + + } + + fromJSON( json ) { + + super.fromJSON( json ); + + this.points = []; + + for ( let i = 0, l = json.points.length; i < l; i ++ ) { + + const point = json.points[ i ]; + this.points.push( new Vector3().fromArray( point ) ); + + } + + this.closed = json.closed; + this.curveType = json.curveType; + this.tension = json.tension; + + return this; + + } + +} + +/** + * Bezier Curves formulas obtained from + * https://en.wikipedia.org/wiki/B%C3%A9zier_curve + */ + +function CatmullRom( t, p0, p1, p2, p3 ) { + + const v0 = ( p2 - p0 ) * 0.5; + const v1 = ( p3 - p1 ) * 0.5; + const t2 = t * t; + const t3 = t * t2; + return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; + +} + +// + +function QuadraticBezierP0( t, p ) { + + const k = 1 - t; + return k * k * p; + +} + +function QuadraticBezierP1( t, p ) { + + return 2 * ( 1 - t ) * t * p; + +} + +function QuadraticBezierP2( t, p ) { + + return t * t * p; + +} + +function QuadraticBezier( t, p0, p1, p2 ) { + + return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + + QuadraticBezierP2( t, p2 ); + +} + +// + +function CubicBezierP0( t, p ) { + + const k = 1 - t; + return k * k * k * p; + +} + +function CubicBezierP1( t, p ) { + + const k = 1 - t; + return 3 * k * k * t * p; + +} + +function CubicBezierP2( t, p ) { + + return 3 * ( 1 - t ) * t * t * p; + +} + +function CubicBezierP3( t, p ) { + + return t * t * t * p; + +} + +function CubicBezier( t, p0, p1, p2, p3 ) { + + return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + + CubicBezierP3( t, p3 ); + +} + +class CubicBezierCurve extends Curve { + + constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) { + + super(); + + this.isCubicBezierCurve = true; + + this.type = 'CubicBezierCurve'; + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + + } + + getPoint( t, optionalTarget = new Vector2() ) { + + const point = optionalTarget; + + const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; + + point.set( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) + ); + + return point; + + } + + copy( source ) { + + super.copy( source ); + + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + this.v3.copy( source.v3 ); + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + data.v3 = this.v3.toArray(); + + return data; + + } + + fromJSON( json ) { + + super.fromJSON( json ); + + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + this.v3.fromArray( json.v3 ); + + return this; + + } + +} + +class CubicBezierCurve3 extends Curve { + + constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) { + + super(); + + this.isCubicBezierCurve3 = true; + + this.type = 'CubicBezierCurve3'; + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + + } + + getPoint( t, optionalTarget = new Vector3() ) { + + const point = optionalTarget; + + const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; + + point.set( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), + CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) + ); + + return point; + + } + + copy( source ) { + + super.copy( source ); + + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + this.v3.copy( source.v3 ); + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + data.v3 = this.v3.toArray(); + + return data; + + } + + fromJSON( json ) { + + super.fromJSON( json ); + + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + this.v3.fromArray( json.v3 ); + + return this; + + } + +} + +class LineCurve extends Curve { + + constructor( v1 = new Vector2(), v2 = new Vector2() ) { + + super(); + + this.isLineCurve = true; + + this.type = 'LineCurve'; + + this.v1 = v1; + this.v2 = v2; + + } + + getPoint( t, optionalTarget = new Vector2() ) { + + const point = optionalTarget; + + if ( t === 1 ) { + + point.copy( this.v2 ); + + } else { + + point.copy( this.v2 ).sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); + + } + + return point; + + } + + // Line curve is linear, so we can overwrite default getPointAt + getPointAt( u, optionalTarget ) { + + return this.getPoint( u, optionalTarget ); + + } + + getTangent( t, optionalTarget = new Vector2() ) { + + return optionalTarget.subVectors( this.v2, this.v1 ).normalize(); + + } + + getTangentAt( u, optionalTarget ) { + + return this.getTangent( u, optionalTarget ); + + } + + copy( source ) { + + super.copy( source ); + + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + + return data; + + } + + fromJSON( json ) { + + super.fromJSON( json ); + + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + + return this; + + } + +} + +class LineCurve3 extends Curve { + + constructor( v1 = new Vector3(), v2 = new Vector3() ) { + + super(); + + this.isLineCurve3 = true; + + this.type = 'LineCurve3'; + + this.v1 = v1; + this.v2 = v2; + + } + + getPoint( t, optionalTarget = new Vector3() ) { + + const point = optionalTarget; + + if ( t === 1 ) { + + point.copy( this.v2 ); + + } else { + + point.copy( this.v2 ).sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); + + } + + return point; + + } + + // Line curve is linear, so we can overwrite default getPointAt + getPointAt( u, optionalTarget ) { + + return this.getPoint( u, optionalTarget ); + + } + + getTangent( t, optionalTarget = new Vector3() ) { + + return optionalTarget.subVectors( this.v2, this.v1 ).normalize(); + + } + + getTangentAt( u, optionalTarget ) { + + return this.getTangent( u, optionalTarget ); + + } + + copy( source ) { + + super.copy( source ); + + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + + return data; + + } + + fromJSON( json ) { + + super.fromJSON( json ); + + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + + return this; + + } + +} + +class QuadraticBezierCurve extends Curve { + + constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) { + + super(); + + this.isQuadraticBezierCurve = true; + + this.type = 'QuadraticBezierCurve'; + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + + } + + getPoint( t, optionalTarget = new Vector2() ) { + + const point = optionalTarget; + + const v0 = this.v0, v1 = this.v1, v2 = this.v2; + + point.set( + QuadraticBezier( t, v0.x, v1.x, v2.x ), + QuadraticBezier( t, v0.y, v1.y, v2.y ) + ); + + return point; + + } + + copy( source ) { + + super.copy( source ); + + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + + return data; + + } + + fromJSON( json ) { + + super.fromJSON( json ); + + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + + return this; + + } + +} + +class QuadraticBezierCurve3 extends Curve { + + constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) { + + super(); + + this.isQuadraticBezierCurve3 = true; + + this.type = 'QuadraticBezierCurve3'; + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + + } + + getPoint( t, optionalTarget = new Vector3() ) { + + const point = optionalTarget; + + const v0 = this.v0, v1 = this.v1, v2 = this.v2; + + point.set( + QuadraticBezier( t, v0.x, v1.x, v2.x ), + QuadraticBezier( t, v0.y, v1.y, v2.y ), + QuadraticBezier( t, v0.z, v1.z, v2.z ) + ); + + return point; + + } + + copy( source ) { + + super.copy( source ); + + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + + return data; + + } + + fromJSON( json ) { + + super.fromJSON( json ); + + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + + return this; + + } + +} + +class SplineCurve extends Curve { + + constructor( points = [] ) { + + super(); + + this.isSplineCurve = true; + + this.type = 'SplineCurve'; + + this.points = points; + + } + + getPoint( t, optionalTarget = new Vector2() ) { + + const point = optionalTarget; + + const points = this.points; + const p = ( points.length - 1 ) * t; + + const intPoint = Math.floor( p ); + const weight = p - intPoint; + + const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; + const p1 = points[ intPoint ]; + const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; + const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; + + point.set( + CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), + CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) + ); + + return point; + + } + + copy( source ) { + + super.copy( source ); + + this.points = []; + + for ( let i = 0, l = source.points.length; i < l; i ++ ) { + + const point = source.points[ i ]; + + this.points.push( point.clone() ); + + } + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.points = []; + + for ( let i = 0, l = this.points.length; i < l; i ++ ) { + + const point = this.points[ i ]; + data.points.push( point.toArray() ); + + } + + return data; + + } + + fromJSON( json ) { + + super.fromJSON( json ); + + this.points = []; + + for ( let i = 0, l = json.points.length; i < l; i ++ ) { + + const point = json.points[ i ]; + this.points.push( new Vector2().fromArray( point ) ); + + } + + return this; + + } + +} + +var Curves = /*#__PURE__*/Object.freeze({ + __proto__: null, + ArcCurve: ArcCurve, + CatmullRomCurve3: CatmullRomCurve3, + CubicBezierCurve: CubicBezierCurve, + CubicBezierCurve3: CubicBezierCurve3, + EllipseCurve: EllipseCurve, + LineCurve: LineCurve, + LineCurve3: LineCurve3, + QuadraticBezierCurve: QuadraticBezierCurve, + QuadraticBezierCurve3: QuadraticBezierCurve3, + SplineCurve: SplineCurve +}); + +/************************************************************** + * Curved Path - a curve path is simply a array of connected + * curves, but retains the api of a curve + **************************************************************/ + +class CurvePath extends Curve { + + constructor() { + + super(); + + this.type = 'CurvePath'; + + this.curves = []; + this.autoClose = false; // Automatically closes the path + + } + + add( curve ) { + + this.curves.push( curve ); + + } + + closePath() { + + // Add a line curve if start and end of lines are not connected + const startPoint = this.curves[ 0 ].getPoint( 0 ); + const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); + + if ( ! startPoint.equals( endPoint ) ) { + + const lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3'; + this.curves.push( new Curves[ lineType ]( endPoint, startPoint ) ); + + } + + return this; + + } + + // To get accurate point with reference to + // entire path distance at time t, + // following has to be done: + + // 1. Length of each sub path have to be known + // 2. Locate and identify type of curve + // 3. Get t for the curve + // 4. Return curve.getPointAt(t') + + getPoint( t, optionalTarget ) { + + const d = t * this.getLength(); + const curveLengths = this.getCurveLengths(); + let i = 0; + + // To think about boundaries points. + + while ( i < curveLengths.length ) { + + if ( curveLengths[ i ] >= d ) { + + const diff = curveLengths[ i ] - d; + const curve = this.curves[ i ]; + + const segmentLength = curve.getLength(); + const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; + + return curve.getPointAt( u, optionalTarget ); + + } + + i ++; + + } + + return null; + + // loop where sum != 0, sum > d , sum+1 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { + + points.push( points[ 0 ] ); + + } + + return points; + + } + + copy( source ) { + + super.copy( source ); + + this.curves = []; + + for ( let i = 0, l = source.curves.length; i < l; i ++ ) { + + const curve = source.curves[ i ]; + + this.curves.push( curve.clone() ); + + } + + this.autoClose = source.autoClose; + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.autoClose = this.autoClose; + data.curves = []; + + for ( let i = 0, l = this.curves.length; i < l; i ++ ) { + + const curve = this.curves[ i ]; + data.curves.push( curve.toJSON() ); + + } + + return data; + + } + + fromJSON( json ) { + + super.fromJSON( json ); + + this.autoClose = json.autoClose; + this.curves = []; + + for ( let i = 0, l = json.curves.length; i < l; i ++ ) { + + const curve = json.curves[ i ]; + this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); + + } + + return this; + + } + +} + +class Path extends CurvePath { + + constructor( points ) { + + super(); + + this.type = 'Path'; + + this.currentPoint = new Vector2(); + + if ( points ) { + + this.setFromPoints( points ); + + } + + } + + setFromPoints( points ) { + + this.moveTo( points[ 0 ].x, points[ 0 ].y ); + + for ( let i = 1, l = points.length; i < l; i ++ ) { + + this.lineTo( points[ i ].x, points[ i ].y ); + + } + + return this; + + } + + moveTo( x, y ) { + + this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? + + return this; + + } + + lineTo( x, y ) { + + const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); + this.curves.push( curve ); + + this.currentPoint.set( x, y ); + + return this; + + } + + quadraticCurveTo( aCPx, aCPy, aX, aY ) { + + const curve = new QuadraticBezierCurve( + this.currentPoint.clone(), + new Vector2( aCPx, aCPy ), + new Vector2( aX, aY ) + ); + + this.curves.push( curve ); + + this.currentPoint.set( aX, aY ); + + return this; + + } + + bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { + + const curve = new CubicBezierCurve( + this.currentPoint.clone(), + new Vector2( aCP1x, aCP1y ), + new Vector2( aCP2x, aCP2y ), + new Vector2( aX, aY ) + ); + + this.curves.push( curve ); + + this.currentPoint.set( aX, aY ); + + return this; + + } + + splineThru( pts /*Array of Vector*/ ) { + + const npts = [ this.currentPoint.clone() ].concat( pts ); + + const curve = new SplineCurve( npts ); + this.curves.push( curve ); + + this.currentPoint.copy( pts[ pts.length - 1 ] ); + + return this; + + } + + arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + + const x0 = this.currentPoint.x; + const y0 = this.currentPoint.y; + + this.absarc( aX + x0, aY + y0, aRadius, + aStartAngle, aEndAngle, aClockwise ); + + return this; + + } + + absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + + this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); + + return this; + + } + + ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + + const x0 = this.currentPoint.x; + const y0 = this.currentPoint.y; + + this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); + + return this; + + } + + absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + + const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); + + if ( this.curves.length > 0 ) { + + // if a previous curve is present, attempt to join + const firstPoint = curve.getPoint( 0 ); + + if ( ! firstPoint.equals( this.currentPoint ) ) { + + this.lineTo( firstPoint.x, firstPoint.y ); + + } + + } + + this.curves.push( curve ); + + const lastPoint = curve.getPoint( 1 ); + this.currentPoint.copy( lastPoint ); + + return this; + + } + + copy( source ) { + + super.copy( source ); + + this.currentPoint.copy( source.currentPoint ); + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.currentPoint = this.currentPoint.toArray(); + + return data; + + } + + fromJSON( json ) { + + super.fromJSON( json ); + + this.currentPoint.fromArray( json.currentPoint ); + + return this; + + } + +} + +class LatheGeometry extends BufferGeometry { + + constructor( points = [ new Vector2( 0, - 0.5 ), new Vector2( 0.5, 0 ), new Vector2( 0, 0.5 ) ], segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) { + + super(); + + this.type = 'LatheGeometry'; + + this.parameters = { + points: points, + segments: segments, + phiStart: phiStart, + phiLength: phiLength + }; + + segments = Math.floor( segments ); + + // clamp phiLength so it's in range of [ 0, 2PI ] + + phiLength = clamp$1( phiLength, 0, Math.PI * 2 ); + + // buffers + + const indices = []; + const vertices = []; + const uvs = []; + const initNormals = []; + const normals = []; + + // helper variables + + const inverseSegments = 1.0 / segments; + const vertex = new Vector3(); + const uv = new Vector2(); + const normal = new Vector3(); + const curNormal = new Vector3(); + const prevNormal = new Vector3(); + let dx = 0; + let dy = 0; + + // pre-compute normals for initial "meridian" + + for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { + + switch ( j ) { + + case 0: // special handling for 1st vertex on path + + dx = points[ j + 1 ].x - points[ j ].x; + dy = points[ j + 1 ].y - points[ j ].y; + + normal.x = dy * 1.0; + normal.y = - dx; + normal.z = dy * 0.0; + + prevNormal.copy( normal ); + + normal.normalize(); + + initNormals.push( normal.x, normal.y, normal.z ); + + break; + + case ( points.length - 1 ): // special handling for last Vertex on path + + initNormals.push( prevNormal.x, prevNormal.y, prevNormal.z ); + + break; + + default: // default handling for all vertices in between + + dx = points[ j + 1 ].x - points[ j ].x; + dy = points[ j + 1 ].y - points[ j ].y; + + normal.x = dy * 1.0; + normal.y = - dx; + normal.z = dy * 0.0; + + curNormal.copy( normal ); + + normal.x += prevNormal.x; + normal.y += prevNormal.y; + normal.z += prevNormal.z; + + normal.normalize(); + + initNormals.push( normal.x, normal.y, normal.z ); + + prevNormal.copy( curNormal ); + + } + + } + + // generate vertices, uvs and normals + + for ( let i = 0; i <= segments; i ++ ) { + + const phi = phiStart + i * inverseSegments * phiLength; + + const sin = Math.sin( phi ); + const cos = Math.cos( phi ); + + for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { + + // vertex + + vertex.x = points[ j ].x * sin; + vertex.y = points[ j ].y; + vertex.z = points[ j ].x * cos; + + vertices.push( vertex.x, vertex.y, vertex.z ); + + // uv + + uv.x = i / segments; + uv.y = j / ( points.length - 1 ); + + uvs.push( uv.x, uv.y ); + + // normal + + const x = initNormals[ 3 * j + 0 ] * sin; + const y = initNormals[ 3 * j + 1 ]; + const z = initNormals[ 3 * j + 0 ] * cos; + + normals.push( x, y, z ); + + } + + } + + // indices + + for ( let i = 0; i < segments; i ++ ) { + + for ( let j = 0; j < ( points.length - 1 ); j ++ ) { + + const base = j + i * points.length; + + const a = base; + const b = base + points.length; + const c = base + points.length + 1; + const d = base + 1; + + // faces + + indices.push( a, b, d ); + indices.push( c, d, b ); + + } + + } + + // build geometry + + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + + static fromJSON( data ) { + + return new LatheGeometry( data.points, data.segments, data.phiStart, data.phiLength ); + + } + +} + +class CapsuleGeometry extends LatheGeometry { + + constructor( radius = 1, length = 1, capSegments = 4, radialSegments = 8 ) { + + const path = new Path(); + path.absarc( 0, - length / 2, radius, Math.PI * 1.5, 0 ); + path.absarc( 0, length / 2, radius, 0, Math.PI * 0.5 ); + + super( path.getPoints( capSegments ), radialSegments ); + + this.type = 'CapsuleGeometry'; + + this.parameters = { + radius: radius, + length: length, + capSegments: capSegments, + radialSegments: radialSegments, + }; + + } + + static fromJSON( data ) { + + return new CapsuleGeometry( data.radius, data.length, data.capSegments, data.radialSegments ); + + } + +} + +class CircleGeometry extends BufferGeometry { + + constructor( radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2 ) { + + super(); + + this.type = 'CircleGeometry'; + + this.parameters = { + radius: radius, + segments: segments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + segments = Math.max( 3, segments ); + + // buffers + + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; + + // helper variables + + const vertex = new Vector3(); + const uv = new Vector2(); + + // center point + + vertices.push( 0, 0, 0 ); + normals.push( 0, 0, 1 ); + uvs.push( 0.5, 0.5 ); + + for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) { + + const segment = thetaStart + s / segments * thetaLength; + + // vertex + + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); + + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal + + normals.push( 0, 0, 1 ); + + // uvs + + uv.x = ( vertices[ i ] / radius + 1 ) / 2; + uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; + + uvs.push( uv.x, uv.y ); + + } + + // indices + + for ( let i = 1; i <= segments; i ++ ) { + + indices.push( i, i + 1, 0 ); + + } + + // build geometry + + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + + static fromJSON( data ) { + + return new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength ); + + } + +} + +class CylinderGeometry extends BufferGeometry { + + constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { + + super(); + + this.type = 'CylinderGeometry'; + + this.parameters = { + radiusTop: radiusTop, + radiusBottom: radiusBottom, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + const scope = this; + + radialSegments = Math.floor( radialSegments ); + heightSegments = Math.floor( heightSegments ); + + // buffers + + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; + + // helper variables + + let index = 0; + const indexArray = []; + const halfHeight = height / 2; + let groupStart = 0; + + // generate geometry + + generateTorso(); + + if ( openEnded === false ) { + + if ( radiusTop > 0 ) generateCap( true ); + if ( radiusBottom > 0 ) generateCap( false ); + + } + + // build geometry + + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + function generateTorso() { + + const normal = new Vector3(); + const vertex = new Vector3(); + + let groupCount = 0; + + // this will be used to calculate the normal + const slope = ( radiusBottom - radiusTop ) / height; + + // generate vertices, normals and uvs + + for ( let y = 0; y <= heightSegments; y ++ ) { + + const indexRow = []; + + const v = y / heightSegments; + + // calculate the radius of the current row + + const radius = v * ( radiusBottom - radiusTop ) + radiusTop; + + for ( let x = 0; x <= radialSegments; x ++ ) { + + const u = x / radialSegments; + + const theta = u * thetaLength + thetaStart; + + const sinTheta = Math.sin( theta ); + const cosTheta = Math.cos( theta ); + + // vertex + + vertex.x = radius * sinTheta; + vertex.y = - v * height + halfHeight; + vertex.z = radius * cosTheta; + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal + + normal.set( sinTheta, slope, cosTheta ).normalize(); + normals.push( normal.x, normal.y, normal.z ); + + // uv + + uvs.push( u, 1 - v ); + + // save index of vertex in respective row + + indexRow.push( index ++ ); + + } + + // now save vertices of the row in our index array + + indexArray.push( indexRow ); + + } + + // generate indices + + for ( let x = 0; x < radialSegments; x ++ ) { + + for ( let y = 0; y < heightSegments; y ++ ) { + + // we use the index array to access the correct indices + + const a = indexArray[ y ][ x ]; + const b = indexArray[ y + 1 ][ x ]; + const c = indexArray[ y + 1 ][ x + 1 ]; + const d = indexArray[ y ][ x + 1 ]; + + // faces + + if ( radiusTop > 0 ) { + + indices.push( a, b, d ); + groupCount += 3; + + } + + if ( radiusBottom > 0 ) { + + indices.push( b, c, d ); + groupCount += 3; + + } + + } + + } + + // add a group to the geometry. this will ensure multi material support + + scope.addGroup( groupStart, groupCount, 0 ); + + // calculate new start value for groups + + groupStart += groupCount; + + } + + function generateCap( top ) { + + // save the index of the first center vertex + const centerIndexStart = index; + + const uv = new Vector2(); + const vertex = new Vector3(); + + let groupCount = 0; + + const radius = ( top === true ) ? radiusTop : radiusBottom; + const sign = ( top === true ) ? 1 : - 1; + + // first we generate the center vertex data of the cap. + // because the geometry needs one set of uvs per face, + // we must generate a center vertex per face/segment + + for ( let x = 1; x <= radialSegments; x ++ ) { + + // vertex + + vertices.push( 0, halfHeight * sign, 0 ); + + // normal + + normals.push( 0, sign, 0 ); + + // uv + + uvs.push( 0.5, 0.5 ); + + // increase index + + index ++; + + } + + // save the index of the last center vertex + const centerIndexEnd = index; + + // now we generate the surrounding vertices, normals and uvs + + for ( let x = 0; x <= radialSegments; x ++ ) { + + const u = x / radialSegments; + const theta = u * thetaLength + thetaStart; + + const cosTheta = Math.cos( theta ); + const sinTheta = Math.sin( theta ); + + // vertex + + vertex.x = radius * sinTheta; + vertex.y = halfHeight * sign; + vertex.z = radius * cosTheta; + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal + + normals.push( 0, sign, 0 ); + + // uv + + uv.x = ( cosTheta * 0.5 ) + 0.5; + uv.y = ( sinTheta * 0.5 * sign ) + 0.5; + uvs.push( uv.x, uv.y ); + + // increase index + + index ++; + + } + + // generate indices + + for ( let x = 0; x < radialSegments; x ++ ) { + + const c = centerIndexStart + x; + const i = centerIndexEnd + x; + + if ( top === true ) { + + // face top + + indices.push( i, i + 1, c ); + + } else { + + // face bottom + + indices.push( i + 1, i, c ); + + } + + groupCount += 3; + + } + + // add a group to the geometry. this will ensure multi material support + + scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); + + // calculate new start value for groups + + groupStart += groupCount; + + } + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + + static fromJSON( data ) { + + return new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); + + } + +} + +class ConeGeometry extends CylinderGeometry { + + constructor( radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { + + super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); + + this.type = 'ConeGeometry'; + + this.parameters = { + radius: radius, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + } + + static fromJSON( data ) { + + return new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); + + } + +} + +class PolyhedronGeometry extends BufferGeometry { + + constructor( vertices = [], indices = [], radius = 1, detail = 0 ) { + + super(); + + this.type = 'PolyhedronGeometry'; + + this.parameters = { + vertices: vertices, + indices: indices, + radius: radius, + detail: detail + }; + + // default buffer data + + const vertexBuffer = []; + const uvBuffer = []; + + // the subdivision creates the vertex buffer data + + subdivide( detail ); + + // all vertices should lie on a conceptual sphere with a given radius + + applyRadius( radius ); + + // finally, create the uv data + + generateUVs(); + + // build non-indexed geometry + + this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); + + if ( detail === 0 ) { + + this.computeVertexNormals(); // flat normals + + } else { + + this.normalizeNormals(); // smooth normals + + } + + // helper functions + + function subdivide( detail ) { + + const a = new Vector3(); + const b = new Vector3(); + const c = new Vector3(); + + // iterate over all faces and apply a subdivision with the given detail value + + for ( let i = 0; i < indices.length; i += 3 ) { + + // get the vertices of the face + + getVertexByIndex( indices[ i + 0 ], a ); + getVertexByIndex( indices[ i + 1 ], b ); + getVertexByIndex( indices[ i + 2 ], c ); + + // perform subdivision + + subdivideFace( a, b, c, detail ); + + } + + } + + function subdivideFace( a, b, c, detail ) { + + const cols = detail + 1; + + // we use this multidimensional array as a data structure for creating the subdivision + + const v = []; + + // construct all of the vertices for this subdivision + + for ( let i = 0; i <= cols; i ++ ) { + + v[ i ] = []; + + const aj = a.clone().lerp( c, i / cols ); + const bj = b.clone().lerp( c, i / cols ); + + const rows = cols - i; + + for ( let j = 0; j <= rows; j ++ ) { + + if ( j === 0 && i === cols ) { + + v[ i ][ j ] = aj; + + } else { + + v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); + + } + + } + + } + + // construct all of the faces + + for ( let i = 0; i < cols; i ++ ) { + + for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { + + const k = Math.floor( j / 2 ); + + if ( j % 2 === 0 ) { + + pushVertex( v[ i ][ k + 1 ] ); + pushVertex( v[ i + 1 ][ k ] ); + pushVertex( v[ i ][ k ] ); + + } else { + + pushVertex( v[ i ][ k + 1 ] ); + pushVertex( v[ i + 1 ][ k + 1 ] ); + pushVertex( v[ i + 1 ][ k ] ); + + } + + } + + } + + } + + function applyRadius( radius ) { + + const vertex = new Vector3(); + + // iterate over the entire buffer and apply the radius to each vertex + + for ( let i = 0; i < vertexBuffer.length; i += 3 ) { + + vertex.x = vertexBuffer[ i + 0 ]; + vertex.y = vertexBuffer[ i + 1 ]; + vertex.z = vertexBuffer[ i + 2 ]; + + vertex.normalize().multiplyScalar( radius ); + + vertexBuffer[ i + 0 ] = vertex.x; + vertexBuffer[ i + 1 ] = vertex.y; + vertexBuffer[ i + 2 ] = vertex.z; + + } + + } + + function generateUVs() { + + const vertex = new Vector3(); + + for ( let i = 0; i < vertexBuffer.length; i += 3 ) { + + vertex.x = vertexBuffer[ i + 0 ]; + vertex.y = vertexBuffer[ i + 1 ]; + vertex.z = vertexBuffer[ i + 2 ]; + + const u = azimuth( vertex ) / 2 / Math.PI + 0.5; + const v = inclination( vertex ) / Math.PI + 0.5; + uvBuffer.push( u, 1 - v ); + + } + + correctUVs(); + + correctSeam(); + + } + + function correctSeam() { + + // handle case when face straddles the seam, see #3269 + + for ( let i = 0; i < uvBuffer.length; i += 6 ) { + + // uv data of a single face + + const x0 = uvBuffer[ i + 0 ]; + const x1 = uvBuffer[ i + 2 ]; + const x2 = uvBuffer[ i + 4 ]; + + const max = Math.max( x0, x1, x2 ); + const min = Math.min( x0, x1, x2 ); + + // 0.9 is somewhat arbitrary + + if ( max > 0.9 && min < 0.1 ) { + + if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; + if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; + if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; + + } + + } + + } + + function pushVertex( vertex ) { + + vertexBuffer.push( vertex.x, vertex.y, vertex.z ); + + } + + function getVertexByIndex( index, vertex ) { + + const stride = index * 3; + + vertex.x = vertices[ stride + 0 ]; + vertex.y = vertices[ stride + 1 ]; + vertex.z = vertices[ stride + 2 ]; + + } + + function correctUVs() { + + const a = new Vector3(); + const b = new Vector3(); + const c = new Vector3(); + + const centroid = new Vector3(); + + const uvA = new Vector2(); + const uvB = new Vector2(); + const uvC = new Vector2(); + + for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { + + a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] ); + b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] ); + c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] ); + + uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); + uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); + uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); + + centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); + + const azi = azimuth( centroid ); + + correctUV( uvA, j + 0, a, azi ); + correctUV( uvB, j + 2, b, azi ); + correctUV( uvC, j + 4, c, azi ); + + } + + } + + function correctUV( uv, stride, vector, azimuth ) { + + if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { + + uvBuffer[ stride ] = uv.x - 1; + + } + + if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { + + uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; + + } + + } + + // Angle around the Y axis, counter-clockwise when looking from above. + + function azimuth( vector ) { + + return Math.atan2( vector.z, - vector.x ); + + } + + + // Angle above the XZ plane. + + function inclination( vector ) { + + return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); + + } + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + + static fromJSON( data ) { + + return new PolyhedronGeometry( data.vertices, data.indices, data.radius, data.details ); + + } + +} + +class DodecahedronGeometry extends PolyhedronGeometry { + + constructor( radius = 1, detail = 0 ) { + + const t = ( 1 + Math.sqrt( 5 ) ) / 2; + const r = 1 / t; + + const vertices = [ + + // (±1, ±1, ±1) + - 1, - 1, - 1, - 1, - 1, 1, + - 1, 1, - 1, - 1, 1, 1, + 1, - 1, - 1, 1, - 1, 1, + 1, 1, - 1, 1, 1, 1, + + // (0, ±1/φ, ±φ) + 0, - r, - t, 0, - r, t, + 0, r, - t, 0, r, t, + + // (±1/φ, ±φ, 0) + - r, - t, 0, - r, t, 0, + r, - t, 0, r, t, 0, + + // (±φ, 0, ±1/φ) + - t, 0, - r, t, 0, - r, + - t, 0, r, t, 0, r + ]; + + const indices = [ + 3, 11, 7, 3, 7, 15, 3, 15, 13, + 7, 19, 17, 7, 17, 6, 7, 6, 15, + 17, 4, 8, 17, 8, 10, 17, 10, 6, + 8, 0, 16, 8, 16, 2, 8, 2, 10, + 0, 12, 1, 0, 1, 18, 0, 18, 16, + 6, 10, 2, 6, 2, 13, 6, 13, 15, + 2, 16, 18, 2, 18, 3, 2, 3, 13, + 18, 1, 9, 18, 9, 11, 18, 11, 3, + 4, 14, 12, 4, 12, 0, 4, 0, 8, + 11, 9, 5, 11, 5, 19, 11, 19, 7, + 19, 5, 14, 19, 14, 4, 19, 4, 17, + 1, 12, 14, 1, 14, 5, 1, 5, 9 + ]; + + super( vertices, indices, radius, detail ); + + this.type = 'DodecahedronGeometry'; + + this.parameters = { + radius: radius, + detail: detail + }; + + } + + static fromJSON( data ) { + + return new DodecahedronGeometry( data.radius, data.detail ); + + } + +} + +const _v0 = /*@__PURE__*/ new Vector3(); +const _v1$1 = /*@__PURE__*/ new Vector3(); +const _normal$1 = /*@__PURE__*/ new Vector3(); +const _triangle = /*@__PURE__*/ new Triangle(); + +class EdgesGeometry extends BufferGeometry { + + constructor( geometry = null, thresholdAngle = 1 ) { + + super(); + + this.type = 'EdgesGeometry'; + + this.parameters = { + geometry: geometry, + thresholdAngle: thresholdAngle + }; + + if ( geometry !== null ) { + + const precisionPoints = 4; + const precision = Math.pow( 10, precisionPoints ); + const thresholdDot = Math.cos( DEG2RAD * thresholdAngle ); + + const indexAttr = geometry.getIndex(); + const positionAttr = geometry.getAttribute( 'position' ); + const indexCount = indexAttr ? indexAttr.count : positionAttr.count; + + const indexArr = [ 0, 0, 0 ]; + const vertKeys = [ 'a', 'b', 'c' ]; + const hashes = new Array( 3 ); + + const edgeData = {}; + const vertices = []; + for ( let i = 0; i < indexCount; i += 3 ) { + + if ( indexAttr ) { + + indexArr[ 0 ] = indexAttr.getX( i ); + indexArr[ 1 ] = indexAttr.getX( i + 1 ); + indexArr[ 2 ] = indexAttr.getX( i + 2 ); + + } else { + + indexArr[ 0 ] = i; + indexArr[ 1 ] = i + 1; + indexArr[ 2 ] = i + 2; + + } + + const { a, b, c } = _triangle; + a.fromBufferAttribute( positionAttr, indexArr[ 0 ] ); + b.fromBufferAttribute( positionAttr, indexArr[ 1 ] ); + c.fromBufferAttribute( positionAttr, indexArr[ 2 ] ); + _triangle.getNormal( _normal$1 ); + + // create hashes for the edge from the vertices + hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`; + hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`; + hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`; + + // skip degenerate triangles + if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) { + + continue; + + } + + // iterate over every edge + for ( let j = 0; j < 3; j ++ ) { + + // get the first and next vertex making up the edge + const jNext = ( j + 1 ) % 3; + const vecHash0 = hashes[ j ]; + const vecHash1 = hashes[ jNext ]; + const v0 = _triangle[ vertKeys[ j ] ]; + const v1 = _triangle[ vertKeys[ jNext ] ]; + + const hash = `${ vecHash0 }_${ vecHash1 }`; + const reverseHash = `${ vecHash1 }_${ vecHash0 }`; + + if ( reverseHash in edgeData && edgeData[ reverseHash ] ) { + + // if we found a sibling edge add it into the vertex array if + // it meets the angle threshold and delete the edge from the map. + if ( _normal$1.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) { + + vertices.push( v0.x, v0.y, v0.z ); + vertices.push( v1.x, v1.y, v1.z ); + + } + + edgeData[ reverseHash ] = null; + + } else if ( ! ( hash in edgeData ) ) { + + // if we've already got an edge here then skip adding a new one + edgeData[ hash ] = { + + index0: indexArr[ j ], + index1: indexArr[ jNext ], + normal: _normal$1.clone(), + + }; + + } + + } + + } + + // iterate over all remaining, unmatched edges and add them to the vertex array + for ( const key in edgeData ) { + + if ( edgeData[ key ] ) { + + const { index0, index1 } = edgeData[ key ]; + _v0.fromBufferAttribute( positionAttr, index0 ); + _v1$1.fromBufferAttribute( positionAttr, index1 ); + + vertices.push( _v0.x, _v0.y, _v0.z ); + vertices.push( _v1$1.x, _v1$1.y, _v1$1.z ); + + } + + } + + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + + } + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + +} + +class Shape extends Path { + + constructor( points ) { + + super( points ); + + this.uuid = generateUUID(); + + this.type = 'Shape'; + + this.holes = []; + + } + + getPointsHoles( divisions ) { + + const holesPts = []; + + for ( let i = 0, l = this.holes.length; i < l; i ++ ) { + + holesPts[ i ] = this.holes[ i ].getPoints( divisions ); + + } + + return holesPts; + + } + + // get points of shape and holes (keypoints based on segments parameter) + + extractPoints( divisions ) { + + return { + + shape: this.getPoints( divisions ), + holes: this.getPointsHoles( divisions ) + + }; + + } + + copy( source ) { + + super.copy( source ); + + this.holes = []; + + for ( let i = 0, l = source.holes.length; i < l; i ++ ) { + + const hole = source.holes[ i ]; + + this.holes.push( hole.clone() ); + + } + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.uuid = this.uuid; + data.holes = []; + + for ( let i = 0, l = this.holes.length; i < l; i ++ ) { + + const hole = this.holes[ i ]; + data.holes.push( hole.toJSON() ); + + } + + return data; + + } + + fromJSON( json ) { + + super.fromJSON( json ); + + this.uuid = json.uuid; + this.holes = []; + + for ( let i = 0, l = json.holes.length; i < l; i ++ ) { + + const hole = json.holes[ i ]; + this.holes.push( new Path().fromJSON( hole ) ); + + } + + return this; + + } + +} + +/** + * Port from https://github.com/mapbox/earcut (v2.2.4) + */ + +const Earcut = { + + triangulate: function ( data, holeIndices, dim = 2 ) { + + const hasHoles = holeIndices && holeIndices.length; + const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length; + let outerNode = linkedList( data, 0, outerLen, dim, true ); + const triangles = []; + + if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles; + + let minX, minY, maxX, maxY, x, y, invSize; + + if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim ); + + // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox + if ( data.length > 80 * dim ) { + + minX = maxX = data[ 0 ]; + minY = maxY = data[ 1 ]; + + for ( let i = dim; i < outerLen; i += dim ) { + + x = data[ i ]; + y = data[ i + 1 ]; + if ( x < minX ) minX = x; + if ( y < minY ) minY = y; + if ( x > maxX ) maxX = x; + if ( y > maxY ) maxY = y; + + } + + // minX, minY and invSize are later used to transform coords into integers for z-order calculation + invSize = Math.max( maxX - minX, maxY - minY ); + invSize = invSize !== 0 ? 32767 / invSize : 0; + + } + + earcutLinked( outerNode, triangles, dim, minX, minY, invSize, 0 ); + + return triangles; + + } + +}; + +// create a circular doubly linked list from polygon points in the specified winding order +function linkedList( data, start, end, dim, clockwise ) { + + let i, last; + + if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) { + + for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); + + } else { + + for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); + + } + + if ( last && equals$1( last, last.next ) ) { + + removeNode( last ); + last = last.next; + + } + + return last; + +} + +// eliminate colinear or duplicate points +function filterPoints( start, end ) { + + if ( ! start ) return start; + if ( ! end ) end = start; + + let p = start, + again; + do { + + again = false; + + if ( ! p.steiner && ( equals$1( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) { + + removeNode( p ); + p = end = p.prev; + if ( p === p.next ) break; + again = true; + + } else { + + p = p.next; + + } + + } while ( again || p !== end ); + + return end; + +} + +// main ear slicing loop which triangulates a polygon (given as a linked list) +function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) { + + if ( ! ear ) return; + + // interlink polygon nodes in z-order + if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize ); + + let stop = ear, + prev, next; + + // iterate through ears, slicing them one by one + while ( ear.prev !== ear.next ) { + + prev = ear.prev; + next = ear.next; + + if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) { + + // cut off the triangle + triangles.push( prev.i / dim | 0 ); + triangles.push( ear.i / dim | 0 ); + triangles.push( next.i / dim | 0 ); + + removeNode( ear ); + + // skipping the next vertex leads to less sliver triangles + ear = next.next; + stop = next.next; + + continue; + + } + + ear = next; + + // if we looped through the whole remaining polygon and can't find any more ears + if ( ear === stop ) { + + // try filtering points and slicing again + if ( ! pass ) { + + earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 ); + + // if this didn't work, try curing all small self-intersections locally + + } else if ( pass === 1 ) { + + ear = cureLocalIntersections( filterPoints( ear ), triangles, dim ); + earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 ); + + // as a last resort, try splitting the remaining polygon into two + + } else if ( pass === 2 ) { + + splitEarcut( ear, triangles, dim, minX, minY, invSize ); + + } + + break; + + } + + } + +} + +// check whether a polygon node forms a valid ear with adjacent nodes +function isEar( ear ) { + + const a = ear.prev, + b = ear, + c = ear.next; + + if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear + + // now make sure we don't have other points inside the potential ear + const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; + + // triangle bbox; min & max are calculated like this for speed + const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ), + y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ), + x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ), + y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy ); + + let p = c.next; + while ( p !== a ) { + + if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && + pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && + area( p.prev, p, p.next ) >= 0 ) return false; + p = p.next; + + } + + return true; + +} + +function isEarHashed( ear, minX, minY, invSize ) { + + const a = ear.prev, + b = ear, + c = ear.next; + + if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear + + const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; + + // triangle bbox; min & max are calculated like this for speed + const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ), + y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ), + x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ), + y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy ); + + // z-order range for the current triangle bbox; + const minZ = zOrder( x0, y0, minX, minY, invSize ), + maxZ = zOrder( x1, y1, minX, minY, invSize ); + + let p = ear.prevZ, + n = ear.nextZ; + + // look for points inside the triangle in both directions + while ( p && p.z >= minZ && n && n.z <= maxZ ) { + + if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && + pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false; + p = p.prevZ; + + if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && + pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false; + n = n.nextZ; + + } + + // look for remaining points in decreasing z-order + while ( p && p.z >= minZ ) { + + if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && + pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false; + p = p.prevZ; + + } + + // look for remaining points in increasing z-order + while ( n && n.z <= maxZ ) { + + if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && + pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false; + n = n.nextZ; + + } + + return true; + +} + +// go through all polygon nodes and cure small local self-intersections +function cureLocalIntersections( start, triangles, dim ) { + + let p = start; + do { + + const a = p.prev, + b = p.next.next; + + if ( ! equals$1( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) { + + triangles.push( a.i / dim | 0 ); + triangles.push( p.i / dim | 0 ); + triangles.push( b.i / dim | 0 ); + + // remove two nodes involved + removeNode( p ); + removeNode( p.next ); + + p = start = b; + + } + + p = p.next; + + } while ( p !== start ); + + return filterPoints( p ); + +} + +// try splitting polygon into two and triangulate them independently +function splitEarcut( start, triangles, dim, minX, minY, invSize ) { + + // look for a valid diagonal that divides the polygon into two + let a = start; + do { + + let b = a.next.next; + while ( b !== a.prev ) { + + if ( a.i !== b.i && isValidDiagonal( a, b ) ) { + + // split the polygon in two by the diagonal + let c = splitPolygon( a, b ); + + // filter colinear points around the cuts + a = filterPoints( a, a.next ); + c = filterPoints( c, c.next ); + + // run earcut on each half + earcutLinked( a, triangles, dim, minX, minY, invSize, 0 ); + earcutLinked( c, triangles, dim, minX, minY, invSize, 0 ); + return; + + } + + b = b.next; + + } + + a = a.next; + + } while ( a !== start ); + +} + +// link every hole into the outer loop, producing a single-ring polygon without holes +function eliminateHoles( data, holeIndices, outerNode, dim ) { + + const queue = []; + let i, len, start, end, list; + + for ( i = 0, len = holeIndices.length; i < len; i ++ ) { + + start = holeIndices[ i ] * dim; + end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length; + list = linkedList( data, start, end, dim, false ); + if ( list === list.next ) list.steiner = true; + queue.push( getLeftmost( list ) ); + + } + + queue.sort( compareX ); + + // process holes from left to right + for ( i = 0; i < queue.length; i ++ ) { + + outerNode = eliminateHole( queue[ i ], outerNode ); + + } + + return outerNode; + +} + +function compareX( a, b ) { + + return a.x - b.x; + +} + +// find a bridge between vertices that connects hole with an outer ring and link it +function eliminateHole( hole, outerNode ) { + + const bridge = findHoleBridge( hole, outerNode ); + if ( ! bridge ) { + + return outerNode; + + } + + const bridgeReverse = splitPolygon( bridge, hole ); + + // filter collinear points around the cuts + filterPoints( bridgeReverse, bridgeReverse.next ); + return filterPoints( bridge, bridge.next ); + +} + +// David Eberly's algorithm for finding a bridge between hole and outer polygon +function findHoleBridge( hole, outerNode ) { + + let p = outerNode, + qx = - Infinity, + m; + + const hx = hole.x, hy = hole.y; + + // find a segment intersected by a ray from the hole's leftmost point to the left; + // segment's endpoint with lesser x will be potential connection point + do { + + if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) { + + const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y ); + if ( x <= hx && x > qx ) { + + qx = x; + m = p.x < p.next.x ? p : p.next; + if ( x === hx ) return m; // hole touches outer segment; pick leftmost endpoint + + } + + } + + p = p.next; + + } while ( p !== outerNode ); + + if ( ! m ) return null; + + // look for points inside the triangle of hole point, segment intersection and endpoint; + // if there are no points found, we have a valid connection; + // otherwise choose the point of the minimum angle with the ray as connection point + + const stop = m, + mx = m.x, + my = m.y; + let tanMin = Infinity, tan; + + p = m; + + do { + + if ( hx >= p.x && p.x >= mx && hx !== p.x && + pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) { + + tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential + + if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) { + + m = p; + tanMin = tan; + + } + + } + + p = p.next; + + } while ( p !== stop ); + + return m; + +} + +// whether sector in vertex m contains sector in vertex p in the same coordinates +function sectorContainsSector( m, p ) { + + return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0; + +} + +// interlink polygon nodes in z-order +function indexCurve( start, minX, minY, invSize ) { + + let p = start; + do { + + if ( p.z === 0 ) p.z = zOrder( p.x, p.y, minX, minY, invSize ); + p.prevZ = p.prev; + p.nextZ = p.next; + p = p.next; + + } while ( p !== start ); + + p.prevZ.nextZ = null; + p.prevZ = null; + + sortLinked( p ); + +} + +// Simon Tatham's linked list merge sort algorithm +// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html +function sortLinked( list ) { + + let i, p, q, e, tail, numMerges, pSize, qSize, + inSize = 1; + + do { + + p = list; + list = null; + tail = null; + numMerges = 0; + + while ( p ) { + + numMerges ++; + q = p; + pSize = 0; + for ( i = 0; i < inSize; i ++ ) { + + pSize ++; + q = q.nextZ; + if ( ! q ) break; + + } + + qSize = inSize; + + while ( pSize > 0 || ( qSize > 0 && q ) ) { + + if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) { + + e = p; + p = p.nextZ; + pSize --; + + } else { + + e = q; + q = q.nextZ; + qSize --; + + } + + if ( tail ) tail.nextZ = e; + else list = e; + + e.prevZ = tail; + tail = e; + + } + + p = q; + + } + + tail.nextZ = null; + inSize *= 2; + + } while ( numMerges > 1 ); + + return list; + +} + +// z-order of a point given coords and inverse of the longer side of data bbox +function zOrder( x, y, minX, minY, invSize ) { + + // coords are transformed into non-negative 15-bit integer range + x = ( x - minX ) * invSize | 0; + y = ( y - minY ) * invSize | 0; + + x = ( x | ( x << 8 ) ) & 0x00FF00FF; + x = ( x | ( x << 4 ) ) & 0x0F0F0F0F; + x = ( x | ( x << 2 ) ) & 0x33333333; + x = ( x | ( x << 1 ) ) & 0x55555555; + + y = ( y | ( y << 8 ) ) & 0x00FF00FF; + y = ( y | ( y << 4 ) ) & 0x0F0F0F0F; + y = ( y | ( y << 2 ) ) & 0x33333333; + y = ( y | ( y << 1 ) ) & 0x55555555; + + return x | ( y << 1 ); + +} + +// find the leftmost node of a polygon ring +function getLeftmost( start ) { + + let p = start, + leftmost = start; + do { + + if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p; + p = p.next; + + } while ( p !== start ); + + return leftmost; + +} + +// check if a point lies within a convex triangle +function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) { + + return ( cx - px ) * ( ay - py ) >= ( ax - px ) * ( cy - py ) && + ( ax - px ) * ( by - py ) >= ( bx - px ) * ( ay - py ) && + ( bx - px ) * ( cy - py ) >= ( cx - px ) * ( by - py ); + +} + +// check if a diagonal between two polygon nodes is valid (lies in polygon interior) +function isValidDiagonal( a, b ) { + + return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges + ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible + ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors + equals$1( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case + +} + +// signed area of a triangle +function area( p, q, r ) { + + return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y ); + +} + +// check if two points are equal +function equals$1( p1, p2 ) { + + return p1.x === p2.x && p1.y === p2.y; + +} + +// check if two segments intersect +function intersects( p1, q1, p2, q2 ) { + + const o1 = sign$1( area( p1, q1, p2 ) ); + const o2 = sign$1( area( p1, q1, q2 ) ); + const o3 = sign$1( area( p2, q2, p1 ) ); + const o4 = sign$1( area( p2, q2, q1 ) ); + + if ( o1 !== o2 && o3 !== o4 ) return true; // general case + + if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 + if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 + if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 + if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 + + return false; + +} + +// for collinear points p, q, r, check if point q lies on segment pr +function onSegment( p, q, r ) { + + return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y ); + +} + +function sign$1( num ) { + + return num > 0 ? 1 : num < 0 ? - 1 : 0; + +} + +// check if a polygon diagonal intersects any polygon segments +function intersectsPolygon( a, b ) { + + let p = a; + do { + + if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && + intersects( p, p.next, a, b ) ) return true; + p = p.next; + + } while ( p !== a ); + + return false; + +} + +// check if a polygon diagonal is locally inside the polygon +function locallyInside( a, b ) { + + return area( a.prev, a, a.next ) < 0 ? + area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 : + area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0; + +} + +// check if the middle point of a polygon diagonal is inside the polygon +function middleInside( a, b ) { + + let p = a, + inside = false; + const px = ( a.x + b.x ) / 2, + py = ( a.y + b.y ) / 2; + do { + + if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y && + ( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) ) + inside = ! inside; + p = p.next; + + } while ( p !== a ); + + return inside; + +} + +// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two; +// if one belongs to the outer ring and another to a hole, it merges it into a single ring +function splitPolygon( a, b ) { + + const a2 = new Node$1( a.i, a.x, a.y ), + b2 = new Node$1( b.i, b.x, b.y ), + an = a.next, + bp = b.prev; + + a.next = b; + b.prev = a; + + a2.next = an; + an.prev = a2; + + b2.next = a2; + a2.prev = b2; + + bp.next = b2; + b2.prev = bp; + + return b2; + +} + +// create a node and optionally link it with previous one (in a circular doubly linked list) +function insertNode( i, x, y, last ) { + + const p = new Node$1( i, x, y ); + + if ( ! last ) { + + p.prev = p; + p.next = p; + + } else { + + p.next = last.next; + p.prev = last; + last.next.prev = p; + last.next = p; + + } + + return p; + +} + +function removeNode( p ) { + + p.next.prev = p.prev; + p.prev.next = p.next; + + if ( p.prevZ ) p.prevZ.nextZ = p.nextZ; + if ( p.nextZ ) p.nextZ.prevZ = p.prevZ; + +} + +function Node$1( i, x, y ) { + + // vertex index in coordinates array + this.i = i; + + // vertex coordinates + this.x = x; + this.y = y; + + // previous and next vertex nodes in a polygon ring + this.prev = null; + this.next = null; + + // z-order curve value + this.z = 0; + + // previous and next nodes in z-order + this.prevZ = null; + this.nextZ = null; + + // indicates whether this is a steiner point + this.steiner = false; + +} + +function signedArea( data, start, end, dim ) { + + let sum = 0; + for ( let i = start, j = end - dim; i < end; i += dim ) { + + sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] ); + j = i; + + } + + return sum; + +} + +class ShapeUtils { + + // calculate area of the contour polygon + + static area( contour ) { + + const n = contour.length; + let a = 0.0; + + for ( let p = n - 1, q = 0; q < n; p = q ++ ) { + + a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; + + } + + return a * 0.5; + + } + + static isClockWise( pts ) { + + return ShapeUtils.area( pts ) < 0; + + } + + static triangulateShape( contour, holes ) { + + const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ] + const holeIndices = []; // array of hole indices + const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ] + + removeDupEndPts( contour ); + addContour( vertices, contour ); + + // + + let holeIndex = contour.length; + + holes.forEach( removeDupEndPts ); + + for ( let i = 0; i < holes.length; i ++ ) { + + holeIndices.push( holeIndex ); + holeIndex += holes[ i ].length; + addContour( vertices, holes[ i ] ); + + } + + // + + const triangles = Earcut.triangulate( vertices, holeIndices ); + + // + + for ( let i = 0; i < triangles.length; i += 3 ) { + + faces.push( triangles.slice( i, i + 3 ) ); + + } + + return faces; + + } + +} + +function removeDupEndPts( points ) { + + const l = points.length; + + if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { + + points.pop(); + + } + +} + +function addContour( vertices, contour ) { + + for ( let i = 0; i < contour.length; i ++ ) { + + vertices.push( contour[ i ].x ); + vertices.push( contour[ i ].y ); + + } + +} + +/** + * Creates extruded geometry from a path shape. + * + * parameters = { + * + * curveSegments: , // number of points on the curves + * steps: , // number of points for z-side extrusions / used for subdividing segments of extrude spline too + * depth: , // Depth to extrude the shape + * + * bevelEnabled: , // turn on bevel + * bevelThickness: , // how deep into the original shape bevel goes + * bevelSize: , // how far from shape outline (including bevelOffset) is bevel + * bevelOffset: , // how far from shape outline does bevel start + * bevelSegments: , // number of bevel layers + * + * extrudePath: // curve to extrude shape along + * + * UVGenerator: // object that provides UV generator functions + * + * } + */ + + +class ExtrudeGeometry extends BufferGeometry { + + constructor( shapes = new Shape( [ new Vector2( 0.5, 0.5 ), new Vector2( - 0.5, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), options = {} ) { + + super(); + + this.type = 'ExtrudeGeometry'; + + this.parameters = { + shapes: shapes, + options: options + }; + + shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; + + const scope = this; + + const verticesArray = []; + const uvArray = []; + + for ( let i = 0, l = shapes.length; i < l; i ++ ) { + + const shape = shapes[ i ]; + addShape( shape ); + + } + + // build geometry + + this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) ); + + this.computeVertexNormals(); + + // functions + + function addShape( shape ) { + + const placeholder = []; + + // options + + const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + const steps = options.steps !== undefined ? options.steps : 1; + const depth = options.depth !== undefined ? options.depth : 1; + + let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; + let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2; + let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1; + let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0; + let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; + + const extrudePath = options.extrudePath; + + const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator; + + // + + let extrudePts, extrudeByPath = false; + let splineTube, binormal, normal, position2; + + if ( extrudePath ) { + + extrudePts = extrudePath.getSpacedPoints( steps ); + + extrudeByPath = true; + bevelEnabled = false; // bevels not supported for path extrusion + + // SETUP TNB variables + + // TODO1 - have a .isClosed in spline? + + splineTube = extrudePath.computeFrenetFrames( steps, false ); + + // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); + + binormal = new Vector3(); + normal = new Vector3(); + position2 = new Vector3(); + + } + + // Safeguards if bevels are not enabled + + if ( ! bevelEnabled ) { + + bevelSegments = 0; + bevelThickness = 0; + bevelSize = 0; + bevelOffset = 0; + + } + + // Variables initialization + + const shapePoints = shape.extractPoints( curveSegments ); + + let vertices = shapePoints.shape; + const holes = shapePoints.holes; + + const reverse = ! ShapeUtils.isClockWise( vertices ); + + if ( reverse ) { + + vertices = vertices.reverse(); + + // Maybe we should also check if holes are in the opposite direction, just to be safe ... + + for ( let h = 0, hl = holes.length; h < hl; h ++ ) { + + const ahole = holes[ h ]; + + if ( ShapeUtils.isClockWise( ahole ) ) { + + holes[ h ] = ahole.reverse(); + + } + + } + + } + + + const faces = ShapeUtils.triangulateShape( vertices, holes ); + + /* Vertices */ + + const contour = vertices; // vertices has all points but contour has only points of circumference + + for ( let h = 0, hl = holes.length; h < hl; h ++ ) { + + const ahole = holes[ h ]; + + vertices = vertices.concat( ahole ); + + } + + + function scalePt2( pt, vec, size ) { + + if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' ); + + return pt.clone().addScaledVector( vec, size ); + + } + + const vlen = vertices.length, flen = faces.length; + + + // Find directions for point movement + + + function getBevelVec( inPt, inPrev, inNext ) { + + // computes for inPt the corresponding point inPt' on a new contour + // shifted by 1 unit (length of normalized vector) to the left + // if we walk along contour clockwise, this new contour is outside the old one + // + // inPt' is the intersection of the two lines parallel to the two + // adjacent edges of inPt at a distance of 1 unit on the left side. + + let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt + + // good reading for geometry algorithms (here: line-line intersection) + // http://geomalgorithms.com/a05-_intersect-1.html + + const v_prev_x = inPt.x - inPrev.x, + v_prev_y = inPt.y - inPrev.y; + const v_next_x = inNext.x - inPt.x, + v_next_y = inNext.y - inPt.y; + + const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); + + // check for collinear edges + const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + + if ( Math.abs( collinear0 ) > Number.EPSILON ) { + + // not collinear + + // length of vectors for normalizing + + const v_prev_len = Math.sqrt( v_prev_lensq ); + const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); + + // shift adjacent points by unit vectors to the left + + const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); + const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); + + const ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); + const ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); + + // scaling factor for v_prev to intersection point + + const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - + ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / + ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + + // vector from inPt to intersection point + + v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); + v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); + + // Don't normalize!, otherwise sharp corners become ugly + // but prevent crazy spikes + const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); + if ( v_trans_lensq <= 2 ) { + + return new Vector2( v_trans_x, v_trans_y ); + + } else { + + shrink_by = Math.sqrt( v_trans_lensq / 2 ); + + } + + } else { + + // handle special case of collinear edges + + let direction_eq = false; // assumes: opposite + + if ( v_prev_x > Number.EPSILON ) { + + if ( v_next_x > Number.EPSILON ) { + + direction_eq = true; + + } + + } else { + + if ( v_prev_x < - Number.EPSILON ) { + + if ( v_next_x < - Number.EPSILON ) { + + direction_eq = true; + + } + + } else { + + if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { + + direction_eq = true; + + } + + } + + } + + if ( direction_eq ) { + + // console.log("Warning: lines are a straight sequence"); + v_trans_x = - v_prev_y; + v_trans_y = v_prev_x; + shrink_by = Math.sqrt( v_prev_lensq ); + + } else { + + // console.log("Warning: lines are a straight spike"); + v_trans_x = v_prev_x; + v_trans_y = v_prev_y; + shrink_by = Math.sqrt( v_prev_lensq / 2 ); + + } + + } + + return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); + + } + + + const contourMovements = []; + + for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + + if ( j === il ) j = 0; + if ( k === il ) k = 0; + + // (j)---(i)---(k) + // console.log('i,j,k', i, j , k) + + contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); + + } + + const holesMovements = []; + let oneHoleMovements, verticesMovements = contourMovements.concat(); + + for ( let h = 0, hl = holes.length; h < hl; h ++ ) { + + const ahole = holes[ h ]; + + oneHoleMovements = []; + + for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + + if ( j === il ) j = 0; + if ( k === il ) k = 0; + + // (j)---(i)---(k) + oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); + + } + + holesMovements.push( oneHoleMovements ); + verticesMovements = verticesMovements.concat( oneHoleMovements ); + + } + + + // Loop bevelSegments, 1 for the front, 1 for the back + + for ( let b = 0; b < bevelSegments; b ++ ) { + + //for ( b = bevelSegments; b > 0; b -- ) { + + const t = b / bevelSegments; + const z = bevelThickness * Math.cos( t * Math.PI / 2 ); + const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; + + // contract shape + + for ( let i = 0, il = contour.length; i < il; i ++ ) { + + const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + + v( vert.x, vert.y, - z ); + + } + + // expand holes + + for ( let h = 0, hl = holes.length; h < hl; h ++ ) { + + const ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; + + for ( let i = 0, il = ahole.length; i < il; i ++ ) { + + const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + + v( vert.x, vert.y, - z ); + + } + + } + + } + + const bs = bevelSize + bevelOffset; + + // Back facing vertices + + for ( let i = 0; i < vlen; i ++ ) { + + const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + + if ( ! extrudeByPath ) { + + v( vert.x, vert.y, 0 ); + + } else { + + // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); + + normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); + + position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); + + v( position2.x, position2.y, position2.z ); + + } + + } + + // Add stepped vertices... + // Including front facing vertices + + for ( let s = 1; s <= steps; s ++ ) { + + for ( let i = 0; i < vlen; i ++ ) { + + const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + + if ( ! extrudeByPath ) { + + v( vert.x, vert.y, depth / steps * s ); + + } else { + + // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); + + normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); + + position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); + + v( position2.x, position2.y, position2.z ); + + } + + } + + } + + + // Add bevel segments planes + + //for ( b = 1; b <= bevelSegments; b ++ ) { + for ( let b = bevelSegments - 1; b >= 0; b -- ) { + + const t = b / bevelSegments; + const z = bevelThickness * Math.cos( t * Math.PI / 2 ); + const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; + + // contract shape + + for ( let i = 0, il = contour.length; i < il; i ++ ) { + + const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + v( vert.x, vert.y, depth + z ); + + } + + // expand holes + + for ( let h = 0, hl = holes.length; h < hl; h ++ ) { + + const ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; + + for ( let i = 0, il = ahole.length; i < il; i ++ ) { + + const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + + if ( ! extrudeByPath ) { + + v( vert.x, vert.y, depth + z ); + + } else { + + v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); + + } + + } + + } + + } + + /* Faces */ + + // Top and bottom faces + + buildLidFaces(); + + // Sides faces + + buildSideFaces(); + + + ///// Internal functions + + function buildLidFaces() { + + const start = verticesArray.length / 3; + + if ( bevelEnabled ) { + + let layer = 0; // steps + 1 + let offset = vlen * layer; + + // Bottom faces + + for ( let i = 0; i < flen; i ++ ) { + + const face = faces[ i ]; + f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); + + } + + layer = steps + bevelSegments * 2; + offset = vlen * layer; + + // Top faces + + for ( let i = 0; i < flen; i ++ ) { + + const face = faces[ i ]; + f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); + + } + + } else { + + // Bottom faces + + for ( let i = 0; i < flen; i ++ ) { + + const face = faces[ i ]; + f3( face[ 2 ], face[ 1 ], face[ 0 ] ); + + } + + // Top faces + + for ( let i = 0; i < flen; i ++ ) { + + const face = faces[ i ]; + f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); + + } + + } + + scope.addGroup( start, verticesArray.length / 3 - start, 0 ); + + } + + // Create faces for the z-sides of the shape + + function buildSideFaces() { + + const start = verticesArray.length / 3; + let layeroffset = 0; + sidewalls( contour, layeroffset ); + layeroffset += contour.length; + + for ( let h = 0, hl = holes.length; h < hl; h ++ ) { + + const ahole = holes[ h ]; + sidewalls( ahole, layeroffset ); + + //, true + layeroffset += ahole.length; + + } + + + scope.addGroup( start, verticesArray.length / 3 - start, 1 ); + + + } + + function sidewalls( contour, layeroffset ) { + + let i = contour.length; + + while ( -- i >= 0 ) { + + const j = i; + let k = i - 1; + if ( k < 0 ) k = contour.length - 1; + + //console.log('b', i,j, i-1, k,vertices.length); + + for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) { + + const slen1 = vlen * s; + const slen2 = vlen * ( s + 1 ); + + const a = layeroffset + j + slen1, + b = layeroffset + k + slen1, + c = layeroffset + k + slen2, + d = layeroffset + j + slen2; + + f4( a, b, c, d ); + + } + + } + + } + + function v( x, y, z ) { + + placeholder.push( x ); + placeholder.push( y ); + placeholder.push( z ); + + } + + + function f3( a, b, c ) { + + addVertex( a ); + addVertex( b ); + addVertex( c ); + + const nextIndex = verticesArray.length / 3; + const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); + + addUV( uvs[ 0 ] ); + addUV( uvs[ 1 ] ); + addUV( uvs[ 2 ] ); + + } + + function f4( a, b, c, d ) { + + addVertex( a ); + addVertex( b ); + addVertex( d ); + + addVertex( b ); + addVertex( c ); + addVertex( d ); + + + const nextIndex = verticesArray.length / 3; + const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); + + addUV( uvs[ 0 ] ); + addUV( uvs[ 1 ] ); + addUV( uvs[ 3 ] ); + + addUV( uvs[ 1 ] ); + addUV( uvs[ 2 ] ); + addUV( uvs[ 3 ] ); + + } + + function addVertex( index ) { + + verticesArray.push( placeholder[ index * 3 + 0 ] ); + verticesArray.push( placeholder[ index * 3 + 1 ] ); + verticesArray.push( placeholder[ index * 3 + 2 ] ); + + } + + + function addUV( vector2 ) { + + uvArray.push( vector2.x ); + uvArray.push( vector2.y ); + + } + + } + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + const shapes = this.parameters.shapes; + const options = this.parameters.options; + + return toJSON$1( shapes, options, data ); + + } + + static fromJSON( data, shapes ) { + + const geometryShapes = []; + + for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { + + const shape = shapes[ data.shapes[ j ] ]; + + geometryShapes.push( shape ); + + } + + const extrudePath = data.options.extrudePath; + + if ( extrudePath !== undefined ) { + + data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath ); + + } + + return new ExtrudeGeometry( geometryShapes, data.options ); + + } + +} + +const WorldUVGenerator = { + + generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { + + const a_x = vertices[ indexA * 3 ]; + const a_y = vertices[ indexA * 3 + 1 ]; + const b_x = vertices[ indexB * 3 ]; + const b_y = vertices[ indexB * 3 + 1 ]; + const c_x = vertices[ indexC * 3 ]; + const c_y = vertices[ indexC * 3 + 1 ]; + + return [ + new Vector2( a_x, a_y ), + new Vector2( b_x, b_y ), + new Vector2( c_x, c_y ) + ]; + + }, + + generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { + + const a_x = vertices[ indexA * 3 ]; + const a_y = vertices[ indexA * 3 + 1 ]; + const a_z = vertices[ indexA * 3 + 2 ]; + const b_x = vertices[ indexB * 3 ]; + const b_y = vertices[ indexB * 3 + 1 ]; + const b_z = vertices[ indexB * 3 + 2 ]; + const c_x = vertices[ indexC * 3 ]; + const c_y = vertices[ indexC * 3 + 1 ]; + const c_z = vertices[ indexC * 3 + 2 ]; + const d_x = vertices[ indexD * 3 ]; + const d_y = vertices[ indexD * 3 + 1 ]; + const d_z = vertices[ indexD * 3 + 2 ]; + + if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) { + + return [ + new Vector2( a_x, 1 - a_z ), + new Vector2( b_x, 1 - b_z ), + new Vector2( c_x, 1 - c_z ), + new Vector2( d_x, 1 - d_z ) + ]; + + } else { + + return [ + new Vector2( a_y, 1 - a_z ), + new Vector2( b_y, 1 - b_z ), + new Vector2( c_y, 1 - c_z ), + new Vector2( d_y, 1 - d_z ) + ]; + + } + + } + +}; + +function toJSON$1( shapes, options, data ) { + + data.shapes = []; + + if ( Array.isArray( shapes ) ) { + + for ( let i = 0, l = shapes.length; i < l; i ++ ) { + + const shape = shapes[ i ]; + + data.shapes.push( shape.uuid ); + + } + + } else { + + data.shapes.push( shapes.uuid ); + + } + + data.options = Object.assign( {}, options ); + + if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON(); + + return data; + +} + +class IcosahedronGeometry extends PolyhedronGeometry { + + constructor( radius = 1, detail = 0 ) { + + const t = ( 1 + Math.sqrt( 5 ) ) / 2; + + const vertices = [ + - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, + 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, + t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 + ]; + + const indices = [ + 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, + 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, + 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, + 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 + ]; + + super( vertices, indices, radius, detail ); + + this.type = 'IcosahedronGeometry'; + + this.parameters = { + radius: radius, + detail: detail + }; + + } + + static fromJSON( data ) { + + return new IcosahedronGeometry( data.radius, data.detail ); + + } + +} + +class OctahedronGeometry extends PolyhedronGeometry { + + constructor( radius = 1, detail = 0 ) { + + const vertices = [ + 1, 0, 0, - 1, 0, 0, 0, 1, 0, + 0, - 1, 0, 0, 0, 1, 0, 0, - 1 + ]; + + const indices = [ + 0, 2, 4, 0, 4, 3, 0, 3, 5, + 0, 5, 2, 1, 2, 5, 1, 5, 3, + 1, 3, 4, 1, 4, 2 + ]; + + super( vertices, indices, radius, detail ); + + this.type = 'OctahedronGeometry'; + + this.parameters = { + radius: radius, + detail: detail + }; + + } + + static fromJSON( data ) { + + return new OctahedronGeometry( data.radius, data.detail ); + + } + +} + +class PlaneGeometry extends BufferGeometry { + + constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) { + + super(); + + this.type = 'PlaneGeometry'; + + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; + + const width_half = width / 2; + const height_half = height / 2; + + const gridX = Math.floor( widthSegments ); + const gridY = Math.floor( heightSegments ); + + const gridX1 = gridX + 1; + const gridY1 = gridY + 1; + + const segment_width = width / gridX; + const segment_height = height / gridY; + + // + + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; + + for ( let iy = 0; iy < gridY1; iy ++ ) { + + const y = iy * segment_height - height_half; + + for ( let ix = 0; ix < gridX1; ix ++ ) { + + const x = ix * segment_width - width_half; + + vertices.push( x, - y, 0 ); + + normals.push( 0, 0, 1 ); + + uvs.push( ix / gridX ); + uvs.push( 1 - ( iy / gridY ) ); + + } + + } + + for ( let iy = 0; iy < gridY; iy ++ ) { + + for ( let ix = 0; ix < gridX; ix ++ ) { + + const a = ix + gridX1 * iy; + const b = ix + gridX1 * ( iy + 1 ); + const c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + const d = ( ix + 1 ) + gridX1 * iy; + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } + + } + + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + + static fromJSON( data ) { + + return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ); + + } + +} + +class RingGeometry extends BufferGeometry { + + constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) { + + super(); + + this.type = 'RingGeometry'; + + this.parameters = { + innerRadius: innerRadius, + outerRadius: outerRadius, + thetaSegments: thetaSegments, + phiSegments: phiSegments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + thetaSegments = Math.max( 3, thetaSegments ); + phiSegments = Math.max( 1, phiSegments ); + + // buffers + + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; + + // some helper variables + + let radius = innerRadius; + const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); + const vertex = new Vector3(); + const uv = new Vector2(); + + // generate vertices, normals and uvs + + for ( let j = 0; j <= phiSegments; j ++ ) { + + for ( let i = 0; i <= thetaSegments; i ++ ) { + + // values are generate from the inside of the ring to the outside + + const segment = thetaStart + i / thetaSegments * thetaLength; + + // vertex + + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); + + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal + + normals.push( 0, 0, 1 ); + + // uv + + uv.x = ( vertex.x / outerRadius + 1 ) / 2; + uv.y = ( vertex.y / outerRadius + 1 ) / 2; + + uvs.push( uv.x, uv.y ); + + } + + // increase the radius for next row of vertices + + radius += radiusStep; + + } + + // indices + + for ( let j = 0; j < phiSegments; j ++ ) { + + const thetaSegmentLevel = j * ( thetaSegments + 1 ); + + for ( let i = 0; i < thetaSegments; i ++ ) { + + const segment = i + thetaSegmentLevel; + + const a = segment; + const b = segment + thetaSegments + 1; + const c = segment + thetaSegments + 2; + const d = segment + 1; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } + + } + + // build geometry + + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + + static fromJSON( data ) { + + return new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength ); + + } + +} + +class ShapeGeometry extends BufferGeometry { + + constructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), curveSegments = 12 ) { + + super(); + + this.type = 'ShapeGeometry'; + + this.parameters = { + shapes: shapes, + curveSegments: curveSegments + }; + + // buffers + + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; + + // helper variables + + let groupStart = 0; + let groupCount = 0; + + // allow single and array values for "shapes" parameter + + if ( Array.isArray( shapes ) === false ) { + + addShape( shapes ); + + } else { + + for ( let i = 0; i < shapes.length; i ++ ) { + + addShape( shapes[ i ] ); + + this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support + + groupStart += groupCount; + groupCount = 0; + + } + + } + + // build geometry + + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + + // helper functions + + function addShape( shape ) { + + const indexOffset = vertices.length / 3; + const points = shape.extractPoints( curveSegments ); + + let shapeVertices = points.shape; + const shapeHoles = points.holes; + + // check direction of vertices + + if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { + + shapeVertices = shapeVertices.reverse(); + + } + + for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { + + const shapeHole = shapeHoles[ i ]; + + if ( ShapeUtils.isClockWise( shapeHole ) === true ) { + + shapeHoles[ i ] = shapeHole.reverse(); + + } + + } + + const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); + + // join vertices of inner and outer paths to a single array + + for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { + + const shapeHole = shapeHoles[ i ]; + shapeVertices = shapeVertices.concat( shapeHole ); + + } + + // vertices, normals, uvs + + for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) { + + const vertex = shapeVertices[ i ]; + + vertices.push( vertex.x, vertex.y, 0 ); + normals.push( 0, 0, 1 ); + uvs.push( vertex.x, vertex.y ); // world uvs + + } + + // indices + + for ( let i = 0, l = faces.length; i < l; i ++ ) { + + const face = faces[ i ]; + + const a = face[ 0 ] + indexOffset; + const b = face[ 1 ] + indexOffset; + const c = face[ 2 ] + indexOffset; + + indices.push( a, b, c ); + groupCount += 3; + + } + + } + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + const shapes = this.parameters.shapes; + + return toJSON( shapes, data ); + + } + + static fromJSON( data, shapes ) { + + const geometryShapes = []; + + for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { + + const shape = shapes[ data.shapes[ j ] ]; + + geometryShapes.push( shape ); + + } + + return new ShapeGeometry( geometryShapes, data.curveSegments ); + + } + +} + +function toJSON( shapes, data ) { + + data.shapes = []; + + if ( Array.isArray( shapes ) ) { + + for ( let i = 0, l = shapes.length; i < l; i ++ ) { + + const shape = shapes[ i ]; + + data.shapes.push( shape.uuid ); + + } + + } else { + + data.shapes.push( shapes.uuid ); + + } + + return data; + +} + +class SphereGeometry extends BufferGeometry { + + constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) { + + super(); + + this.type = 'SphereGeometry'; + + this.parameters = { + radius: radius, + widthSegments: widthSegments, + heightSegments: heightSegments, + phiStart: phiStart, + phiLength: phiLength, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + widthSegments = Math.max( 3, Math.floor( widthSegments ) ); + heightSegments = Math.max( 2, Math.floor( heightSegments ) ); + + const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI ); + + let index = 0; + const grid = []; + + const vertex = new Vector3(); + const normal = new Vector3(); + + // buffers + + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; + + // generate vertices, normals and uvs + + for ( let iy = 0; iy <= heightSegments; iy ++ ) { + + const verticesRow = []; + + const v = iy / heightSegments; + + // special case for the poles + + let uOffset = 0; + + if ( iy === 0 && thetaStart === 0 ) { + + uOffset = 0.5 / widthSegments; + + } else if ( iy === heightSegments && thetaEnd === Math.PI ) { + + uOffset = - 0.5 / widthSegments; + + } + + for ( let ix = 0; ix <= widthSegments; ix ++ ) { + + const u = ix / widthSegments; + + // vertex + + vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); + vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal + + normal.copy( vertex ).normalize(); + normals.push( normal.x, normal.y, normal.z ); + + // uv + + uvs.push( u + uOffset, 1 - v ); + + verticesRow.push( index ++ ); + + } + + grid.push( verticesRow ); + + } + + // indices + + for ( let iy = 0; iy < heightSegments; iy ++ ) { + + for ( let ix = 0; ix < widthSegments; ix ++ ) { + + const a = grid[ iy ][ ix + 1 ]; + const b = grid[ iy ][ ix ]; + const c = grid[ iy + 1 ][ ix ]; + const d = grid[ iy + 1 ][ ix + 1 ]; + + if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); + if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); + + } + + } + + // build geometry + + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + + static fromJSON( data ) { + + return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ); + + } + +} + +class TetrahedronGeometry extends PolyhedronGeometry { + + constructor( radius = 1, detail = 0 ) { + + const vertices = [ + 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 + ]; + + const indices = [ + 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 + ]; + + super( vertices, indices, radius, detail ); + + this.type = 'TetrahedronGeometry'; + + this.parameters = { + radius: radius, + detail: detail + }; + + } + + static fromJSON( data ) { + + return new TetrahedronGeometry( data.radius, data.detail ); + + } + +} + +class TorusGeometry extends BufferGeometry { + + constructor( radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2 ) { + + super(); + + this.type = 'TorusGeometry'; + + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + arc: arc + }; + + radialSegments = Math.floor( radialSegments ); + tubularSegments = Math.floor( tubularSegments ); + + // buffers + + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; + + // helper variables + + const center = new Vector3(); + const vertex = new Vector3(); + const normal = new Vector3(); + + // generate vertices, normals and uvs + + for ( let j = 0; j <= radialSegments; j ++ ) { + + for ( let i = 0; i <= tubularSegments; i ++ ) { + + const u = i / tubularSegments * arc; + const v = j / radialSegments * Math.PI * 2; + + // vertex + + vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); + vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); + vertex.z = tube * Math.sin( v ); + + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal + + center.x = radius * Math.cos( u ); + center.y = radius * Math.sin( u ); + normal.subVectors( vertex, center ).normalize(); + + normals.push( normal.x, normal.y, normal.z ); + + // uv + + uvs.push( i / tubularSegments ); + uvs.push( j / radialSegments ); + + } + + } + + // generate indices + + for ( let j = 1; j <= radialSegments; j ++ ) { + + for ( let i = 1; i <= tubularSegments; i ++ ) { + + // indices + + const a = ( tubularSegments + 1 ) * j + i - 1; + const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; + const c = ( tubularSegments + 1 ) * ( j - 1 ) + i; + const d = ( tubularSegments + 1 ) * j + i; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } + + } + + // build geometry + + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + + static fromJSON( data ) { + + return new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc ); + + } + +} + +class TorusKnotGeometry extends BufferGeometry { + + constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) { + + super(); + + this.type = 'TorusKnotGeometry'; + + this.parameters = { + radius: radius, + tube: tube, + tubularSegments: tubularSegments, + radialSegments: radialSegments, + p: p, + q: q + }; + + tubularSegments = Math.floor( tubularSegments ); + radialSegments = Math.floor( radialSegments ); + + // buffers + + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; + + // helper variables + + const vertex = new Vector3(); + const normal = new Vector3(); + + const P1 = new Vector3(); + const P2 = new Vector3(); + + const B = new Vector3(); + const T = new Vector3(); + const N = new Vector3(); + + // generate vertices, normals and uvs + + for ( let i = 0; i <= tubularSegments; ++ i ) { + + // the radian "u" is used to calculate the position on the torus curve of the current tubular segment + + const u = i / tubularSegments * p * Math.PI * 2; + + // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead. + // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions + + calculatePositionOnCurve( u, p, q, radius, P1 ); + calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); + + // calculate orthonormal basis + + T.subVectors( P2, P1 ); + N.addVectors( P2, P1 ); + B.crossVectors( T, N ); + N.crossVectors( B, T ); + + // normalize B, N. T can be ignored, we don't use it + + B.normalize(); + N.normalize(); + + for ( let j = 0; j <= radialSegments; ++ j ) { + + // now calculate the vertices. they are nothing more than an extrusion of the torus curve. + // because we extrude a shape in the xy-plane, there is no need to calculate a z-value. + + const v = j / radialSegments * Math.PI * 2; + const cx = - tube * Math.cos( v ); + const cy = tube * Math.sin( v ); + + // now calculate the final vertex position. + // first we orient the extrusion with our basis vectors, then we add it to the current position on the curve + + vertex.x = P1.x + ( cx * N.x + cy * B.x ); + vertex.y = P1.y + ( cx * N.y + cy * B.y ); + vertex.z = P1.z + ( cx * N.z + cy * B.z ); + + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) + + normal.subVectors( vertex, P1 ).normalize(); + + normals.push( normal.x, normal.y, normal.z ); + + // uv + + uvs.push( i / tubularSegments ); + uvs.push( j / radialSegments ); + + } + + } + + // generate indices + + for ( let j = 1; j <= tubularSegments; j ++ ) { + + for ( let i = 1; i <= radialSegments; i ++ ) { + + // indices + + const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); + const b = ( radialSegments + 1 ) * j + ( i - 1 ); + const c = ( radialSegments + 1 ) * j + i; + const d = ( radialSegments + 1 ) * ( j - 1 ) + i; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } + + } + + // build geometry + + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + // this function calculates the current position on the torus curve + + function calculatePositionOnCurve( u, p, q, radius, position ) { + + const cu = Math.cos( u ); + const su = Math.sin( u ); + const quOverP = q / p * u; + const cs = Math.cos( quOverP ); + + position.x = radius * ( 2 + cs ) * 0.5 * cu; + position.y = radius * ( 2 + cs ) * su * 0.5; + position.z = radius * Math.sin( quOverP ) * 0.5; + + } + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + + static fromJSON( data ) { + + return new TorusKnotGeometry( data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q ); + + } + +} + +class TubeGeometry extends BufferGeometry { + + constructor( path = new QuadraticBezierCurve3( new Vector3( - 1, - 1, 0 ), new Vector3( - 1, 1, 0 ), new Vector3( 1, 1, 0 ) ), tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) { + + super(); + + this.type = 'TubeGeometry'; + + this.parameters = { + path: path, + tubularSegments: tubularSegments, + radius: radius, + radialSegments: radialSegments, + closed: closed + }; + + const frames = path.computeFrenetFrames( tubularSegments, closed ); + + // expose internals + + this.tangents = frames.tangents; + this.normals = frames.normals; + this.binormals = frames.binormals; + + // helper variables + + const vertex = new Vector3(); + const normal = new Vector3(); + const uv = new Vector2(); + let P = new Vector3(); + + // buffer + + const vertices = []; + const normals = []; + const uvs = []; + const indices = []; + + // create buffer data + + generateBufferData(); + + // build geometry + + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + // functions + + function generateBufferData() { + + for ( let i = 0; i < tubularSegments; i ++ ) { + + generateSegment( i ); + + } + + // if the geometry is not closed, generate the last row of vertices and normals + // at the regular position on the given path + // + // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) + + generateSegment( ( closed === false ) ? tubularSegments : 0 ); + + // uvs are generated in a separate function. + // this makes it easy compute correct values for closed geometries + + generateUVs(); + + // finally create faces + + generateIndices(); + + } + + function generateSegment( i ) { + + // we use getPointAt to sample evenly distributed points from the given path + + P = path.getPointAt( i / tubularSegments, P ); + + // retrieve corresponding normal and binormal + + const N = frames.normals[ i ]; + const B = frames.binormals[ i ]; + + // generate normals and vertices for the current segment + + for ( let j = 0; j <= radialSegments; j ++ ) { + + const v = j / radialSegments * Math.PI * 2; + + const sin = Math.sin( v ); + const cos = - Math.cos( v ); + + // normal + + normal.x = ( cos * N.x + sin * B.x ); + normal.y = ( cos * N.y + sin * B.y ); + normal.z = ( cos * N.z + sin * B.z ); + normal.normalize(); + + normals.push( normal.x, normal.y, normal.z ); + + // vertex + + vertex.x = P.x + radius * normal.x; + vertex.y = P.y + radius * normal.y; + vertex.z = P.z + radius * normal.z; + + vertices.push( vertex.x, vertex.y, vertex.z ); + + } + + } + + function generateIndices() { + + for ( let j = 1; j <= tubularSegments; j ++ ) { + + for ( let i = 1; i <= radialSegments; i ++ ) { + + const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); + const b = ( radialSegments + 1 ) * j + ( i - 1 ); + const c = ( radialSegments + 1 ) * j + i; + const d = ( radialSegments + 1 ) * ( j - 1 ) + i; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } + + } + + } + + function generateUVs() { + + for ( let i = 0; i <= tubularSegments; i ++ ) { + + for ( let j = 0; j <= radialSegments; j ++ ) { + + uv.x = i / tubularSegments; + uv.y = j / radialSegments; + + uvs.push( uv.x, uv.y ); + + } + + } + + } + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.path = this.parameters.path.toJSON(); + + return data; + + } + + static fromJSON( data ) { + + // This only works for built-in curves (e.g. CatmullRomCurve3). + // User defined curves or instances of CurvePath will not be deserialized. + return new TubeGeometry( + new Curves[ data.path.type ]().fromJSON( data.path ), + data.tubularSegments, + data.radius, + data.radialSegments, + data.closed + ); + + } + +} + +class WireframeGeometry extends BufferGeometry { + + constructor( geometry = null ) { + + super(); + + this.type = 'WireframeGeometry'; + + this.parameters = { + geometry: geometry + }; + + if ( geometry !== null ) { + + // buffer + + const vertices = []; + const edges = new Set(); + + // helper variables + + const start = new Vector3(); + const end = new Vector3(); + + if ( geometry.index !== null ) { + + // indexed BufferGeometry + + const position = geometry.attributes.position; + const indices = geometry.index; + let groups = geometry.groups; + + if ( groups.length === 0 ) { + + groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; + + } + + // create a data structure that contains all edges without duplicates + + for ( let o = 0, ol = groups.length; o < ol; ++ o ) { + + const group = groups[ o ]; + + const groupStart = group.start; + const groupCount = group.count; + + for ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) { + + for ( let j = 0; j < 3; j ++ ) { + + const index1 = indices.getX( i + j ); + const index2 = indices.getX( i + ( j + 1 ) % 3 ); + + start.fromBufferAttribute( position, index1 ); + end.fromBufferAttribute( position, index2 ); + + if ( isUniqueEdge( start, end, edges ) === true ) { + + vertices.push( start.x, start.y, start.z ); + vertices.push( end.x, end.y, end.z ); + + } + + } + + } + + } + + } else { + + // non-indexed BufferGeometry + + const position = geometry.attributes.position; + + for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) { + + for ( let j = 0; j < 3; j ++ ) { + + // three edges per triangle, an edge is represented as (index1, index2) + // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) + + const index1 = 3 * i + j; + const index2 = 3 * i + ( ( j + 1 ) % 3 ); + + start.fromBufferAttribute( position, index1 ); + end.fromBufferAttribute( position, index2 ); + + if ( isUniqueEdge( start, end, edges ) === true ) { + + vertices.push( start.x, start.y, start.z ); + vertices.push( end.x, end.y, end.z ); + + } + + } + + } + + } + + // build geometry + + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + + } + + } + + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + +} + +function isUniqueEdge( start, end, edges ) { + + const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`; + const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge + + if ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) { + + return false; + + } else { + + edges.add( hash1 ); + edges.add( hash2 ); + return true; + + } + +} + +var Geometries$1 = /*#__PURE__*/Object.freeze({ + __proto__: null, + BoxGeometry: BoxGeometry, + CapsuleGeometry: CapsuleGeometry, + CircleGeometry: CircleGeometry, + ConeGeometry: ConeGeometry, + CylinderGeometry: CylinderGeometry, + DodecahedronGeometry: DodecahedronGeometry, + EdgesGeometry: EdgesGeometry, + ExtrudeGeometry: ExtrudeGeometry, + IcosahedronGeometry: IcosahedronGeometry, + LatheGeometry: LatheGeometry, + OctahedronGeometry: OctahedronGeometry, + PlaneGeometry: PlaneGeometry, + PolyhedronGeometry: PolyhedronGeometry, + RingGeometry: RingGeometry, + ShapeGeometry: ShapeGeometry, + SphereGeometry: SphereGeometry, + TetrahedronGeometry: TetrahedronGeometry, + TorusGeometry: TorusGeometry, + TorusKnotGeometry: TorusKnotGeometry, + TubeGeometry: TubeGeometry, + WireframeGeometry: WireframeGeometry +}); + +class ShadowMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isShadowMaterial = true; + + this.type = 'ShadowMaterial'; + + this.color = new Color( 0x000000 ); + this.transparent = true; + + this.fog = true; + + this.setValues( parameters ); + + } + + copy( source ) { + + super.copy( source ); + + this.color.copy( source.color ); + + this.fog = source.fog; + + return this; + + } + +} + +class RawShaderMaterial extends ShaderMaterial { + + constructor( parameters ) { + + super( parameters ); + + this.isRawShaderMaterial = true; + + this.type = 'RawShaderMaterial'; + + } + +} + +class MeshStandardMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isMeshStandardMaterial = true; + + this.defines = { 'STANDARD': '' }; + + this.type = 'MeshStandardMaterial'; + + this.color = new Color( 0xffffff ); // diffuse + this.roughness = 1.0; + this.metalness = 0.0; + + this.map = null; + + this.lightMap = null; + this.lightMapIntensity = 1.0; + + this.aoMap = null; + this.aoMapIntensity = 1.0; + + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); + + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; + + this.roughnessMap = null; + + this.metalnessMap = null; + + this.alphaMap = null; + + this.envMap = null; + this.envMapRotation = new Euler(); + this.envMapIntensity = 1.0; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.flatShading = false; + + this.fog = true; + + this.setValues( parameters ); + + } + + copy( source ) { + + super.copy( source ); + + this.defines = { 'STANDARD': '' }; + + this.color.copy( source.color ); + this.roughness = source.roughness; + this.metalness = source.metalness; + + this.map = source.map; + + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; + + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; + + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; + + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; + + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + this.roughnessMap = source.roughnessMap; + + this.metalnessMap = source.metalnessMap; + + this.alphaMap = source.alphaMap; + + this.envMap = source.envMap; + this.envMapRotation.copy( source.envMapRotation ); + this.envMapIntensity = source.envMapIntensity; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; + + this.flatShading = source.flatShading; + + this.fog = source.fog; + + return this; + + } + +} + +class MeshPhysicalMaterial extends MeshStandardMaterial { + + constructor( parameters ) { + + super(); + + this.isMeshPhysicalMaterial = true; + + this.defines = { + + 'STANDARD': '', + 'PHYSICAL': '' + + }; + + this.type = 'MeshPhysicalMaterial'; + + this.anisotropyRotation = 0; + this.anisotropyMap = null; + + this.clearcoatMap = null; + this.clearcoatRoughness = 0.0; + this.clearcoatRoughnessMap = null; + this.clearcoatNormalScale = new Vector2( 1, 1 ); + this.clearcoatNormalMap = null; + + this.ior = 1.5; + + Object.defineProperty( this, 'reflectivity', { + get: function () { + + return ( clamp$1( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) ); + + }, + set: function ( reflectivity ) { + + this.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity ); + + } + } ); + + this.iridescenceMap = null; + this.iridescenceIOR = 1.3; + this.iridescenceThicknessRange = [ 100, 400 ]; + this.iridescenceThicknessMap = null; + + this.sheenColor = new Color( 0x000000 ); + this.sheenColorMap = null; + this.sheenRoughness = 1.0; + this.sheenRoughnessMap = null; + + this.transmissionMap = null; + + this.thickness = 0; + this.thicknessMap = null; + this.attenuationDistance = Infinity; + this.attenuationColor = new Color( 1, 1, 1 ); + + this.specularIntensity = 1.0; + this.specularIntensityMap = null; + this.specularColor = new Color( 1, 1, 1 ); + this.specularColorMap = null; + + this._anisotropy = 0; + this._clearcoat = 0; + this._dispersion = 0; + this._iridescence = 0; + this._sheen = 0.0; + this._transmission = 0; + + this.setValues( parameters ); + + } + + get anisotropy() { + + return this._anisotropy; + + } + + set anisotropy( value ) { + + if ( this._anisotropy > 0 !== value > 0 ) { + + this.version ++; + + } + + this._anisotropy = value; + + } + + get clearcoat() { + + return this._clearcoat; + + } + + set clearcoat( value ) { + + if ( this._clearcoat > 0 !== value > 0 ) { + + this.version ++; + + } + + this._clearcoat = value; + + } + + get iridescence() { + + return this._iridescence; + + } + + set iridescence( value ) { + + if ( this._iridescence > 0 !== value > 0 ) { + + this.version ++; + + } + + this._iridescence = value; + + } + + get dispersion() { + + return this._dispersion; + + } + + set dispersion( value ) { + + if ( this._dispersion > 0 !== value > 0 ) { + + this.version ++; + + } + + this._dispersion = value; + + } + + get sheen() { + + return this._sheen; + + } + + set sheen( value ) { + + if ( this._sheen > 0 !== value > 0 ) { + + this.version ++; + + } + + this._sheen = value; + + } + + get transmission() { + + return this._transmission; + + } + + set transmission( value ) { + + if ( this._transmission > 0 !== value > 0 ) { + + this.version ++; + + } + + this._transmission = value; + + } + + copy( source ) { + + super.copy( source ); + + this.defines = { + + 'STANDARD': '', + 'PHYSICAL': '' + + }; + + this.anisotropy = source.anisotropy; + this.anisotropyRotation = source.anisotropyRotation; + this.anisotropyMap = source.anisotropyMap; + + this.clearcoat = source.clearcoat; + this.clearcoatMap = source.clearcoatMap; + this.clearcoatRoughness = source.clearcoatRoughness; + this.clearcoatRoughnessMap = source.clearcoatRoughnessMap; + this.clearcoatNormalMap = source.clearcoatNormalMap; + this.clearcoatNormalScale.copy( source.clearcoatNormalScale ); + + this.dispersion = source.dispersion; + this.ior = source.ior; + + this.iridescence = source.iridescence; + this.iridescenceMap = source.iridescenceMap; + this.iridescenceIOR = source.iridescenceIOR; + this.iridescenceThicknessRange = [ ...source.iridescenceThicknessRange ]; + this.iridescenceThicknessMap = source.iridescenceThicknessMap; + + this.sheen = source.sheen; + this.sheenColor.copy( source.sheenColor ); + this.sheenColorMap = source.sheenColorMap; + this.sheenRoughness = source.sheenRoughness; + this.sheenRoughnessMap = source.sheenRoughnessMap; + + this.transmission = source.transmission; + this.transmissionMap = source.transmissionMap; + + this.thickness = source.thickness; + this.thicknessMap = source.thicknessMap; + this.attenuationDistance = source.attenuationDistance; + this.attenuationColor.copy( source.attenuationColor ); + + this.specularIntensity = source.specularIntensity; + this.specularIntensityMap = source.specularIntensityMap; + this.specularColor.copy( source.specularColor ); + this.specularColorMap = source.specularColorMap; + + return this; + + } + +} + +class MeshPhongMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isMeshPhongMaterial = true; + + this.type = 'MeshPhongMaterial'; + + this.color = new Color( 0xffffff ); // diffuse + this.specular = new Color( 0x111111 ); + this.shininess = 30; + + this.map = null; + + this.lightMap = null; + this.lightMapIntensity = 1.0; + + this.aoMap = null; + this.aoMapIntensity = 1.0; + + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); + + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; + + this.specularMap = null; + + this.alphaMap = null; + + this.envMap = null; + this.envMapRotation = new Euler(); + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.flatShading = false; + + this.fog = true; + + this.setValues( parameters ); + + } + + copy( source ) { + + super.copy( source ); + + this.color.copy( source.color ); + this.specular.copy( source.specular ); + this.shininess = source.shininess; + + this.map = source.map; + + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; + + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; + + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; + + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; + + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + this.specularMap = source.specularMap; + + this.alphaMap = source.alphaMap; + + this.envMap = source.envMap; + this.envMapRotation.copy( source.envMapRotation ); + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; + + this.flatShading = source.flatShading; + + this.fog = source.fog; + + return this; + + } + +} + +class MeshToonMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isMeshToonMaterial = true; + + this.defines = { 'TOON': '' }; + + this.type = 'MeshToonMaterial'; + + this.color = new Color( 0xffffff ); + + this.map = null; + this.gradientMap = null; + + this.lightMap = null; + this.lightMapIntensity = 1.0; + + this.aoMap = null; + this.aoMapIntensity = 1.0; + + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); + + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; + + this.alphaMap = null; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.fog = true; + + this.setValues( parameters ); + + } + + copy( source ) { + + super.copy( source ); + + this.color.copy( source.color ); + + this.map = source.map; + this.gradientMap = source.gradientMap; + + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; + + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; + + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; + + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; + + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + this.alphaMap = source.alphaMap; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; + + this.fog = source.fog; + + return this; + + } + +} + +class MeshNormalMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isMeshNormalMaterial = true; + + this.type = 'MeshNormalMaterial'; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); + + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.flatShading = false; + + this.setValues( parameters ); + + } + + copy( source ) { + + super.copy( source ); + + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; + + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + + this.flatShading = source.flatShading; + + return this; + + } + +} + +class MeshLambertMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isMeshLambertMaterial = true; + + this.type = 'MeshLambertMaterial'; + + this.color = new Color( 0xffffff ); // diffuse + + this.map = null; + + this.lightMap = null; + this.lightMapIntensity = 1.0; + + this.aoMap = null; + this.aoMapIntensity = 1.0; + + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); + + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; + + this.specularMap = null; + + this.alphaMap = null; + + this.envMap = null; + this.envMapRotation = new Euler(); + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.flatShading = false; + + this.fog = true; + + this.setValues( parameters ); + + } + + copy( source ) { + + super.copy( source ); + + this.color.copy( source.color ); + + this.map = source.map; + + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; + + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; + + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; + + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; + + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + this.specularMap = source.specularMap; + + this.alphaMap = source.alphaMap; + + this.envMap = source.envMap; + this.envMapRotation.copy( source.envMapRotation ); + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; + + this.flatShading = source.flatShading; + + this.fog = source.fog; + + return this; + + } + +} + +class MeshDepthMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isMeshDepthMaterial = true; + + this.type = 'MeshDepthMaterial'; + + this.depthPacking = BasicDepthPacking; + + this.map = null; + + this.alphaMap = null; + + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.setValues( parameters ); + + } + + copy( source ) { + + super.copy( source ); + + this.depthPacking = source.depthPacking; + + this.map = source.map; + + this.alphaMap = source.alphaMap; + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + + return this; + + } + +} + +class MeshDistanceMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isMeshDistanceMaterial = true; + + this.type = 'MeshDistanceMaterial'; + + this.map = null; + + this.alphaMap = null; + + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; + + this.setValues( parameters ); + + } + + copy( source ) { + + super.copy( source ); + + this.map = source.map; + + this.alphaMap = source.alphaMap; + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + return this; + + } + +} + +class MeshMatcapMaterial extends Material { + + constructor( parameters ) { + + super(); + + this.isMeshMatcapMaterial = true; + + this.defines = { 'MATCAP': '' }; + + this.type = 'MeshMatcapMaterial'; + + this.color = new Color( 0xffffff ); // diffuse + + this.matcap = null; + + this.map = null; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); + + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; + + this.alphaMap = null; + + this.flatShading = false; + + this.fog = true; + + this.setValues( parameters ); + + } + + + copy( source ) { + + super.copy( source ); + + this.defines = { 'MATCAP': '' }; + + this.color.copy( source.color ); + + this.matcap = source.matcap; + + this.map = source.map; + + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; + + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + this.alphaMap = source.alphaMap; + + this.flatShading = source.flatShading; + + this.fog = source.fog; + + return this; + + } + +} + +class LineDashedMaterial extends LineBasicMaterial { + + constructor( parameters ) { + + super(); + + this.isLineDashedMaterial = true; + + this.type = 'LineDashedMaterial'; + + this.scale = 1; + this.dashSize = 3; + this.gapSize = 1; + + this.setValues( parameters ); + + } + + copy( source ) { + + super.copy( source ); + + this.scale = source.scale; + this.dashSize = source.dashSize; + this.gapSize = source.gapSize; + + return this; + + } + +} + +// converts an array to a specific type +function convertArray( array, type, forceClone ) { + + if ( ! array || // let 'undefined' and 'null' pass + ! forceClone && array.constructor === type ) return array; + + if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { + + return new type( array ); // create typed array + + } + + return Array.prototype.slice.call( array ); // create Array + +} + +function isTypedArray( object ) { + + return ArrayBuffer.isView( object ) && + ! ( object instanceof DataView ); + +} + +// returns an array by which times and values can be sorted +function getKeyframeOrder( times ) { + + function compareTime( i, j ) { + + return times[ i ] - times[ j ]; + + } + + const n = times.length; + const result = new Array( n ); + for ( let i = 0; i !== n; ++ i ) result[ i ] = i; + + result.sort( compareTime ); + + return result; + +} + +// uses the array previously returned by 'getKeyframeOrder' to sort data +function sortedArray( values, stride, order ) { + + const nValues = values.length; + const result = new values.constructor( nValues ); + + for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { + + const srcOffset = order[ i ] * stride; + + for ( let j = 0; j !== stride; ++ j ) { + + result[ dstOffset ++ ] = values[ srcOffset + j ]; + + } + + } + + return result; + +} + +// function for parsing AOS keyframe formats +function flattenJSON( jsonKeys, times, values, valuePropertyName ) { + + let i = 1, key = jsonKeys[ 0 ]; + + while ( key !== undefined && key[ valuePropertyName ] === undefined ) { + + key = jsonKeys[ i ++ ]; + + } + + if ( key === undefined ) return; // no data + + let value = key[ valuePropertyName ]; + if ( value === undefined ) return; // no data + + if ( Array.isArray( value ) ) { + + do { + + value = key[ valuePropertyName ]; + + if ( value !== undefined ) { + + times.push( key.time ); + values.push.apply( values, value ); // push all elements + + } + + key = jsonKeys[ i ++ ]; + + } while ( key !== undefined ); + + } else if ( value.toArray !== undefined ) { + + // ...assume THREE.Math-ish + + do { + + value = key[ valuePropertyName ]; + + if ( value !== undefined ) { + + times.push( key.time ); + value.toArray( values, values.length ); + + } + + key = jsonKeys[ i ++ ]; + + } while ( key !== undefined ); + + } else { + + // otherwise push as-is + + do { + + value = key[ valuePropertyName ]; + + if ( value !== undefined ) { + + times.push( key.time ); + values.push( value ); + + } + + key = jsonKeys[ i ++ ]; + + } while ( key !== undefined ); + + } + +} + +function subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) { + + const clip = sourceClip.clone(); + + clip.name = name; + + const tracks = []; + + for ( let i = 0; i < clip.tracks.length; ++ i ) { + + const track = clip.tracks[ i ]; + const valueSize = track.getValueSize(); + + const times = []; + const values = []; + + for ( let j = 0; j < track.times.length; ++ j ) { + + const frame = track.times[ j ] * fps; + + if ( frame < startFrame || frame >= endFrame ) continue; + + times.push( track.times[ j ] ); + + for ( let k = 0; k < valueSize; ++ k ) { + + values.push( track.values[ j * valueSize + k ] ); + + } + + } + + if ( times.length === 0 ) continue; + + track.times = convertArray( times, track.times.constructor ); + track.values = convertArray( values, track.values.constructor ); + + tracks.push( track ); + + } + + clip.tracks = tracks; + + // find minimum .times value across all tracks in the trimmed clip + + let minStartTime = Infinity; + + for ( let i = 0; i < clip.tracks.length; ++ i ) { + + if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) { + + minStartTime = clip.tracks[ i ].times[ 0 ]; + + } + + } + + // shift all tracks such that clip begins at t=0 + + for ( let i = 0; i < clip.tracks.length; ++ i ) { + + clip.tracks[ i ].shift( - 1 * minStartTime ); + + } + + clip.resetDuration(); + + return clip; + +} + +function makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) { + + if ( fps <= 0 ) fps = 30; + + const numTracks = referenceClip.tracks.length; + const referenceTime = referenceFrame / fps; + + // Make each track's values relative to the values at the reference frame + for ( let i = 0; i < numTracks; ++ i ) { + + const referenceTrack = referenceClip.tracks[ i ]; + const referenceTrackType = referenceTrack.ValueTypeName; + + // Skip this track if it's non-numeric + if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue; + + // Find the track in the target clip whose name and type matches the reference track + const targetTrack = targetClip.tracks.find( function ( track ) { + + return track.name === referenceTrack.name + && track.ValueTypeName === referenceTrackType; + + } ); + + if ( targetTrack === undefined ) continue; + + let referenceOffset = 0; + const referenceValueSize = referenceTrack.getValueSize(); + + if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { + + referenceOffset = referenceValueSize / 3; + + } + + let targetOffset = 0; + const targetValueSize = targetTrack.getValueSize(); + + if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { + + targetOffset = targetValueSize / 3; + + } + + const lastIndex = referenceTrack.times.length - 1; + let referenceValue; + + // Find the value to subtract out of the track + if ( referenceTime <= referenceTrack.times[ 0 ] ) { + + // Reference frame is earlier than the first keyframe, so just use the first keyframe + const startIndex = referenceOffset; + const endIndex = referenceValueSize - referenceOffset; + referenceValue = referenceTrack.values.slice( startIndex, endIndex ); + + } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) { + + // Reference frame is after the last keyframe, so just use the last keyframe + const startIndex = lastIndex * referenceValueSize + referenceOffset; + const endIndex = startIndex + referenceValueSize - referenceOffset; + referenceValue = referenceTrack.values.slice( startIndex, endIndex ); + + } else { + + // Interpolate to the reference value + const interpolant = referenceTrack.createInterpolant(); + const startIndex = referenceOffset; + const endIndex = referenceValueSize - referenceOffset; + interpolant.evaluate( referenceTime ); + referenceValue = interpolant.resultBuffer.slice( startIndex, endIndex ); + + } + + // Conjugate the quaternion + if ( referenceTrackType === 'quaternion' ) { + + const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate(); + referenceQuat.toArray( referenceValue ); + + } + + // Subtract the reference value from all of the track values + + const numTimes = targetTrack.times.length; + for ( let j = 0; j < numTimes; ++ j ) { + + const valueStart = j * targetValueSize + targetOffset; + + if ( referenceTrackType === 'quaternion' ) { + + // Multiply the conjugate for quaternion track types + Quaternion.multiplyQuaternionsFlat( + targetTrack.values, + valueStart, + referenceValue, + 0, + targetTrack.values, + valueStart + ); + + } else { + + const valueEnd = targetValueSize - targetOffset * 2; + + // Subtract each value for all other numeric track types + for ( let k = 0; k < valueEnd; ++ k ) { + + targetTrack.values[ valueStart + k ] -= referenceValue[ k ]; + + } + + } + + } + + } + + targetClip.blendMode = AdditiveAnimationBlendMode; + + return targetClip; + +} + +const AnimationUtils = { + convertArray: convertArray, + isTypedArray: isTypedArray, + getKeyframeOrder: getKeyframeOrder, + sortedArray: sortedArray, + flattenJSON: flattenJSON, + subclip: subclip, + makeClipAdditive: makeClipAdditive +}; + +/** + * Abstract base class of interpolants over parametric samples. + * + * The parameter domain is one dimensional, typically the time or a path + * along a curve defined by the data. + * + * The sample values can have any dimensionality and derived classes may + * apply special interpretations to the data. + * + * This class provides the interval seek in a Template Method, deferring + * the actual interpolation to derived classes. + * + * Time complexity is O(1) for linear access crossing at most two points + * and O(log N) for random access, where N is the number of positions. + * + * References: + * + * http://www.oodesign.com/template-method-pattern.html + * + */ + +class Interpolant { + + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + this.parameterPositions = parameterPositions; + this._cachedIndex = 0; + + this.resultBuffer = resultBuffer !== undefined ? + resultBuffer : new sampleValues.constructor( sampleSize ); + this.sampleValues = sampleValues; + this.valueSize = sampleSize; + + this.settings = null; + this.DefaultSettings_ = {}; + + } + + evaluate( t ) { + + const pp = this.parameterPositions; + let i1 = this._cachedIndex, + t1 = pp[ i1 ], + t0 = pp[ i1 - 1 ]; + + validate_interval: { + + seek: { + + let right; + + linear_scan: { + + //- See http://jsperf.com/comparison-to-undefined/3 + //- slower code: + //- + //- if ( t >= t1 || t1 === undefined ) { + forward_scan: if ( ! ( t < t1 ) ) { + + for ( let giveUpAt = i1 + 2; ; ) { + + if ( t1 === undefined ) { + + if ( t < t0 ) break forward_scan; + + // after end + + i1 = pp.length; + this._cachedIndex = i1; + return this.copySampleValue_( i1 - 1 ); + + } + + if ( i1 === giveUpAt ) break; // this loop + + t0 = t1; + t1 = pp[ ++ i1 ]; + + if ( t < t1 ) { + + // we have arrived at the sought interval + break seek; + + } + + } + + // prepare binary search on the right side of the index + right = pp.length; + break linear_scan; + + } + + //- slower code: + //- if ( t < t0 || t0 === undefined ) { + if ( ! ( t >= t0 ) ) { + + // looping? + + const t1global = pp[ 1 ]; + + if ( t < t1global ) { + + i1 = 2; // + 1, using the scan for the details + t0 = t1global; + + } + + // linear reverse scan + + for ( let giveUpAt = i1 - 2; ; ) { + + if ( t0 === undefined ) { + + // before start + + this._cachedIndex = 0; + return this.copySampleValue_( 0 ); + + } + + if ( i1 === giveUpAt ) break; // this loop + + t1 = t0; + t0 = pp[ -- i1 - 1 ]; + + if ( t >= t0 ) { + + // we have arrived at the sought interval + break seek; + + } + + } + + // prepare binary search on the left side of the index + right = i1; + i1 = 0; + break linear_scan; + + } + + // the interval is valid + + break validate_interval; + + } // linear scan + + // binary search + + while ( i1 < right ) { + + const mid = ( i1 + right ) >>> 1; + + if ( t < pp[ mid ] ) { + + right = mid; + + } else { + + i1 = mid + 1; + + } + + } + + t1 = pp[ i1 ]; + t0 = pp[ i1 - 1 ]; + + // check boundary cases, again + + if ( t0 === undefined ) { + + this._cachedIndex = 0; + return this.copySampleValue_( 0 ); + + } + + if ( t1 === undefined ) { + + i1 = pp.length; + this._cachedIndex = i1; + return this.copySampleValue_( i1 - 1 ); + + } + + } // seek + + this._cachedIndex = i1; + + this.intervalChanged_( i1, t0, t1 ); + + } // validate_interval + + return this.interpolate_( i1, t0, t, t1 ); + + } + + getSettings_() { + + return this.settings || this.DefaultSettings_; + + } + + copySampleValue_( index ) { + + // copies a sample value to the result buffer + + const result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + offset = index * stride; + + for ( let i = 0; i !== stride; ++ i ) { + + result[ i ] = values[ offset + i ]; + + } + + return result; + + } + + // Template methods for derived classes: + + interpolate_( /* i1, t0, t, t1 */ ) { + + throw new Error( 'call to abstract method' ); + // implementations shall return this.resultBuffer + + } + + intervalChanged_( /* i1, t0, t1 */ ) { + + // empty + + } + +} + +/** + * Fast and simple cubic spline interpolant. + * + * It was derived from a Hermitian construction setting the first derivative + * at each sample position to the linear slope between neighboring positions + * over their parameter interval. + */ + +class CubicInterpolant extends Interpolant { + + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + super( parameterPositions, sampleValues, sampleSize, resultBuffer ); + + this._weightPrev = - 0; + this._offsetPrev = - 0; + this._weightNext = - 0; + this._offsetNext = - 0; + + this.DefaultSettings_ = { + + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding + + }; + + } + + intervalChanged_( i1, t0, t1 ) { + + const pp = this.parameterPositions; + let iPrev = i1 - 2, + iNext = i1 + 1, + + tPrev = pp[ iPrev ], + tNext = pp[ iNext ]; + + if ( tPrev === undefined ) { + + switch ( this.getSettings_().endingStart ) { + + case ZeroSlopeEnding: + + // f'(t0) = 0 + iPrev = i1; + tPrev = 2 * t0 - t1; + + break; + + case WrapAroundEnding: + + // use the other end of the curve + iPrev = pp.length - 2; + tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; + + break; + + default: // ZeroCurvatureEnding + + // f''(t0) = 0 a.k.a. Natural Spline + iPrev = i1; + tPrev = t1; + + } + + } + + if ( tNext === undefined ) { + + switch ( this.getSettings_().endingEnd ) { + + case ZeroSlopeEnding: + + // f'(tN) = 0 + iNext = i1; + tNext = 2 * t1 - t0; + + break; + + case WrapAroundEnding: + + // use the other end of the curve + iNext = 1; + tNext = t1 + pp[ 1 ] - pp[ 0 ]; + + break; + + default: // ZeroCurvatureEnding + + // f''(tN) = 0, a.k.a. Natural Spline + iNext = i1 - 1; + tNext = t0; + + } + + } + + const halfDt = ( t1 - t0 ) * 0.5, + stride = this.valueSize; + + this._weightPrev = halfDt / ( t0 - tPrev ); + this._weightNext = halfDt / ( tNext - t1 ); + this._offsetPrev = iPrev * stride; + this._offsetNext = iNext * stride; + + } + + interpolate_( i1, t0, t, t1 ) { + + const result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + + o1 = i1 * stride, o0 = o1 - stride, + oP = this._offsetPrev, oN = this._offsetNext, + wP = this._weightPrev, wN = this._weightNext, + + p = ( t - t0 ) / ( t1 - t0 ), + pp = p * p, + ppp = pp * p; + + // evaluate polynomials + + const sP = - wP * ppp + 2 * wP * pp - wP * p; + const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; + const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; + const sN = wN * ppp - wN * pp; + + // combine data linearly + + for ( let i = 0; i !== stride; ++ i ) { + + result[ i ] = + sP * values[ oP + i ] + + s0 * values[ o0 + i ] + + s1 * values[ o1 + i ] + + sN * values[ oN + i ]; + + } + + return result; + + } + +} + +class LinearInterpolant extends Interpolant { + + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + super( parameterPositions, sampleValues, sampleSize, resultBuffer ); + + } + + interpolate_( i1, t0, t, t1 ) { + + const result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + + offset1 = i1 * stride, + offset0 = offset1 - stride, + + weight1 = ( t - t0 ) / ( t1 - t0 ), + weight0 = 1 - weight1; + + for ( let i = 0; i !== stride; ++ i ) { + + result[ i ] = + values[ offset0 + i ] * weight0 + + values[ offset1 + i ] * weight1; + + } + + return result; + + } + +} + +/** + * + * Interpolant that evaluates to the sample value at the position preceding + * the parameter. + */ + +class DiscreteInterpolant extends Interpolant { + + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + super( parameterPositions, sampleValues, sampleSize, resultBuffer ); + + } + + interpolate_( i1 /*, t0, t, t1 */ ) { + + return this.copySampleValue_( i1 - 1 ); + + } + +} + +class KeyframeTrack { + + constructor( name, times, values, interpolation ) { + + if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); + if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); + + this.name = name; + + this.times = convertArray( times, this.TimeBufferType ); + this.values = convertArray( values, this.ValueBufferType ); + + this.setInterpolation( interpolation || this.DefaultInterpolation ); + + } + + // Serialization (in static context, because of constructor invocation + // and automatic invocation of .toJSON): + + static toJSON( track ) { + + const trackType = track.constructor; + + let json; + + // derived classes can define a static toJSON method + if ( trackType.toJSON !== this.toJSON ) { + + json = trackType.toJSON( track ); + + } else { + + // by default, we assume the data can be serialized as-is + json = { + + 'name': track.name, + 'times': convertArray( track.times, Array ), + 'values': convertArray( track.values, Array ) + + }; + + const interpolation = track.getInterpolation(); + + if ( interpolation !== track.DefaultInterpolation ) { + + json.interpolation = interpolation; + + } + + } + + json.type = track.ValueTypeName; // mandatory + + return json; + + } + + InterpolantFactoryMethodDiscrete( result ) { + + return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); + + } + + InterpolantFactoryMethodLinear( result ) { + + return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); + + } + + InterpolantFactoryMethodSmooth( result ) { + + return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); + + } + + setInterpolation( interpolation ) { + + let factoryMethod; + + switch ( interpolation ) { + + case InterpolateDiscrete: + + factoryMethod = this.InterpolantFactoryMethodDiscrete; + + break; + + case InterpolateLinear: + + factoryMethod = this.InterpolantFactoryMethodLinear; + + break; + + case InterpolateSmooth: + + factoryMethod = this.InterpolantFactoryMethodSmooth; + + break; + + } + + if ( factoryMethod === undefined ) { + + const message = 'unsupported interpolation for ' + + this.ValueTypeName + ' keyframe track named ' + this.name; + + if ( this.createInterpolant === undefined ) { + + // fall back to default, unless the default itself is messed up + if ( interpolation !== this.DefaultInterpolation ) { + + this.setInterpolation( this.DefaultInterpolation ); + + } else { + + throw new Error( message ); // fatal, in this case + + } + + } + + console.warn( 'THREE.KeyframeTrack:', message ); + return this; + + } + + this.createInterpolant = factoryMethod; + + return this; + + } + + getInterpolation() { + + switch ( this.createInterpolant ) { + + case this.InterpolantFactoryMethodDiscrete: + + return InterpolateDiscrete; + + case this.InterpolantFactoryMethodLinear: + + return InterpolateLinear; + + case this.InterpolantFactoryMethodSmooth: + + return InterpolateSmooth; + + } + + } + + getValueSize() { + + return this.values.length / this.times.length; + + } + + // move all keyframes either forwards or backwards in time + shift( timeOffset ) { + + if ( timeOffset !== 0.0 ) { + + const times = this.times; + + for ( let i = 0, n = times.length; i !== n; ++ i ) { + + times[ i ] += timeOffset; + + } + + } + + return this; + + } + + // scale all keyframe times by a factor (useful for frame <-> seconds conversions) + scale( timeScale ) { + + if ( timeScale !== 1.0 ) { + + const times = this.times; + + for ( let i = 0, n = times.length; i !== n; ++ i ) { + + times[ i ] *= timeScale; + + } + + } + + return this; + + } + + // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. + // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values + trim( startTime, endTime ) { + + const times = this.times, + nKeys = times.length; + + let from = 0, + to = nKeys - 1; + + while ( from !== nKeys && times[ from ] < startTime ) { + + ++ from; + + } + + while ( to !== - 1 && times[ to ] > endTime ) { + + -- to; + + } + + ++ to; // inclusive -> exclusive bound + + if ( from !== 0 || to !== nKeys ) { + + // empty tracks are forbidden, so keep at least one keyframe + if ( from >= to ) { + + to = Math.max( to, 1 ); + from = to - 1; + + } + + const stride = this.getValueSize(); + this.times = times.slice( from, to ); + this.values = this.values.slice( from * stride, to * stride ); + + } + + return this; + + } + + // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable + validate() { + + let valid = true; + + const valueSize = this.getValueSize(); + if ( valueSize - Math.floor( valueSize ) !== 0 ) { + + console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); + valid = false; + + } + + const times = this.times, + values = this.values, + + nKeys = times.length; + + if ( nKeys === 0 ) { + + console.error( 'THREE.KeyframeTrack: Track is empty.', this ); + valid = false; + + } + + let prevTime = null; + + for ( let i = 0; i !== nKeys; i ++ ) { + + const currTime = times[ i ]; + + if ( typeof currTime === 'number' && isNaN( currTime ) ) { + + console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); + valid = false; + break; + + } + + if ( prevTime !== null && prevTime > currTime ) { + + console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); + valid = false; + break; + + } + + prevTime = currTime; + + } + + if ( values !== undefined ) { + + if ( isTypedArray( values ) ) { + + for ( let i = 0, n = values.length; i !== n; ++ i ) { + + const value = values[ i ]; + + if ( isNaN( value ) ) { + + console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); + valid = false; + break; + + } + + } + + } + + } + + return valid; + + } + + // removes equivalent sequential keys as common in morph target sequences + // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) + optimize() { + + // times or values may be shared with other tracks, so overwriting is unsafe + const times = this.times.slice(), + values = this.values.slice(), + stride = this.getValueSize(), + + smoothInterpolation = this.getInterpolation() === InterpolateSmooth, + + lastIndex = times.length - 1; + + let writeIndex = 1; + + for ( let i = 1; i < lastIndex; ++ i ) { + + let keep = false; + + const time = times[ i ]; + const timeNext = times[ i + 1 ]; + + // remove adjacent keyframes scheduled at the same time + + if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) { + + if ( ! smoothInterpolation ) { + + // remove unnecessary keyframes same as their neighbors + + const offset = i * stride, + offsetP = offset - stride, + offsetN = offset + stride; + + for ( let j = 0; j !== stride; ++ j ) { + + const value = values[ offset + j ]; + + if ( value !== values[ offsetP + j ] || + value !== values[ offsetN + j ] ) { + + keep = true; + break; + + } + + } + + } else { + + keep = true; + + } + + } + + // in-place compaction + + if ( keep ) { + + if ( i !== writeIndex ) { + + times[ writeIndex ] = times[ i ]; + + const readOffset = i * stride, + writeOffset = writeIndex * stride; + + for ( let j = 0; j !== stride; ++ j ) { + + values[ writeOffset + j ] = values[ readOffset + j ]; + + } + + } + + ++ writeIndex; + + } + + } + + // flush last keyframe (compaction looks ahead) + + if ( lastIndex > 0 ) { + + times[ writeIndex ] = times[ lastIndex ]; + + for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { + + values[ writeOffset + j ] = values[ readOffset + j ]; + + } + + ++ writeIndex; + + } + + if ( writeIndex !== times.length ) { + + this.times = times.slice( 0, writeIndex ); + this.values = values.slice( 0, writeIndex * stride ); + + } else { + + this.times = times; + this.values = values; + + } + + return this; + + } + + clone() { + + const times = this.times.slice(); + const values = this.values.slice(); + + const TypedKeyframeTrack = this.constructor; + const track = new TypedKeyframeTrack( this.name, times, values ); + + // Interpolant argument to constructor is not saved, so copy the factory method directly. + track.createInterpolant = this.createInterpolant; + + return track; + + } + +} + +KeyframeTrack.prototype.TimeBufferType = Float32Array; +KeyframeTrack.prototype.ValueBufferType = Float32Array; +KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; + +/** + * A Track of Boolean keyframe values. + */ +class BooleanKeyframeTrack extends KeyframeTrack { + + // No interpolation parameter because only InterpolateDiscrete is valid. + constructor( name, times, values ) { + + super( name, times, values ); + + } + +} + +BooleanKeyframeTrack.prototype.ValueTypeName = 'bool'; +BooleanKeyframeTrack.prototype.ValueBufferType = Array; +BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; +BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; +BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; + +/** + * A Track of keyframe values that represent color. + */ +class ColorKeyframeTrack extends KeyframeTrack {} + +ColorKeyframeTrack.prototype.ValueTypeName = 'color'; + +/** + * A Track of numeric keyframe values. + */ +class NumberKeyframeTrack extends KeyframeTrack {} + +NumberKeyframeTrack.prototype.ValueTypeName = 'number'; + +/** + * Spherical linear unit quaternion interpolant. + */ + +class QuaternionLinearInterpolant extends Interpolant { + + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + super( parameterPositions, sampleValues, sampleSize, resultBuffer ); + + } + + interpolate_( i1, t0, t, t1 ) { + + const result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + + alpha = ( t - t0 ) / ( t1 - t0 ); + + let offset = i1 * stride; + + for ( let end = offset + stride; offset !== end; offset += 4 ) { + + Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); + + } + + return result; + + } + +} + +/** + * A Track of quaternion keyframe values. + */ +class QuaternionKeyframeTrack extends KeyframeTrack { + + InterpolantFactoryMethodLinear( result ) { + + return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); + + } + +} + +QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion'; +// ValueBufferType is inherited +// DefaultInterpolation is inherited; +QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; + +/** + * A Track that interpolates Strings + */ +class StringKeyframeTrack extends KeyframeTrack { + + // No interpolation parameter because only InterpolateDiscrete is valid. + constructor( name, times, values ) { + + super( name, times, values ); + + } + +} + +StringKeyframeTrack.prototype.ValueTypeName = 'string'; +StringKeyframeTrack.prototype.ValueBufferType = Array; +StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; +StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; +StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; + +/** + * A Track of vectored keyframe values. + */ +class VectorKeyframeTrack extends KeyframeTrack {} + +VectorKeyframeTrack.prototype.ValueTypeName = 'vector'; + +class AnimationClip { + + constructor( name = '', duration = - 1, tracks = [], blendMode = NormalAnimationBlendMode ) { + + this.name = name; + this.tracks = tracks; + this.duration = duration; + this.blendMode = blendMode; + + this.uuid = generateUUID(); + + // this means it should figure out its duration by scanning the tracks + if ( this.duration < 0 ) { + + this.resetDuration(); + + } + + } + + + static parse( json ) { + + const tracks = [], + jsonTracks = json.tracks, + frameTime = 1.0 / ( json.fps || 1.0 ); + + for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) { + + tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) ); + + } + + const clip = new this( json.name, json.duration, tracks, json.blendMode ); + clip.uuid = json.uuid; + + return clip; + + } + + static toJSON( clip ) { + + const tracks = [], + clipTracks = clip.tracks; + + const json = { + + 'name': clip.name, + 'duration': clip.duration, + 'tracks': tracks, + 'uuid': clip.uuid, + 'blendMode': clip.blendMode + + }; + + for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) { + + tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); + + } + + return json; + + } + + static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) { + + const numMorphTargets = morphTargetSequence.length; + const tracks = []; + + for ( let i = 0; i < numMorphTargets; i ++ ) { + + let times = []; + let values = []; + + times.push( + ( i + numMorphTargets - 1 ) % numMorphTargets, + i, + ( i + 1 ) % numMorphTargets ); + + values.push( 0, 1, 0 ); + + const order = getKeyframeOrder( times ); + times = sortedArray( times, 1, order ); + values = sortedArray( values, 1, order ); + + // if there is a key at the first frame, duplicate it as the + // last frame as well for perfect loop. + if ( ! noLoop && times[ 0 ] === 0 ) { + + times.push( numMorphTargets ); + values.push( values[ 0 ] ); + + } + + tracks.push( + new NumberKeyframeTrack( + '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', + times, values + ).scale( 1.0 / fps ) ); + + } + + return new this( name, - 1, tracks ); + + } + + static findByName( objectOrClipArray, name ) { + + let clipArray = objectOrClipArray; + + if ( ! Array.isArray( objectOrClipArray ) ) { + + const o = objectOrClipArray; + clipArray = o.geometry && o.geometry.animations || o.animations; + + } + + for ( let i = 0; i < clipArray.length; i ++ ) { + + if ( clipArray[ i ].name === name ) { + + return clipArray[ i ]; + + } + + } + + return null; + + } + + static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) { + + const animationToMorphTargets = {}; + + // tested with https://regex101.com/ on trick sequences + // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 + const pattern = /^([\w-]*?)([\d]+)$/; + + // sort morph target names into animation groups based + // patterns like Walk_001, Walk_002, Run_001, Run_002 + for ( let i = 0, il = morphTargets.length; i < il; i ++ ) { + + const morphTarget = morphTargets[ i ]; + const parts = morphTarget.name.match( pattern ); + + if ( parts && parts.length > 1 ) { + + const name = parts[ 1 ]; + + let animationMorphTargets = animationToMorphTargets[ name ]; + + if ( ! animationMorphTargets ) { + + animationToMorphTargets[ name ] = animationMorphTargets = []; + + } + + animationMorphTargets.push( morphTarget ); + + } + + } + + const clips = []; + + for ( const name in animationToMorphTargets ) { + + clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); + + } + + return clips; + + } + + // parse the animation.hierarchy format + static parseAnimation( animation, bones ) { + + if ( ! animation ) { + + console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); + return null; + + } + + const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { + + // only return track if there are actually keys. + if ( animationKeys.length !== 0 ) { + + const times = []; + const values = []; + + flattenJSON( animationKeys, times, values, propertyName ); + + // empty keys are filtered out, so check again + if ( times.length !== 0 ) { + + destTracks.push( new trackType( trackName, times, values ) ); + + } + + } + + }; + + const tracks = []; + + const clipName = animation.name || 'default'; + const fps = animation.fps || 30; + const blendMode = animation.blendMode; + + // automatic length determination in AnimationClip. + let duration = animation.length || - 1; + + const hierarchyTracks = animation.hierarchy || []; + + for ( let h = 0; h < hierarchyTracks.length; h ++ ) { + + const animationKeys = hierarchyTracks[ h ].keys; + + // skip empty tracks + if ( ! animationKeys || animationKeys.length === 0 ) continue; + + // process morph targets + if ( animationKeys[ 0 ].morphTargets ) { + + // figure out all morph targets used in this track + const morphTargetNames = {}; + + let k; + + for ( k = 0; k < animationKeys.length; k ++ ) { + + if ( animationKeys[ k ].morphTargets ) { + + for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { + + morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; + + } + + } + + } + + // create a track for each morph target with all zero + // morphTargetInfluences except for the keys in which + // the morphTarget is named. + for ( const morphTargetName in morphTargetNames ) { + + const times = []; + const values = []; + + for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { + + const animationKey = animationKeys[ k ]; + + times.push( animationKey.time ); + values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); + + } + + tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); + + } + + duration = morphTargetNames.length * fps; + + } else { + + // ...assume skeletal animation + + const boneName = '.bones[' + bones[ h ].name + ']'; + + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.position', + animationKeys, 'pos', tracks ); + + addNonemptyTrack( + QuaternionKeyframeTrack, boneName + '.quaternion', + animationKeys, 'rot', tracks ); + + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.scale', + animationKeys, 'scl', tracks ); + + } + + } + + if ( tracks.length === 0 ) { + + return null; + + } + + const clip = new this( clipName, duration, tracks, blendMode ); + + return clip; + + } + + resetDuration() { + + const tracks = this.tracks; + let duration = 0; + + for ( let i = 0, n = tracks.length; i !== n; ++ i ) { + + const track = this.tracks[ i ]; + + duration = Math.max( duration, track.times[ track.times.length - 1 ] ); + + } + + this.duration = duration; + + return this; + + } + + trim() { + + for ( let i = 0; i < this.tracks.length; i ++ ) { + + this.tracks[ i ].trim( 0, this.duration ); + + } + + return this; + + } + + validate() { + + let valid = true; + + for ( let i = 0; i < this.tracks.length; i ++ ) { + + valid = valid && this.tracks[ i ].validate(); + + } + + return valid; + + } + + optimize() { + + for ( let i = 0; i < this.tracks.length; i ++ ) { + + this.tracks[ i ].optimize(); + + } + + return this; + + } + + clone() { + + const tracks = []; + + for ( let i = 0; i < this.tracks.length; i ++ ) { + + tracks.push( this.tracks[ i ].clone() ); + + } + + return new this.constructor( this.name, this.duration, tracks, this.blendMode ); + + } + + toJSON() { + + return this.constructor.toJSON( this ); + + } + +} + +function getTrackTypeForValueTypeName( typeName ) { + + switch ( typeName.toLowerCase() ) { + + case 'scalar': + case 'double': + case 'float': + case 'number': + case 'integer': + + return NumberKeyframeTrack; + + case 'vector': + case 'vector2': + case 'vector3': + case 'vector4': + + return VectorKeyframeTrack; + + case 'color': + + return ColorKeyframeTrack; + + case 'quaternion': + + return QuaternionKeyframeTrack; + + case 'bool': + case 'boolean': + + return BooleanKeyframeTrack; + + case 'string': + + return StringKeyframeTrack; + + } + + throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); + +} + +function parseKeyframeTrack( json ) { + + if ( json.type === undefined ) { + + throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); + + } + + const trackType = getTrackTypeForValueTypeName( json.type ); + + if ( json.times === undefined ) { + + const times = [], values = []; + + flattenJSON( json.keys, times, values, 'value' ); + + json.times = times; + json.values = values; + + } + + // derived classes can define a static parse method + if ( trackType.parse !== undefined ) { + + return trackType.parse( json ); + + } else { + + // by default, we assume a constructor compatible with the base + return new trackType( json.name, json.times, json.values, json.interpolation ); + + } + +} + +const Cache = { + + enabled: false, + + files: {}, + + add: function ( key, file ) { + + if ( this.enabled === false ) return; + + // console.log( 'THREE.Cache', 'Adding key:', key ); + + this.files[ key ] = file; + + }, + + get: function ( key ) { + + if ( this.enabled === false ) return; + + // console.log( 'THREE.Cache', 'Checking key:', key ); + + return this.files[ key ]; + + }, + + remove: function ( key ) { + + delete this.files[ key ]; + + }, + + clear: function () { + + this.files = {}; + + } + +}; + +class LoadingManager { + + constructor( onLoad, onProgress, onError ) { + + const scope = this; + + let isLoading = false; + let itemsLoaded = 0; + let itemsTotal = 0; + let urlModifier = undefined; + const handlers = []; + + // Refer to #5689 for the reason why we don't set .onStart + // in the constructor + + this.onStart = undefined; + this.onLoad = onLoad; + this.onProgress = onProgress; + this.onError = onError; + + this.itemStart = function ( url ) { + + itemsTotal ++; + + if ( isLoading === false ) { + + if ( scope.onStart !== undefined ) { + + scope.onStart( url, itemsLoaded, itemsTotal ); + + } + + } + + isLoading = true; + + }; + + this.itemEnd = function ( url ) { + + itemsLoaded ++; + + if ( scope.onProgress !== undefined ) { + + scope.onProgress( url, itemsLoaded, itemsTotal ); + + } + + if ( itemsLoaded === itemsTotal ) { + + isLoading = false; + + if ( scope.onLoad !== undefined ) { + + scope.onLoad(); + + } + + } + + }; + + this.itemError = function ( url ) { + + if ( scope.onError !== undefined ) { + + scope.onError( url ); + + } + + }; + + this.resolveURL = function ( url ) { + + if ( urlModifier ) { + + return urlModifier( url ); + + } + + return url; + + }; + + this.setURLModifier = function ( transform ) { + + urlModifier = transform; + + return this; + + }; + + this.addHandler = function ( regex, loader ) { + + handlers.push( regex, loader ); + + return this; + + }; + + this.removeHandler = function ( regex ) { + + const index = handlers.indexOf( regex ); + + if ( index !== - 1 ) { + + handlers.splice( index, 2 ); + + } + + return this; + + }; + + this.getHandler = function ( file ) { + + for ( let i = 0, l = handlers.length; i < l; i += 2 ) { + + const regex = handlers[ i ]; + const loader = handlers[ i + 1 ]; + + if ( regex.global ) regex.lastIndex = 0; // see #17920 + + if ( regex.test( file ) ) { + + return loader; + + } + + } + + return null; + + }; + + } + +} + +const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager(); + +class Loader { + + constructor( manager ) { + + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + + this.crossOrigin = 'anonymous'; + this.withCredentials = false; + this.path = ''; + this.resourcePath = ''; + this.requestHeader = {}; + + } + + load( /* url, onLoad, onProgress, onError */ ) {} + + loadAsync( url, onProgress ) { + + const scope = this; + + return new Promise( function ( resolve, reject ) { + + scope.load( url, resolve, onProgress, reject ); + + } ); + + } + + parse( /* data */ ) {} + + setCrossOrigin( crossOrigin ) { + + this.crossOrigin = crossOrigin; + return this; + + } + + setWithCredentials( value ) { + + this.withCredentials = value; + return this; + + } + + setPath( path ) { + + this.path = path; + return this; + + } + + setResourcePath( resourcePath ) { + + this.resourcePath = resourcePath; + return this; + + } + + setRequestHeader( requestHeader ) { + + this.requestHeader = requestHeader; + return this; + + } + +} + +Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT'; + +const loading = {}; + +class HttpError extends Error { + + constructor( message, response ) { + + super( message ); + this.response = response; + + } + +} + +class FileLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + } + + load( url, onLoad, onProgress, onError ) { + + if ( url === undefined ) url = ''; + + if ( this.path !== undefined ) url = this.path + url; + + url = this.manager.resolveURL( url ); + + const cached = Cache.get( url ); + + if ( cached !== undefined ) { + + this.manager.itemStart( url ); + + setTimeout( () => { + + if ( onLoad ) onLoad( cached ); + + this.manager.itemEnd( url ); + + }, 0 ); + + return cached; + + } + + // Check if request is duplicate + + if ( loading[ url ] !== undefined ) { + + loading[ url ].push( { + + onLoad: onLoad, + onProgress: onProgress, + onError: onError + + } ); + + return; + + } + + // Initialise array for duplicate requests + loading[ url ] = []; + + loading[ url ].push( { + onLoad: onLoad, + onProgress: onProgress, + onError: onError, + } ); + + // create request + const req = new Request( url, { + headers: new Headers( this.requestHeader ), + credentials: this.withCredentials ? 'include' : 'same-origin', + // An abort controller could be added within a future PR + } ); + + // record states ( avoid data race ) + const mimeType = this.mimeType; + const responseType = this.responseType; + + // start the fetch + fetch( req ) + .then( response => { + + if ( response.status === 200 || response.status === 0 ) { + + // Some browsers return HTTP Status 0 when using non-http protocol + // e.g. 'file://' or 'data://'. Handle as success. + + if ( response.status === 0 ) { + + console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); + + } + + // Workaround: Checking if response.body === undefined for Alipay browser #23548 + + if ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) { + + return response; + + } + + const callbacks = loading[ url ]; + const reader = response.body.getReader(); + + // Nginx needs X-File-Size check + // https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content + const contentLength = response.headers.get( 'X-File-Size' ) || response.headers.get( 'Content-Length' ); + const total = contentLength ? parseInt( contentLength ) : 0; + const lengthComputable = total !== 0; + let loaded = 0; + + // periodically read data into the new stream tracking while download progress + const stream = new ReadableStream( { + start( controller ) { + + readData(); + + function readData() { + + reader.read().then( ( { done, value } ) => { + + if ( done ) { + + controller.close(); + + } else { + + loaded += value.byteLength; + + const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } ); + for ( let i = 0, il = callbacks.length; i < il; i ++ ) { + + const callback = callbacks[ i ]; + if ( callback.onProgress ) callback.onProgress( event ); + + } + + controller.enqueue( value ); + readData(); + + } + + }, ( e ) => { + + controller.error( e ); + + } ); + + } + + } + + } ); + + return new Response( stream ); + + } else { + + throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response ); + + } + + } ) + .then( response => { + + switch ( responseType ) { + + case 'arraybuffer': + + return response.arrayBuffer(); + + case 'blob': + + return response.blob(); + + case 'document': + + return response.text() + .then( text => { + + const parser = new DOMParser(); + return parser.parseFromString( text, mimeType ); + + } ); + + case 'json': + + return response.json(); + + default: + + if ( mimeType === undefined ) { + + return response.text(); + + } else { + + // sniff encoding + const re = /charset="?([^;"\s]*)"?/i; + const exec = re.exec( mimeType ); + const label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined; + const decoder = new TextDecoder( label ); + return response.arrayBuffer().then( ab => decoder.decode( ab ) ); + + } + + } + + } ) + .then( data => { + + // Add to cache only on HTTP success, so that we do not cache + // error response bodies as proper responses to requests. + Cache.add( url, data ); + + const callbacks = loading[ url ]; + delete loading[ url ]; + + for ( let i = 0, il = callbacks.length; i < il; i ++ ) { + + const callback = callbacks[ i ]; + if ( callback.onLoad ) callback.onLoad( data ); + + } + + } ) + .catch( err => { + + // Abort errors and other errors are handled the same + + const callbacks = loading[ url ]; + + if ( callbacks === undefined ) { + + // When onLoad was called and url was deleted in `loading` + this.manager.itemError( url ); + throw err; + + } + + delete loading[ url ]; + + for ( let i = 0, il = callbacks.length; i < il; i ++ ) { + + const callback = callbacks[ i ]; + if ( callback.onError ) callback.onError( err ); + + } + + this.manager.itemError( url ); + + } ) + .finally( () => { + + this.manager.itemEnd( url ); + + } ); + + this.manager.itemStart( url ); + + } + + setResponseType( value ) { + + this.responseType = value; + return this; + + } + + setMimeType( value ) { + + this.mimeType = value; + return this; + + } + +} + +class AnimationLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + } + + load( url, onLoad, onProgress, onError ) { + + const scope = this; + + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( text ) { + + try { + + onLoad( scope.parse( JSON.parse( text ) ) ); + + } catch ( e ) { + + if ( onError ) { + + onError( e ); + + } else { + + console.error( e ); + + } + + scope.manager.itemError( url ); + + } + + }, onProgress, onError ); + + } + + parse( json ) { + + const animations = []; + + for ( let i = 0; i < json.length; i ++ ) { + + const clip = AnimationClip.parse( json[ i ] ); + + animations.push( clip ); + + } + + return animations; + + } + +} + +/** + * Abstract Base class to block based textures loader (dds, pvr, ...) + * + * Sub classes have to implement the parse() method which will be used in load(). + */ + +class CompressedTextureLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + } + + load( url, onLoad, onProgress, onError ) { + + const scope = this; + + const images = []; + + const texture = new CompressedTexture(); + + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setResponseType( 'arraybuffer' ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( scope.withCredentials ); + + let loaded = 0; + + function loadTexture( i ) { + + loader.load( url[ i ], function ( buffer ) { + + const texDatas = scope.parse( buffer, true ); + + images[ i ] = { + width: texDatas.width, + height: texDatas.height, + format: texDatas.format, + mipmaps: texDatas.mipmaps + }; + + loaded += 1; + + if ( loaded === 6 ) { + + if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter; + + texture.image = images; + texture.format = texDatas.format; + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); + + } + + }, onProgress, onError ); + + } + + if ( Array.isArray( url ) ) { + + for ( let i = 0, il = url.length; i < il; ++ i ) { + + loadTexture( i ); + + } + + } else { + + // compressed cubemap texture stored in a single DDS file + + loader.load( url, function ( buffer ) { + + const texDatas = scope.parse( buffer, true ); + + if ( texDatas.isCubemap ) { + + const faces = texDatas.mipmaps.length / texDatas.mipmapCount; + + for ( let f = 0; f < faces; f ++ ) { + + images[ f ] = { mipmaps: [] }; + + for ( let i = 0; i < texDatas.mipmapCount; i ++ ) { + + images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); + images[ f ].format = texDatas.format; + images[ f ].width = texDatas.width; + images[ f ].height = texDatas.height; + + } + + } + + texture.image = images; + + } else { + + texture.image.width = texDatas.width; + texture.image.height = texDatas.height; + texture.mipmaps = texDatas.mipmaps; + + } + + if ( texDatas.mipmapCount === 1 ) { + + texture.minFilter = LinearFilter; + + } + + texture.format = texDatas.format; + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); + + }, onProgress, onError ); + + } + + return texture; + + } + +} + +class ImageLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + } + + load( url, onLoad, onProgress, onError ) { + + if ( this.path !== undefined ) url = this.path + url; + + url = this.manager.resolveURL( url ); + + const scope = this; + + const cached = Cache.get( url ); + + if ( cached !== undefined ) { + + scope.manager.itemStart( url ); + + setTimeout( function () { + + if ( onLoad ) onLoad( cached ); + + scope.manager.itemEnd( url ); + + }, 0 ); + + return cached; + + } + + const image = createElementNS( 'img' ); + + function onImageLoad() { + + removeEventListeners(); + + Cache.add( url, this ); + + if ( onLoad ) onLoad( this ); + + scope.manager.itemEnd( url ); + + } + + function onImageError( event ) { + + removeEventListeners(); + + if ( onError ) onError( event ); + + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); + + } + + function removeEventListeners() { + + image.removeEventListener( 'load', onImageLoad, false ); + image.removeEventListener( 'error', onImageError, false ); + + } + + image.addEventListener( 'load', onImageLoad, false ); + image.addEventListener( 'error', onImageError, false ); + + if ( url.slice( 0, 5 ) !== 'data:' ) { + + if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; + + } + + scope.manager.itemStart( url ); + + image.src = url; + + return image; + + } + +} + +class CubeTextureLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + } + + load( urls, onLoad, onProgress, onError ) { + + const texture = new CubeTexture(); + texture.colorSpace = SRGBColorSpace; + + const loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setPath( this.path ); + + let loaded = 0; + + function loadTexture( i ) { + + loader.load( urls[ i ], function ( image ) { + + texture.images[ i ] = image; + + loaded ++; + + if ( loaded === 6 ) { + + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); + + } + + }, undefined, onError ); + + } + + for ( let i = 0; i < urls.length; ++ i ) { + + loadTexture( i ); + + } + + return texture; + + } + +} + +/** + * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) + * + * Sub classes have to implement the parse() method which will be used in load(). + */ + +class DataTextureLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + } + + load( url, onLoad, onProgress, onError ) { + + const scope = this; + + const texture = new DataTexture(); + + const loader = new FileLoader( this.manager ); + loader.setResponseType( 'arraybuffer' ); + loader.setRequestHeader( this.requestHeader ); + loader.setPath( this.path ); + loader.setWithCredentials( scope.withCredentials ); + loader.load( url, function ( buffer ) { + + let texData; + + try { + + texData = scope.parse( buffer ); + + } catch ( error ) { + + if ( onError !== undefined ) { + + onError( error ); + + } else { + + console.error( error ); + return; + + } + + } + + if ( texData.image !== undefined ) { + + texture.image = texData.image; + + } else if ( texData.data !== undefined ) { + + texture.image.width = texData.width; + texture.image.height = texData.height; + texture.image.data = texData.data; + + } + + texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; + texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; + + texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; + texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter; + + texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; + + if ( texData.colorSpace !== undefined ) { + + texture.colorSpace = texData.colorSpace; + + } + + if ( texData.flipY !== undefined ) { + + texture.flipY = texData.flipY; + + } + + if ( texData.format !== undefined ) { + + texture.format = texData.format; + + } + + if ( texData.type !== undefined ) { + + texture.type = texData.type; + + } + + if ( texData.mipmaps !== undefined ) { + + texture.mipmaps = texData.mipmaps; + texture.minFilter = LinearMipmapLinearFilter; // presumably... + + } + + if ( texData.mipmapCount === 1 ) { + + texture.minFilter = LinearFilter; + + } + + if ( texData.generateMipmaps !== undefined ) { + + texture.generateMipmaps = texData.generateMipmaps; + + } + + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture, texData ); + + }, onProgress, onError ); + + + return texture; + + } + +} + +class TextureLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + } + + load( url, onLoad, onProgress, onError ) { + + const texture = new Texture(); + + const loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setPath( this.path ); + + loader.load( url, function ( image ) { + + texture.image = image; + texture.needsUpdate = true; + + if ( onLoad !== undefined ) { + + onLoad( texture ); + + } + + }, onProgress, onError ); + + return texture; + + } + +} + +class Light extends Object3D { + + constructor( color, intensity = 1 ) { + + super(); + + this.isLight = true; + + this.type = 'Light'; + + this.color = new Color( color ); + this.intensity = intensity; + + } + + dispose() { + + // Empty here in base class; some subclasses override. + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.color.copy( source.color ); + this.intensity = source.intensity; + + return this; + + } + + toJSON( meta ) { + + const data = super.toJSON( meta ); + + data.object.color = this.color.getHex(); + data.object.intensity = this.intensity; + + if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); + + if ( this.distance !== undefined ) data.object.distance = this.distance; + if ( this.angle !== undefined ) data.object.angle = this.angle; + if ( this.decay !== undefined ) data.object.decay = this.decay; + if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; + + if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); + if ( this.target !== undefined ) data.object.target = this.target.uuid; + + return data; + + } + +} + +class HemisphereLight extends Light { + + constructor( skyColor, groundColor, intensity ) { + + super( skyColor, intensity ); + + this.isHemisphereLight = true; + + this.type = 'HemisphereLight'; + + this.position.copy( Object3D.DEFAULT_UP ); + this.updateMatrix(); + + this.groundColor = new Color( groundColor ); + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.groundColor.copy( source.groundColor ); + + return this; + + } + +} + +const _projScreenMatrix$2 = /*@__PURE__*/ new Matrix4(); +const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3(); +const _lookTarget$1 = /*@__PURE__*/ new Vector3(); + +class LightShadow { + + constructor( camera ) { + + this.camera = camera; + + this.intensity = 1; + + this.bias = 0; + this.normalBias = 0; + this.radius = 1; + this.blurSamples = 8; + + this.mapSize = new Vector2( 512, 512 ); + + this.map = null; + this.mapPass = null; + this.matrix = new Matrix4(); + + this.autoUpdate = true; + this.needsUpdate = false; + + this._frustum = new Frustum(); + this._frameExtents = new Vector2( 1, 1 ); + + this._viewportCount = 1; + + this._viewports = [ + + new Vector4( 0, 0, 1, 1 ) + + ]; + + } + + getViewportCount() { + + return this._viewportCount; + + } + + getFrustum() { + + return this._frustum; + + } + + updateMatrices( light ) { + + const shadowCamera = this.camera; + const shadowMatrix = this.matrix; + + _lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld ); + shadowCamera.position.copy( _lightPositionWorld$1 ); + + _lookTarget$1.setFromMatrixPosition( light.target.matrixWorld ); + shadowCamera.lookAt( _lookTarget$1 ); + shadowCamera.updateMatrixWorld(); + + _projScreenMatrix$2.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); + this._frustum.setFromProjectionMatrix( _projScreenMatrix$2 ); + + shadowMatrix.set( + 0.5, 0.0, 0.0, 0.5, + 0.0, 0.5, 0.0, 0.5, + 0.0, 0.0, 0.5, 0.5, + 0.0, 0.0, 0.0, 1.0 + ); + + shadowMatrix.multiply( _projScreenMatrix$2 ); + + } + + getViewport( viewportIndex ) { + + return this._viewports[ viewportIndex ]; + + } + + getFrameExtents() { + + return this._frameExtents; + + } + + dispose() { + + if ( this.map ) { + + this.map.dispose(); + + } + + if ( this.mapPass ) { + + this.mapPass.dispose(); + + } + + } + + copy( source ) { + + this.camera = source.camera.clone(); + + this.intensity = source.intensity; + + this.bias = source.bias; + this.radius = source.radius; + + this.mapSize.copy( source.mapSize ); + + return this; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + toJSON() { + + const object = {}; + + if ( this.intensity !== 1 ) object.intensity = this.intensity; + if ( this.bias !== 0 ) object.bias = this.bias; + if ( this.normalBias !== 0 ) object.normalBias = this.normalBias; + if ( this.radius !== 1 ) object.radius = this.radius; + if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); + + object.camera = this.camera.toJSON( false ).object; + delete object.camera.matrix; + + return object; + + } + +} + +class SpotLightShadow extends LightShadow { + + constructor() { + + super( new PerspectiveCamera( 50, 1, 0.5, 500 ) ); + + this.isSpotLightShadow = true; + + this.focus = 1; + + } + + updateMatrices( light ) { + + const camera = this.camera; + + const fov = RAD2DEG * 2 * light.angle * this.focus; + const aspect = this.mapSize.width / this.mapSize.height; + const far = light.distance || camera.far; + + if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { + + camera.fov = fov; + camera.aspect = aspect; + camera.far = far; + camera.updateProjectionMatrix(); + + } + + super.updateMatrices( light ); + + } + + copy( source ) { + + super.copy( source ); + + this.focus = source.focus; + + return this; + + } + +} + +class SpotLight extends Light { + + constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2 ) { + + super( color, intensity ); + + this.isSpotLight = true; + + this.type = 'SpotLight'; + + this.position.copy( Object3D.DEFAULT_UP ); + this.updateMatrix(); + + this.target = new Object3D(); + + this.distance = distance; + this.angle = angle; + this.penumbra = penumbra; + this.decay = decay; + + this.map = null; + + this.shadow = new SpotLightShadow(); + + } + + get power() { + + // compute the light's luminous power (in lumens) from its intensity (in candela) + // by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd) + return this.intensity * Math.PI; + + } + + set power( power ) { + + // set the light's intensity (in candela) from the desired luminous power (in lumens) + this.intensity = power / Math.PI; + + } + + dispose() { + + this.shadow.dispose(); + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.distance = source.distance; + this.angle = source.angle; + this.penumbra = source.penumbra; + this.decay = source.decay; + + this.target = source.target.clone(); + + this.shadow = source.shadow.clone(); + + return this; + + } + +} + +const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4(); +const _lightPositionWorld = /*@__PURE__*/ new Vector3(); +const _lookTarget = /*@__PURE__*/ new Vector3(); + +class PointLightShadow extends LightShadow { + + constructor() { + + super( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); + + this.isPointLightShadow = true; + + this._frameExtents = new Vector2( 4, 2 ); + + this._viewportCount = 6; + + this._viewports = [ + // These viewports map a cube-map onto a 2D texture with the + // following orientation: + // + // xzXZ + // y Y + // + // X - Positive x direction + // x - Negative x direction + // Y - Positive y direction + // y - Negative y direction + // Z - Positive z direction + // z - Negative z direction + + // positive X + new Vector4( 2, 1, 1, 1 ), + // negative X + new Vector4( 0, 1, 1, 1 ), + // positive Z + new Vector4( 3, 1, 1, 1 ), + // negative Z + new Vector4( 1, 1, 1, 1 ), + // positive Y + new Vector4( 3, 0, 1, 1 ), + // negative Y + new Vector4( 1, 0, 1, 1 ) + ]; + + this._cubeDirections = [ + new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ), + new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 ) + ]; + + this._cubeUps = [ + new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), + new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 ) + ]; + + } + + updateMatrices( light, viewportIndex = 0 ) { + + const camera = this.camera; + const shadowMatrix = this.matrix; + + const far = light.distance || camera.far; + + if ( far !== camera.far ) { + + camera.far = far; + camera.updateProjectionMatrix(); + + } + + _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); + camera.position.copy( _lightPositionWorld ); + + _lookTarget.copy( camera.position ); + _lookTarget.add( this._cubeDirections[ viewportIndex ] ); + camera.up.copy( this._cubeUps[ viewportIndex ] ); + camera.lookAt( _lookTarget ); + camera.updateMatrixWorld(); + + shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); + + _projScreenMatrix$1.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 ); + + } + +} + +class PointLight extends Light { + + constructor( color, intensity, distance = 0, decay = 2 ) { + + super( color, intensity ); + + this.isPointLight = true; + + this.type = 'PointLight'; + + this.distance = distance; + this.decay = decay; + + this.shadow = new PointLightShadow(); + + } + + get power() { + + // compute the light's luminous power (in lumens) from its intensity (in candela) + // for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd) + return this.intensity * 4 * Math.PI; + + } + + set power( power ) { + + // set the light's intensity (in candela) from the desired luminous power (in lumens) + this.intensity = power / ( 4 * Math.PI ); + + } + + dispose() { + + this.shadow.dispose(); + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.distance = source.distance; + this.decay = source.decay; + + this.shadow = source.shadow.clone(); + + return this; + + } + +} + +class OrthographicCamera extends Camera { + + constructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) { + + super(); + + this.isOrthographicCamera = true; + + this.type = 'OrthographicCamera'; + + this.zoom = 1; + this.view = null; + + this.left = left; + this.right = right; + this.top = top; + this.bottom = bottom; + + this.near = near; + this.far = far; + + this.updateProjectionMatrix(); + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.left = source.left; + this.right = source.right; + this.top = source.top; + this.bottom = source.bottom; + this.near = source.near; + this.far = source.far; + + this.zoom = source.zoom; + this.view = source.view === null ? null : Object.assign( {}, source.view ); + + return this; + + } + + setViewOffset( fullWidth, fullHeight, x, y, width, height ) { + + if ( this.view === null ) { + + this.view = { + enabled: true, + fullWidth: 1, + fullHeight: 1, + offsetX: 0, + offsetY: 0, + width: 1, + height: 1 + }; + + } + + this.view.enabled = true; + this.view.fullWidth = fullWidth; + this.view.fullHeight = fullHeight; + this.view.offsetX = x; + this.view.offsetY = y; + this.view.width = width; + this.view.height = height; + + this.updateProjectionMatrix(); + + } + + clearViewOffset() { + + if ( this.view !== null ) { + + this.view.enabled = false; + + } + + this.updateProjectionMatrix(); + + } + + updateProjectionMatrix() { + + const dx = ( this.right - this.left ) / ( 2 * this.zoom ); + const dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); + const cx = ( this.right + this.left ) / 2; + const cy = ( this.top + this.bottom ) / 2; + + let left = cx - dx; + let right = cx + dx; + let top = cy + dy; + let bottom = cy - dy; + + if ( this.view !== null && this.view.enabled ) { + + const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom; + const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom; + + left += scaleW * this.view.offsetX; + right = left + scaleW * this.view.width; + top -= scaleH * this.view.offsetY; + bottom = top - scaleH * this.view.height; + + } + + this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem ); + + this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); + + } + + toJSON( meta ) { + + const data = super.toJSON( meta ); + + data.object.zoom = this.zoom; + data.object.left = this.left; + data.object.right = this.right; + data.object.top = this.top; + data.object.bottom = this.bottom; + data.object.near = this.near; + data.object.far = this.far; + + if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); + + return data; + + } + +} + +class DirectionalLightShadow extends LightShadow { + + constructor() { + + super( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); + + this.isDirectionalLightShadow = true; + + } + +} + +class DirectionalLight extends Light { + + constructor( color, intensity ) { + + super( color, intensity ); + + this.isDirectionalLight = true; + + this.type = 'DirectionalLight'; + + this.position.copy( Object3D.DEFAULT_UP ); + this.updateMatrix(); + + this.target = new Object3D(); + + this.shadow = new DirectionalLightShadow(); + + } + + dispose() { + + this.shadow.dispose(); + + } + + copy( source ) { + + super.copy( source ); + + this.target = source.target.clone(); + this.shadow = source.shadow.clone(); + + return this; + + } + +} + +class AmbientLight extends Light { + + constructor( color, intensity ) { + + super( color, intensity ); + + this.isAmbientLight = true; + + this.type = 'AmbientLight'; + + } + +} + +class RectAreaLight extends Light { + + constructor( color, intensity, width = 10, height = 10 ) { + + super( color, intensity ); + + this.isRectAreaLight = true; + + this.type = 'RectAreaLight'; + + this.width = width; + this.height = height; + + } + + get power() { + + // compute the light's luminous power (in lumens) from its intensity (in nits) + return this.intensity * this.width * this.height * Math.PI; + + } + + set power( power ) { + + // set the light's intensity (in nits) from the desired luminous power (in lumens) + this.intensity = power / ( this.width * this.height * Math.PI ); + + } + + copy( source ) { + + super.copy( source ); + + this.width = source.width; + this.height = source.height; + + return this; + + } + + toJSON( meta ) { + + const data = super.toJSON( meta ); + + data.object.width = this.width; + data.object.height = this.height; + + return data; + + } + +} + +/** + * Primary reference: + * https://graphics.stanford.edu/papers/envmap/envmap.pdf + * + * Secondary reference: + * https://www.ppsloan.org/publications/StupidSH36.pdf + */ + +// 3-band SH defined by 9 coefficients + +class SphericalHarmonics3 { + + constructor() { + + this.isSphericalHarmonics3 = true; + + this.coefficients = []; + + for ( let i = 0; i < 9; i ++ ) { + + this.coefficients.push( new Vector3() ); + + } + + } + + set( coefficients ) { + + for ( let i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].copy( coefficients[ i ] ); + + } + + return this; + + } + + zero() { + + for ( let i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].set( 0, 0, 0 ); + + } + + return this; + + } + + // get the radiance in the direction of the normal + // target is a Vector3 + getAt( normal, target ) { + + // normal is assumed to be unit length + + const x = normal.x, y = normal.y, z = normal.z; + + const coeff = this.coefficients; + + // band 0 + target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 ); + + // band 1 + target.addScaledVector( coeff[ 1 ], 0.488603 * y ); + target.addScaledVector( coeff[ 2 ], 0.488603 * z ); + target.addScaledVector( coeff[ 3 ], 0.488603 * x ); + + // band 2 + target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) ); + target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) ); + target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) ); + target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) ); + target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) ); + + return target; + + } + + // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal + // target is a Vector3 + // https://graphics.stanford.edu/papers/envmap/envmap.pdf + getIrradianceAt( normal, target ) { + + // normal is assumed to be unit length + + const x = normal.x, y = normal.y, z = normal.z; + + const coeff = this.coefficients; + + // band 0 + target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095 + + // band 1 + target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603 + target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z ); + target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x ); + + // band 2 + target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548 + target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z ); + target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3 + target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z ); + target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274 + + return target; + + } + + add( sh ) { + + for ( let i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].add( sh.coefficients[ i ] ); + + } + + return this; + + } + + addScaledSH( sh, s ) { + + for ( let i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s ); + + } + + return this; + + } + + scale( s ) { + + for ( let i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].multiplyScalar( s ); + + } + + return this; + + } + + lerp( sh, alpha ) { + + for ( let i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha ); + + } + + return this; + + } + + equals( sh ) { + + for ( let i = 0; i < 9; i ++ ) { + + if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) { + + return false; + + } + + } + + return true; + + } + + copy( sh ) { + + return this.set( sh.coefficients ); + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + fromArray( array, offset = 0 ) { + + const coefficients = this.coefficients; + + for ( let i = 0; i < 9; i ++ ) { + + coefficients[ i ].fromArray( array, offset + ( i * 3 ) ); + + } + + return this; + + } + + toArray( array = [], offset = 0 ) { + + const coefficients = this.coefficients; + + for ( let i = 0; i < 9; i ++ ) { + + coefficients[ i ].toArray( array, offset + ( i * 3 ) ); + + } + + return array; + + } + + // evaluate the basis functions + // shBasis is an Array[ 9 ] + static getBasisAt( normal, shBasis ) { + + // normal is assumed to be unit length + + const x = normal.x, y = normal.y, z = normal.z; + + // band 0 + shBasis[ 0 ] = 0.282095; + + // band 1 + shBasis[ 1 ] = 0.488603 * y; + shBasis[ 2 ] = 0.488603 * z; + shBasis[ 3 ] = 0.488603 * x; + + // band 2 + shBasis[ 4 ] = 1.092548 * x * y; + shBasis[ 5 ] = 1.092548 * y * z; + shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 ); + shBasis[ 7 ] = 1.092548 * x * z; + shBasis[ 8 ] = 0.546274 * ( x * x - y * y ); + + } + +} + +class LightProbe extends Light { + + constructor( sh = new SphericalHarmonics3(), intensity = 1 ) { + + super( undefined, intensity ); + + this.isLightProbe = true; + + this.sh = sh; + + } + + copy( source ) { + + super.copy( source ); + + this.sh.copy( source.sh ); + + return this; + + } + + fromJSON( json ) { + + this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON(); + this.sh.fromArray( json.sh ); + + return this; + + } + + toJSON( meta ) { + + const data = super.toJSON( meta ); + + data.object.sh = this.sh.toArray(); + + return data; + + } + +} + +class MaterialLoader extends Loader { + + constructor( manager ) { + + super( manager ); + this.textures = {}; + + } + + load( url, onLoad, onProgress, onError ) { + + const scope = this; + + const loader = new FileLoader( scope.manager ); + loader.setPath( scope.path ); + loader.setRequestHeader( scope.requestHeader ); + loader.setWithCredentials( scope.withCredentials ); + loader.load( url, function ( text ) { + + try { + + onLoad( scope.parse( JSON.parse( text ) ) ); + + } catch ( e ) { + + if ( onError ) { + + onError( e ); + + } else { + + console.error( e ); + + } + + scope.manager.itemError( url ); + + } + + }, onProgress, onError ); + + } + + parse( json ) { + + const textures = this.textures; + + function getTexture( name ) { + + if ( textures[ name ] === undefined ) { + + console.warn( 'THREE.MaterialLoader: Undefined texture', name ); + + } + + return textures[ name ]; + + } + + const material = this.createMaterialFromType( json.type ); + + if ( json.uuid !== undefined ) material.uuid = json.uuid; + if ( json.name !== undefined ) material.name = json.name; + if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color ); + if ( json.roughness !== undefined ) material.roughness = json.roughness; + if ( json.metalness !== undefined ) material.metalness = json.metalness; + if ( json.sheen !== undefined ) material.sheen = json.sheen; + if ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor ); + if ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness; + if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive ); + if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular ); + if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity; + if ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor ); + if ( json.shininess !== undefined ) material.shininess = json.shininess; + if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat; + if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness; + if ( json.dispersion !== undefined ) material.dispersion = json.dispersion; + if ( json.iridescence !== undefined ) material.iridescence = json.iridescence; + if ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR; + if ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange; + if ( json.transmission !== undefined ) material.transmission = json.transmission; + if ( json.thickness !== undefined ) material.thickness = json.thickness; + if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance; + if ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor ); + if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy; + if ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation; + if ( json.fog !== undefined ) material.fog = json.fog; + if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; + if ( json.blending !== undefined ) material.blending = json.blending; + if ( json.combine !== undefined ) material.combine = json.combine; + if ( json.side !== undefined ) material.side = json.side; + if ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide; + if ( json.opacity !== undefined ) material.opacity = json.opacity; + if ( json.transparent !== undefined ) material.transparent = json.transparent; + if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; + if ( json.alphaHash !== undefined ) material.alphaHash = json.alphaHash; + if ( json.depthFunc !== undefined ) material.depthFunc = json.depthFunc; + if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; + if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; + if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; + if ( json.blendSrc !== undefined ) material.blendSrc = json.blendSrc; + if ( json.blendDst !== undefined ) material.blendDst = json.blendDst; + if ( json.blendEquation !== undefined ) material.blendEquation = json.blendEquation; + if ( json.blendSrcAlpha !== undefined ) material.blendSrcAlpha = json.blendSrcAlpha; + if ( json.blendDstAlpha !== undefined ) material.blendDstAlpha = json.blendDstAlpha; + if ( json.blendEquationAlpha !== undefined ) material.blendEquationAlpha = json.blendEquationAlpha; + if ( json.blendColor !== undefined && material.blendColor !== undefined ) material.blendColor.setHex( json.blendColor ); + if ( json.blendAlpha !== undefined ) material.blendAlpha = json.blendAlpha; + if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask; + if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc; + if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef; + if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask; + if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail; + if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail; + if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass; + if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite; + + if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; + if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; + if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; + if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; + + if ( json.rotation !== undefined ) material.rotation = json.rotation; + + if ( json.linewidth !== undefined ) material.linewidth = json.linewidth; + if ( json.dashSize !== undefined ) material.dashSize = json.dashSize; + if ( json.gapSize !== undefined ) material.gapSize = json.gapSize; + if ( json.scale !== undefined ) material.scale = json.scale; + + if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset; + if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor; + if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits; + + if ( json.dithering !== undefined ) material.dithering = json.dithering; + + if ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage; + if ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha; + if ( json.forceSinglePass !== undefined ) material.forceSinglePass = json.forceSinglePass; + + if ( json.visible !== undefined ) material.visible = json.visible; + + if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped; + + if ( json.userData !== undefined ) material.userData = json.userData; + + if ( json.vertexColors !== undefined ) { + + if ( typeof json.vertexColors === 'number' ) { + + material.vertexColors = ( json.vertexColors > 0 ) ? true : false; + + } else { + + material.vertexColors = json.vertexColors; + + } + + } + + // Shader Material + + if ( json.uniforms !== undefined ) { + + for ( const name in json.uniforms ) { + + const uniform = json.uniforms[ name ]; + + material.uniforms[ name ] = {}; + + switch ( uniform.type ) { + + case 't': + material.uniforms[ name ].value = getTexture( uniform.value ); + break; + + case 'c': + material.uniforms[ name ].value = new Color().setHex( uniform.value ); + break; + + case 'v2': + material.uniforms[ name ].value = new Vector2().fromArray( uniform.value ); + break; + + case 'v3': + material.uniforms[ name ].value = new Vector3().fromArray( uniform.value ); + break; + + case 'v4': + material.uniforms[ name ].value = new Vector4().fromArray( uniform.value ); + break; + + case 'm3': + material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value ); + break; + + case 'm4': + material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value ); + break; + + default: + material.uniforms[ name ].value = uniform.value; + + } + + } + + } + + if ( json.defines !== undefined ) material.defines = json.defines; + if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; + if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; + if ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion; + + if ( json.extensions !== undefined ) { + + for ( const key in json.extensions ) { + + material.extensions[ key ] = json.extensions[ key ]; + + } + + } + + if ( json.lights !== undefined ) material.lights = json.lights; + if ( json.clipping !== undefined ) material.clipping = json.clipping; + + // for PointsMaterial + + if ( json.size !== undefined ) material.size = json.size; + if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; + + // maps + + if ( json.map !== undefined ) material.map = getTexture( json.map ); + if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap ); + + if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap ); + + if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); + if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; + + if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); + if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType; + if ( json.normalScale !== undefined ) { + + let normalScale = json.normalScale; + + if ( Array.isArray( normalScale ) === false ) { + + // Blender exporter used to export a scalar. See #7459 + + normalScale = [ normalScale, normalScale ]; + + } + + material.normalScale = new Vector2().fromArray( normalScale ); + + } + + if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); + if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; + if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; + + if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); + if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); + + if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); + if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; + + if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); + if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap ); + if ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap ); + + if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); + if ( json.envMapRotation !== undefined ) material.envMapRotation.fromArray( json.envMapRotation ); + if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity; + + if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; + if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio; + + if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); + if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; + + if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); + if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; + + if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); + + if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap ); + if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap ); + if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap ); + if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale ); + + if ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap ); + if ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap ); + + if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap ); + if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap ); + + if ( json.anisotropyMap !== undefined ) material.anisotropyMap = getTexture( json.anisotropyMap ); + + if ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap ); + if ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap ); + + return material; + + } + + setTextures( value ) { + + this.textures = value; + return this; + + } + + createMaterialFromType( type ) { + + return MaterialLoader.createMaterialFromType( type ); + + } + + static createMaterialFromType( type ) { + + const materialLib = { + ShadowMaterial, + SpriteMaterial, + RawShaderMaterial, + ShaderMaterial, + PointsMaterial, + MeshPhysicalMaterial, + MeshStandardMaterial, + MeshPhongMaterial, + MeshToonMaterial, + MeshNormalMaterial, + MeshLambertMaterial, + MeshDepthMaterial, + MeshDistanceMaterial, + MeshBasicMaterial, + MeshMatcapMaterial, + LineDashedMaterial, + LineBasicMaterial, + Material + }; + + return new materialLib[ type ](); + + } + +} + +class LoaderUtils { + + static decodeText( array ) { // @deprecated, r165 + + console.warn( 'THREE.LoaderUtils: decodeText() has been deprecated with r165 and will be removed with r175. Use TextDecoder instead.' ); + + if ( typeof TextDecoder !== 'undefined' ) { + + return new TextDecoder().decode( array ); + + } + + // Avoid the String.fromCharCode.apply(null, array) shortcut, which + // throws a "maximum call stack size exceeded" error for large arrays. + + let s = ''; + + for ( let i = 0, il = array.length; i < il; i ++ ) { + + // Implicitly assumes little-endian. + s += String.fromCharCode( array[ i ] ); + + } + + try { + + // merges multi-byte utf-8 characters. + + return decodeURIComponent( escape( s ) ); + + } catch ( e ) { // see #16358 + + return s; + + } + + } + + static extractUrlBase( url ) { + + const index = url.lastIndexOf( '/' ); + + if ( index === - 1 ) return './'; + + return url.slice( 0, index + 1 ); + + } + + static resolveURL( url, path ) { + + // Invalid URL + if ( typeof url !== 'string' || url === '' ) return ''; + + // Host Relative URL + if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) { + + path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' ); + + } + + // Absolute URL http://,https://,// + if ( /^(https?:)?\/\//i.test( url ) ) return url; + + // Data URI + if ( /^data:.*,.*$/i.test( url ) ) return url; + + // Blob URL + if ( /^blob:.*$/i.test( url ) ) return url; + + // Relative URL + return path + url; + + } + +} + +class InstancedBufferGeometry extends BufferGeometry { + + constructor() { + + super(); + + this.isInstancedBufferGeometry = true; + + this.type = 'InstancedBufferGeometry'; + this.instanceCount = Infinity; + + } + + copy( source ) { + + super.copy( source ); + + this.instanceCount = source.instanceCount; + + return this; + + } + + toJSON() { + + const data = super.toJSON(); + + data.instanceCount = this.instanceCount; + + data.isInstancedBufferGeometry = true; + + return data; + + } + +} + +class BufferGeometryLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + } + + load( url, onLoad, onProgress, onError ) { + + const scope = this; + + const loader = new FileLoader( scope.manager ); + loader.setPath( scope.path ); + loader.setRequestHeader( scope.requestHeader ); + loader.setWithCredentials( scope.withCredentials ); + loader.load( url, function ( text ) { + + try { + + onLoad( scope.parse( JSON.parse( text ) ) ); + + } catch ( e ) { + + if ( onError ) { + + onError( e ); + + } else { + + console.error( e ); + + } + + scope.manager.itemError( url ); + + } + + }, onProgress, onError ); + + } + + parse( json ) { + + const interleavedBufferMap = {}; + const arrayBufferMap = {}; + + function getInterleavedBuffer( json, uuid ) { + + if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ]; + + const interleavedBuffers = json.interleavedBuffers; + const interleavedBuffer = interleavedBuffers[ uuid ]; + + const buffer = getArrayBuffer( json, interleavedBuffer.buffer ); + + const array = getTypedArray( interleavedBuffer.type, buffer ); + const ib = new InterleavedBuffer( array, interleavedBuffer.stride ); + ib.uuid = interleavedBuffer.uuid; + + interleavedBufferMap[ uuid ] = ib; + + return ib; + + } + + function getArrayBuffer( json, uuid ) { + + if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ]; + + const arrayBuffers = json.arrayBuffers; + const arrayBuffer = arrayBuffers[ uuid ]; + + const ab = new Uint32Array( arrayBuffer ).buffer; + + arrayBufferMap[ uuid ] = ab; + + return ab; + + } + + const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry(); + + const index = json.data.index; + + if ( index !== undefined ) { + + const typedArray = getTypedArray( index.type, index.array ); + geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); + + } + + const attributes = json.data.attributes; + + for ( const key in attributes ) { + + const attribute = attributes[ key ]; + let bufferAttribute; + + if ( attribute.isInterleavedBufferAttribute ) { + + const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); + bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); + + } else { + + const typedArray = getTypedArray( attribute.type, attribute.array ); + const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute; + bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized ); + + } + + if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; + if ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage ); + + geometry.setAttribute( key, bufferAttribute ); + + } + + const morphAttributes = json.data.morphAttributes; + + if ( morphAttributes ) { + + for ( const key in morphAttributes ) { + + const attributeArray = morphAttributes[ key ]; + + const array = []; + + for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { + + const attribute = attributeArray[ i ]; + let bufferAttribute; + + if ( attribute.isInterleavedBufferAttribute ) { + + const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); + bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); + + } else { + + const typedArray = getTypedArray( attribute.type, attribute.array ); + bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ); + + } + + if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; + array.push( bufferAttribute ); + + } + + geometry.morphAttributes[ key ] = array; + + } + + } + + const morphTargetsRelative = json.data.morphTargetsRelative; + + if ( morphTargetsRelative ) { + + geometry.morphTargetsRelative = true; + + } + + const groups = json.data.groups || json.data.drawcalls || json.data.offsets; + + if ( groups !== undefined ) { + + for ( let i = 0, n = groups.length; i !== n; ++ i ) { + + const group = groups[ i ]; + + geometry.addGroup( group.start, group.count, group.materialIndex ); + + } + + } + + const boundingSphere = json.data.boundingSphere; + + if ( boundingSphere !== undefined ) { + + const center = new Vector3(); + + if ( boundingSphere.center !== undefined ) { + + center.fromArray( boundingSphere.center ); + + } + + geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); + + } + + if ( json.name ) geometry.name = json.name; + if ( json.userData ) geometry.userData = json.userData; + + return geometry; + + } + +} + +class ObjectLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + } + + load( url, onLoad, onProgress, onError ) { + + const scope = this; + + const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; + this.resourcePath = this.resourcePath || path; + + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( text ) { + + let json = null; + + try { + + json = JSON.parse( text ); + + } catch ( error ) { + + if ( onError !== undefined ) onError( error ); + + console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); + + return; + + } + + const metadata = json.metadata; + + if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { + + if ( onError !== undefined ) onError( new Error( 'THREE.ObjectLoader: Can\'t load ' + url ) ); + + console.error( 'THREE.ObjectLoader: Can\'t load ' + url ); + return; + + } + + scope.parse( json, onLoad ); + + }, onProgress, onError ); + + } + + async loadAsync( url, onProgress ) { + + const scope = this; + + const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; + this.resourcePath = this.resourcePath || path; + + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); + + const text = await loader.loadAsync( url, onProgress ); + + const json = JSON.parse( text ); + + const metadata = json.metadata; + + if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { + + throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url ); + + } + + return await scope.parseAsync( json ); + + } + + parse( json, onLoad ) { + + const animations = this.parseAnimations( json.animations ); + const shapes = this.parseShapes( json.shapes ); + const geometries = this.parseGeometries( json.geometries, shapes ); + + const images = this.parseImages( json.images, function () { + + if ( onLoad !== undefined ) onLoad( object ); + + } ); + + const textures = this.parseTextures( json.textures, images ); + const materials = this.parseMaterials( json.materials, textures ); + + const object = this.parseObject( json.object, geometries, materials, textures, animations ); + const skeletons = this.parseSkeletons( json.skeletons, object ); + + this.bindSkeletons( object, skeletons ); + this.bindLightTargets( object ); + + // + + if ( onLoad !== undefined ) { + + let hasImages = false; + + for ( const uuid in images ) { + + if ( images[ uuid ].data instanceof HTMLImageElement ) { + + hasImages = true; + break; + + } + + } + + if ( hasImages === false ) onLoad( object ); + + } + + return object; + + } + + async parseAsync( json ) { + + const animations = this.parseAnimations( json.animations ); + const shapes = this.parseShapes( json.shapes ); + const geometries = this.parseGeometries( json.geometries, shapes ); + + const images = await this.parseImagesAsync( json.images ); + + const textures = this.parseTextures( json.textures, images ); + const materials = this.parseMaterials( json.materials, textures ); + + const object = this.parseObject( json.object, geometries, materials, textures, animations ); + const skeletons = this.parseSkeletons( json.skeletons, object ); + + this.bindSkeletons( object, skeletons ); + this.bindLightTargets( object ); + + return object; + + } + + parseShapes( json ) { + + const shapes = {}; + + if ( json !== undefined ) { + + for ( let i = 0, l = json.length; i < l; i ++ ) { + + const shape = new Shape().fromJSON( json[ i ] ); + + shapes[ shape.uuid ] = shape; + + } + + } + + return shapes; + + } + + parseSkeletons( json, object ) { + + const skeletons = {}; + const bones = {}; + + // generate bone lookup table + + object.traverse( function ( child ) { + + if ( child.isBone ) bones[ child.uuid ] = child; + + } ); + + // create skeletons + + if ( json !== undefined ) { + + for ( let i = 0, l = json.length; i < l; i ++ ) { + + const skeleton = new Skeleton().fromJSON( json[ i ], bones ); + + skeletons[ skeleton.uuid ] = skeleton; + + } + + } + + return skeletons; + + } + + parseGeometries( json, shapes ) { + + const geometries = {}; + + if ( json !== undefined ) { + + const bufferGeometryLoader = new BufferGeometryLoader(); + + for ( let i = 0, l = json.length; i < l; i ++ ) { + + let geometry; + const data = json[ i ]; + + switch ( data.type ) { + + case 'BufferGeometry': + case 'InstancedBufferGeometry': + + geometry = bufferGeometryLoader.parse( data ); + break; + + default: + + if ( data.type in Geometries$1 ) { + + geometry = Geometries$1[ data.type ].fromJSON( data, shapes ); + + } else { + + console.warn( `THREE.ObjectLoader: Unsupported geometry type "${ data.type }"` ); + + } + + } + + geometry.uuid = data.uuid; + + if ( data.name !== undefined ) geometry.name = data.name; + if ( data.userData !== undefined ) geometry.userData = data.userData; + + geometries[ data.uuid ] = geometry; + + } + + } + + return geometries; + + } + + parseMaterials( json, textures ) { + + const cache = {}; // MultiMaterial + const materials = {}; + + if ( json !== undefined ) { + + const loader = new MaterialLoader(); + loader.setTextures( textures ); + + for ( let i = 0, l = json.length; i < l; i ++ ) { + + const data = json[ i ]; + + if ( cache[ data.uuid ] === undefined ) { + + cache[ data.uuid ] = loader.parse( data ); + + } + + materials[ data.uuid ] = cache[ data.uuid ]; + + } + + } + + return materials; + + } + + parseAnimations( json ) { + + const animations = {}; + + if ( json !== undefined ) { + + for ( let i = 0; i < json.length; i ++ ) { + + const data = json[ i ]; + + const clip = AnimationClip.parse( data ); + + animations[ clip.uuid ] = clip; + + } + + } + + return animations; + + } + + parseImages( json, onLoad ) { + + const scope = this; + const images = {}; + + let loader; + + function loadImage( url ) { + + scope.manager.itemStart( url ); + + return loader.load( url, function () { + + scope.manager.itemEnd( url ); + + }, undefined, function () { + + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); + + } ); + + } + + function deserializeImage( image ) { + + if ( typeof image === 'string' ) { + + const url = image; + + const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; + + return loadImage( path ); + + } else { + + if ( image.data ) { + + return { + data: getTypedArray( image.type, image.data ), + width: image.width, + height: image.height + }; + + } else { + + return null; + + } + + } + + } + + if ( json !== undefined && json.length > 0 ) { + + const manager = new LoadingManager( onLoad ); + + loader = new ImageLoader( manager ); + loader.setCrossOrigin( this.crossOrigin ); + + for ( let i = 0, il = json.length; i < il; i ++ ) { + + const image = json[ i ]; + const url = image.url; + + if ( Array.isArray( url ) ) { + + // load array of images e.g CubeTexture + + const imageArray = []; + + for ( let j = 0, jl = url.length; j < jl; j ++ ) { + + const currentUrl = url[ j ]; + + const deserializedImage = deserializeImage( currentUrl ); + + if ( deserializedImage !== null ) { + + if ( deserializedImage instanceof HTMLImageElement ) { + + imageArray.push( deserializedImage ); + + } else { + + // special case: handle array of data textures for cube textures + + imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); + + } + + } + + } + + images[ image.uuid ] = new Source( imageArray ); + + } else { + + // load single image + + const deserializedImage = deserializeImage( image.url ); + images[ image.uuid ] = new Source( deserializedImage ); + + + } + + } + + } + + return images; + + } + + async parseImagesAsync( json ) { + + const scope = this; + const images = {}; + + let loader; + + async function deserializeImage( image ) { + + if ( typeof image === 'string' ) { + + const url = image; + + const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; + + return await loader.loadAsync( path ); + + } else { + + if ( image.data ) { + + return { + data: getTypedArray( image.type, image.data ), + width: image.width, + height: image.height + }; + + } else { + + return null; + + } + + } + + } + + if ( json !== undefined && json.length > 0 ) { + + loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + + for ( let i = 0, il = json.length; i < il; i ++ ) { + + const image = json[ i ]; + const url = image.url; + + if ( Array.isArray( url ) ) { + + // load array of images e.g CubeTexture + + const imageArray = []; + + for ( let j = 0, jl = url.length; j < jl; j ++ ) { + + const currentUrl = url[ j ]; + + const deserializedImage = await deserializeImage( currentUrl ); + + if ( deserializedImage !== null ) { + + if ( deserializedImage instanceof HTMLImageElement ) { + + imageArray.push( deserializedImage ); + + } else { + + // special case: handle array of data textures for cube textures + + imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); + + } + + } + + } + + images[ image.uuid ] = new Source( imageArray ); + + } else { + + // load single image + + const deserializedImage = await deserializeImage( image.url ); + images[ image.uuid ] = new Source( deserializedImage ); + + } + + } + + } + + return images; + + } + + parseTextures( json, images ) { + + function parseConstant( value, type ) { + + if ( typeof value === 'number' ) return value; + + console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); + + return type[ value ]; + + } + + const textures = {}; + + if ( json !== undefined ) { + + for ( let i = 0, l = json.length; i < l; i ++ ) { + + const data = json[ i ]; + + if ( data.image === undefined ) { + + console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); + + } + + if ( images[ data.image ] === undefined ) { + + console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); + + } + + const source = images[ data.image ]; + const image = source.data; + + let texture; + + if ( Array.isArray( image ) ) { + + texture = new CubeTexture(); + + if ( image.length === 6 ) texture.needsUpdate = true; + + } else { + + if ( image && image.data ) { + + texture = new DataTexture(); + + } else { + + texture = new Texture(); + + } + + if ( image ) texture.needsUpdate = true; // textures can have undefined image data + + } + + texture.source = source; + + texture.uuid = data.uuid; + + if ( data.name !== undefined ) texture.name = data.name; + + if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); + if ( data.channel !== undefined ) texture.channel = data.channel; + + if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); + if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); + if ( data.center !== undefined ) texture.center.fromArray( data.center ); + if ( data.rotation !== undefined ) texture.rotation = data.rotation; + + if ( data.wrap !== undefined ) { + + texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); + texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); + + } + + if ( data.format !== undefined ) texture.format = data.format; + if ( data.internalFormat !== undefined ) texture.internalFormat = data.internalFormat; + if ( data.type !== undefined ) texture.type = data.type; + if ( data.colorSpace !== undefined ) texture.colorSpace = data.colorSpace; + + if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); + if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); + if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; + + if ( data.flipY !== undefined ) texture.flipY = data.flipY; + + if ( data.generateMipmaps !== undefined ) texture.generateMipmaps = data.generateMipmaps; + if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha; + if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment; + if ( data.compareFunction !== undefined ) texture.compareFunction = data.compareFunction; + + if ( data.userData !== undefined ) texture.userData = data.userData; + + textures[ data.uuid ] = texture; + + } + + } + + return textures; + + } + + parseObject( data, geometries, materials, textures, animations ) { + + let object; + + function getGeometry( name ) { + + if ( geometries[ name ] === undefined ) { + + console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); + + } + + return geometries[ name ]; + + } + + function getMaterial( name ) { + + if ( name === undefined ) return undefined; + + if ( Array.isArray( name ) ) { + + const array = []; + + for ( let i = 0, l = name.length; i < l; i ++ ) { + + const uuid = name[ i ]; + + if ( materials[ uuid ] === undefined ) { + + console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); + + } + + array.push( materials[ uuid ] ); + + } + + return array; + + } + + if ( materials[ name ] === undefined ) { + + console.warn( 'THREE.ObjectLoader: Undefined material', name ); + + } + + return materials[ name ]; + + } + + function getTexture( uuid ) { + + if ( textures[ uuid ] === undefined ) { + + console.warn( 'THREE.ObjectLoader: Undefined texture', uuid ); + + } + + return textures[ uuid ]; + + } + + let geometry, material; + + switch ( data.type ) { + + case 'Scene': + + object = new Scene(); + + if ( data.background !== undefined ) { + + if ( Number.isInteger( data.background ) ) { + + object.background = new Color( data.background ); + + } else { + + object.background = getTexture( data.background ); + + } + + } + + if ( data.environment !== undefined ) { + + object.environment = getTexture( data.environment ); + + } + + if ( data.fog !== undefined ) { + + if ( data.fog.type === 'Fog' ) { + + object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); + + } else if ( data.fog.type === 'FogExp2' ) { + + object.fog = new FogExp2( data.fog.color, data.fog.density ); + + } + + if ( data.fog.name !== '' ) { + + object.fog.name = data.fog.name; + + } + + } + + if ( data.backgroundBlurriness !== undefined ) object.backgroundBlurriness = data.backgroundBlurriness; + if ( data.backgroundIntensity !== undefined ) object.backgroundIntensity = data.backgroundIntensity; + if ( data.backgroundRotation !== undefined ) object.backgroundRotation.fromArray( data.backgroundRotation ); + + if ( data.environmentIntensity !== undefined ) object.environmentIntensity = data.environmentIntensity; + if ( data.environmentRotation !== undefined ) object.environmentRotation.fromArray( data.environmentRotation ); + + break; + + case 'PerspectiveCamera': + + object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); + + if ( data.focus !== undefined ) object.focus = data.focus; + if ( data.zoom !== undefined ) object.zoom = data.zoom; + if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; + if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; + if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); + + break; + + case 'OrthographicCamera': + + object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); + + if ( data.zoom !== undefined ) object.zoom = data.zoom; + if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); + + break; + + case 'AmbientLight': + + object = new AmbientLight( data.color, data.intensity ); + + break; + + case 'DirectionalLight': + + object = new DirectionalLight( data.color, data.intensity ); + object.target = data.target || ''; + + break; + + case 'PointLight': + + object = new PointLight( data.color, data.intensity, data.distance, data.decay ); + + break; + + case 'RectAreaLight': + + object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); + + break; + + case 'SpotLight': + + object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); + object.target = data.target || ''; + + break; + + case 'HemisphereLight': + + object = new HemisphereLight( data.color, data.groundColor, data.intensity ); + + break; + + case 'LightProbe': + + object = new LightProbe().fromJSON( data ); + + break; + + case 'SkinnedMesh': + + geometry = getGeometry( data.geometry ); + material = getMaterial( data.material ); + + object = new SkinnedMesh( geometry, material ); + + if ( data.bindMode !== undefined ) object.bindMode = data.bindMode; + if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix ); + if ( data.skeleton !== undefined ) object.skeleton = data.skeleton; + + break; + + case 'Mesh': + + geometry = getGeometry( data.geometry ); + material = getMaterial( data.material ); + + object = new Mesh( geometry, material ); + + break; + + case 'InstancedMesh': + + geometry = getGeometry( data.geometry ); + material = getMaterial( data.material ); + const count = data.count; + const instanceMatrix = data.instanceMatrix; + const instanceColor = data.instanceColor; + + object = new InstancedMesh( geometry, material, count ); + object.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 ); + if ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize ); + + break; + + case 'BatchedMesh': + + geometry = getGeometry( data.geometry ); + material = getMaterial( data.material ); + + object = new BatchedMesh( data.maxInstanceCount, data.maxVertexCount, data.maxIndexCount, material ); + object.geometry = geometry; + object.perObjectFrustumCulled = data.perObjectFrustumCulled; + object.sortObjects = data.sortObjects; + + object._drawRanges = data.drawRanges; + object._reservedRanges = data.reservedRanges; + + object._visibility = data.visibility; + object._active = data.active; + object._bounds = data.bounds.map( bound => { + + const box = new Box3(); + box.min.fromArray( bound.boxMin ); + box.max.fromArray( bound.boxMax ); + + const sphere = new Sphere(); + sphere.radius = bound.sphereRadius; + sphere.center.fromArray( bound.sphereCenter ); + + return { + boxInitialized: bound.boxInitialized, + box: box, + + sphereInitialized: bound.sphereInitialized, + sphere: sphere + }; + + } ); + + object._maxInstanceCount = data.maxInstanceCount; + object._maxVertexCount = data.maxVertexCount; + object._maxIndexCount = data.maxIndexCount; + + object._geometryInitialized = data.geometryInitialized; + object._geometryCount = data.geometryCount; + + object._matricesTexture = getTexture( data.matricesTexture.uuid ); + if ( data.colorsTexture !== undefined ) object._colorsTexture = getTexture( data.colorsTexture.uuid ); + + break; + + case 'LOD': + + object = new LOD(); + + break; + + case 'Line': + + object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) ); + + break; + + case 'LineLoop': + + object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); + + break; + + case 'LineSegments': + + object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); + + break; + + case 'PointCloud': + case 'Points': + + object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); + + break; + + case 'Sprite': + + object = new Sprite( getMaterial( data.material ) ); + + break; + + case 'Group': + + object = new Group(); + + break; + + case 'Bone': + + object = new Bone(); + + break; + + default: + + object = new Object3D(); + + } + + object.uuid = data.uuid; + + if ( data.name !== undefined ) object.name = data.name; + + if ( data.matrix !== undefined ) { + + object.matrix.fromArray( data.matrix ); + + if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate; + if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale ); + + } else { + + if ( data.position !== undefined ) object.position.fromArray( data.position ); + if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); + if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); + if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); + + } + + if ( data.up !== undefined ) object.up.fromArray( data.up ); + + if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; + if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; + + if ( data.shadow ) { + + if ( data.shadow.intensity !== undefined ) object.shadow.intensity = data.shadow.intensity; + if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; + if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias; + if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; + if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); + if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); + + } + + if ( data.visible !== undefined ) object.visible = data.visible; + if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled; + if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder; + if ( data.userData !== undefined ) object.userData = data.userData; + if ( data.layers !== undefined ) object.layers.mask = data.layers; + + if ( data.children !== undefined ) { + + const children = data.children; + + for ( let i = 0; i < children.length; i ++ ) { + + object.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) ); + + } + + } + + if ( data.animations !== undefined ) { + + const objectAnimations = data.animations; + + for ( let i = 0; i < objectAnimations.length; i ++ ) { + + const uuid = objectAnimations[ i ]; + + object.animations.push( animations[ uuid ] ); + + } + + } + + if ( data.type === 'LOD' ) { + + if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate; + + const levels = data.levels; + + for ( let l = 0; l < levels.length; l ++ ) { + + const level = levels[ l ]; + const child = object.getObjectByProperty( 'uuid', level.object ); + + if ( child !== undefined ) { + + object.addLevel( child, level.distance, level.hysteresis ); + + } + + } + + } + + return object; + + } + + bindSkeletons( object, skeletons ) { + + if ( Object.keys( skeletons ).length === 0 ) return; + + object.traverse( function ( child ) { + + if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) { + + const skeleton = skeletons[ child.skeleton ]; + + if ( skeleton === undefined ) { + + console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton ); + + } else { + + child.bind( skeleton, child.bindMatrix ); + + } + + } + + } ); + + } + + bindLightTargets( object ) { + + object.traverse( function ( child ) { + + if ( child.isDirectionalLight || child.isSpotLight ) { + + const uuid = child.target; + + const target = object.getObjectByProperty( 'uuid', uuid ); + + if ( target !== undefined ) { + + child.target = target; + + } else { + + child.target = new Object3D(); + + } + + } + + } ); + + } + +} + +const TEXTURE_MAPPING = { + UVMapping: UVMapping, + CubeReflectionMapping: CubeReflectionMapping, + CubeRefractionMapping: CubeRefractionMapping, + EquirectangularReflectionMapping: EquirectangularReflectionMapping, + EquirectangularRefractionMapping: EquirectangularRefractionMapping, + CubeUVReflectionMapping: CubeUVReflectionMapping +}; + +const TEXTURE_WRAPPING = { + RepeatWrapping: RepeatWrapping, + ClampToEdgeWrapping: ClampToEdgeWrapping, + MirroredRepeatWrapping: MirroredRepeatWrapping +}; + +const TEXTURE_FILTER = { + NearestFilter: NearestFilter, + NearestMipmapNearestFilter: NearestMipmapNearestFilter, + NearestMipmapLinearFilter: NearestMipmapLinearFilter, + LinearFilter: LinearFilter, + LinearMipmapNearestFilter: LinearMipmapNearestFilter, + LinearMipmapLinearFilter: LinearMipmapLinearFilter +}; + +class ImageBitmapLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + this.isImageBitmapLoader = true; + + if ( typeof createImageBitmap === 'undefined' ) { + + console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); + + } + + if ( typeof fetch === 'undefined' ) { + + console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); + + } + + this.options = { premultiplyAlpha: 'none' }; + + } + + setOptions( options ) { + + this.options = options; + + return this; + + } + + load( url, onLoad, onProgress, onError ) { + + if ( url === undefined ) url = ''; + + if ( this.path !== undefined ) url = this.path + url; + + url = this.manager.resolveURL( url ); + + const scope = this; + + const cached = Cache.get( url ); + + if ( cached !== undefined ) { + + scope.manager.itemStart( url ); + + // If cached is a promise, wait for it to resolve + if ( cached.then ) { + + cached.then( imageBitmap => { + + if ( onLoad ) onLoad( imageBitmap ); + + scope.manager.itemEnd( url ); + + } ).catch( e => { + + if ( onError ) onError( e ); + + } ); + return; + + } + + // If cached is not a promise (i.e., it's already an imageBitmap) + setTimeout( function () { + + if ( onLoad ) onLoad( cached ); + + scope.manager.itemEnd( url ); + + }, 0 ); + + return cached; + + } + + const fetchOptions = {}; + fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include'; + fetchOptions.headers = this.requestHeader; + + const promise = fetch( url, fetchOptions ).then( function ( res ) { + + return res.blob(); + + } ).then( function ( blob ) { + + return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) ); + + } ).then( function ( imageBitmap ) { + + Cache.add( url, imageBitmap ); + + if ( onLoad ) onLoad( imageBitmap ); + + scope.manager.itemEnd( url ); + + return imageBitmap; + + } ).catch( function ( e ) { + + if ( onError ) onError( e ); + + Cache.remove( url ); + + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); + + } ); + + Cache.add( url, promise ); + scope.manager.itemStart( url ); + + } + +} + +let _context; + +class AudioContext { + + static getContext() { + + if ( _context === undefined ) { + + _context = new ( window.AudioContext || window.webkitAudioContext )(); + + } + + return _context; + + } + + static setContext( value ) { + + _context = value; + + } + +} + +class AudioLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + } + + load( url, onLoad, onProgress, onError ) { + + const scope = this; + + const loader = new FileLoader( this.manager ); + loader.setResponseType( 'arraybuffer' ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( buffer ) { + + try { + + // Create a copy of the buffer. The `decodeAudioData` method + // detaches the buffer when complete, preventing reuse. + const bufferCopy = buffer.slice( 0 ); + + const context = AudioContext.getContext(); + context.decodeAudioData( bufferCopy, function ( audioBuffer ) { + + onLoad( audioBuffer ); + + } ).catch( handleError ); + + } catch ( e ) { + + handleError( e ); + + } + + }, onProgress, onError ); + + function handleError( e ) { + + if ( onError ) { + + onError( e ); + + } else { + + console.error( e ); + + } + + scope.manager.itemError( url ); + + } + + } + +} + +const _eyeRight = /*@__PURE__*/ new Matrix4(); +const _eyeLeft = /*@__PURE__*/ new Matrix4(); +const _projectionMatrix = /*@__PURE__*/ new Matrix4(); + +class StereoCamera { + + constructor() { + + this.type = 'StereoCamera'; + + this.aspect = 1; + + this.eyeSep = 0.064; + + this.cameraL = new PerspectiveCamera(); + this.cameraL.layers.enable( 1 ); + this.cameraL.matrixAutoUpdate = false; + + this.cameraR = new PerspectiveCamera(); + this.cameraR.layers.enable( 2 ); + this.cameraR.matrixAutoUpdate = false; + + this._cache = { + focus: null, + fov: null, + aspect: null, + near: null, + far: null, + zoom: null, + eyeSep: null + }; + + } + + update( camera ) { + + const cache = this._cache; + + const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov || + cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near || + cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep; + + if ( needsUpdate ) { + + cache.focus = camera.focus; + cache.fov = camera.fov; + cache.aspect = camera.aspect * this.aspect; + cache.near = camera.near; + cache.far = camera.far; + cache.zoom = camera.zoom; + cache.eyeSep = this.eyeSep; + + // Off-axis stereoscopic effect based on + // http://paulbourke.net/stereographics/stereorender/ + + _projectionMatrix.copy( camera.projectionMatrix ); + const eyeSepHalf = cache.eyeSep / 2; + const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus; + const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom; + let xmin, xmax; + + // translate xOffset + + _eyeLeft.elements[ 12 ] = - eyeSepHalf; + _eyeRight.elements[ 12 ] = eyeSepHalf; + + // for left eye + + xmin = - ymax * cache.aspect + eyeSepOnProjection; + xmax = ymax * cache.aspect + eyeSepOnProjection; + + _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); + _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); + + this.cameraL.projectionMatrix.copy( _projectionMatrix ); + + // for right eye + + xmin = - ymax * cache.aspect - eyeSepOnProjection; + xmax = ymax * cache.aspect - eyeSepOnProjection; + + _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); + _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); + + this.cameraR.projectionMatrix.copy( _projectionMatrix ); + + } + + this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft ); + this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight ); + + } + +} + +class ArrayCamera extends PerspectiveCamera { + + constructor( array = [] ) { + + super(); + + this.isArrayCamera = true; + + this.cameras = array; + + } + +} + +class Clock { + + constructor( autoStart = true ) { + + this.autoStart = autoStart; + + this.startTime = 0; + this.oldTime = 0; + this.elapsedTime = 0; + + this.running = false; + + } + + start() { + + this.startTime = now(); + + this.oldTime = this.startTime; + this.elapsedTime = 0; + this.running = true; + + } + + stop() { + + this.getElapsedTime(); + this.running = false; + this.autoStart = false; + + } + + getElapsedTime() { + + this.getDelta(); + return this.elapsedTime; + + } + + getDelta() { + + let diff = 0; + + if ( this.autoStart && ! this.running ) { + + this.start(); + return 0; + + } + + if ( this.running ) { + + const newTime = now(); + + diff = ( newTime - this.oldTime ) / 1000; + this.oldTime = newTime; + + this.elapsedTime += diff; + + } + + return diff; + + } + +} + +function now() { + + return performance.now(); + +} + +const _position$1 = /*@__PURE__*/ new Vector3(); +const _quaternion$1 = /*@__PURE__*/ new Quaternion(); +const _scale$1 = /*@__PURE__*/ new Vector3(); +const _orientation$1 = /*@__PURE__*/ new Vector3(); + +class AudioListener extends Object3D { + + constructor() { + + super(); + + this.type = 'AudioListener'; + + this.context = AudioContext.getContext(); + + this.gain = this.context.createGain(); + this.gain.connect( this.context.destination ); + + this.filter = null; + + this.timeDelta = 0; + + // private + + this._clock = new Clock(); + + } + + getInput() { + + return this.gain; + + } + + removeFilter() { + + if ( this.filter !== null ) { + + this.gain.disconnect( this.filter ); + this.filter.disconnect( this.context.destination ); + this.gain.connect( this.context.destination ); + this.filter = null; + + } + + return this; + + } + + getFilter() { + + return this.filter; + + } + + setFilter( value ) { + + if ( this.filter !== null ) { + + this.gain.disconnect( this.filter ); + this.filter.disconnect( this.context.destination ); + + } else { + + this.gain.disconnect( this.context.destination ); + + } + + this.filter = value; + this.gain.connect( this.filter ); + this.filter.connect( this.context.destination ); + + return this; + + } + + getMasterVolume() { + + return this.gain.gain.value; + + } + + setMasterVolume( value ) { + + this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); + + return this; + + } + + updateMatrixWorld( force ) { + + super.updateMatrixWorld( force ); + + const listener = this.context.listener; + const up = this.up; + + this.timeDelta = this._clock.getDelta(); + + this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 ); + + _orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 ); + + if ( listener.positionX ) { + + // code path for Chrome (see #14393) + + const endTime = this.context.currentTime + this.timeDelta; + + listener.positionX.linearRampToValueAtTime( _position$1.x, endTime ); + listener.positionY.linearRampToValueAtTime( _position$1.y, endTime ); + listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime ); + listener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime ); + listener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime ); + listener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime ); + listener.upX.linearRampToValueAtTime( up.x, endTime ); + listener.upY.linearRampToValueAtTime( up.y, endTime ); + listener.upZ.linearRampToValueAtTime( up.z, endTime ); + + } else { + + listener.setPosition( _position$1.x, _position$1.y, _position$1.z ); + listener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z ); + + } + + } + +} + +class Audio extends Object3D { + + constructor( listener ) { + + super(); + + this.type = 'Audio'; + + this.listener = listener; + this.context = listener.context; + + this.gain = this.context.createGain(); + this.gain.connect( listener.getInput() ); + + this.autoplay = false; + + this.buffer = null; + this.detune = 0; + this.loop = false; + this.loopStart = 0; + this.loopEnd = 0; + this.offset = 0; + this.duration = undefined; + this.playbackRate = 1; + this.isPlaying = false; + this.hasPlaybackControl = true; + this.source = null; + this.sourceType = 'empty'; + + this._startedAt = 0; + this._progress = 0; + this._connected = false; + + this.filters = []; + + } + + getOutput() { + + return this.gain; + + } + + setNodeSource( audioNode ) { + + this.hasPlaybackControl = false; + this.sourceType = 'audioNode'; + this.source = audioNode; + this.connect(); + + return this; + + } + + setMediaElementSource( mediaElement ) { + + this.hasPlaybackControl = false; + this.sourceType = 'mediaNode'; + this.source = this.context.createMediaElementSource( mediaElement ); + this.connect(); + + return this; + + } + + setMediaStreamSource( mediaStream ) { + + this.hasPlaybackControl = false; + this.sourceType = 'mediaStreamNode'; + this.source = this.context.createMediaStreamSource( mediaStream ); + this.connect(); + + return this; + + } + + setBuffer( audioBuffer ) { + + this.buffer = audioBuffer; + this.sourceType = 'buffer'; + + if ( this.autoplay ) this.play(); + + return this; + + } + + play( delay = 0 ) { + + if ( this.isPlaying === true ) { + + console.warn( 'THREE.Audio: Audio is already playing.' ); + return; + + } + + if ( this.hasPlaybackControl === false ) { + + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; + + } + + this._startedAt = this.context.currentTime + delay; + + const source = this.context.createBufferSource(); + source.buffer = this.buffer; + source.loop = this.loop; + source.loopStart = this.loopStart; + source.loopEnd = this.loopEnd; + source.onended = this.onEnded.bind( this ); + source.start( this._startedAt, this._progress + this.offset, this.duration ); + + this.isPlaying = true; + + this.source = source; + + this.setDetune( this.detune ); + this.setPlaybackRate( this.playbackRate ); + + return this.connect(); + + } + + pause() { + + if ( this.hasPlaybackControl === false ) { + + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; + + } + + if ( this.isPlaying === true ) { + + // update current progress + + this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate; + + if ( this.loop === true ) { + + // ensure _progress does not exceed duration with looped audios + + this._progress = this._progress % ( this.duration || this.buffer.duration ); + + } + + this.source.stop(); + this.source.onended = null; + + this.isPlaying = false; + + } + + return this; + + } + + stop( delay = 0 ) { + + if ( this.hasPlaybackControl === false ) { + + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; + + } + + this._progress = 0; + + if ( this.source !== null ) { + + this.source.stop( this.context.currentTime + delay ); + this.source.onended = null; + + } + + this.isPlaying = false; + + return this; + + } + + connect() { + + if ( this.filters.length > 0 ) { + + this.source.connect( this.filters[ 0 ] ); + + for ( let i = 1, l = this.filters.length; i < l; i ++ ) { + + this.filters[ i - 1 ].connect( this.filters[ i ] ); + + } + + this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); + + } else { + + this.source.connect( this.getOutput() ); + + } + + this._connected = true; + + return this; + + } + + disconnect() { + + if ( this._connected === false ) { + + return; + + } + + if ( this.filters.length > 0 ) { + + this.source.disconnect( this.filters[ 0 ] ); + + for ( let i = 1, l = this.filters.length; i < l; i ++ ) { + + this.filters[ i - 1 ].disconnect( this.filters[ i ] ); + + } + + this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); + + } else { + + this.source.disconnect( this.getOutput() ); + + } + + this._connected = false; + + return this; + + } + + getFilters() { + + return this.filters; + + } + + setFilters( value ) { + + if ( ! value ) value = []; + + if ( this._connected === true ) { + + this.disconnect(); + this.filters = value.slice(); + this.connect(); + + } else { + + this.filters = value.slice(); + + } + + return this; + + } + + setDetune( value ) { + + this.detune = value; + + if ( this.isPlaying === true && this.source.detune !== undefined ) { + + this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 ); + + } + + return this; + + } + + getDetune() { + + return this.detune; + + } + + getFilter() { + + return this.getFilters()[ 0 ]; + + } + + setFilter( filter ) { + + return this.setFilters( filter ? [ filter ] : [] ); + + } + + setPlaybackRate( value ) { + + if ( this.hasPlaybackControl === false ) { + + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; + + } + + this.playbackRate = value; + + if ( this.isPlaying === true ) { + + this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 ); + + } + + return this; + + } + + getPlaybackRate() { + + return this.playbackRate; + + } + + onEnded() { + + this.isPlaying = false; + + } + + getLoop() { + + if ( this.hasPlaybackControl === false ) { + + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return false; + + } + + return this.loop; + + } + + setLoop( value ) { + + if ( this.hasPlaybackControl === false ) { + + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; + + } + + this.loop = value; + + if ( this.isPlaying === true ) { + + this.source.loop = this.loop; + + } + + return this; + + } + + setLoopStart( value ) { + + this.loopStart = value; + + return this; + + } + + setLoopEnd( value ) { + + this.loopEnd = value; + + return this; + + } + + getVolume() { + + return this.gain.gain.value; + + } + + setVolume( value ) { + + this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); + + return this; + + } + +} + +const _position = /*@__PURE__*/ new Vector3(); +const _quaternion = /*@__PURE__*/ new Quaternion(); +const _scale = /*@__PURE__*/ new Vector3(); +const _orientation = /*@__PURE__*/ new Vector3(); + +class PositionalAudio extends Audio { + + constructor( listener ) { + + super( listener ); + + this.panner = this.context.createPanner(); + this.panner.panningModel = 'HRTF'; + this.panner.connect( this.gain ); + + } + + connect() { + + super.connect(); + + this.panner.connect( this.gain ); + + } + + disconnect() { + + super.disconnect(); + + this.panner.disconnect( this.gain ); + + } + + getOutput() { + + return this.panner; + + } + + getRefDistance() { + + return this.panner.refDistance; + + } + + setRefDistance( value ) { + + this.panner.refDistance = value; + + return this; + + } + + getRolloffFactor() { + + return this.panner.rolloffFactor; + + } + + setRolloffFactor( value ) { + + this.panner.rolloffFactor = value; + + return this; + + } + + getDistanceModel() { + + return this.panner.distanceModel; + + } + + setDistanceModel( value ) { + + this.panner.distanceModel = value; + + return this; + + } + + getMaxDistance() { + + return this.panner.maxDistance; + + } + + setMaxDistance( value ) { + + this.panner.maxDistance = value; + + return this; + + } + + setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) { + + this.panner.coneInnerAngle = coneInnerAngle; + this.panner.coneOuterAngle = coneOuterAngle; + this.panner.coneOuterGain = coneOuterGain; + + return this; + + } + + updateMatrixWorld( force ) { + + super.updateMatrixWorld( force ); + + if ( this.hasPlaybackControl === true && this.isPlaying === false ) return; + + this.matrixWorld.decompose( _position, _quaternion, _scale ); + + _orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion ); + + const panner = this.panner; + + if ( panner.positionX ) { + + // code path for Chrome and Firefox (see #14393) + + const endTime = this.context.currentTime + this.listener.timeDelta; + + panner.positionX.linearRampToValueAtTime( _position.x, endTime ); + panner.positionY.linearRampToValueAtTime( _position.y, endTime ); + panner.positionZ.linearRampToValueAtTime( _position.z, endTime ); + panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime ); + panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime ); + panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime ); + + } else { + + panner.setPosition( _position.x, _position.y, _position.z ); + panner.setOrientation( _orientation.x, _orientation.y, _orientation.z ); + + } + + } + +} + +class AudioAnalyser { + + constructor( audio, fftSize = 2048 ) { + + this.analyser = audio.context.createAnalyser(); + this.analyser.fftSize = fftSize; + + this.data = new Uint8Array( this.analyser.frequencyBinCount ); + + audio.getOutput().connect( this.analyser ); + + } + + + getFrequencyData() { + + this.analyser.getByteFrequencyData( this.data ); + + return this.data; + + } + + getAverageFrequency() { + + let value = 0; + const data = this.getFrequencyData(); + + for ( let i = 0; i < data.length; i ++ ) { + + value += data[ i ]; + + } + + return value / data.length; + + } + +} + +class PropertyMixer { + + constructor( binding, typeName, valueSize ) { + + this.binding = binding; + this.valueSize = valueSize; + + let mixFunction, + mixFunctionAdditive, + setIdentity; + + // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ] + // + // interpolators can use .buffer as their .result + // the data then goes to 'incoming' + // + // 'accu0' and 'accu1' are used frame-interleaved for + // the cumulative result and are compared to detect + // changes + // + // 'orig' stores the original state of the property + // + // 'add' is used for additive cumulative results + // + // 'work' is optional and is only present for quaternion types. It is used + // to store intermediate quaternion multiplication results + + switch ( typeName ) { + + case 'quaternion': + mixFunction = this._slerp; + mixFunctionAdditive = this._slerpAdditive; + setIdentity = this._setAdditiveIdentityQuaternion; + + this.buffer = new Float64Array( valueSize * 6 ); + this._workIndex = 5; + break; + + case 'string': + case 'bool': + mixFunction = this._select; + + // Use the regular mix function and for additive on these types, + // additive is not relevant for non-numeric types + mixFunctionAdditive = this._select; + + setIdentity = this._setAdditiveIdentityOther; + + this.buffer = new Array( valueSize * 5 ); + break; + + default: + mixFunction = this._lerp; + mixFunctionAdditive = this._lerpAdditive; + setIdentity = this._setAdditiveIdentityNumeric; + + this.buffer = new Float64Array( valueSize * 5 ); + + } + + this._mixBufferRegion = mixFunction; + this._mixBufferRegionAdditive = mixFunctionAdditive; + this._setIdentity = setIdentity; + this._origIndex = 3; + this._addIndex = 4; + + this.cumulativeWeight = 0; + this.cumulativeWeightAdditive = 0; + + this.useCount = 0; + this.referenceCount = 0; + + } + + // accumulate data in the 'incoming' region into 'accu' + accumulate( accuIndex, weight ) { + + // note: happily accumulating nothing when weight = 0, the caller knows + // the weight and shouldn't have made the call in the first place + + const buffer = this.buffer, + stride = this.valueSize, + offset = accuIndex * stride + stride; + + let currentWeight = this.cumulativeWeight; + + if ( currentWeight === 0 ) { + + // accuN := incoming * weight + + for ( let i = 0; i !== stride; ++ i ) { + + buffer[ offset + i ] = buffer[ i ]; + + } + + currentWeight = weight; + + } else { + + // accuN := accuN + incoming * weight + + currentWeight += weight; + const mix = weight / currentWeight; + this._mixBufferRegion( buffer, offset, 0, mix, stride ); + + } + + this.cumulativeWeight = currentWeight; + + } + + // accumulate data in the 'incoming' region into 'add' + accumulateAdditive( weight ) { + + const buffer = this.buffer, + stride = this.valueSize, + offset = stride * this._addIndex; + + if ( this.cumulativeWeightAdditive === 0 ) { + + // add = identity + + this._setIdentity(); + + } + + // add := add + incoming * weight + + this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride ); + this.cumulativeWeightAdditive += weight; + + } + + // apply the state of 'accu' to the binding when accus differ + apply( accuIndex ) { + + const stride = this.valueSize, + buffer = this.buffer, + offset = accuIndex * stride + stride, + + weight = this.cumulativeWeight, + weightAdditive = this.cumulativeWeightAdditive, + + binding = this.binding; + + this.cumulativeWeight = 0; + this.cumulativeWeightAdditive = 0; + + if ( weight < 1 ) { + + // accuN := accuN + original * ( 1 - cumulativeWeight ) + + const originalValueOffset = stride * this._origIndex; + + this._mixBufferRegion( + buffer, offset, originalValueOffset, 1 - weight, stride ); + + } + + if ( weightAdditive > 0 ) { + + // accuN := accuN + additive accuN + + this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride ); + + } + + for ( let i = stride, e = stride + stride; i !== e; ++ i ) { + + if ( buffer[ i ] !== buffer[ i + stride ] ) { + + // value has changed -> update scene graph + + binding.setValue( buffer, offset ); + break; + + } + + } + + } + + // remember the state of the bound property and copy it to both accus + saveOriginalState() { + + const binding = this.binding; + + const buffer = this.buffer, + stride = this.valueSize, + + originalValueOffset = stride * this._origIndex; + + binding.getValue( buffer, originalValueOffset ); + + // accu[0..1] := orig -- initially detect changes against the original + for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) { + + buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; + + } + + // Add to identity for additive + this._setIdentity(); + + this.cumulativeWeight = 0; + this.cumulativeWeightAdditive = 0; + + } + + // apply the state previously taken via 'saveOriginalState' to the binding + restoreOriginalState() { + + const originalValueOffset = this.valueSize * 3; + this.binding.setValue( this.buffer, originalValueOffset ); + + } + + _setAdditiveIdentityNumeric() { + + const startIndex = this._addIndex * this.valueSize; + const endIndex = startIndex + this.valueSize; + + for ( let i = startIndex; i < endIndex; i ++ ) { + + this.buffer[ i ] = 0; + + } + + } + + _setAdditiveIdentityQuaternion() { + + this._setAdditiveIdentityNumeric(); + this.buffer[ this._addIndex * this.valueSize + 3 ] = 1; + + } + + _setAdditiveIdentityOther() { + + const startIndex = this._origIndex * this.valueSize; + const targetIndex = this._addIndex * this.valueSize; + + for ( let i = 0; i < this.valueSize; i ++ ) { + + this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ]; + + } + + } + + + // mix functions + + _select( buffer, dstOffset, srcOffset, t, stride ) { + + if ( t >= 0.5 ) { + + for ( let i = 0; i !== stride; ++ i ) { + + buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; + + } + + } + + } + + _slerp( buffer, dstOffset, srcOffset, t ) { + + Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); + + } + + _slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { + + const workOffset = this._workIndex * stride; + + // Store result in intermediate buffer offset + Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset ); + + // Slerp to the intermediate result + Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t ); + + } + + _lerp( buffer, dstOffset, srcOffset, t, stride ) { + + const s = 1 - t; + + for ( let i = 0; i !== stride; ++ i ) { + + const j = dstOffset + i; + + buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; + + } + + } + + _lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { + + for ( let i = 0; i !== stride; ++ i ) { + + const j = dstOffset + i; + + buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t; + + } + + } + +} + +// Characters [].:/ are reserved for track binding syntax. +const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; +const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' ); + +// Attempts to allow node names from any language. ES5's `\w` regexp matches +// only latin characters, and the unicode \p{L} is not yet supported. So +// instead, we exclude reserved characters and match everything else. +const _wordChar = '[^' + _RESERVED_CHARS_RE + ']'; +const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; + +// Parent directories, delimited by '/' or ':'. Currently unused, but must +// be matched to parse the rest of the track name. +const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar ); + +// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. +const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot ); + +// Object on target node, and accessor. May not contain reserved +// characters. Accessor may contain any character except closing bracket. +const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar ); + +// Property and accessor. May not contain reserved characters. Accessor may +// contain any non-bracket characters. +const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar ); + +const _trackRe = new RegExp( '' + + '^' + + _directoryRe + + _nodeRe + + _objectRe + + _propertyRe + + '$' +); + +const _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ]; + +class Composite { + + constructor( targetGroup, path, optionalParsedPath ) { + + const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); + + this._targetGroup = targetGroup; + this._bindings = targetGroup.subscribe_( path, parsedPath ); + + } + + getValue( array, offset ) { + + this.bind(); // bind all binding + + const firstValidIndex = this._targetGroup.nCachedObjects_, + binding = this._bindings[ firstValidIndex ]; + + // and only call .getValue on the first + if ( binding !== undefined ) binding.getValue( array, offset ); + + } + + setValue( array, offset ) { + + const bindings = this._bindings; + + for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { + + bindings[ i ].setValue( array, offset ); + + } + + } + + bind() { + + const bindings = this._bindings; + + for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { + + bindings[ i ].bind(); + + } + + } + + unbind() { + + const bindings = this._bindings; + + for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { + + bindings[ i ].unbind(); + + } + + } + +} + +// Note: This class uses a State pattern on a per-method basis: +// 'bind' sets 'this.getValue' / 'setValue' and shadows the +// prototype version of these methods with one that represents +// the bound state. When the property is not found, the methods +// become no-ops. +class PropertyBinding { + + constructor( rootNode, path, parsedPath ) { + + this.path = path; + this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); + + this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ); + + this.rootNode = rootNode; + + // initial state of these methods that calls 'bind' + this.getValue = this._getValue_unbound; + this.setValue = this._setValue_unbound; + + } + + + static create( root, path, parsedPath ) { + + if ( ! ( root && root.isAnimationObjectGroup ) ) { + + return new PropertyBinding( root, path, parsedPath ); + + } else { + + return new PropertyBinding.Composite( root, path, parsedPath ); + + } + + } + + /** + * Replaces spaces with underscores and removes unsupported characters from + * node names, to ensure compatibility with parseTrackName(). + * + * @param {string} name Node name to be sanitized. + * @return {string} + */ + static sanitizeNodeName( name ) { + + return name.replace( /\s/g, '_' ).replace( _reservedRe, '' ); + + } + + static parseTrackName( trackName ) { + + const matches = _trackRe.exec( trackName ); + + if ( matches === null ) { + + throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); + + } + + const results = { + // directoryName: matches[ 1 ], // (tschw) currently unused + nodeName: matches[ 2 ], + objectName: matches[ 3 ], + objectIndex: matches[ 4 ], + propertyName: matches[ 5 ], // required + propertyIndex: matches[ 6 ] + }; + + const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); + + if ( lastDot !== undefined && lastDot !== - 1 ) { + + const objectName = results.nodeName.substring( lastDot + 1 ); + + // Object names must be checked against an allowlist. Otherwise, there + // is no way to parse 'foo.bar.baz': 'baz' must be a property, but + // 'bar' could be the objectName, or part of a nodeName (which can + // include '.' characters). + if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) { + + results.nodeName = results.nodeName.substring( 0, lastDot ); + results.objectName = objectName; + + } + + } + + if ( results.propertyName === null || results.propertyName.length === 0 ) { + + throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); + + } + + return results; + + } + + static findNode( root, nodeName ) { + + if ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { + + return root; + + } + + // search into skeleton bones. + if ( root.skeleton ) { + + const bone = root.skeleton.getBoneByName( nodeName ); + + if ( bone !== undefined ) { + + return bone; + + } + + } + + // search into node subtree. + if ( root.children ) { + + const searchNodeSubtree = function ( children ) { + + for ( let i = 0; i < children.length; i ++ ) { + + const childNode = children[ i ]; + + if ( childNode.name === nodeName || childNode.uuid === nodeName ) { + + return childNode; + + } + + const result = searchNodeSubtree( childNode.children ); + + if ( result ) return result; + + } + + return null; + + }; + + const subTreeNode = searchNodeSubtree( root.children ); + + if ( subTreeNode ) { + + return subTreeNode; + + } + + } + + return null; + + } + + // these are used to "bind" a nonexistent property + _getValue_unavailable() {} + _setValue_unavailable() {} + + // Getters + + _getValue_direct( buffer, offset ) { + + buffer[ offset ] = this.targetObject[ this.propertyName ]; + + } + + _getValue_array( buffer, offset ) { + + const source = this.resolvedProperty; + + for ( let i = 0, n = source.length; i !== n; ++ i ) { + + buffer[ offset ++ ] = source[ i ]; + + } + + } + + _getValue_arrayElement( buffer, offset ) { + + buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; + + } + + _getValue_toArray( buffer, offset ) { + + this.resolvedProperty.toArray( buffer, offset ); + + } + + // Direct + + _setValue_direct( buffer, offset ) { + + this.targetObject[ this.propertyName ] = buffer[ offset ]; + + } + + _setValue_direct_setNeedsUpdate( buffer, offset ) { + + this.targetObject[ this.propertyName ] = buffer[ offset ]; + this.targetObject.needsUpdate = true; + + } + + _setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { + + this.targetObject[ this.propertyName ] = buffer[ offset ]; + this.targetObject.matrixWorldNeedsUpdate = true; + + } + + // EntireArray + + _setValue_array( buffer, offset ) { + + const dest = this.resolvedProperty; + + for ( let i = 0, n = dest.length; i !== n; ++ i ) { + + dest[ i ] = buffer[ offset ++ ]; + + } + + } + + _setValue_array_setNeedsUpdate( buffer, offset ) { + + const dest = this.resolvedProperty; + + for ( let i = 0, n = dest.length; i !== n; ++ i ) { + + dest[ i ] = buffer[ offset ++ ]; + + } + + this.targetObject.needsUpdate = true; + + } + + _setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { + + const dest = this.resolvedProperty; + + for ( let i = 0, n = dest.length; i !== n; ++ i ) { + + dest[ i ] = buffer[ offset ++ ]; + + } + + this.targetObject.matrixWorldNeedsUpdate = true; + + } + + // ArrayElement + + _setValue_arrayElement( buffer, offset ) { + + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + + } + + _setValue_arrayElement_setNeedsUpdate( buffer, offset ) { + + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + this.targetObject.needsUpdate = true; + + } + + _setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { + + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + this.targetObject.matrixWorldNeedsUpdate = true; + + } + + // HasToFromArray + + _setValue_fromArray( buffer, offset ) { + + this.resolvedProperty.fromArray( buffer, offset ); + + } + + _setValue_fromArray_setNeedsUpdate( buffer, offset ) { + + this.resolvedProperty.fromArray( buffer, offset ); + this.targetObject.needsUpdate = true; + + } + + _setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { + + this.resolvedProperty.fromArray( buffer, offset ); + this.targetObject.matrixWorldNeedsUpdate = true; + + } + + _getValue_unbound( targetArray, offset ) { + + this.bind(); + this.getValue( targetArray, offset ); + + } + + _setValue_unbound( sourceArray, offset ) { + + this.bind(); + this.setValue( sourceArray, offset ); + + } + + // create getter / setter pair for a property in the scene graph + bind() { + + let targetObject = this.node; + const parsedPath = this.parsedPath; + + const objectName = parsedPath.objectName; + const propertyName = parsedPath.propertyName; + let propertyIndex = parsedPath.propertyIndex; + + if ( ! targetObject ) { + + targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ); + + this.node = targetObject; + + } + + // set fail state so we can just 'return' on error + this.getValue = this._getValue_unavailable; + this.setValue = this._setValue_unavailable; + + // ensure there is a value node + if ( ! targetObject ) { + + console.warn( 'THREE.PropertyBinding: No target node found for track: ' + this.path + '.' ); + return; + + } + + if ( objectName ) { + + let objectIndex = parsedPath.objectIndex; + + // special cases were we need to reach deeper into the hierarchy to get the face materials.... + switch ( objectName ) { + + case 'materials': + + if ( ! targetObject.material ) { + + console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); + return; + + } + + if ( ! targetObject.material.materials ) { + + console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); + return; + + } + + targetObject = targetObject.material.materials; + + break; + + case 'bones': + + if ( ! targetObject.skeleton ) { + + console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); + return; + + } + + // potential future optimization: skip this if propertyIndex is already an integer + // and convert the integer string to a true integer. + + targetObject = targetObject.skeleton.bones; + + // support resolving morphTarget names into indices. + for ( let i = 0; i < targetObject.length; i ++ ) { + + if ( targetObject[ i ].name === objectIndex ) { + + objectIndex = i; + break; + + } + + } + + break; + + case 'map': + + if ( 'map' in targetObject ) { + + targetObject = targetObject.map; + break; + + } + + if ( ! targetObject.material ) { + + console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); + return; + + } + + if ( ! targetObject.material.map ) { + + console.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this ); + return; + + } + + targetObject = targetObject.material.map; + break; + + default: + + if ( targetObject[ objectName ] === undefined ) { + + console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); + return; + + } + + targetObject = targetObject[ objectName ]; + + } + + + if ( objectIndex !== undefined ) { + + if ( targetObject[ objectIndex ] === undefined ) { + + console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); + return; + + } + + targetObject = targetObject[ objectIndex ]; + + } + + } + + // resolve property + const nodeProperty = targetObject[ propertyName ]; + + if ( nodeProperty === undefined ) { + + const nodeName = parsedPath.nodeName; + + console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + + '.' + propertyName + ' but it wasn\'t found.', targetObject ); + return; + + } + + // determine versioning scheme + let versioning = this.Versioning.None; + + this.targetObject = targetObject; + + if ( targetObject.needsUpdate !== undefined ) { // material + + versioning = this.Versioning.NeedsUpdate; + + } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform + + versioning = this.Versioning.MatrixWorldNeedsUpdate; + + } + + // determine how the property gets bound + let bindingType = this.BindingType.Direct; + + if ( propertyIndex !== undefined ) { + + // access a sub element of the property array (only primitives are supported right now) + + if ( propertyName === 'morphTargetInfluences' ) { + + // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. + + // support resolving morphTarget names into indices. + if ( ! targetObject.geometry ) { + + console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); + return; + + } + + if ( ! targetObject.geometry.morphAttributes ) { + + console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); + return; + + } + + if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) { + + propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ]; + + } + + } + + bindingType = this.BindingType.ArrayElement; + + this.resolvedProperty = nodeProperty; + this.propertyIndex = propertyIndex; + + } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { + + // must use copy for Object3D.Euler/Quaternion + + bindingType = this.BindingType.HasFromToArray; + + this.resolvedProperty = nodeProperty; + + } else if ( Array.isArray( nodeProperty ) ) { + + bindingType = this.BindingType.EntireArray; + + this.resolvedProperty = nodeProperty; + + } else { + + this.propertyName = propertyName; + + } + + // select getter / setter + this.getValue = this.GetterByBindingType[ bindingType ]; + this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; + + } + + unbind() { + + this.node = null; + + // back to the prototype version of getValue / setValue + // note: avoiding to mutate the shape of 'this' via 'delete' + this.getValue = this._getValue_unbound; + this.setValue = this._setValue_unbound; + + } + +} + +PropertyBinding.Composite = Composite; + +PropertyBinding.prototype.BindingType = { + Direct: 0, + EntireArray: 1, + ArrayElement: 2, + HasFromToArray: 3 +}; + +PropertyBinding.prototype.Versioning = { + None: 0, + NeedsUpdate: 1, + MatrixWorldNeedsUpdate: 2 +}; + +PropertyBinding.prototype.GetterByBindingType = [ + + PropertyBinding.prototype._getValue_direct, + PropertyBinding.prototype._getValue_array, + PropertyBinding.prototype._getValue_arrayElement, + PropertyBinding.prototype._getValue_toArray, + +]; + +PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [ + + [ + // Direct + PropertyBinding.prototype._setValue_direct, + PropertyBinding.prototype._setValue_direct_setNeedsUpdate, + PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate, + + ], [ + + // EntireArray + + PropertyBinding.prototype._setValue_array, + PropertyBinding.prototype._setValue_array_setNeedsUpdate, + PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate, + + ], [ + + // ArrayElement + PropertyBinding.prototype._setValue_arrayElement, + PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate, + PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate, + + ], [ + + // HasToFromArray + PropertyBinding.prototype._setValue_fromArray, + PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate, + PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate, + + ] + +]; + +/** + * + * A group of objects that receives a shared animation state. + * + * Usage: + * + * - Add objects you would otherwise pass as 'root' to the + * constructor or the .clipAction method of AnimationMixer. + * + * - Instead pass this object as 'root'. + * + * - You can also add and remove objects later when the mixer + * is running. + * + * Note: + * + * Objects of this class appear as one object to the mixer, + * so cache control of the individual objects must be done + * on the group. + * + * Limitation: + * + * - The animated properties must be compatible among the + * all objects in the group. + * + * - A single property can either be controlled through a + * target group or directly, but not both. + */ + +class AnimationObjectGroup { + + constructor() { + + this.isAnimationObjectGroup = true; + + this.uuid = generateUUID(); + + // cached objects followed by the active ones + this._objects = Array.prototype.slice.call( arguments ); + + this.nCachedObjects_ = 0; // threshold + // note: read by PropertyBinding.Composite + + const indices = {}; + this._indicesByUUID = indices; // for bookkeeping + + for ( let i = 0, n = arguments.length; i !== n; ++ i ) { + + indices[ arguments[ i ].uuid ] = i; + + } + + this._paths = []; // inside: string + this._parsedPaths = []; // inside: { we don't care, here } + this._bindings = []; // inside: Array< PropertyBinding > + this._bindingsIndicesByPath = {}; // inside: indices in these arrays + + const scope = this; + + this.stats = { + + objects: { + get total() { + + return scope._objects.length; + + }, + get inUse() { + + return this.total - scope.nCachedObjects_; + + } + }, + get bindingsPerObject() { + + return scope._bindings.length; + + } + + }; + + } + + add() { + + const objects = this._objects, + indicesByUUID = this._indicesByUUID, + paths = this._paths, + parsedPaths = this._parsedPaths, + bindings = this._bindings, + nBindings = bindings.length; + + let knownObject = undefined, + nObjects = objects.length, + nCachedObjects = this.nCachedObjects_; + + for ( let i = 0, n = arguments.length; i !== n; ++ i ) { + + const object = arguments[ i ], + uuid = object.uuid; + let index = indicesByUUID[ uuid ]; + + if ( index === undefined ) { + + // unknown object -> add it to the ACTIVE region + + index = nObjects ++; + indicesByUUID[ uuid ] = index; + objects.push( object ); + + // accounting is done, now do the same for all bindings + + for ( let j = 0, m = nBindings; j !== m; ++ j ) { + + bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); + + } + + } else if ( index < nCachedObjects ) { + + knownObject = objects[ index ]; + + // move existing object to the ACTIVE region + + const firstActiveIndex = -- nCachedObjects, + lastCachedObject = objects[ firstActiveIndex ]; + + indicesByUUID[ lastCachedObject.uuid ] = index; + objects[ index ] = lastCachedObject; + + indicesByUUID[ uuid ] = firstActiveIndex; + objects[ firstActiveIndex ] = object; + + // accounting is done, now do the same for all bindings + + for ( let j = 0, m = nBindings; j !== m; ++ j ) { + + const bindingsForPath = bindings[ j ], + lastCached = bindingsForPath[ firstActiveIndex ]; + + let binding = bindingsForPath[ index ]; + + bindingsForPath[ index ] = lastCached; + + if ( binding === undefined ) { + + // since we do not bother to create new bindings + // for objects that are cached, the binding may + // or may not exist + + binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ); + + } + + bindingsForPath[ firstActiveIndex ] = binding; + + } + + } else if ( objects[ index ] !== knownObject ) { + + console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' + + 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); + + } // else the object is already where we want it to be + + } // for arguments + + this.nCachedObjects_ = nCachedObjects; + + } + + remove() { + + const objects = this._objects, + indicesByUUID = this._indicesByUUID, + bindings = this._bindings, + nBindings = bindings.length; + + let nCachedObjects = this.nCachedObjects_; + + for ( let i = 0, n = arguments.length; i !== n; ++ i ) { + + const object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ]; + + if ( index !== undefined && index >= nCachedObjects ) { + + // move existing object into the CACHED region + + const lastCachedIndex = nCachedObjects ++, + firstActiveObject = objects[ lastCachedIndex ]; + + indicesByUUID[ firstActiveObject.uuid ] = index; + objects[ index ] = firstActiveObject; + + indicesByUUID[ uuid ] = lastCachedIndex; + objects[ lastCachedIndex ] = object; + + // accounting is done, now do the same for all bindings + + for ( let j = 0, m = nBindings; j !== m; ++ j ) { + + const bindingsForPath = bindings[ j ], + firstActive = bindingsForPath[ lastCachedIndex ], + binding = bindingsForPath[ index ]; + + bindingsForPath[ index ] = firstActive; + bindingsForPath[ lastCachedIndex ] = binding; + + } + + } + + } // for arguments + + this.nCachedObjects_ = nCachedObjects; + + } + + // remove & forget + uncache() { + + const objects = this._objects, + indicesByUUID = this._indicesByUUID, + bindings = this._bindings, + nBindings = bindings.length; + + let nCachedObjects = this.nCachedObjects_, + nObjects = objects.length; + + for ( let i = 0, n = arguments.length; i !== n; ++ i ) { + + const object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ]; + + if ( index !== undefined ) { + + delete indicesByUUID[ uuid ]; + + if ( index < nCachedObjects ) { + + // object is cached, shrink the CACHED region + + const firstActiveIndex = -- nCachedObjects, + lastCachedObject = objects[ firstActiveIndex ], + lastIndex = -- nObjects, + lastObject = objects[ lastIndex ]; + + // last cached object takes this object's place + indicesByUUID[ lastCachedObject.uuid ] = index; + objects[ index ] = lastCachedObject; + + // last object goes to the activated slot and pop + indicesByUUID[ lastObject.uuid ] = firstActiveIndex; + objects[ firstActiveIndex ] = lastObject; + objects.pop(); + + // accounting is done, now do the same for all bindings + + for ( let j = 0, m = nBindings; j !== m; ++ j ) { + + const bindingsForPath = bindings[ j ], + lastCached = bindingsForPath[ firstActiveIndex ], + last = bindingsForPath[ lastIndex ]; + + bindingsForPath[ index ] = lastCached; + bindingsForPath[ firstActiveIndex ] = last; + bindingsForPath.pop(); + + } + + } else { + + // object is active, just swap with the last and pop + + const lastIndex = -- nObjects, + lastObject = objects[ lastIndex ]; + + if ( lastIndex > 0 ) { + + indicesByUUID[ lastObject.uuid ] = index; + + } + + objects[ index ] = lastObject; + objects.pop(); + + // accounting is done, now do the same for all bindings + + for ( let j = 0, m = nBindings; j !== m; ++ j ) { + + const bindingsForPath = bindings[ j ]; + + bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; + bindingsForPath.pop(); + + } + + } // cached or active + + } // if object is known + + } // for arguments + + this.nCachedObjects_ = nCachedObjects; + + } + + // Internal interface used by befriended PropertyBinding.Composite: + + subscribe_( path, parsedPath ) { + + // returns an array of bindings for the given path that is changed + // according to the contained objects in the group + + const indicesByPath = this._bindingsIndicesByPath; + let index = indicesByPath[ path ]; + const bindings = this._bindings; + + if ( index !== undefined ) return bindings[ index ]; + + const paths = this._paths, + parsedPaths = this._parsedPaths, + objects = this._objects, + nObjects = objects.length, + nCachedObjects = this.nCachedObjects_, + bindingsForPath = new Array( nObjects ); + + index = bindings.length; + + indicesByPath[ path ] = index; + + paths.push( path ); + parsedPaths.push( parsedPath ); + bindings.push( bindingsForPath ); + + for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) { + + const object = objects[ i ]; + bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); + + } + + return bindingsForPath; + + } + + unsubscribe_( path ) { + + // tells the group to forget about a property path and no longer + // update the array previously obtained with 'subscribe_' + + const indicesByPath = this._bindingsIndicesByPath, + index = indicesByPath[ path ]; + + if ( index !== undefined ) { + + const paths = this._paths, + parsedPaths = this._parsedPaths, + bindings = this._bindings, + lastBindingsIndex = bindings.length - 1, + lastBindings = bindings[ lastBindingsIndex ], + lastBindingsPath = path[ lastBindingsIndex ]; + + indicesByPath[ lastBindingsPath ] = index; + + bindings[ index ] = lastBindings; + bindings.pop(); + + parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; + parsedPaths.pop(); + + paths[ index ] = paths[ lastBindingsIndex ]; + paths.pop(); + + } + + } + +} + +class AnimationAction { + + constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) { + + this._mixer = mixer; + this._clip = clip; + this._localRoot = localRoot; + this.blendMode = blendMode; + + const tracks = clip.tracks, + nTracks = tracks.length, + interpolants = new Array( nTracks ); + + const interpolantSettings = { + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding + }; + + for ( let i = 0; i !== nTracks; ++ i ) { + + const interpolant = tracks[ i ].createInterpolant( null ); + interpolants[ i ] = interpolant; + interpolant.settings = interpolantSettings; + + } + + this._interpolantSettings = interpolantSettings; + + this._interpolants = interpolants; // bound by the mixer + + // inside: PropertyMixer (managed by the mixer) + this._propertyBindings = new Array( nTracks ); + + this._cacheIndex = null; // for the memory manager + this._byClipCacheIndex = null; // for the memory manager + + this._timeScaleInterpolant = null; + this._weightInterpolant = null; + + this.loop = LoopRepeat; + this._loopCount = - 1; + + // global mixer time when the action is to be started + // it's set back to 'null' upon start of the action + this._startTime = null; + + // scaled local time of the action + // gets clamped or wrapped to 0..clip.duration according to loop + this.time = 0; + + this.timeScale = 1; + this._effectiveTimeScale = 1; + + this.weight = 1; + this._effectiveWeight = 1; + + this.repetitions = Infinity; // no. of repetitions when looping + + this.paused = false; // true -> zero effective time scale + this.enabled = true; // false -> zero effective weight + + this.clampWhenFinished = false;// keep feeding the last frame? + + this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate + this.zeroSlopeAtEnd = true;// clips for start, loop and end + + } + + // State & Scheduling + + play() { + + this._mixer._activateAction( this ); + + return this; + + } + + stop() { + + this._mixer._deactivateAction( this ); + + return this.reset(); + + } + + reset() { + + this.paused = false; + this.enabled = true; + + this.time = 0; // restart clip + this._loopCount = - 1;// forget previous loops + this._startTime = null;// forget scheduling + + return this.stopFading().stopWarping(); + + } + + isRunning() { + + return this.enabled && ! this.paused && this.timeScale !== 0 && + this._startTime === null && this._mixer._isActiveAction( this ); + + } + + // return true when play has been called + isScheduled() { + + return this._mixer._isActiveAction( this ); + + } + + startAt( time ) { + + this._startTime = time; + + return this; + + } + + setLoop( mode, repetitions ) { + + this.loop = mode; + this.repetitions = repetitions; + + return this; + + } + + // Weight + + // set the weight stopping any scheduled fading + // although .enabled = false yields an effective weight of zero, this + // method does *not* change .enabled, because it would be confusing + setEffectiveWeight( weight ) { + + this.weight = weight; + + // note: same logic as when updated at runtime + this._effectiveWeight = this.enabled ? weight : 0; + + return this.stopFading(); + + } + + // return the weight considering fading and .enabled + getEffectiveWeight() { + + return this._effectiveWeight; + + } + + fadeIn( duration ) { + + return this._scheduleFading( duration, 0, 1 ); + + } + + fadeOut( duration ) { + + return this._scheduleFading( duration, 1, 0 ); + + } + + crossFadeFrom( fadeOutAction, duration, warp ) { + + fadeOutAction.fadeOut( duration ); + this.fadeIn( duration ); + + if ( warp ) { + + const fadeInDuration = this._clip.duration, + fadeOutDuration = fadeOutAction._clip.duration, + + startEndRatio = fadeOutDuration / fadeInDuration, + endStartRatio = fadeInDuration / fadeOutDuration; + + fadeOutAction.warp( 1.0, startEndRatio, duration ); + this.warp( endStartRatio, 1.0, duration ); + + } + + return this; + + } + + crossFadeTo( fadeInAction, duration, warp ) { + + return fadeInAction.crossFadeFrom( this, duration, warp ); + + } + + stopFading() { + + const weightInterpolant = this._weightInterpolant; + + if ( weightInterpolant !== null ) { + + this._weightInterpolant = null; + this._mixer._takeBackControlInterpolant( weightInterpolant ); + + } + + return this; + + } + + // Time Scale Control + + // set the time scale stopping any scheduled warping + // although .paused = true yields an effective time scale of zero, this + // method does *not* change .paused, because it would be confusing + setEffectiveTimeScale( timeScale ) { + + this.timeScale = timeScale; + this._effectiveTimeScale = this.paused ? 0 : timeScale; + + return this.stopWarping(); + + } + + // return the time scale considering warping and .paused + getEffectiveTimeScale() { + + return this._effectiveTimeScale; + + } + + setDuration( duration ) { + + this.timeScale = this._clip.duration / duration; + + return this.stopWarping(); + + } + + syncWith( action ) { + + this.time = action.time; + this.timeScale = action.timeScale; + + return this.stopWarping(); + + } + + halt( duration ) { + + return this.warp( this._effectiveTimeScale, 0, duration ); + + } + + warp( startTimeScale, endTimeScale, duration ) { + + const mixer = this._mixer, + now = mixer.time, + timeScale = this.timeScale; + + let interpolant = this._timeScaleInterpolant; + + if ( interpolant === null ) { + + interpolant = mixer._lendControlInterpolant(); + this._timeScaleInterpolant = interpolant; + + } + + const times = interpolant.parameterPositions, + values = interpolant.sampleValues; + + times[ 0 ] = now; + times[ 1 ] = now + duration; + + values[ 0 ] = startTimeScale / timeScale; + values[ 1 ] = endTimeScale / timeScale; + + return this; + + } + + stopWarping() { + + const timeScaleInterpolant = this._timeScaleInterpolant; + + if ( timeScaleInterpolant !== null ) { + + this._timeScaleInterpolant = null; + this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); + + } + + return this; + + } + + // Object Accessors + + getMixer() { + + return this._mixer; + + } + + getClip() { + + return this._clip; + + } + + getRoot() { + + return this._localRoot || this._mixer._root; + + } + + // Interna + + _update( time, deltaTime, timeDirection, accuIndex ) { + + // called by the mixer + + if ( ! this.enabled ) { + + // call ._updateWeight() to update ._effectiveWeight + + this._updateWeight( time ); + return; + + } + + const startTime = this._startTime; + + if ( startTime !== null ) { + + // check for scheduled start of action + + const timeRunning = ( time - startTime ) * timeDirection; + if ( timeRunning < 0 || timeDirection === 0 ) { + + deltaTime = 0; + + } else { + + + this._startTime = null; // unschedule + deltaTime = timeDirection * timeRunning; + + } + + } + + // apply time scale and advance time + + deltaTime *= this._updateTimeScale( time ); + const clipTime = this._updateTime( deltaTime ); + + // note: _updateTime may disable the action resulting in + // an effective weight of 0 + + const weight = this._updateWeight( time ); + + if ( weight > 0 ) { + + const interpolants = this._interpolants; + const propertyMixers = this._propertyBindings; + + switch ( this.blendMode ) { + + case AdditiveAnimationBlendMode: + + for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { + + interpolants[ j ].evaluate( clipTime ); + propertyMixers[ j ].accumulateAdditive( weight ); + + } + + break; + + case NormalAnimationBlendMode: + default: + + for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { + + interpolants[ j ].evaluate( clipTime ); + propertyMixers[ j ].accumulate( accuIndex, weight ); + + } + + } + + } + + } + + _updateWeight( time ) { + + let weight = 0; + + if ( this.enabled ) { + + weight = this.weight; + const interpolant = this._weightInterpolant; + + if ( interpolant !== null ) { + + const interpolantValue = interpolant.evaluate( time )[ 0 ]; + + weight *= interpolantValue; + + if ( time > interpolant.parameterPositions[ 1 ] ) { + + this.stopFading(); + + if ( interpolantValue === 0 ) { + + // faded out, disable + this.enabled = false; + + } + + } + + } + + } + + this._effectiveWeight = weight; + return weight; + + } + + _updateTimeScale( time ) { + + let timeScale = 0; + + if ( ! this.paused ) { + + timeScale = this.timeScale; + + const interpolant = this._timeScaleInterpolant; + + if ( interpolant !== null ) { + + const interpolantValue = interpolant.evaluate( time )[ 0 ]; + + timeScale *= interpolantValue; + + if ( time > interpolant.parameterPositions[ 1 ] ) { + + this.stopWarping(); + + if ( timeScale === 0 ) { + + // motion has halted, pause + this.paused = true; + + } else { + + // warp done - apply final time scale + this.timeScale = timeScale; + + } + + } + + } + + } + + this._effectiveTimeScale = timeScale; + return timeScale; + + } + + _updateTime( deltaTime ) { + + const duration = this._clip.duration; + const loop = this.loop; + + let time = this.time + deltaTime; + let loopCount = this._loopCount; + + const pingPong = ( loop === LoopPingPong ); + + if ( deltaTime === 0 ) { + + if ( loopCount === - 1 ) return time; + + return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time; + + } + + if ( loop === LoopOnce ) { + + if ( loopCount === - 1 ) { + + // just started + + this._loopCount = 0; + this._setEndings( true, true, false ); + + } + + handle_stop: { + + if ( time >= duration ) { + + time = duration; + + } else if ( time < 0 ) { + + time = 0; + + } else { + + this.time = time; + + break handle_stop; + + } + + if ( this.clampWhenFinished ) this.paused = true; + else this.enabled = false; + + this.time = time; + + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime < 0 ? - 1 : 1 + } ); + + } + + } else { // repetitive Repeat or PingPong + + if ( loopCount === - 1 ) { + + // just started + + if ( deltaTime >= 0 ) { + + loopCount = 0; + + this._setEndings( true, this.repetitions === 0, pingPong ); + + } else { + + // when looping in reverse direction, the initial + // transition through zero counts as a repetition, + // so leave loopCount at -1 + + this._setEndings( this.repetitions === 0, true, pingPong ); + + } + + } + + if ( time >= duration || time < 0 ) { + + // wrap around + + const loopDelta = Math.floor( time / duration ); // signed + time -= duration * loopDelta; + + loopCount += Math.abs( loopDelta ); + + const pending = this.repetitions - loopCount; + + if ( pending <= 0 ) { + + // have to stop (switch state, clamp time, fire event) + + if ( this.clampWhenFinished ) this.paused = true; + else this.enabled = false; + + time = deltaTime > 0 ? duration : 0; + + this.time = time; + + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime > 0 ? 1 : - 1 + } ); + + } else { + + // keep running + + if ( pending === 1 ) { + + // entering the last round + + const atStart = deltaTime < 0; + this._setEndings( atStart, ! atStart, pingPong ); + + } else { + + this._setEndings( false, false, pingPong ); + + } + + this._loopCount = loopCount; + + this.time = time; + + this._mixer.dispatchEvent( { + type: 'loop', action: this, loopDelta: loopDelta + } ); + + } + + } else { + + this.time = time; + + } + + if ( pingPong && ( loopCount & 1 ) === 1 ) { + + // invert time for the "pong round" + + return duration - time; + + } + + } + + return time; + + } + + _setEndings( atStart, atEnd, pingPong ) { + + const settings = this._interpolantSettings; + + if ( pingPong ) { + + settings.endingStart = ZeroSlopeEnding; + settings.endingEnd = ZeroSlopeEnding; + + } else { + + // assuming for LoopOnce atStart == atEnd == true + + if ( atStart ) { + + settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; + + } else { + + settings.endingStart = WrapAroundEnding; + + } + + if ( atEnd ) { + + settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; + + } else { + + settings.endingEnd = WrapAroundEnding; + + } + + } + + } + + _scheduleFading( duration, weightNow, weightThen ) { + + const mixer = this._mixer, now = mixer.time; + let interpolant = this._weightInterpolant; + + if ( interpolant === null ) { + + interpolant = mixer._lendControlInterpolant(); + this._weightInterpolant = interpolant; + + } + + const times = interpolant.parameterPositions, + values = interpolant.sampleValues; + + times[ 0 ] = now; + values[ 0 ] = weightNow; + times[ 1 ] = now + duration; + values[ 1 ] = weightThen; + + return this; + + } + +} + +const _controlInterpolantsResultBuffer = new Float32Array( 1 ); + + +class AnimationMixer extends EventDispatcher { + + constructor( root ) { + + super(); + + this._root = root; + this._initMemoryManager(); + this._accuIndex = 0; + this.time = 0; + this.timeScale = 1.0; + + } + + _bindAction( action, prototypeAction ) { + + const root = action._localRoot || this._root, + tracks = action._clip.tracks, + nTracks = tracks.length, + bindings = action._propertyBindings, + interpolants = action._interpolants, + rootUuid = root.uuid, + bindingsByRoot = this._bindingsByRootAndName; + + let bindingsByName = bindingsByRoot[ rootUuid ]; + + if ( bindingsByName === undefined ) { + + bindingsByName = {}; + bindingsByRoot[ rootUuid ] = bindingsByName; + + } + + for ( let i = 0; i !== nTracks; ++ i ) { + + const track = tracks[ i ], + trackName = track.name; + + let binding = bindingsByName[ trackName ]; + + if ( binding !== undefined ) { + + ++ binding.referenceCount; + bindings[ i ] = binding; + + } else { + + binding = bindings[ i ]; + + if ( binding !== undefined ) { + + // existing binding, make sure the cache knows + + if ( binding._cacheIndex === null ) { + + ++ binding.referenceCount; + this._addInactiveBinding( binding, rootUuid, trackName ); + + } + + continue; + + } + + const path = prototypeAction && prototypeAction. + _propertyBindings[ i ].binding.parsedPath; + + binding = new PropertyMixer( + PropertyBinding.create( root, trackName, path ), + track.ValueTypeName, track.getValueSize() ); + + ++ binding.referenceCount; + this._addInactiveBinding( binding, rootUuid, trackName ); + + bindings[ i ] = binding; + + } + + interpolants[ i ].resultBuffer = binding.buffer; + + } + + } + + _activateAction( action ) { + + if ( ! this._isActiveAction( action ) ) { + + if ( action._cacheIndex === null ) { + + // this action has been forgotten by the cache, but the user + // appears to be still using it -> rebind + + const rootUuid = ( action._localRoot || this._root ).uuid, + clipUuid = action._clip.uuid, + actionsForClip = this._actionsByClip[ clipUuid ]; + + this._bindAction( action, + actionsForClip && actionsForClip.knownActions[ 0 ] ); + + this._addInactiveAction( action, clipUuid, rootUuid ); + + } + + const bindings = action._propertyBindings; + + // increment reference counts / sort out state + for ( let i = 0, n = bindings.length; i !== n; ++ i ) { + + const binding = bindings[ i ]; + + if ( binding.useCount ++ === 0 ) { + + this._lendBinding( binding ); + binding.saveOriginalState(); + + } + + } + + this._lendAction( action ); + + } + + } + + _deactivateAction( action ) { + + if ( this._isActiveAction( action ) ) { + + const bindings = action._propertyBindings; + + // decrement reference counts / sort out state + for ( let i = 0, n = bindings.length; i !== n; ++ i ) { + + const binding = bindings[ i ]; + + if ( -- binding.useCount === 0 ) { + + binding.restoreOriginalState(); + this._takeBackBinding( binding ); + + } + + } + + this._takeBackAction( action ); + + } + + } + + // Memory manager + + _initMemoryManager() { + + this._actions = []; // 'nActiveActions' followed by inactive ones + this._nActiveActions = 0; + + this._actionsByClip = {}; + // inside: + // { + // knownActions: Array< AnimationAction > - used as prototypes + // actionByRoot: AnimationAction - lookup + // } + + + this._bindings = []; // 'nActiveBindings' followed by inactive ones + this._nActiveBindings = 0; + + this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > + + + this._controlInterpolants = []; // same game as above + this._nActiveControlInterpolants = 0; + + const scope = this; + + this.stats = { + + actions: { + get total() { + + return scope._actions.length; + + }, + get inUse() { + + return scope._nActiveActions; + + } + }, + bindings: { + get total() { + + return scope._bindings.length; + + }, + get inUse() { + + return scope._nActiveBindings; + + } + }, + controlInterpolants: { + get total() { + + return scope._controlInterpolants.length; + + }, + get inUse() { + + return scope._nActiveControlInterpolants; + + } + } + + }; + + } + + // Memory management for AnimationAction objects + + _isActiveAction( action ) { + + const index = action._cacheIndex; + return index !== null && index < this._nActiveActions; + + } + + _addInactiveAction( action, clipUuid, rootUuid ) { + + const actions = this._actions, + actionsByClip = this._actionsByClip; + + let actionsForClip = actionsByClip[ clipUuid ]; + + if ( actionsForClip === undefined ) { + + actionsForClip = { + + knownActions: [ action ], + actionByRoot: {} + + }; + + action._byClipCacheIndex = 0; + + actionsByClip[ clipUuid ] = actionsForClip; + + } else { + + const knownActions = actionsForClip.knownActions; + + action._byClipCacheIndex = knownActions.length; + knownActions.push( action ); + + } + + action._cacheIndex = actions.length; + actions.push( action ); + + actionsForClip.actionByRoot[ rootUuid ] = action; + + } + + _removeInactiveAction( action ) { + + const actions = this._actions, + lastInactiveAction = actions[ actions.length - 1 ], + cacheIndex = action._cacheIndex; + + lastInactiveAction._cacheIndex = cacheIndex; + actions[ cacheIndex ] = lastInactiveAction; + actions.pop(); + + action._cacheIndex = null; + + + const clipUuid = action._clip.uuid, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ], + knownActionsForClip = actionsForClip.knownActions, + + lastKnownAction = + knownActionsForClip[ knownActionsForClip.length - 1 ], + + byClipCacheIndex = action._byClipCacheIndex; + + lastKnownAction._byClipCacheIndex = byClipCacheIndex; + knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; + knownActionsForClip.pop(); + + action._byClipCacheIndex = null; + + + const actionByRoot = actionsForClip.actionByRoot, + rootUuid = ( action._localRoot || this._root ).uuid; + + delete actionByRoot[ rootUuid ]; + + if ( knownActionsForClip.length === 0 ) { + + delete actionsByClip[ clipUuid ]; + + } + + this._removeInactiveBindingsForAction( action ); + + } + + _removeInactiveBindingsForAction( action ) { + + const bindings = action._propertyBindings; + + for ( let i = 0, n = bindings.length; i !== n; ++ i ) { + + const binding = bindings[ i ]; + + if ( -- binding.referenceCount === 0 ) { + + this._removeInactiveBinding( binding ); + + } + + } + + } + + _lendAction( action ) { + + // [ active actions | inactive actions ] + // [ active actions >| inactive actions ] + // s a + // <-swap-> + // a s + + const actions = this._actions, + prevIndex = action._cacheIndex, + + lastActiveIndex = this._nActiveActions ++, + + firstInactiveAction = actions[ lastActiveIndex ]; + + action._cacheIndex = lastActiveIndex; + actions[ lastActiveIndex ] = action; + + firstInactiveAction._cacheIndex = prevIndex; + actions[ prevIndex ] = firstInactiveAction; + + } + + _takeBackAction( action ) { + + // [ active actions | inactive actions ] + // [ active actions |< inactive actions ] + // a s + // <-swap-> + // s a + + const actions = this._actions, + prevIndex = action._cacheIndex, + + firstInactiveIndex = -- this._nActiveActions, + + lastActiveAction = actions[ firstInactiveIndex ]; + + action._cacheIndex = firstInactiveIndex; + actions[ firstInactiveIndex ] = action; + + lastActiveAction._cacheIndex = prevIndex; + actions[ prevIndex ] = lastActiveAction; + + } + + // Memory management for PropertyMixer objects + + _addInactiveBinding( binding, rootUuid, trackName ) { + + const bindingsByRoot = this._bindingsByRootAndName, + bindings = this._bindings; + + let bindingByName = bindingsByRoot[ rootUuid ]; + + if ( bindingByName === undefined ) { + + bindingByName = {}; + bindingsByRoot[ rootUuid ] = bindingByName; + + } + + bindingByName[ trackName ] = binding; + + binding._cacheIndex = bindings.length; + bindings.push( binding ); + + } + + _removeInactiveBinding( binding ) { + + const bindings = this._bindings, + propBinding = binding.binding, + rootUuid = propBinding.rootNode.uuid, + trackName = propBinding.path, + bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ], + + lastInactiveBinding = bindings[ bindings.length - 1 ], + cacheIndex = binding._cacheIndex; + + lastInactiveBinding._cacheIndex = cacheIndex; + bindings[ cacheIndex ] = lastInactiveBinding; + bindings.pop(); + + delete bindingByName[ trackName ]; + + if ( Object.keys( bindingByName ).length === 0 ) { + + delete bindingsByRoot[ rootUuid ]; + + } + + } + + _lendBinding( binding ) { + + const bindings = this._bindings, + prevIndex = binding._cacheIndex, + + lastActiveIndex = this._nActiveBindings ++, + + firstInactiveBinding = bindings[ lastActiveIndex ]; + + binding._cacheIndex = lastActiveIndex; + bindings[ lastActiveIndex ] = binding; + + firstInactiveBinding._cacheIndex = prevIndex; + bindings[ prevIndex ] = firstInactiveBinding; + + } + + _takeBackBinding( binding ) { + + const bindings = this._bindings, + prevIndex = binding._cacheIndex, + + firstInactiveIndex = -- this._nActiveBindings, + + lastActiveBinding = bindings[ firstInactiveIndex ]; + + binding._cacheIndex = firstInactiveIndex; + bindings[ firstInactiveIndex ] = binding; + + lastActiveBinding._cacheIndex = prevIndex; + bindings[ prevIndex ] = lastActiveBinding; + + } + + + // Memory management of Interpolants for weight and time scale + + _lendControlInterpolant() { + + const interpolants = this._controlInterpolants, + lastActiveIndex = this._nActiveControlInterpolants ++; + + let interpolant = interpolants[ lastActiveIndex ]; + + if ( interpolant === undefined ) { + + interpolant = new LinearInterpolant( + new Float32Array( 2 ), new Float32Array( 2 ), + 1, _controlInterpolantsResultBuffer ); + + interpolant.__cacheIndex = lastActiveIndex; + interpolants[ lastActiveIndex ] = interpolant; + + } + + return interpolant; + + } + + _takeBackControlInterpolant( interpolant ) { + + const interpolants = this._controlInterpolants, + prevIndex = interpolant.__cacheIndex, + + firstInactiveIndex = -- this._nActiveControlInterpolants, + + lastActiveInterpolant = interpolants[ firstInactiveIndex ]; + + interpolant.__cacheIndex = firstInactiveIndex; + interpolants[ firstInactiveIndex ] = interpolant; + + lastActiveInterpolant.__cacheIndex = prevIndex; + interpolants[ prevIndex ] = lastActiveInterpolant; + + } + + // return an action for a clip optionally using a custom root target + // object (this method allocates a lot of dynamic memory in case a + // previously unknown clip/root combination is specified) + clipAction( clip, optionalRoot, blendMode ) { + + const root = optionalRoot || this._root, + rootUuid = root.uuid; + + let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip; + + const clipUuid = clipObject !== null ? clipObject.uuid : clip; + + const actionsForClip = this._actionsByClip[ clipUuid ]; + let prototypeAction = null; + + if ( blendMode === undefined ) { + + if ( clipObject !== null ) { + + blendMode = clipObject.blendMode; + + } else { + + blendMode = NormalAnimationBlendMode; + + } + + } + + if ( actionsForClip !== undefined ) { + + const existingAction = actionsForClip.actionByRoot[ rootUuid ]; + + if ( existingAction !== undefined && existingAction.blendMode === blendMode ) { + + return existingAction; + + } + + // we know the clip, so we don't have to parse all + // the bindings again but can just copy + prototypeAction = actionsForClip.knownActions[ 0 ]; + + // also, take the clip from the prototype action + if ( clipObject === null ) + clipObject = prototypeAction._clip; + + } + + // clip must be known when specified via string + if ( clipObject === null ) return null; + + // allocate all resources required to run it + const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode ); + + this._bindAction( newAction, prototypeAction ); + + // and make the action known to the memory manager + this._addInactiveAction( newAction, clipUuid, rootUuid ); + + return newAction; + + } + + // get an existing action + existingAction( clip, optionalRoot ) { + + const root = optionalRoot || this._root, + rootUuid = root.uuid, + + clipObject = typeof clip === 'string' ? + AnimationClip.findByName( root, clip ) : clip, + + clipUuid = clipObject ? clipObject.uuid : clip, + + actionsForClip = this._actionsByClip[ clipUuid ]; + + if ( actionsForClip !== undefined ) { + + return actionsForClip.actionByRoot[ rootUuid ] || null; + + } + + return null; + + } + + // deactivates all previously scheduled actions + stopAllAction() { + + const actions = this._actions, + nActions = this._nActiveActions; + + for ( let i = nActions - 1; i >= 0; -- i ) { + + actions[ i ].stop(); + + } + + return this; + + } + + // advance the time and update apply the animation + update( deltaTime ) { + + deltaTime *= this.timeScale; + + const actions = this._actions, + nActions = this._nActiveActions, + + time = this.time += deltaTime, + timeDirection = Math.sign( deltaTime ), + + accuIndex = this._accuIndex ^= 1; + + // run active actions + + for ( let i = 0; i !== nActions; ++ i ) { + + const action = actions[ i ]; + + action._update( time, deltaTime, timeDirection, accuIndex ); + + } + + // update scene graph + + const bindings = this._bindings, + nBindings = this._nActiveBindings; + + for ( let i = 0; i !== nBindings; ++ i ) { + + bindings[ i ].apply( accuIndex ); + + } + + return this; + + } + + // Allows you to seek to a specific time in an animation. + setTime( timeInSeconds ) { + + this.time = 0; // Zero out time attribute for AnimationMixer object; + for ( let i = 0; i < this._actions.length; i ++ ) { + + this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects. + + } + + return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object. + + } + + // return this mixer's root target object + getRoot() { + + return this._root; + + } + + // free all resources specific to a particular clip + uncacheClip( clip ) { + + const actions = this._actions, + clipUuid = clip.uuid, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ]; + + if ( actionsForClip !== undefined ) { + + // note: just calling _removeInactiveAction would mess up the + // iteration state and also require updating the state we can + // just throw away + + const actionsToRemove = actionsForClip.knownActions; + + for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) { + + const action = actionsToRemove[ i ]; + + this._deactivateAction( action ); + + const cacheIndex = action._cacheIndex, + lastInactiveAction = actions[ actions.length - 1 ]; + + action._cacheIndex = null; + action._byClipCacheIndex = null; + + lastInactiveAction._cacheIndex = cacheIndex; + actions[ cacheIndex ] = lastInactiveAction; + actions.pop(); + + this._removeInactiveBindingsForAction( action ); + + } + + delete actionsByClip[ clipUuid ]; + + } + + } + + // free all resources specific to a particular root target object + uncacheRoot( root ) { + + const rootUuid = root.uuid, + actionsByClip = this._actionsByClip; + + for ( const clipUuid in actionsByClip ) { + + const actionByRoot = actionsByClip[ clipUuid ].actionByRoot, + action = actionByRoot[ rootUuid ]; + + if ( action !== undefined ) { + + this._deactivateAction( action ); + this._removeInactiveAction( action ); + + } + + } + + const bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ]; + + if ( bindingByName !== undefined ) { + + for ( const trackName in bindingByName ) { + + const binding = bindingByName[ trackName ]; + binding.restoreOriginalState(); + this._removeInactiveBinding( binding ); + + } + + } + + } + + // remove a targeted clip from the cache + uncacheAction( clip, optionalRoot ) { + + const action = this.existingAction( clip, optionalRoot ); + + if ( action !== null ) { + + this._deactivateAction( action ); + this._removeInactiveAction( action ); + + } + + } + +} + +let Uniform$1 = class Uniform { + + constructor( value ) { + + this.value = value; + + } + + clone() { + + return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); + + } + +}; + +let _id$8 = 0; + +let UniformsGroup$1 = class UniformsGroup extends EventDispatcher { + + constructor() { + + super(); + + this.isUniformsGroup = true; + + Object.defineProperty( this, 'id', { value: _id$8 ++ } ); + + this.name = ''; + + this.usage = StaticDrawUsage; + this.uniforms = []; + + } + + add( uniform ) { + + this.uniforms.push( uniform ); + + return this; + + } + + remove( uniform ) { + + const index = this.uniforms.indexOf( uniform ); + + if ( index !== - 1 ) this.uniforms.splice( index, 1 ); + + return this; + + } + + setName( name ) { + + this.name = name; + + return this; + + } + + setUsage( value ) { + + this.usage = value; + + return this; + + } + + dispose() { + + this.dispatchEvent( { type: 'dispose' } ); + + return this; + + } + + copy( source ) { + + this.name = source.name; + this.usage = source.usage; + + const uniformsSource = source.uniforms; + + this.uniforms.length = 0; + + for ( let i = 0, l = uniformsSource.length; i < l; i ++ ) { + + const uniforms = Array.isArray( uniformsSource[ i ] ) ? uniformsSource[ i ] : [ uniformsSource[ i ] ]; + + for ( let j = 0; j < uniforms.length; j ++ ) { + + this.uniforms.push( uniforms[ j ].clone() ); + + } + + } + + return this; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + +}; + +class InstancedInterleavedBuffer extends InterleavedBuffer { + + constructor( array, stride, meshPerAttribute = 1 ) { + + super( array, stride ); + + this.isInstancedInterleavedBuffer = true; + + this.meshPerAttribute = meshPerAttribute; + + } + + copy( source ) { + + super.copy( source ); + + this.meshPerAttribute = source.meshPerAttribute; + + return this; + + } + + clone( data ) { + + const ib = super.clone( data ); + + ib.meshPerAttribute = this.meshPerAttribute; + + return ib; + + } + + toJSON( data ) { + + const json = super.toJSON( data ); + + json.isInstancedInterleavedBuffer = true; + json.meshPerAttribute = this.meshPerAttribute; + + return json; + + } + +} + +class GLBufferAttribute { + + constructor( buffer, type, itemSize, elementSize, count ) { + + this.isGLBufferAttribute = true; + + this.name = ''; + + this.buffer = buffer; + this.type = type; + this.itemSize = itemSize; + this.elementSize = elementSize; + this.count = count; + + this.version = 0; + + } + + set needsUpdate( value ) { + + if ( value === true ) this.version ++; + + } + + setBuffer( buffer ) { + + this.buffer = buffer; + + return this; + + } + + setType( type, elementSize ) { + + this.type = type; + this.elementSize = elementSize; + + return this; + + } + + setItemSize( itemSize ) { + + this.itemSize = itemSize; + + return this; + + } + + setCount( count ) { + + this.count = count; + + return this; + + } + +} + +const _matrix = /*@__PURE__*/ new Matrix4(); + +class Raycaster { + + constructor( origin, direction, near = 0, far = Infinity ) { + + this.ray = new Ray( origin, direction ); + // direction is assumed to be normalized (for accurate distance calculations) + + this.near = near; + this.far = far; + this.camera = null; + this.layers = new Layers(); + + this.params = { + Mesh: {}, + Line: { threshold: 1 }, + LOD: {}, + Points: { threshold: 1 }, + Sprite: {} + }; + + } + + set( origin, direction ) { + + // direction is assumed to be normalized (for accurate distance calculations) + + this.ray.set( origin, direction ); + + } + + setFromCamera( coords, camera ) { + + if ( camera.isPerspectiveCamera ) { + + this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); + this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); + this.camera = camera; + + } else if ( camera.isOrthographicCamera ) { + + this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera + this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); + this.camera = camera; + + } else { + + console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type ); + + } + + } + + setFromXRController( controller ) { + + _matrix.identity().extractRotation( controller.matrixWorld ); + + this.ray.origin.setFromMatrixPosition( controller.matrixWorld ); + this.ray.direction.set( 0, 0, - 1 ).applyMatrix4( _matrix ); + + return this; + + } + + intersectObject( object, recursive = true, intersects = [] ) { + + intersect( object, this, intersects, recursive ); + + intersects.sort( ascSort ); + + return intersects; + + } + + intersectObjects( objects, recursive = true, intersects = [] ) { + + for ( let i = 0, l = objects.length; i < l; i ++ ) { + + intersect( objects[ i ], this, intersects, recursive ); + + } + + intersects.sort( ascSort ); + + return intersects; + + } + +} + +function ascSort( a, b ) { + + return a.distance - b.distance; + +} + +function intersect( object, raycaster, intersects, recursive ) { + + let propagate = true; + + if ( object.layers.test( raycaster.layers ) ) { + + const result = object.raycast( raycaster, intersects ); + + if ( result === false ) propagate = false; + + } + + if ( propagate === true && recursive === true ) { + + const children = object.children; + + for ( let i = 0, l = children.length; i < l; i ++ ) { + + intersect( children[ i ], raycaster, intersects, true ); + + } + + } + +} + +/** + * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system + * + * phi (the polar angle) is measured from the positive y-axis. The positive y-axis is up. + * theta (the azimuthal angle) is measured from the positive z-axis. + */ +class Spherical { + + constructor( radius = 1, phi = 0, theta = 0 ) { + + this.radius = radius; + this.phi = phi; // polar angle + this.theta = theta; // azimuthal angle + + return this; + + } + + set( radius, phi, theta ) { + + this.radius = radius; + this.phi = phi; + this.theta = theta; + + return this; + + } + + copy( other ) { + + this.radius = other.radius; + this.phi = other.phi; + this.theta = other.theta; + + return this; + + } + + // restrict phi to be between EPS and PI-EPS + makeSafe() { + + const EPS = 0.000001; + this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); + + return this; + + } + + setFromVector3( v ) { + + return this.setFromCartesianCoords( v.x, v.y, v.z ); + + } + + setFromCartesianCoords( x, y, z ) { + + this.radius = Math.sqrt( x * x + y * y + z * z ); + + if ( this.radius === 0 ) { + + this.theta = 0; + this.phi = 0; + + } else { + + this.theta = Math.atan2( x, z ); + this.phi = Math.acos( clamp$1( y / this.radius, - 1, 1 ) ); + + } + + return this; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + +} + +/** + * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system + */ + +class Cylindrical { + + constructor( radius = 1, theta = 0, y = 0 ) { + + this.radius = radius; // distance from the origin to a point in the x-z plane + this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis + this.y = y; // height above the x-z plane + + return this; + + } + + set( radius, theta, y ) { + + this.radius = radius; + this.theta = theta; + this.y = y; + + return this; + + } + + copy( other ) { + + this.radius = other.radius; + this.theta = other.theta; + this.y = other.y; + + return this; + + } + + setFromVector3( v ) { + + return this.setFromCartesianCoords( v.x, v.y, v.z ); + + } + + setFromCartesianCoords( x, y, z ) { + + this.radius = Math.sqrt( x * x + z * z ); + this.theta = Math.atan2( x, z ); + this.y = y; + + return this; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + +} + +class Matrix2 { + + constructor( n11, n12, n21, n22 ) { + + Matrix2.prototype.isMatrix2 = true; + + this.elements = [ + 1, 0, + 0, 1, + ]; + + if ( n11 !== undefined ) { + + this.set( n11, n12, n21, n22 ); + + } + + } + + identity() { + + this.set( + 1, 0, + 0, 1, + ); + + return this; + + } + + fromArray( array, offset = 0 ) { + + for ( let i = 0; i < 4; i ++ ) { + + this.elements[ i ] = array[ i + offset ]; + + } + + return this; + + } + + set( n11, n12, n21, n22 ) { + + const te = this.elements; + + te[ 0 ] = n11; te[ 2 ] = n12; + te[ 1 ] = n21; te[ 3 ] = n22; + + return this; + + } + +} + +const _vector$4 = /*@__PURE__*/ new Vector2(); + +class Box2 { + + constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) { + + this.isBox2 = true; + + this.min = min; + this.max = max; + + } + + set( min, max ) { + + this.min.copy( min ); + this.max.copy( max ); + + return this; + + } + + setFromPoints( points ) { + + this.makeEmpty(); + + for ( let i = 0, il = points.length; i < il; i ++ ) { + + this.expandByPoint( points[ i ] ); + + } + + return this; + + } + + setFromCenterAndSize( center, size ) { + + const halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 ); + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); + + return this; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + copy( box ) { + + this.min.copy( box.min ); + this.max.copy( box.max ); + + return this; + + } + + makeEmpty() { + + this.min.x = this.min.y = + Infinity; + this.max.x = this.max.y = - Infinity; + + return this; + + } + + isEmpty() { + + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); + + } + + getCenter( target ) { + + return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + + } + + getSize( target ) { + + return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); + + } + + expandByPoint( point ) { + + this.min.min( point ); + this.max.max( point ); + + return this; + + } + + expandByVector( vector ) { + + this.min.sub( vector ); + this.max.add( vector ); + + return this; + + } + + expandByScalar( scalar ) { + + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); + + return this; + + } + + containsPoint( point ) { + + return point.x >= this.min.x && point.x <= this.max.x && + point.y >= this.min.y && point.y <= this.max.y; + + } + + containsBox( box ) { + + return this.min.x <= box.min.x && box.max.x <= this.max.x && + this.min.y <= box.min.y && box.max.y <= this.max.y; + + } + + getParameter( point, target ) { + + // This can potentially have a divide by zero if the box + // has a size dimension of 0. + + return target.set( + ( point.x - this.min.x ) / ( this.max.x - this.min.x ), + ( point.y - this.min.y ) / ( this.max.y - this.min.y ) + ); + + } + + intersectsBox( box ) { + + // using 4 splitting planes to rule out intersections + + return box.max.x >= this.min.x && box.min.x <= this.max.x && + box.max.y >= this.min.y && box.min.y <= this.max.y; + + } + + clampPoint( point, target ) { + + return target.copy( point ).clamp( this.min, this.max ); + + } + + distanceToPoint( point ) { + + return this.clampPoint( point, _vector$4 ).distanceTo( point ); + + } + + intersect( box ) { + + this.min.max( box.min ); + this.max.min( box.max ); + + if ( this.isEmpty() ) this.makeEmpty(); + + return this; + + } + + union( box ) { + + this.min.min( box.min ); + this.max.max( box.max ); + + return this; + + } + + translate( offset ) { + + this.min.add( offset ); + this.max.add( offset ); + + return this; + + } + + equals( box ) { + + return box.min.equals( this.min ) && box.max.equals( this.max ); + + } + +} + +const _startP = /*@__PURE__*/ new Vector3(); +const _startEnd = /*@__PURE__*/ new Vector3(); + +class Line3 { + + constructor( start = new Vector3(), end = new Vector3() ) { + + this.start = start; + this.end = end; + + } + + set( start, end ) { + + this.start.copy( start ); + this.end.copy( end ); + + return this; + + } + + copy( line ) { + + this.start.copy( line.start ); + this.end.copy( line.end ); + + return this; + + } + + getCenter( target ) { + + return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); + + } + + delta( target ) { + + return target.subVectors( this.end, this.start ); + + } + + distanceSq() { + + return this.start.distanceToSquared( this.end ); + + } + + distance() { + + return this.start.distanceTo( this.end ); + + } + + at( t, target ) { + + return this.delta( target ).multiplyScalar( t ).add( this.start ); + + } + + closestPointToPointParameter( point, clampToLine ) { + + _startP.subVectors( point, this.start ); + _startEnd.subVectors( this.end, this.start ); + + const startEnd2 = _startEnd.dot( _startEnd ); + const startEnd_startP = _startEnd.dot( _startP ); + + let t = startEnd_startP / startEnd2; + + if ( clampToLine ) { + + t = clamp$1( t, 0, 1 ); + + } + + return t; + + } + + closestPointToPoint( point, clampToLine, target ) { + + const t = this.closestPointToPointParameter( point, clampToLine ); + + return this.delta( target ).multiplyScalar( t ).add( this.start ); + + } + + applyMatrix4( matrix ) { + + this.start.applyMatrix4( matrix ); + this.end.applyMatrix4( matrix ); + + return this; + + } + + equals( line ) { + + return line.start.equals( this.start ) && line.end.equals( this.end ); + + } + + clone() { + + return new this.constructor().copy( this ); + + } + +} + +const _vector$3 = /*@__PURE__*/ new Vector3(); + +class SpotLightHelper extends Object3D { + + constructor( light, color ) { + + super(); + + this.light = light; + + this.matrixAutoUpdate = false; + + this.color = color; + + this.type = 'SpotLightHelper'; + + const geometry = new BufferGeometry(); + + const positions = [ + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 1, 0, 1, + 0, 0, 0, - 1, 0, 1, + 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, - 1, 1 + ]; + + for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { + + const p1 = ( i / l ) * Math.PI * 2; + const p2 = ( j / l ) * Math.PI * 2; + + positions.push( + Math.cos( p1 ), Math.sin( p1 ), 1, + Math.cos( p2 ), Math.sin( p2 ), 1 + ); + + } + + geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + + const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); + + this.cone = new LineSegments( geometry, material ); + this.add( this.cone ); + + this.update(); + + } + + dispose() { + + this.cone.geometry.dispose(); + this.cone.material.dispose(); + + } + + update() { + + this.light.updateWorldMatrix( true, false ); + this.light.target.updateWorldMatrix( true, false ); + + // update the local matrix based on the parent and light target transforms + if ( this.parent ) { + + this.parent.updateWorldMatrix( true ); + + this.matrix + .copy( this.parent.matrixWorld ) + .invert() + .multiply( this.light.matrixWorld ); + + } else { + + this.matrix.copy( this.light.matrixWorld ); + + } + + this.matrixWorld.copy( this.light.matrixWorld ); + + const coneLength = this.light.distance ? this.light.distance : 1000; + const coneWidth = coneLength * Math.tan( this.light.angle ); + + this.cone.scale.set( coneWidth, coneWidth, coneLength ); + + _vector$3.setFromMatrixPosition( this.light.target.matrixWorld ); + + this.cone.lookAt( _vector$3 ); + + if ( this.color !== undefined ) { + + this.cone.material.color.set( this.color ); + + } else { + + this.cone.material.color.copy( this.light.color ); + + } + + } + +} + +const _vector$2 = /*@__PURE__*/ new Vector3(); +const _boneMatrix = /*@__PURE__*/ new Matrix4(); +const _matrixWorldInv = /*@__PURE__*/ new Matrix4(); + + +class SkeletonHelper extends LineSegments { + + constructor( object ) { + + const bones = getBoneList( object ); + + const geometry = new BufferGeometry(); + + const vertices = []; + const colors = []; + + const color1 = new Color( 0, 0, 1 ); + const color2 = new Color( 0, 1, 0 ); + + for ( let i = 0; i < bones.length; i ++ ) { + + const bone = bones[ i ]; + + if ( bone.parent && bone.parent.isBone ) { + + vertices.push( 0, 0, 0 ); + vertices.push( 0, 0, 0 ); + colors.push( color1.r, color1.g, color1.b ); + colors.push( color2.r, color2.g, color2.b ); + + } + + } + + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } ); + + super( geometry, material ); + + this.isSkeletonHelper = true; + + this.type = 'SkeletonHelper'; + + this.root = object; + this.bones = bones; + + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; + + } + + updateMatrixWorld( force ) { + + const bones = this.bones; + + const geometry = this.geometry; + const position = geometry.getAttribute( 'position' ); + + _matrixWorldInv.copy( this.root.matrixWorld ).invert(); + + for ( let i = 0, j = 0; i < bones.length; i ++ ) { + + const bone = bones[ i ]; + + if ( bone.parent && bone.parent.isBone ) { + + _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld ); + _vector$2.setFromMatrixPosition( _boneMatrix ); + position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z ); + + _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld ); + _vector$2.setFromMatrixPosition( _boneMatrix ); + position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z ); + + j += 2; + + } + + } + + geometry.getAttribute( 'position' ).needsUpdate = true; + + super.updateMatrixWorld( force ); + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + +} + + +function getBoneList( object ) { + + const boneList = []; + + if ( object.isBone === true ) { + + boneList.push( object ); + + } + + for ( let i = 0; i < object.children.length; i ++ ) { + + boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); + + } + + return boneList; + +} + +class PointLightHelper extends Mesh { + + constructor( light, sphereSize, color ) { + + const geometry = new SphereGeometry( sphereSize, 4, 2 ); + const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); + + super( geometry, material ); + + this.light = light; + + this.color = color; + + this.type = 'PointLightHelper'; + + this.matrix = this.light.matrixWorld; + this.matrixAutoUpdate = false; + + this.update(); + + + /* + // TODO: delete this comment? + const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); + const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); + + this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); + this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); + + const d = light.distance; + + if ( d === 0.0 ) { + + this.lightDistance.visible = false; + + } else { + + this.lightDistance.scale.set( d, d, d ); + + } + + this.add( this.lightDistance ); + */ + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + + update() { + + this.light.updateWorldMatrix( true, false ); + + if ( this.color !== undefined ) { + + this.material.color.set( this.color ); + + } else { + + this.material.color.copy( this.light.color ); + + } + + /* + const d = this.light.distance; + + if ( d === 0.0 ) { + + this.lightDistance.visible = false; + + } else { + + this.lightDistance.visible = true; + this.lightDistance.scale.set( d, d, d ); + + } + */ + + } + +} + +const _vector$1 = /*@__PURE__*/ new Vector3(); +const _color1 = /*@__PURE__*/ new Color(); +const _color2 = /*@__PURE__*/ new Color(); + +class HemisphereLightHelper extends Object3D { + + constructor( light, size, color ) { + + super(); + + this.light = light; + + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; + + this.color = color; + + this.type = 'HemisphereLightHelper'; + + const geometry = new OctahedronGeometry( size ); + geometry.rotateY( Math.PI * 0.5 ); + + this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); + if ( this.color === undefined ) this.material.vertexColors = true; + + const position = geometry.getAttribute( 'position' ); + const colors = new Float32Array( position.count * 3 ); + + geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) ); + + this.add( new Mesh( geometry, this.material ) ); + + this.update(); + + } + + dispose() { + + this.children[ 0 ].geometry.dispose(); + this.children[ 0 ].material.dispose(); + + } + + update() { + + const mesh = this.children[ 0 ]; + + if ( this.color !== undefined ) { + + this.material.color.set( this.color ); + + } else { + + const colors = mesh.geometry.getAttribute( 'color' ); + + _color1.copy( this.light.color ); + _color2.copy( this.light.groundColor ); + + for ( let i = 0, l = colors.count; i < l; i ++ ) { + + const color = ( i < ( l / 2 ) ) ? _color1 : _color2; + + colors.setXYZ( i, color.r, color.g, color.b ); + + } + + colors.needsUpdate = true; + + } + + this.light.updateWorldMatrix( true, false ); + + mesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() ); + + } + +} + +class GridHelper extends LineSegments { + + constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) { + + color1 = new Color( color1 ); + color2 = new Color( color2 ); + + const center = divisions / 2; + const step = size / divisions; + const halfSize = size / 2; + + const vertices = [], colors = []; + + for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { + + vertices.push( - halfSize, 0, k, halfSize, 0, k ); + vertices.push( k, 0, - halfSize, k, 0, halfSize ); + + const color = i === center ? color1 : color2; + + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + + } + + const geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); + + super( geometry, material ); + + this.type = 'GridHelper'; + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + +} + +class PolarGridHelper extends LineSegments { + + constructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) { + + color1 = new Color( color1 ); + color2 = new Color( color2 ); + + const vertices = []; + const colors = []; + + // create the sectors + + if ( sectors > 1 ) { + + for ( let i = 0; i < sectors; i ++ ) { + + const v = ( i / sectors ) * ( Math.PI * 2 ); + + const x = Math.sin( v ) * radius; + const z = Math.cos( v ) * radius; + + vertices.push( 0, 0, 0 ); + vertices.push( x, 0, z ); + + const color = ( i & 1 ) ? color1 : color2; + + colors.push( color.r, color.g, color.b ); + colors.push( color.r, color.g, color.b ); + + } + + } + + // create the rings + + for ( let i = 0; i < rings; i ++ ) { + + const color = ( i & 1 ) ? color1 : color2; + + const r = radius - ( radius / rings * i ); + + for ( let j = 0; j < divisions; j ++ ) { + + // first vertex + + let v = ( j / divisions ) * ( Math.PI * 2 ); + + let x = Math.sin( v ) * r; + let z = Math.cos( v ) * r; + + vertices.push( x, 0, z ); + colors.push( color.r, color.g, color.b ); + + // second vertex + + v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); + + x = Math.sin( v ) * r; + z = Math.cos( v ) * r; + + vertices.push( x, 0, z ); + colors.push( color.r, color.g, color.b ); + + } + + } + + const geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); + + super( geometry, material ); + + this.type = 'PolarGridHelper'; + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + +} + +const _v1 = /*@__PURE__*/ new Vector3(); +const _v2 = /*@__PURE__*/ new Vector3(); +const _v3 = /*@__PURE__*/ new Vector3(); + +class DirectionalLightHelper extends Object3D { + + constructor( light, size, color ) { + + super(); + + this.light = light; + + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; + + this.color = color; + + this.type = 'DirectionalLightHelper'; + + if ( size === undefined ) size = 1; + + let geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( [ + - size, size, 0, + size, size, 0, + size, - size, 0, + - size, - size, 0, + - size, size, 0 + ], 3 ) ); + + const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); + + this.lightPlane = new Line( geometry, material ); + this.add( this.lightPlane ); + + geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); + + this.targetLine = new Line( geometry, material ); + this.add( this.targetLine ); + + this.update(); + + } + + dispose() { + + this.lightPlane.geometry.dispose(); + this.lightPlane.material.dispose(); + this.targetLine.geometry.dispose(); + this.targetLine.material.dispose(); + + } + + update() { + + this.light.updateWorldMatrix( true, false ); + this.light.target.updateWorldMatrix( true, false ); + + _v1.setFromMatrixPosition( this.light.matrixWorld ); + _v2.setFromMatrixPosition( this.light.target.matrixWorld ); + _v3.subVectors( _v2, _v1 ); + + this.lightPlane.lookAt( _v2 ); + + if ( this.color !== undefined ) { + + this.lightPlane.material.color.set( this.color ); + this.targetLine.material.color.set( this.color ); + + } else { + + this.lightPlane.material.color.copy( this.light.color ); + this.targetLine.material.color.copy( this.light.color ); + + } + + this.targetLine.lookAt( _v2 ); + this.targetLine.scale.z = _v3.length(); + + } + +} + +const _vector = /*@__PURE__*/ new Vector3(); +const _camera$1 = /*@__PURE__*/ new Camera(); + +/** + * - shows frustum, line of sight and up of the camera + * - suitable for fast updates + * - based on frustum visualization in lightgl.js shadowmap example + * https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html + */ + +class CameraHelper extends LineSegments { + + constructor( camera ) { + + const geometry = new BufferGeometry(); + const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } ); + + const vertices = []; + const colors = []; + + const pointMap = {}; + + // near + + addLine( 'n1', 'n2' ); + addLine( 'n2', 'n4' ); + addLine( 'n4', 'n3' ); + addLine( 'n3', 'n1' ); + + // far + + addLine( 'f1', 'f2' ); + addLine( 'f2', 'f4' ); + addLine( 'f4', 'f3' ); + addLine( 'f3', 'f1' ); + + // sides + + addLine( 'n1', 'f1' ); + addLine( 'n2', 'f2' ); + addLine( 'n3', 'f3' ); + addLine( 'n4', 'f4' ); + + // cone + + addLine( 'p', 'n1' ); + addLine( 'p', 'n2' ); + addLine( 'p', 'n3' ); + addLine( 'p', 'n4' ); + + // up + + addLine( 'u1', 'u2' ); + addLine( 'u2', 'u3' ); + addLine( 'u3', 'u1' ); + + // target + + addLine( 'c', 't' ); + addLine( 'p', 'c' ); + + // cross + + addLine( 'cn1', 'cn2' ); + addLine( 'cn3', 'cn4' ); + + addLine( 'cf1', 'cf2' ); + addLine( 'cf3', 'cf4' ); + + function addLine( a, b ) { + + addPoint( a ); + addPoint( b ); + + } + + function addPoint( id ) { + + vertices.push( 0, 0, 0 ); + colors.push( 0, 0, 0 ); + + if ( pointMap[ id ] === undefined ) { + + pointMap[ id ] = []; + + } + + pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); + + } + + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + super( geometry, material ); + + this.type = 'CameraHelper'; + + this.camera = camera; + if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); + + this.matrix = camera.matrixWorld; + this.matrixAutoUpdate = false; + + this.pointMap = pointMap; + + this.update(); + + // colors + + const colorFrustum = new Color( 0xffaa00 ); + const colorCone = new Color( 0xff0000 ); + const colorUp = new Color( 0x00aaff ); + const colorTarget = new Color( 0xffffff ); + const colorCross = new Color( 0x333333 ); + + this.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross ); + + } + + setColors( frustum, cone, up, target, cross ) { + + const geometry = this.geometry; + + const colorAttribute = geometry.getAttribute( 'color' ); + + // near + + colorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2 + colorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4 + colorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3 + colorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1 + + // far + + colorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2 + colorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4 + colorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3 + colorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1 + + // sides + + colorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1 + colorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2 + colorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3 + colorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4 + + // cone + + colorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1 + colorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2 + colorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3 + colorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4 + + // up + + colorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2 + colorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3 + colorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1 + + // target + + colorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t + colorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c + + // cross + + colorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2 + colorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4 + + colorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2 + colorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4 + + colorAttribute.needsUpdate = true; + + } + + update() { + + const geometry = this.geometry; + const pointMap = this.pointMap; + + const w = 1, h = 1; + + // we need just camera projection matrix inverse + // world matrix must be identity + + _camera$1.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); + + // center / target + + setPoint( 'c', pointMap, geometry, _camera$1, 0, 0, - 1 ); + setPoint( 't', pointMap, geometry, _camera$1, 0, 0, 1 ); + + // near + + setPoint( 'n1', pointMap, geometry, _camera$1, - w, - h, - 1 ); + setPoint( 'n2', pointMap, geometry, _camera$1, w, - h, - 1 ); + setPoint( 'n3', pointMap, geometry, _camera$1, - w, h, - 1 ); + setPoint( 'n4', pointMap, geometry, _camera$1, w, h, - 1 ); + + // far + + setPoint( 'f1', pointMap, geometry, _camera$1, - w, - h, 1 ); + setPoint( 'f2', pointMap, geometry, _camera$1, w, - h, 1 ); + setPoint( 'f3', pointMap, geometry, _camera$1, - w, h, 1 ); + setPoint( 'f4', pointMap, geometry, _camera$1, w, h, 1 ); + + // up + + setPoint( 'u1', pointMap, geometry, _camera$1, w * 0.7, h * 1.1, - 1 ); + setPoint( 'u2', pointMap, geometry, _camera$1, - w * 0.7, h * 1.1, - 1 ); + setPoint( 'u3', pointMap, geometry, _camera$1, 0, h * 2, - 1 ); + + // cross + + setPoint( 'cf1', pointMap, geometry, _camera$1, - w, 0, 1 ); + setPoint( 'cf2', pointMap, geometry, _camera$1, w, 0, 1 ); + setPoint( 'cf3', pointMap, geometry, _camera$1, 0, - h, 1 ); + setPoint( 'cf4', pointMap, geometry, _camera$1, 0, h, 1 ); + + setPoint( 'cn1', pointMap, geometry, _camera$1, - w, 0, - 1 ); + setPoint( 'cn2', pointMap, geometry, _camera$1, w, 0, - 1 ); + setPoint( 'cn3', pointMap, geometry, _camera$1, 0, - h, - 1 ); + setPoint( 'cn4', pointMap, geometry, _camera$1, 0, h, - 1 ); + + geometry.getAttribute( 'position' ).needsUpdate = true; + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + +} + + +function setPoint( point, pointMap, geometry, camera, x, y, z ) { + + _vector.set( x, y, z ).unproject( camera ); + + const points = pointMap[ point ]; + + if ( points !== undefined ) { + + const position = geometry.getAttribute( 'position' ); + + for ( let i = 0, l = points.length; i < l; i ++ ) { + + position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z ); + + } + + } + +} + +const _box = /*@__PURE__*/ new Box3(); + +class BoxHelper extends LineSegments { + + constructor( object, color = 0xffff00 ) { + + const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); + const positions = new Float32Array( 8 * 3 ); + + const geometry = new BufferGeometry(); + geometry.setIndex( new BufferAttribute( indices, 1 ) ); + geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) ); + + super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + + this.object = object; + this.type = 'BoxHelper'; + + this.matrixAutoUpdate = false; + + this.update(); + + } + + update( object ) { + + if ( object !== undefined ) { + + console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); + + } + + if ( this.object !== undefined ) { + + _box.setFromObject( this.object ); + + } + + if ( _box.isEmpty() ) return; + + const min = _box.min; + const max = _box.max; + + /* + 5____4 + 1/___0/| + | 6__|_7 + 2/___3/ + + 0: max.x, max.y, max.z + 1: min.x, max.y, max.z + 2: min.x, min.y, max.z + 3: max.x, min.y, max.z + 4: max.x, max.y, min.z + 5: min.x, max.y, min.z + 6: min.x, min.y, min.z + 7: max.x, min.y, min.z + */ + + const position = this.geometry.attributes.position; + const array = position.array; + + array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; + array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; + array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; + array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; + array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; + array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; + array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; + array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; + + position.needsUpdate = true; + + this.geometry.computeBoundingSphere(); + + } + + setFromObject( object ) { + + this.object = object; + this.update(); + + return this; + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.object = source.object; + + return this; + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + +} + +class Box3Helper extends LineSegments { + + constructor( box, color = 0xffff00 ) { + + const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); + + const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ]; + + const geometry = new BufferGeometry(); + + geometry.setIndex( new BufferAttribute( indices, 1 ) ); + + geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + + super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + + this.box = box; + + this.type = 'Box3Helper'; + + this.geometry.computeBoundingSphere(); + + } + + updateMatrixWorld( force ) { + + const box = this.box; + + if ( box.isEmpty() ) return; + + box.getCenter( this.position ); + + box.getSize( this.scale ); + + this.scale.multiplyScalar( 0.5 ); + + super.updateMatrixWorld( force ); + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + +} + +class PlaneHelper extends Line { + + constructor( plane, size = 1, hex = 0xffff00 ) { + + const color = hex; + + const positions = [ 1, - 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, - 1, 0, 1, 1, 0 ]; + + const geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + geometry.computeBoundingSphere(); + + super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + + this.type = 'PlaneHelper'; + + this.plane = plane; + + this.size = size; + + const positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ]; + + const geometry2 = new BufferGeometry(); + geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); + geometry2.computeBoundingSphere(); + + this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) ); + + } + + updateMatrixWorld( force ) { + + this.position.set( 0, 0, 0 ); + + this.scale.set( 0.5 * this.size, 0.5 * this.size, 1 ); + + this.lookAt( this.plane.normal ); + + this.translateZ( - this.plane.constant ); + + super.updateMatrixWorld( force ); + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + this.children[ 0 ].geometry.dispose(); + this.children[ 0 ].material.dispose(); + + } + +} + +const _axis = /*@__PURE__*/ new Vector3(); +let _lineGeometry, _coneGeometry; + +class ArrowHelper extends Object3D { + + // dir is assumed to be normalized + + constructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) { + + super(); + + this.type = 'ArrowHelper'; + + if ( _lineGeometry === undefined ) { + + _lineGeometry = new BufferGeometry(); + _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); + + _coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 ); + _coneGeometry.translate( 0, - 0.5, 0 ); + + } + + this.position.copy( origin ); + + this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + this.line.matrixAutoUpdate = false; + this.add( this.line ); + + this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) ); + this.cone.matrixAutoUpdate = false; + this.add( this.cone ); + + this.setDirection( dir ); + this.setLength( length, headLength, headWidth ); + + } + + setDirection( dir ) { + + // dir is assumed to be normalized + + if ( dir.y > 0.99999 ) { + + this.quaternion.set( 0, 0, 0, 1 ); + + } else if ( dir.y < - 0.99999 ) { + + this.quaternion.set( 1, 0, 0, 0 ); + + } else { + + _axis.set( dir.z, 0, - dir.x ).normalize(); + + const radians = Math.acos( dir.y ); + + this.quaternion.setFromAxisAngle( _axis, radians ); + + } + + } + + setLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) { + + this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458 + this.line.updateMatrix(); + + this.cone.scale.set( headWidth, headLength, headWidth ); + this.cone.position.y = length; + this.cone.updateMatrix(); + + } + + setColor( color ) { + + this.line.material.color.set( color ); + this.cone.material.color.set( color ); + + } + + copy( source ) { + + super.copy( source, false ); + + this.line.copy( source.line ); + this.cone.copy( source.cone ); + + return this; + + } + + dispose() { + + this.line.geometry.dispose(); + this.line.material.dispose(); + this.cone.geometry.dispose(); + this.cone.material.dispose(); + + } + +} + +class AxesHelper extends LineSegments { + + constructor( size = 1 ) { + + const vertices = [ + 0, 0, 0, size, 0, 0, + 0, 0, 0, 0, size, 0, + 0, 0, 0, 0, 0, size + ]; + + const colors = [ + 1, 0, 0, 1, 0.6, 0, + 0, 1, 0, 0.6, 1, 0, + 0, 0, 1, 0, 0.6, 1 + ]; + + const geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); + + super( geometry, material ); + + this.type = 'AxesHelper'; + + } + + setColors( xAxisColor, yAxisColor, zAxisColor ) { + + const color = new Color(); + const array = this.geometry.attributes.color.array; + + color.set( xAxisColor ); + color.toArray( array, 0 ); + color.toArray( array, 3 ); + + color.set( yAxisColor ); + color.toArray( array, 6 ); + color.toArray( array, 9 ); + + color.set( zAxisColor ); + color.toArray( array, 12 ); + color.toArray( array, 15 ); + + this.geometry.attributes.color.needsUpdate = true; + + return this; + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + +} + +class ShapePath { + + constructor() { + + this.type = 'ShapePath'; + + this.color = new Color(); + + this.subPaths = []; + this.currentPath = null; + + } + + moveTo( x, y ) { + + this.currentPath = new Path(); + this.subPaths.push( this.currentPath ); + this.currentPath.moveTo( x, y ); + + return this; + + } + + lineTo( x, y ) { + + this.currentPath.lineTo( x, y ); + + return this; + + } + + quadraticCurveTo( aCPx, aCPy, aX, aY ) { + + this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); + + return this; + + } + + bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { + + this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); + + return this; + + } + + splineThru( pts ) { + + this.currentPath.splineThru( pts ); + + return this; + + } + + toShapes( isCCW ) { + + function toShapesNoHoles( inSubpaths ) { + + const shapes = []; + + for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) { + + const tmpPath = inSubpaths[ i ]; + + const tmpShape = new Shape(); + tmpShape.curves = tmpPath.curves; + + shapes.push( tmpShape ); + + } + + return shapes; + + } + + function isPointInsidePolygon( inPt, inPolygon ) { + + const polyLen = inPolygon.length; + + // inPt on polygon contour => immediate success or + // toggling of inside/outside at every single! intersection point of an edge + // with the horizontal line through inPt, left of inPt + // not counting lowerY endpoints of edges and whole edges on that line + let inside = false; + for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { + + let edgeLowPt = inPolygon[ p ]; + let edgeHighPt = inPolygon[ q ]; + + let edgeDx = edgeHighPt.x - edgeLowPt.x; + let edgeDy = edgeHighPt.y - edgeLowPt.y; + + if ( Math.abs( edgeDy ) > Number.EPSILON ) { + + // not parallel + if ( edgeDy < 0 ) { + + edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; + edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; + + } + + if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; + + if ( inPt.y === edgeLowPt.y ) { + + if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? + // continue; // no intersection or edgeLowPt => doesn't count !!! + + } else { + + const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); + if ( perpEdge === 0 ) return true; // inPt is on contour ? + if ( perpEdge < 0 ) continue; + inside = ! inside; // true intersection left of inPt + + } + + } else { + + // parallel or collinear + if ( inPt.y !== edgeLowPt.y ) continue; // parallel + // edge lies on the same horizontal line as inPt + if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || + ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! + // continue; + + } + + } + + return inside; + + } + + const isClockWise = ShapeUtils.isClockWise; + + const subPaths = this.subPaths; + if ( subPaths.length === 0 ) return []; + + let solid, tmpPath, tmpShape; + const shapes = []; + + if ( subPaths.length === 1 ) { + + tmpPath = subPaths[ 0 ]; + tmpShape = new Shape(); + tmpShape.curves = tmpPath.curves; + shapes.push( tmpShape ); + return shapes; + + } + + let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); + holesFirst = isCCW ? ! holesFirst : holesFirst; + + // console.log("Holes first", holesFirst); + + const betterShapeHoles = []; + const newShapes = []; + let newShapeHoles = []; + let mainIdx = 0; + let tmpPoints; + + newShapes[ mainIdx ] = undefined; + newShapeHoles[ mainIdx ] = []; + + for ( let i = 0, l = subPaths.length; i < l; i ++ ) { + + tmpPath = subPaths[ i ]; + tmpPoints = tmpPath.getPoints(); + solid = isClockWise( tmpPoints ); + solid = isCCW ? ! solid : solid; + + if ( solid ) { + + if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; + + newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; + newShapes[ mainIdx ].s.curves = tmpPath.curves; + + if ( holesFirst ) mainIdx ++; + newShapeHoles[ mainIdx ] = []; + + //console.log('cw', i); + + } else { + + newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); + + //console.log('ccw', i); + + } + + } + + // only Holes? -> probably all Shapes with wrong orientation + if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); + + + if ( newShapes.length > 1 ) { + + let ambiguous = false; + let toChange = 0; + + for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + + betterShapeHoles[ sIdx ] = []; + + } + + for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + + const sho = newShapeHoles[ sIdx ]; + + for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) { + + const ho = sho[ hIdx ]; + let hole_unassigned = true; + + for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { + + if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { + + if ( sIdx !== s2Idx ) toChange ++; + + if ( hole_unassigned ) { + + hole_unassigned = false; + betterShapeHoles[ s2Idx ].push( ho ); + + } else { + + ambiguous = true; + + } + + } + + } + + if ( hole_unassigned ) { + + betterShapeHoles[ sIdx ].push( ho ); + + } + + } + + } + + if ( toChange > 0 && ambiguous === false ) { + + newShapeHoles = betterShapeHoles; + + } + + } + + let tmpHoles; + + for ( let i = 0, il = newShapes.length; i < il; i ++ ) { + + tmpShape = newShapes[ i ].s; + shapes.push( tmpShape ); + tmpHoles = newShapeHoles[ i ]; + + for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) { + + tmpShape.holes.push( tmpHoles[ j ].h ); + + } + + } + + //console.log("shape", shapes); + + return shapes; + + } + +} + +class Controls extends EventDispatcher { + + constructor( object, domElement = null ) { + + super(); + + this.object = object; + this.domElement = domElement; + + this.enabled = true; + + this.state = - 1; + + this.keys = {}; + this.mouseButtons = { LEFT: null, MIDDLE: null, RIGHT: null }; + this.touches = { ONE: null, TWO: null }; + + } + + connect() {} + + disconnect() {} + + dispose() {} + + update( /* delta */ ) {} + +} + +class WebGLMultipleRenderTargets extends WebGLRenderTarget { // @deprecated, r162 + + constructor( width = 1, height = 1, count = 1, options = {} ) { + + console.warn( 'THREE.WebGLMultipleRenderTargets has been deprecated and will be removed in r172. Use THREE.WebGLRenderTarget and set the "count" parameter to enable MRT.' ); + + super( width, height, { ...options, count } ); + + this.isWebGLMultipleRenderTargets = true; + + } + + get texture() { + + return this.textures; + + } + +} + +const refreshUniforms = [ + 'alphaMap', + 'alphaTest', + 'anisotropy', + 'anisotropyMap', + 'anisotropyRotation', + 'aoMap', + 'attenuationColor', + 'attenuationDistance', + 'bumpMap', + 'clearcoat', + 'clearcoatMap', + 'clearcoatNormalMap', + 'clearcoatNormalScale', + 'clearcoatRoughness', + 'color', + 'dispersion', + 'displacementMap', + 'emissive', + 'emissiveMap', + 'envMap', + 'gradientMap', + 'ior', + 'iridescence', + 'iridescenceIOR', + 'iridescenceMap', + 'iridescenceThicknessMap', + 'lightMap', + 'map', + 'matcap', + 'metalness', + 'metalnessMap', + 'normalMap', + 'normalScale', + 'opacity', + 'roughness', + 'roughnessMap', + 'sheen', + 'sheenColor', + 'sheenColorMap', + 'sheenRoughnessMap', + 'shininess', + 'specular', + 'specularColor', + 'specularColorMap', + 'specularIntensity', + 'specularIntensityMap', + 'specularMap', + 'thickness', + 'transmission', + 'transmissionMap' +]; + +class NodeMaterialObserver { + + constructor( builder ) { + + this.renderObjects = new WeakMap(); + this.hasNode = this.containsNode( builder ); + this.hasAnimation = builder.object.isSkinnedMesh === true; + this.refreshUniforms = refreshUniforms; + this.renderId = 0; + + } + + firstInitialization( renderObject ) { + + const hasInitialized = this.renderObjects.has( renderObject ); + + if ( hasInitialized === false ) { + + this.getRenderObjectData( renderObject ); + + return true; + + } + + return false; + + } + + getRenderObjectData( renderObject ) { + + let data = this.renderObjects.get( renderObject ); + + if ( data === undefined ) { + + data = { + material: this.getMaterialData( renderObject.material ), + worldMatrix: renderObject.object.matrixWorld.clone() + }; + + if ( renderObject.object.center ) { + + data.center = renderObject.object.center.clone(); + + } + + if ( renderObject.object.morphTargetInfluences ) { + + data.morphTargetInfluences = renderObject.object.morphTargetInfluences.slice(); + + } + + if ( renderObject.bundle !== null ) { + + data.version = renderObject.bundle.version; + + } + + this.renderObjects.set( renderObject, data ); + + } + + return data; + + } + + containsNode( builder ) { + + const material = builder.material; + + for ( const property in material ) { + + if ( material[ property ] && material[ property ].isNode ) + return true; + + } + + if ( builder.renderer.nodes.modelViewMatrix !== null || builder.renderer.nodes.modelNormalViewMatrix !== null ) + return true; + + return false; + + } + + getMaterialData( material ) { + + const data = {}; + + for ( const property of this.refreshUniforms ) { + + const value = material[ property ]; + + if ( value === null || value === undefined ) continue; + + if ( typeof value === 'object' && value.clone !== undefined ) { + + if ( value.isTexture === true ) { + + data[ property ] = { id: value.id, version: value.version }; + + } else { + + data[ property ] = value.clone(); + + } + + } else { + + data[ property ] = value; + + } + + } + + return data; + + } + + equals( renderObject ) { + + const { object, material } = renderObject; + + const renderObjectData = this.getRenderObjectData( renderObject ); + + // world matrix + + if ( renderObjectData.worldMatrix.equals( object.matrixWorld ) !== true ) { + + renderObjectData.worldMatrix.copy( object.matrixWorld ); + + return false; + + } + + // material + + const materialData = renderObjectData.material; + + for ( const property in materialData ) { + + const value = materialData[ property ]; + const mtlValue = material[ property ]; + + if ( value.equals !== undefined ) { + + if ( value.equals( mtlValue ) === false ) { + + value.copy( mtlValue ); + + return false; + + } + + } else if ( mtlValue.isTexture === true ) { + + if ( value.id !== mtlValue.id || value.version !== mtlValue.version ) { + + value.id = mtlValue.id; + value.version = mtlValue.version; + + return false; + + } + + } else if ( value !== mtlValue ) { + + materialData[ property ] = mtlValue; + + return false; + + } + + } + + // morph targets + + if ( renderObjectData.morphTargetInfluences ) { + + let morphChanged = false; + + for ( let i = 0; i < renderObjectData.morphTargetInfluences.length; i ++ ) { + + if ( renderObjectData.morphTargetInfluences[ i ] !== object.morphTargetInfluences[ i ] ) { + + morphChanged = true; + + } + + } + + if ( morphChanged ) return true; + + } + + // center + + if ( renderObjectData.center ) { + + if ( renderObjectData.center.equals( object.center ) === false ) { + + renderObjectData.center.copy( object.center ); + + return true; + + } + + } + + // bundle + + if ( renderObject.bundle !== null ) { + + renderObjectData.version = renderObject.bundle.version; + + } + + return true; + + } + + needsRefresh( renderObject, nodeFrame ) { + + if ( this.hasNode || this.hasAnimation || this.firstInitialization( renderObject ) ) + return true; + + const { renderId } = nodeFrame; + + if ( this.renderId !== renderId ) { + + this.renderId = renderId; + + return true; + + } + + const isStatic = renderObject.object.static === true; + const isBundle = renderObject.bundle !== null && renderObject.bundle.static === true && this.getRenderObjectData( renderObject ).version === renderObject.bundle.version; + + if ( isStatic || isBundle ) + return false; + + const notEqual = this.equals( renderObject ) !== true; + + return notEqual; + + } + +} + +// cyrb53 (c) 2018 bryc (github.com/bryc). License: Public domain. Attribution appreciated. +// A fast and simple 64-bit (or 53-bit) string hash function with decent collision resistance. +// Largely inspired by MurmurHash2/3, but with a focus on speed/simplicity. +// See https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript/52171480#52171480 +// https://github.com/bryc/code/blob/master/jshash/experimental/cyrb53.js +function cyrb53( value, seed = 0 ) { + + let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; + + if ( value instanceof Array ) { + + for ( let i = 0, val; i < value.length; i ++ ) { + + val = value[ i ]; + h1 = Math.imul( h1 ^ val, 2654435761 ); + h2 = Math.imul( h2 ^ val, 1597334677 ); + + } + + } else { + + for ( let i = 0, ch; i < value.length; i ++ ) { + + ch = value.charCodeAt( i ); + h1 = Math.imul( h1 ^ ch, 2654435761 ); + h2 = Math.imul( h2 ^ ch, 1597334677 ); + + } + + } + + h1 = Math.imul( h1 ^ ( h1 >>> 16 ), 2246822507 ); + h1 ^= Math.imul( h2 ^ ( h2 >>> 13 ), 3266489909 ); + h2 = Math.imul( h2 ^ ( h2 >>> 16 ), 2246822507 ); + h2 ^= Math.imul( h1 ^ ( h1 >>> 13 ), 3266489909 ); + + return 4294967296 * ( 2097151 & h2 ) + ( h1 >>> 0 ); + +} + +const hashString = ( str ) => cyrb53( str ); +const hashArray = ( array ) => cyrb53( array ); +const hash$1 = ( ...params ) => cyrb53( params ); + +function getCacheKey$1( object, force = false ) { + + const values = []; + + if ( object.isNode === true ) { + + values.push( object.id ); + object = object.getSelf(); + + } + + for ( const { property, childNode } of getNodeChildren( object ) ) { + + values.push( values, cyrb53( property.slice( 0, - 4 ) ), childNode.getCacheKey( force ) ); + + } + + return cyrb53( values ); + +} + +function* getNodeChildren( node, toJSON = false ) { + + for ( const property in node ) { + + // Ignore private properties. + if ( property.startsWith( '_' ) === true ) continue; + + const object = node[ property ]; + + if ( Array.isArray( object ) === true ) { + + for ( let i = 0; i < object.length; i ++ ) { + + const child = object[ i ]; + + if ( child && ( child.isNode === true || toJSON && typeof child.toJSON === 'function' ) ) { + + yield { property, index: i, childNode: child }; + + } + + } + + } else if ( object && object.isNode === true ) { + + yield { property, childNode: object }; + + } else if ( typeof object === 'object' ) { + + for ( const subProperty in object ) { + + const child = object[ subProperty ]; + + if ( child && ( child.isNode === true || toJSON && typeof child.toJSON === 'function' ) ) { + + yield { property, index: subProperty, childNode: child }; + + } + + } + + } + + } + +} + +function getValueType( value ) { + + if ( value === undefined || value === null ) return null; + + const typeOf = typeof value; + + if ( value.isNode === true ) { + + return 'node'; + + } else if ( typeOf === 'number' ) { + + return 'float'; + + } else if ( typeOf === 'boolean' ) { + + return 'bool'; + + } else if ( typeOf === 'string' ) { + + return 'string'; + + } else if ( typeOf === 'function' ) { + + return 'shader'; + + } else if ( value.isVector2 === true ) { + + return 'vec2'; + + } else if ( value.isVector3 === true ) { + + return 'vec3'; + + } else if ( value.isVector4 === true ) { + + return 'vec4'; + + } else if ( value.isMatrix3 === true ) { + + return 'mat3'; + + } else if ( value.isMatrix4 === true ) { + + return 'mat4'; + + } else if ( value.isColor === true ) { + + return 'color'; + + } else if ( value instanceof ArrayBuffer ) { + + return 'ArrayBuffer'; + + } + + return null; + +} + +function getValueFromType( type, ...params ) { + + const last4 = type ? type.slice( - 4 ) : undefined; + + if ( params.length === 1 ) { // ensure same behaviour as in NodeBuilder.format() + + if ( last4 === 'vec2' ) params = [ params[ 0 ], params[ 0 ] ]; + else if ( last4 === 'vec3' ) params = [ params[ 0 ], params[ 0 ], params[ 0 ] ]; + else if ( last4 === 'vec4' ) params = [ params[ 0 ], params[ 0 ], params[ 0 ], params[ 0 ] ]; + + } + + if ( type === 'color' ) { + + return new Color( ...params ); + + } else if ( last4 === 'vec2' ) { + + return new Vector2( ...params ); + + } else if ( last4 === 'vec3' ) { + + return new Vector3( ...params ); + + } else if ( last4 === 'vec4' ) { + + return new Vector4( ...params ); + + } else if ( last4 === 'mat3' ) { + + return new Matrix3( ...params ); + + } else if ( last4 === 'mat4' ) { + + return new Matrix4( ...params ); + + } else if ( type === 'bool' ) { + + return params[ 0 ] || false; + + } else if ( ( type === 'float' ) || ( type === 'int' ) || ( type === 'uint' ) ) { + + return params[ 0 ] || 0; + + } else if ( type === 'string' ) { + + return params[ 0 ] || ''; + + } else if ( type === 'ArrayBuffer' ) { + + return base64ToArrayBuffer( params[ 0 ] ); + + } + + return null; + +} + +function arrayBufferToBase64( arrayBuffer ) { + + let chars = ''; + + const array = new Uint8Array( arrayBuffer ); + + for ( let i = 0; i < array.length; i ++ ) { + + chars += String.fromCharCode( array[ i ] ); + + } + + return btoa( chars ); + +} + +function base64ToArrayBuffer( base64 ) { + + return Uint8Array.from( atob( base64 ), c => c.charCodeAt( 0 ) ).buffer; + +} + +var NodeUtils = /*#__PURE__*/Object.freeze({ + __proto__: null, + arrayBufferToBase64: arrayBufferToBase64, + base64ToArrayBuffer: base64ToArrayBuffer, + getCacheKey: getCacheKey$1, + getNodeChildren: getNodeChildren, + getValueFromType: getValueFromType, + getValueType: getValueType, + hash: hash$1, + hashArray: hashArray, + hashString: hashString +}); + +const NodeShaderStage = { + VERTEX: 'vertex', + FRAGMENT: 'fragment' +}; + +const NodeUpdateType = { + NONE: 'none', + FRAME: 'frame', + RENDER: 'render', + OBJECT: 'object' +}; + +const NodeType = { + BOOLEAN: 'bool', + INTEGER: 'int', + FLOAT: 'float', + VECTOR2: 'vec2', + VECTOR3: 'vec3', + VECTOR4: 'vec4', + MATRIX2: 'mat2', + MATRIX3: 'mat3', + MATRIX4: 'mat4' +}; + +const defaultShaderStages = [ 'fragment', 'vertex' ]; +const defaultBuildStages = [ 'setup', 'analyze', 'generate' ]; +const shaderStages = [ ...defaultShaderStages, 'compute' ]; +const vectorComponents = [ 'x', 'y', 'z', 'w' ]; + +let _nodeId = 0; + +class Node extends EventDispatcher { + + static get type() { + + return 'Node'; + + } + + constructor( nodeType = null ) { + + super(); + + this.nodeType = nodeType; + + this.updateType = NodeUpdateType.NONE; + this.updateBeforeType = NodeUpdateType.NONE; + this.updateAfterType = NodeUpdateType.NONE; + + this.uuid = MathUtils.generateUUID(); + + this.version = 0; + + this._cacheKey = null; + this._cacheKeyVersion = 0; + + this.global = false; + + this.isNode = true; + + Object.defineProperty( this, 'id', { value: _nodeId ++ } ); + + } + + set needsUpdate( value ) { + + if ( value === true ) { + + this.version ++; + + } + + } + + get type() { + + return this.constructor.type; + + } + + onUpdate( callback, updateType ) { + + this.updateType = updateType; + this.update = callback.bind( this.getSelf() ); + + return this; + + } + + onFrameUpdate( callback ) { + + return this.onUpdate( callback, NodeUpdateType.FRAME ); + + } + + onRenderUpdate( callback ) { + + return this.onUpdate( callback, NodeUpdateType.RENDER ); + + } + + onObjectUpdate( callback ) { + + return this.onUpdate( callback, NodeUpdateType.OBJECT ); + + } + + onReference( callback ) { + + this.updateReference = callback.bind( this.getSelf() ); + + return this; + + } + + getSelf() { + + // Returns non-node object. + + return this.self || this; + + } + + updateReference( /*state*/ ) { + + return this; + + } + + isGlobal( /*builder*/ ) { + + return this.global; + + } + + * getChildren() { + + for ( const { childNode } of getNodeChildren( this ) ) { + + yield childNode; + + } + + } + + dispose() { + + this.dispatchEvent( { type: 'dispose' } ); + + } + + traverse( callback ) { + + callback( this ); + + for ( const childNode of this.getChildren() ) { + + childNode.traverse( callback ); + + } + + } + + getCacheKey( force = false ) { + + force = force || this.version !== this._cacheKeyVersion; + + if ( force === true || this._cacheKey === null ) { + + this._cacheKey = getCacheKey$1( this, force ); + this._cacheKeyVersion = this.version; + + } + + return this._cacheKey; + + } + + getScope() { + + return this; + + } + + getHash( /*builder*/ ) { + + return this.uuid; + + } + + getUpdateType() { + + return this.updateType; + + } + + getUpdateBeforeType() { + + return this.updateBeforeType; + + } + + getUpdateAfterType() { + + return this.updateAfterType; + + } + + getElementType( builder ) { + + const type = this.getNodeType( builder ); + const elementType = builder.getElementType( type ); + + return elementType; + + } + + getNodeType( builder ) { + + const nodeProperties = builder.getNodeProperties( this ); + + if ( nodeProperties.outputNode ) { + + return nodeProperties.outputNode.getNodeType( builder ); + + } + + return this.nodeType; + + } + + getShared( builder ) { + + const hash = this.getHash( builder ); + const nodeFromHash = builder.getNodeFromHash( hash ); + + return nodeFromHash || this; + + } + + setup( builder ) { + + const nodeProperties = builder.getNodeProperties( this ); + + let index = 0; + + for ( const childNode of this.getChildren() ) { + + nodeProperties[ 'node' + index ++ ] = childNode; + + } + + // return a outputNode if exists + return null; + + } + + analyze( builder ) { + + const usageCount = builder.increaseUsage( this ); + + if ( usageCount === 1 ) { + + // node flow children + + const nodeProperties = builder.getNodeProperties( this ); + + for ( const childNode of Object.values( nodeProperties ) ) { + + if ( childNode && childNode.isNode === true ) { + + childNode.build( builder ); + + } + + } + + } + + } + + generate( builder, output ) { + + const { outputNode } = builder.getNodeProperties( this ); + + if ( outputNode && outputNode.isNode === true ) { + + return outputNode.build( builder, output ); + + } + + } + + updateBefore( /*frame*/ ) { + + console.warn( 'Abstract function.' ); + + } + + updateAfter( /*frame*/ ) { + + console.warn( 'Abstract function.' ); + + } + + update( /*frame*/ ) { + + console.warn( 'Abstract function.' ); + + } + + build( builder, output = null ) { + + const refNode = this.getShared( builder ); + + if ( this !== refNode ) { + + return refNode.build( builder, output ); + + } + + builder.addNode( this ); + builder.addChain( this ); + + /* Build stages expected results: + - "setup" -> Node + - "analyze" -> null + - "generate" -> String + */ + let result = null; + + const buildStage = builder.getBuildStage(); + + if ( buildStage === 'setup' ) { + + this.updateReference( builder ); + + const properties = builder.getNodeProperties( this ); + + if ( properties.initialized !== true ) { + + const stackNodesBeforeSetup = builder.stack.nodes.length; + + properties.initialized = true; + properties.outputNode = this.setup( builder ); + + if ( properties.outputNode !== null && builder.stack.nodes.length !== stackNodesBeforeSetup ) ; + + for ( const childNode of Object.values( properties ) ) { + + if ( childNode && childNode.isNode === true ) { + + childNode.build( builder ); + + } + + } + + } + + } else if ( buildStage === 'analyze' ) { + + this.analyze( builder ); + + } else if ( buildStage === 'generate' ) { + + const isGenerateOnce = this.generate.length === 1; + + if ( isGenerateOnce ) { + + const type = this.getNodeType( builder ); + const nodeData = builder.getDataFromNode( this ); + + result = nodeData.snippet; + + if ( result === undefined ) { + + result = this.generate( builder ) || ''; + + nodeData.snippet = result; + + } else if ( nodeData.flowCodes !== undefined && builder.context.nodeBlock !== undefined ) { + + builder.addFlowCodeHierarchy( this, builder.context.nodeBlock ); + + } + + result = builder.format( result, type, output ); + + } else { + + result = this.generate( builder, output ) || ''; + + } + + } + + builder.removeChain( this ); + + return result; + + } + + getSerializeChildren() { + + return getNodeChildren( this ); + + } + + serialize( json ) { + + const nodeChildren = this.getSerializeChildren(); + + const inputNodes = {}; + + for ( const { property, index, childNode } of nodeChildren ) { + + if ( index !== undefined ) { + + if ( inputNodes[ property ] === undefined ) { + + inputNodes[ property ] = Number.isInteger( index ) ? [] : {}; + + } + + inputNodes[ property ][ index ] = childNode.toJSON( json.meta ).uuid; + + } else { + + inputNodes[ property ] = childNode.toJSON( json.meta ).uuid; + + } + + } + + if ( Object.keys( inputNodes ).length > 0 ) { + + json.inputNodes = inputNodes; + + } + + } + + deserialize( json ) { + + if ( json.inputNodes !== undefined ) { + + const nodes = json.meta.nodes; + + for ( const property in json.inputNodes ) { + + if ( Array.isArray( json.inputNodes[ property ] ) ) { + + const inputArray = []; + + for ( const uuid of json.inputNodes[ property ] ) { + + inputArray.push( nodes[ uuid ] ); + + } + + this[ property ] = inputArray; + + } else if ( typeof json.inputNodes[ property ] === 'object' ) { + + const inputObject = {}; + + for ( const subProperty in json.inputNodes[ property ] ) { + + const uuid = json.inputNodes[ property ][ subProperty ]; + + inputObject[ subProperty ] = nodes[ uuid ]; + + } + + this[ property ] = inputObject; + + } else { + + const uuid = json.inputNodes[ property ]; + + this[ property ] = nodes[ uuid ]; + + } + + } + + } + + } + + toJSON( meta ) { + + const { uuid, type } = this; + const isRoot = ( meta === undefined || typeof meta === 'string' ); + + if ( isRoot ) { + + meta = { + textures: {}, + images: {}, + nodes: {} + }; + + } + + // serialize + + let data = meta.nodes[ uuid ]; + + if ( data === undefined ) { + + data = { + uuid, + type, + meta, + metadata: { + version: 4.6, + type: 'Node', + generator: 'Node.toJSON' + } + }; + + if ( isRoot !== true ) meta.nodes[ data.uuid ] = data; + + this.serialize( data ); + + delete data.meta; + + } + + // TODO: Copied from Object3D.toJSON + + function extractFromCache( cache ) { + + const values = []; + + for ( const key in cache ) { + + const data = cache[ key ]; + delete data.metadata; + values.push( data ); + + } + + return values; + + } + + if ( isRoot ) { + + const textures = extractFromCache( meta.textures ); + const images = extractFromCache( meta.images ); + const nodes = extractFromCache( meta.nodes ); + + if ( textures.length > 0 ) data.textures = textures; + if ( images.length > 0 ) data.images = images; + if ( nodes.length > 0 ) data.nodes = nodes; + + } + + return data; + + } + +} + +class ArrayElementNode extends Node { + + static get type() { + + return 'ArrayElementNode'; + + } // @TODO: If extending from TempNode it breaks webgpu_compute + + constructor( node, indexNode ) { + + super(); + + this.node = node; + this.indexNode = indexNode; + + this.isArrayElementNode = true; + + } + + getNodeType( builder ) { + + return this.node.getElementType( builder ); + + } + + generate( builder ) { + + const nodeSnippet = this.node.build( builder ); + const indexSnippet = this.indexNode.build( builder, 'uint' ); + + return `${nodeSnippet}[ ${indexSnippet} ]`; + + } + +} + +class ConvertNode extends Node { + + static get type() { + + return 'ConvertNode'; + + } + + constructor( node, convertTo ) { + + super(); + + this.node = node; + this.convertTo = convertTo; + + } + + getNodeType( builder ) { + + const requestType = this.node.getNodeType( builder ); + + let convertTo = null; + + for ( const overloadingType of this.convertTo.split( '|' ) ) { + + if ( convertTo === null || builder.getTypeLength( requestType ) === builder.getTypeLength( overloadingType ) ) { + + convertTo = overloadingType; + + } + + } + + return convertTo; + + } + + serialize( data ) { + + super.serialize( data ); + + data.convertTo = this.convertTo; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.convertTo = data.convertTo; + + } + + generate( builder, output ) { + + const node = this.node; + const type = this.getNodeType( builder ); + + const snippet = node.build( builder, type ); + + return builder.format( snippet, type, output ); + + } + +} + +class TempNode extends Node { + + static get type() { + + return 'TempNode'; + + } + + constructor( type ) { + + super( type ); + + this.isTempNode = true; + + } + + hasDependencies( builder ) { + + return builder.getDataFromNode( this ).usageCount > 1; + + } + + build( builder, output ) { + + const buildStage = builder.getBuildStage(); + + if ( buildStage === 'generate' ) { + + const type = builder.getVectorType( this.getNodeType( builder, output ) ); + const nodeData = builder.getDataFromNode( this ); + + if ( nodeData.propertyName !== undefined ) { + + return builder.format( nodeData.propertyName, type, output ); + + } else if ( type !== 'void' && output !== 'void' && this.hasDependencies( builder ) ) { + + const snippet = super.build( builder, type ); + + const nodeVar = builder.getVarFromNode( this, null, type ); + const propertyName = builder.getPropertyName( nodeVar ); + + builder.addLineFlowCode( `${propertyName} = ${snippet}`, this ); + + nodeData.snippet = snippet; + nodeData.propertyName = propertyName; + + return builder.format( nodeData.propertyName, type, output ); + + } + + } + + return super.build( builder, output ); + + } + +} + +class JoinNode extends TempNode { + + static get type() { + + return 'JoinNode'; + + } + + constructor( nodes = [], nodeType = null ) { + + super( nodeType ); + + this.nodes = nodes; + + } + + getNodeType( builder ) { + + if ( this.nodeType !== null ) { + + return builder.getVectorType( this.nodeType ); + + } + + return builder.getTypeFromLength( this.nodes.reduce( ( count, cur ) => count + builder.getTypeLength( cur.getNodeType( builder ) ), 0 ) ); + + } + + generate( builder, output ) { + + const type = this.getNodeType( builder ); + const nodes = this.nodes; + + const primitiveType = builder.getComponentType( type ); + + const snippetValues = []; + + for ( const input of nodes ) { + + let inputSnippet = input.build( builder ); + + const inputPrimitiveType = builder.getComponentType( input.getNodeType( builder ) ); + + if ( inputPrimitiveType !== primitiveType ) { + + inputSnippet = builder.format( inputSnippet, inputPrimitiveType, primitiveType ); + + } + + snippetValues.push( inputSnippet ); + + } + + const snippet = `${ builder.getType( type ) }( ${ snippetValues.join( ', ' ) } )`; + + return builder.format( snippet, type, output ); + + } + +} + +const stringVectorComponents = vectorComponents.join( '' ); + +class SplitNode extends Node { + + static get type() { + + return 'SplitNode'; + + } + + constructor( node, components = 'x' ) { + + super(); + + this.node = node; + this.components = components; + + this.isSplitNode = true; + + } + + getVectorLength() { + + let vectorLength = this.components.length; + + for ( const c of this.components ) { + + vectorLength = Math.max( vectorComponents.indexOf( c ) + 1, vectorLength ); + + } + + return vectorLength; + + } + + getComponentType( builder ) { + + return builder.getComponentType( this.node.getNodeType( builder ) ); + + } + + getNodeType( builder ) { + + return builder.getTypeFromLength( this.components.length, this.getComponentType( builder ) ); + + } + + generate( builder, output ) { + + const node = this.node; + const nodeTypeLength = builder.getTypeLength( node.getNodeType( builder ) ); + + let snippet = null; + + if ( nodeTypeLength > 1 ) { + + let type = null; + + const componentsLength = this.getVectorLength(); + + if ( componentsLength >= nodeTypeLength ) { + + // needed expand the input node + + type = builder.getTypeFromLength( this.getVectorLength(), this.getComponentType( builder ) ); + + } + + const nodeSnippet = node.build( builder, type ); + + if ( this.components.length === nodeTypeLength && this.components === stringVectorComponents.slice( 0, this.components.length ) ) { + + // unnecessary swizzle + + snippet = builder.format( nodeSnippet, type, output ); + + } else { + + snippet = builder.format( `${nodeSnippet}.${this.components}`, this.getNodeType( builder ), output ); + + } + + } else { + + // ignore .components if .node returns float/integer + + snippet = node.build( builder, output ); + + } + + return snippet; + + } + + serialize( data ) { + + super.serialize( data ); + + data.components = this.components; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.components = data.components; + + } + +} + +class SetNode extends TempNode { + + static get type() { + + return 'SetNode'; + + } + + constructor( sourceNode, components, targetNode ) { + + super(); + + this.sourceNode = sourceNode; + this.components = components; + this.targetNode = targetNode; + + } + + getNodeType( builder ) { + + return this.sourceNode.getNodeType( builder ); + + } + + generate( builder ) { + + const { sourceNode, components, targetNode } = this; + + const sourceType = this.getNodeType( builder ); + const targetType = builder.getTypeFromLength( components.length, targetNode.getNodeType( builder ) ); + + const targetSnippet = targetNode.build( builder, targetType ); + const sourceSnippet = sourceNode.build( builder, sourceType ); + + const length = builder.getTypeLength( sourceType ); + const snippetValues = []; + + for ( let i = 0; i < length; i ++ ) { + + const component = vectorComponents[ i ]; + + if ( component === components[ 0 ] ) { + + snippetValues.push( targetSnippet ); + + i += components.length - 1; + + } else { + + snippetValues.push( sourceSnippet + '.' + component ); + + } + + } + + return `${ builder.getType( sourceType ) }( ${ snippetValues.join( ', ' ) } )`; + + } + +} + +class FlipNode extends TempNode { + + static get type() { + + return 'FlipNode'; + + } + + constructor( sourceNode, components ) { + + super(); + + this.sourceNode = sourceNode; + this.components = components; + + } + + getNodeType( builder ) { + + return this.sourceNode.getNodeType( builder ); + + } + + generate( builder ) { + + const { components, sourceNode } = this; + + const sourceType = this.getNodeType( builder ); + const sourceSnippet = sourceNode.build( builder ); + + const sourceCache = builder.getVarFromNode( this ); + const sourceProperty = builder.getPropertyName( sourceCache ); + + builder.addLineFlowCode( sourceProperty + ' = ' + sourceSnippet, this ); + + const length = builder.getTypeLength( sourceType ); + const snippetValues = []; + + let componentIndex = 0; + + for ( let i = 0; i < length; i ++ ) { + + const component = vectorComponents[ i ]; + + if ( component === components[ componentIndex ] ) { + + snippetValues.push( '1.0 - ' + ( sourceProperty + '.' + component ) ); + + componentIndex ++; + + } else { + + snippetValues.push( sourceProperty + '.' + component ); + + } + + } + + return `${ builder.getType( sourceType ) }( ${ snippetValues.join( ', ' ) } )`; + + } + +} + +class InputNode extends Node { + + static get type() { + + return 'InputNode'; + + } + + constructor( value, nodeType = null ) { + + super( nodeType ); + + this.isInputNode = true; + + this.value = value; + this.precision = null; + + } + + getNodeType( /*builder*/ ) { + + if ( this.nodeType === null ) { + + return getValueType( this.value ); + + } + + return this.nodeType; + + } + + getInputType( builder ) { + + return this.getNodeType( builder ); + + } + + setPrecision( precision ) { + + this.precision = precision; + + return this; + + } + + serialize( data ) { + + super.serialize( data ); + + data.value = this.value; + + if ( this.value && this.value.toArray ) data.value = this.value.toArray(); + + data.valueType = getValueType( this.value ); + data.nodeType = this.nodeType; + + if ( data.valueType === 'ArrayBuffer' ) data.value = arrayBufferToBase64( data.value ); + + data.precision = this.precision; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.nodeType = data.nodeType; + this.value = Array.isArray( data.value ) ? getValueFromType( data.valueType, ...data.value ) : data.value; + + this.precision = data.precision || null; + + if ( this.value && this.value.fromArray ) this.value = this.value.fromArray( data.value ); + + } + + generate( /*builder, output*/ ) { + + console.warn( 'Abstract function.' ); + + } + +} + +class ConstNode extends InputNode { + + static get type() { + + return 'ConstNode'; + + } + + constructor( value, nodeType = null ) { + + super( value, nodeType ); + + this.isConstNode = true; + + } + + generateConst( builder ) { + + return builder.generateConst( this.getNodeType( builder ), this.value ); + + } + + generate( builder, output ) { + + const type = this.getNodeType( builder ); + + return builder.format( this.generateConst( builder ), type, output ); + + } + +} + +// + +let currentStack = null; + +const NodeElements = new Map(); + +function addMethodChaining( name, nodeElement ) { + + if ( NodeElements.has( name ) ) { + + console.warn( `Redefinition of method chaining ${ name }` ); + return; + + } + + if ( typeof nodeElement !== 'function' ) throw new Error( `Node element ${ name } is not a function` ); + + NodeElements.set( name, nodeElement ); + +} + +const parseSwizzle = ( props ) => props.replace( /r|s/g, 'x' ).replace( /g|t/g, 'y' ).replace( /b|p/g, 'z' ).replace( /a|q/g, 'w' ); +const parseSwizzleAndSort = ( props ) => parseSwizzle( props ).split( '' ).sort().join( '' ); + +const shaderNodeHandler = { + + setup( NodeClosure, params ) { + + const inputs = params.shift(); + + return NodeClosure( nodeObjects( inputs ), ...params ); + + }, + + get( node, prop, nodeObj ) { + + if ( typeof prop === 'string' && node[ prop ] === undefined ) { + + if ( node.isStackNode !== true && prop === 'assign' ) { + + return ( ...params ) => { + + currentStack.assign( nodeObj, ...params ); + + return nodeObj; + + }; + + } else if ( NodeElements.has( prop ) ) { + + const nodeElement = NodeElements.get( prop ); + + return node.isStackNode ? ( ...params ) => nodeObj.add( nodeElement( ...params ) ) : ( ...params ) => nodeElement( nodeObj, ...params ); + + } else if ( prop === 'self' ) { + + return node; + + } else if ( prop.endsWith( 'Assign' ) && NodeElements.has( prop.slice( 0, prop.length - 'Assign'.length ) ) ) { + + const nodeElement = NodeElements.get( prop.slice( 0, prop.length - 'Assign'.length ) ); + + return node.isStackNode ? ( ...params ) => nodeObj.assign( params[ 0 ], nodeElement( ...params ) ) : ( ...params ) => nodeObj.assign( nodeElement( nodeObj, ...params ) ); + + } else if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true ) { + + // accessing properties ( swizzle ) + + prop = parseSwizzle( prop ); + + return nodeObject( new SplitNode( nodeObj, prop ) ); + + } else if ( /^set[XYZWRGBASTPQ]{1,4}$/.test( prop ) === true ) { + + // set properties ( swizzle ) and sort to xyzw sequence + + prop = parseSwizzleAndSort( prop.slice( 3 ).toLowerCase() ); + + return ( value ) => nodeObject( new SetNode( node, prop, value ) ); + + } else if ( /^flip[XYZWRGBASTPQ]{1,4}$/.test( prop ) === true ) { + + // set properties ( swizzle ) and sort to xyzw sequence + + prop = parseSwizzleAndSort( prop.slice( 4 ).toLowerCase() ); + + return () => nodeObject( new FlipNode( nodeObject( node ), prop ) ); + + } else if ( prop === 'width' || prop === 'height' || prop === 'depth' ) { + + // accessing property + + if ( prop === 'width' ) prop = 'x'; + else if ( prop === 'height' ) prop = 'y'; + else if ( prop === 'depth' ) prop = 'z'; + + return nodeObject( new SplitNode( node, prop ) ); + + } else if ( /^\d+$/.test( prop ) === true ) { + + // accessing array + + return nodeObject( new ArrayElementNode( nodeObj, new ConstNode( Number( prop ), 'uint' ) ) ); + + } + + } + + return Reflect.get( node, prop, nodeObj ); + + }, + + set( node, prop, value, nodeObj ) { + + if ( typeof prop === 'string' && node[ prop ] === undefined ) { + + // setting properties + + if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true || prop === 'width' || prop === 'height' || prop === 'depth' || /^\d+$/.test( prop ) === true ) { + + nodeObj[ prop ].assign( value ); + + return true; + + } + + } + + return Reflect.set( node, prop, value, nodeObj ); + + } + +}; + +const nodeObjectsCacheMap = new WeakMap(); +const nodeBuilderFunctionsCacheMap = new WeakMap(); + +const ShaderNodeObject = function ( obj, altType = null ) { + + const type = getValueType( obj ); + + if ( type === 'node' ) { + + let nodeObject = nodeObjectsCacheMap.get( obj ); + + if ( nodeObject === undefined ) { + + nodeObject = new Proxy( obj, shaderNodeHandler ); + + nodeObjectsCacheMap.set( obj, nodeObject ); + nodeObjectsCacheMap.set( nodeObject, nodeObject ); + + } + + return nodeObject; + + } else if ( ( altType === null && ( type === 'float' || type === 'boolean' ) ) || ( type && type !== 'shader' && type !== 'string' ) ) { + + return nodeObject( getConstNode( obj, altType ) ); + + } else if ( type === 'shader' ) { + + return Fn( obj ); + + } + + return obj; + +}; + +const ShaderNodeObjects = function ( objects, altType = null ) { + + for ( const name in objects ) { + + objects[ name ] = nodeObject( objects[ name ], altType ); + + } + + return objects; + +}; + +const ShaderNodeArray = function ( array, altType = null ) { + + const len = array.length; + + for ( let i = 0; i < len; i ++ ) { + + array[ i ] = nodeObject( array[ i ], altType ); + + } + + return array; + +}; + +const ShaderNodeProxy = function ( NodeClass, scope = null, factor = null, settings = null ) { + + const assignNode = ( node ) => nodeObject( settings !== null ? Object.assign( node, settings ) : node ); + + if ( scope === null ) { + + return ( ...params ) => { + + return assignNode( new NodeClass( ...nodeArray( params ) ) ); + + }; + + } else if ( factor !== null ) { + + factor = nodeObject( factor ); + + return ( ...params ) => { + + return assignNode( new NodeClass( scope, ...nodeArray( params ), factor ) ); + + }; + + } else { + + return ( ...params ) => { + + return assignNode( new NodeClass( scope, ...nodeArray( params ) ) ); + + }; + + } + +}; + +const ShaderNodeImmutable = function ( NodeClass, ...params ) { + + return nodeObject( new NodeClass( ...nodeArray( params ) ) ); + +}; + +class ShaderCallNodeInternal extends Node { + + constructor( shaderNode, inputNodes ) { + + super(); + + this.shaderNode = shaderNode; + this.inputNodes = inputNodes; + + } + + getNodeType( builder ) { + + return this.shaderNode.nodeType || this.getOutputNode( builder ).getNodeType( builder ); + + } + + call( builder ) { + + const { shaderNode, inputNodes } = this; + + const properties = builder.getNodeProperties( shaderNode ); + if ( properties.onceOutput ) return properties.onceOutput; + + // + + let result = null; + + if ( shaderNode.layout ) { + + let functionNodesCacheMap = nodeBuilderFunctionsCacheMap.get( builder.constructor ); + + if ( functionNodesCacheMap === undefined ) { + + functionNodesCacheMap = new WeakMap(); + + nodeBuilderFunctionsCacheMap.set( builder.constructor, functionNodesCacheMap ); + + } + + let functionNode = functionNodesCacheMap.get( shaderNode ); + + if ( functionNode === undefined ) { + + functionNode = nodeObject( builder.buildFunctionNode( shaderNode ) ); + + functionNodesCacheMap.set( shaderNode, functionNode ); + + } + + if ( builder.currentFunctionNode !== null ) { + + builder.currentFunctionNode.includes.push( functionNode ); + + } + + result = nodeObject( functionNode.call( inputNodes ) ); + + } else { + + const jsFunc = shaderNode.jsFunc; + const outputNode = inputNodes !== null ? jsFunc( inputNodes, builder ) : jsFunc( builder ); + + result = nodeObject( outputNode ); + + } + + if ( shaderNode.once ) { + + properties.onceOutput = result; + + } + + return result; + + } + + getOutputNode( builder ) { + + const properties = builder.getNodeProperties( this ); + + if ( properties.outputNode === null ) { + + properties.outputNode = this.setupOutput( builder ); + + } + + return properties.outputNode; + + } + + setup( builder ) { + + return this.getOutputNode( builder ); + + } + + setupOutput( builder ) { + + builder.addStack(); + + builder.stack.outputNode = this.call( builder ); + + return builder.removeStack(); + + } + + generate( builder, output ) { + + const outputNode = this.getOutputNode( builder ); + + return outputNode.build( builder, output ); + + } + +} + +class ShaderNodeInternal extends Node { + + constructor( jsFunc, nodeType ) { + + super( nodeType ); + + this.jsFunc = jsFunc; + this.layout = null; + + this.global = true; + + this.once = false; + + } + + setLayout( layout ) { + + this.layout = layout; + + return this; + + } + + call( inputs = null ) { + + nodeObjects( inputs ); + + return nodeObject( new ShaderCallNodeInternal( this, inputs ) ); + + } + + setup() { + + return this.call(); + + } + +} + +const bools = [ false, true ]; +const uints = [ 0, 1, 2, 3 ]; +const ints = [ - 1, - 2 ]; +const floats = [ 0.5, 1.5, 1 / 3, 1e-6, 1e6, Math.PI, Math.PI * 2, 1 / Math.PI, 2 / Math.PI, 1 / ( Math.PI * 2 ), Math.PI / 2 ]; + +const boolsCacheMap = new Map(); +for ( const bool of bools ) boolsCacheMap.set( bool, new ConstNode( bool ) ); + +const uintsCacheMap = new Map(); +for ( const uint of uints ) uintsCacheMap.set( uint, new ConstNode( uint, 'uint' ) ); + +const intsCacheMap = new Map( [ ...uintsCacheMap ].map( el => new ConstNode( el.value, 'int' ) ) ); +for ( const int of ints ) intsCacheMap.set( int, new ConstNode( int, 'int' ) ); + +const floatsCacheMap = new Map( [ ...intsCacheMap ].map( el => new ConstNode( el.value ) ) ); +for ( const float of floats ) floatsCacheMap.set( float, new ConstNode( float ) ); +for ( const float of floats ) floatsCacheMap.set( - float, new ConstNode( - float ) ); + +const cacheMaps = { bool: boolsCacheMap, uint: uintsCacheMap, ints: intsCacheMap, float: floatsCacheMap }; + +const constNodesCacheMap = new Map( [ ...boolsCacheMap, ...floatsCacheMap ] ); + +const getConstNode = ( value, type ) => { + + if ( constNodesCacheMap.has( value ) ) { + + return constNodesCacheMap.get( value ); + + } else if ( value.isNode === true ) { + + return value; + + } else { + + return new ConstNode( value, type ); + + } + +}; + +const safeGetNodeType = ( node ) => { + + try { + + return node.getNodeType(); + + } catch ( _ ) { + + return undefined; + + } + +}; + +const ConvertType = function ( type, cacheMap = null ) { + + return ( ...params ) => { + + if ( params.length === 0 || ( ! [ 'bool', 'float', 'int', 'uint' ].includes( type ) && params.every( param => typeof param !== 'object' ) ) ) { + + params = [ getValueFromType( type, ...params ) ]; + + } + + if ( params.length === 1 && cacheMap !== null && cacheMap.has( params[ 0 ] ) ) { + + return nodeObject( cacheMap.get( params[ 0 ] ) ); + + } + + if ( params.length === 1 ) { + + const node = getConstNode( params[ 0 ], type ); + if ( safeGetNodeType( node ) === type ) return nodeObject( node ); + return nodeObject( new ConvertNode( node, type ) ); + + } + + const nodes = params.map( param => getConstNode( param ) ); + return nodeObject( new JoinNode( nodes, type ) ); + + }; + +}; + +// exports + +const defined = ( v ) => typeof v === 'object' && v !== null ? v.value : v; // TODO: remove boolean conversion and defined function + +// utils + +const getConstNodeType = ( value ) => ( value !== undefined && value !== null ) ? ( value.nodeType || value.convertTo || ( typeof value === 'string' ? value : null ) ) : null; + +// shader node base + +function ShaderNode( jsFunc, nodeType ) { + + return new Proxy( new ShaderNodeInternal( jsFunc, nodeType ), shaderNodeHandler ); + +} + +const nodeObject = ( val, altType = null ) => /* new */ ShaderNodeObject( val, altType ); +const nodeObjects = ( val, altType = null ) => new ShaderNodeObjects( val, altType ); +const nodeArray = ( val, altType = null ) => new ShaderNodeArray( val, altType ); +const nodeProxy = ( ...params ) => new ShaderNodeProxy( ...params ); +const nodeImmutable = ( ...params ) => new ShaderNodeImmutable( ...params ); + +const Fn = ( jsFunc, nodeType ) => { + + const shaderNode = new ShaderNode( jsFunc, nodeType ); + + const fn = ( ...params ) => { + + let inputs; + + nodeObjects( params ); + + if ( params[ 0 ] && params[ 0 ].isNode ) { + + inputs = [ ...params ]; + + } else { + + inputs = params[ 0 ]; + + } + + return shaderNode.call( inputs ); + + }; + + fn.shaderNode = shaderNode; + + fn.setLayout = ( layout ) => { + + shaderNode.setLayout( layout ); + + return fn; + + }; + + fn.once = () => { + + shaderNode.once = true; + + return fn; + + }; + + return fn; + +}; + +const tslFn = ( ...params ) => { // @deprecated, r168 + + console.warn( 'TSL.ShaderNode: tslFn() has been renamed to Fn().' ); + return Fn( ...params ); + +}; + +// + +addMethodChaining( 'toGlobal', ( node ) => { + + node.global = true; + + return node; + +} ); + +// + +const setCurrentStack = ( stack ) => { + + currentStack = stack; + +}; + +const getCurrentStack = () => currentStack; + +const If = ( ...params ) => currentStack.If( ...params ); + +function append( node ) { + + if ( currentStack ) currentStack.add( node ); + + return node; + +} + +addMethodChaining( 'append', append ); + +// types + +const color = new ConvertType( 'color' ); + +const float = new ConvertType( 'float', cacheMaps.float ); +const int = new ConvertType( 'int', cacheMaps.ints ); +const uint = new ConvertType( 'uint', cacheMaps.uint ); +const bool = new ConvertType( 'bool', cacheMaps.bool ); + +const vec2 = new ConvertType( 'vec2' ); +const ivec2 = new ConvertType( 'ivec2' ); +const uvec2 = new ConvertType( 'uvec2' ); +const bvec2 = new ConvertType( 'bvec2' ); + +const vec3 = new ConvertType( 'vec3' ); +const ivec3 = new ConvertType( 'ivec3' ); +const uvec3 = new ConvertType( 'uvec3' ); +const bvec3 = new ConvertType( 'bvec3' ); + +const vec4 = new ConvertType( 'vec4' ); +const ivec4 = new ConvertType( 'ivec4' ); +const uvec4 = new ConvertType( 'uvec4' ); +const bvec4 = new ConvertType( 'bvec4' ); + +const mat2 = new ConvertType( 'mat2' ); +const mat3 = new ConvertType( 'mat3' ); +const mat4 = new ConvertType( 'mat4' ); + +const string = ( value = '' ) => nodeObject( new ConstNode( value, 'string' ) ); +const arrayBuffer = ( value ) => nodeObject( new ConstNode( value, 'ArrayBuffer' ) ); + +addMethodChaining( 'toColor', color ); +addMethodChaining( 'toFloat', float ); +addMethodChaining( 'toInt', int ); +addMethodChaining( 'toUint', uint ); +addMethodChaining( 'toBool', bool ); +addMethodChaining( 'toVec2', vec2 ); +addMethodChaining( 'toIVec2', ivec2 ); +addMethodChaining( 'toUVec2', uvec2 ); +addMethodChaining( 'toBVec2', bvec2 ); +addMethodChaining( 'toVec3', vec3 ); +addMethodChaining( 'toIVec3', ivec3 ); +addMethodChaining( 'toUVec3', uvec3 ); +addMethodChaining( 'toBVec3', bvec3 ); +addMethodChaining( 'toVec4', vec4 ); +addMethodChaining( 'toIVec4', ivec4 ); +addMethodChaining( 'toUVec4', uvec4 ); +addMethodChaining( 'toBVec4', bvec4 ); +addMethodChaining( 'toMat2', mat2 ); +addMethodChaining( 'toMat3', mat3 ); +addMethodChaining( 'toMat4', mat4 ); + +// basic nodes + +const element = /*@__PURE__*/ nodeProxy( ArrayElementNode ); +const convert = ( node, types ) => nodeObject( new ConvertNode( nodeObject( node ), types ) ); +const split = ( node, channels ) => nodeObject( new SplitNode( nodeObject( node ), channels ) ); + +addMethodChaining( 'element', element ); +addMethodChaining( 'convert', convert ); + +class UniformGroupNode extends Node { + + static get type() { + + return 'UniformGroupNode'; + + } + + constructor( name, shared = false, order = 1 ) { + + super( 'string' ); + + this.name = name; + this.version = 0; + + this.shared = shared; + this.order = order; + this.isUniformGroup = true; + + } + + set needsUpdate( value ) { + + if ( value === true ) this.version ++; + + } + + serialize( data ) { + + super.serialize( data ); + + data.name = this.name; + data.version = this.version; + data.shared = this.shared; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.name = data.name; + this.version = data.version; + this.shared = data.shared; + + } + +} + +const uniformGroup = ( name ) => new UniformGroupNode( name ); +const sharedUniformGroup = ( name, order = 0 ) => new UniformGroupNode( name, true, order ); + +const frameGroup = /*@__PURE__*/ sharedUniformGroup( 'frame' ); +const renderGroup = /*@__PURE__*/ sharedUniformGroup( 'render' ); +const objectGroup = /*@__PURE__*/ uniformGroup( 'object' ); + +class UniformNode extends InputNode { + + static get type() { + + return 'UniformNode'; + + } + + constructor( value, nodeType = null ) { + + super( value, nodeType ); + + this.isUniformNode = true; + + this.name = ''; + this.groupNode = objectGroup; + + } + + label( name ) { + + this.name = name; + + return this; + + } + + setGroup( group ) { + + this.groupNode = group; + + return this; + + } + + getGroup() { + + return this.groupNode; + + } + + getUniformHash( builder ) { + + return this.getHash( builder ); + + } + + onUpdate( callback, updateType ) { + + const self = this.getSelf(); + + callback = callback.bind( self ); + + return super.onUpdate( ( frame ) => { + + const value = callback( frame, self ); + + if ( value !== undefined ) { + + this.value = value; + + } + + }, updateType ); + + } + + generate( builder, output ) { + + const type = this.getNodeType( builder ); + + const hash = this.getUniformHash( builder ); + + let sharedNode = builder.getNodeFromHash( hash ); + + if ( sharedNode === undefined ) { + + builder.setHashNode( this, hash ); + + sharedNode = this; + + } + + const sharedNodeType = sharedNode.getInputType( builder ); + + const nodeUniform = builder.getUniformFromNode( sharedNode, sharedNodeType, builder.shaderStage, this.name || builder.context.label ); + const propertyName = builder.getPropertyName( nodeUniform ); + + if ( builder.context.label !== undefined ) delete builder.context.label; + + return builder.format( propertyName, type, output ); + + } + +} + +const uniform = ( arg1, arg2 ) => { + + const nodeType = getConstNodeType( arg2 || arg1 ); + + // @TODO: get ConstNode from .traverse() in the future + const value = ( arg1 && arg1.isNode === true ) ? ( arg1.node && arg1.node.value ) || arg1.value : arg1; + + return nodeObject( new UniformNode( value, nodeType ) ); + +}; + +class PropertyNode extends Node { + + static get type() { + + return 'PropertyNode'; + + } + + constructor( nodeType, name = null, varying = false ) { + + super( nodeType ); + + this.name = name; + this.varying = varying; + + this.isPropertyNode = true; + + } + + getHash( builder ) { + + return this.name || super.getHash( builder ); + + } + + isGlobal( /*builder*/ ) { + + return true; + + } + + generate( builder ) { + + let nodeVar; + + if ( this.varying === true ) { + + nodeVar = builder.getVaryingFromNode( this, this.name ); + nodeVar.needsInterpolation = true; + + } else { + + nodeVar = builder.getVarFromNode( this, this.name ); + + } + + return builder.getPropertyName( nodeVar ); + + } + +} + +const property = ( type, name ) => nodeObject( new PropertyNode( type, name ) ); +const varyingProperty = ( type, name ) => nodeObject( new PropertyNode( type, name, true ) ); + +const diffuseColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec4', 'DiffuseColor' ); +const emissive = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'EmissiveColor' ); +const roughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Roughness' ); +const metalness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Metalness' ); +const clearcoat = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Clearcoat' ); +const clearcoatRoughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'ClearcoatRoughness' ); +const sheen = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'Sheen' ); +const sheenRoughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'SheenRoughness' ); +const iridescence = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Iridescence' ); +const iridescenceIOR = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IridescenceIOR' ); +const iridescenceThickness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IridescenceThickness' ); +const alphaT = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'AlphaT' ); +const anisotropy = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Anisotropy' ); +const anisotropyT = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'AnisotropyT' ); +const anisotropyB = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'AnisotropyB' ); +const specularColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'color', 'SpecularColor' ); +const specularF90 = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'SpecularF90' ); +const shininess = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Shininess' ); +const output = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec4', 'Output' ); +const dashSize = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'dashSize' ); +const gapSize = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'gapSize' ); +const pointWidth = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'pointWidth' ); +const ior = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IOR' ); +const transmission = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Transmission' ); +const thickness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Thickness' ); +const attenuationDistance = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'AttenuationDistance' ); +const attenuationColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'color', 'AttenuationColor' ); +const dispersion = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Dispersion' ); + +class AssignNode extends TempNode { + + static get type() { + + return 'AssignNode'; + + } + + constructor( targetNode, sourceNode ) { + + super(); + + this.targetNode = targetNode; + this.sourceNode = sourceNode; + + } + + hasDependencies() { + + return false; + + } + + getNodeType( builder, output ) { + + return output !== 'void' ? this.targetNode.getNodeType( builder ) : 'void'; + + } + + needsSplitAssign( builder ) { + + const { targetNode } = this; + + if ( builder.isAvailable( 'swizzleAssign' ) === false && targetNode.isSplitNode && targetNode.components.length > 1 ) { + + const targetLength = builder.getTypeLength( targetNode.node.getNodeType( builder ) ); + const assignDiferentVector = vectorComponents.join( '' ).slice( 0, targetLength ) !== targetNode.components; + + return assignDiferentVector; + + } + + return false; + + } + + generate( builder, output ) { + + const { targetNode, sourceNode } = this; + + const needsSplitAssign = this.needsSplitAssign( builder ); + + const targetType = targetNode.getNodeType( builder ); + + const target = targetNode.context( { assign: true } ).build( builder ); + const source = sourceNode.build( builder, targetType ); + + const sourceType = sourceNode.getNodeType( builder ); + + const nodeData = builder.getDataFromNode( this ); + + // + + let snippet; + + if ( nodeData.initialized === true ) { + + if ( output !== 'void' ) { + + snippet = target; + + } + + } else if ( needsSplitAssign ) { + + const sourceVar = builder.getVarFromNode( this, null, targetType ); + const sourceProperty = builder.getPropertyName( sourceVar ); + + builder.addLineFlowCode( `${ sourceProperty } = ${ source }`, this ); + + const targetRoot = targetNode.node.context( { assign: true } ).build( builder ); + + for ( let i = 0; i < targetNode.components.length; i ++ ) { + + const component = targetNode.components[ i ]; + + builder.addLineFlowCode( `${ targetRoot }.${ component } = ${ sourceProperty }[ ${ i } ]`, this ); + + } + + if ( output !== 'void' ) { + + snippet = target; + + } + + } else { + + snippet = `${ target } = ${ source }`; + + if ( output === 'void' || sourceType === 'void' ) { + + builder.addLineFlowCode( snippet, this ); + + if ( output !== 'void' ) { + + snippet = target; + + } + + } + + } + + nodeData.initialized = true; + + return builder.format( snippet, targetType, output ); + + } + +} + +const assign = /*@__PURE__*/ nodeProxy( AssignNode ); + +addMethodChaining( 'assign', assign ); + +class FunctionCallNode extends TempNode { + + static get type() { + + return 'FunctionCallNode'; + + } + + constructor( functionNode = null, parameters = {} ) { + + super(); + + this.functionNode = functionNode; + this.parameters = parameters; + + } + + setParameters( parameters ) { + + this.parameters = parameters; + + return this; + + } + + getParameters() { + + return this.parameters; + + } + + getNodeType( builder ) { + + return this.functionNode.getNodeType( builder ); + + } + + generate( builder ) { + + const params = []; + + const functionNode = this.functionNode; + + const inputs = functionNode.getInputs( builder ); + const parameters = this.parameters; + + if ( Array.isArray( parameters ) ) { + + for ( let i = 0; i < parameters.length; i ++ ) { + + const inputNode = inputs[ i ]; + const node = parameters[ i ]; + + params.push( node.build( builder, inputNode.type ) ); + + } + + } else { + + for ( const inputNode of inputs ) { + + const node = parameters[ inputNode.name ]; + + if ( node !== undefined ) { + + params.push( node.build( builder, inputNode.type ) ); + + } else { + + throw new Error( `FunctionCallNode: Input '${inputNode.name}' not found in FunctionNode.` ); + + } + + } + + } + + const functionName = functionNode.build( builder, 'property' ); + + return `${functionName}( ${params.join( ', ' )} )`; + + } + +} + +const call = ( func, ...params ) => { + + params = params.length > 1 || ( params[ 0 ] && params[ 0 ].isNode === true ) ? nodeArray( params ) : nodeObjects( params[ 0 ] ); + + return nodeObject( new FunctionCallNode( nodeObject( func ), params ) ); + +}; + +addMethodChaining( 'call', call ); + +class OperatorNode extends TempNode { + + static get type() { + + return 'OperatorNode'; + + } + + constructor( op, aNode, bNode, ...params ) { + + super(); + + if ( params.length > 0 ) { + + let finalOp = new OperatorNode( op, aNode, bNode ); + + for ( let i = 0; i < params.length - 1; i ++ ) { + + finalOp = new OperatorNode( op, finalOp, params[ i ] ); + + } + + aNode = finalOp; + bNode = params[ params.length - 1 ]; + + } + + this.op = op; + this.aNode = aNode; + this.bNode = bNode; + + } + + getNodeType( builder, output ) { + + const op = this.op; + + const aNode = this.aNode; + const bNode = this.bNode; + + const typeA = aNode.getNodeType( builder ); + const typeB = typeof bNode !== 'undefined' ? bNode.getNodeType( builder ) : null; + + if ( typeA === 'void' || typeB === 'void' ) { + + return 'void'; + + } else if ( op === '%' ) { + + return typeA; + + } else if ( op === '~' || op === '&' || op === '|' || op === '^' || op === '>>' || op === '<<' ) { + + return builder.getIntegerType( typeA ); + + } else if ( op === '!' || op === '==' || op === '&&' || op === '||' || op === '^^' ) { + + return 'bool'; + + } else if ( op === '<' || op === '>' || op === '<=' || op === '>=' ) { + + const typeLength = output ? builder.getTypeLength( output ) : Math.max( builder.getTypeLength( typeA ), builder.getTypeLength( typeB ) ); + + return typeLength > 1 ? `bvec${ typeLength }` : 'bool'; + + } else { + + if ( typeA === 'float' && builder.isMatrix( typeB ) ) { + + return typeB; + + } else if ( builder.isMatrix( typeA ) && builder.isVector( typeB ) ) { + + // matrix x vector + + return builder.getVectorFromMatrix( typeA ); + + } else if ( builder.isVector( typeA ) && builder.isMatrix( typeB ) ) { + + // vector x matrix + + return builder.getVectorFromMatrix( typeB ); + + } else if ( builder.getTypeLength( typeB ) > builder.getTypeLength( typeA ) ) { + + // anytype x anytype: use the greater length vector + + return typeB; + + } + + return typeA; + + } + + } + + generate( builder, output ) { + + const op = this.op; + + const aNode = this.aNode; + const bNode = this.bNode; + + const type = this.getNodeType( builder, output ); + + let typeA = null; + let typeB = null; + + if ( type !== 'void' ) { + + typeA = aNode.getNodeType( builder ); + typeB = typeof bNode !== 'undefined' ? bNode.getNodeType( builder ) : null; + + if ( op === '<' || op === '>' || op === '<=' || op === '>=' || op === '==' ) { + + if ( builder.isVector( typeA ) ) { + + typeB = typeA; + + } else if ( typeA !== typeB ) { + + typeA = typeB = 'float'; + + } + + } else if ( op === '>>' || op === '<<' ) { + + typeA = type; + typeB = builder.changeComponentType( typeB, 'uint' ); + + } else if ( builder.isMatrix( typeA ) && builder.isVector( typeB ) ) { + + // matrix x vector + + typeB = builder.getVectorFromMatrix( typeA ); + + } else if ( builder.isVector( typeA ) && builder.isMatrix( typeB ) ) { + + // vector x matrix + + typeA = builder.getVectorFromMatrix( typeB ); + + } else { + + // anytype x anytype + + typeA = typeB = type; + + } + + } else { + + typeA = typeB = type; + + } + + const a = aNode.build( builder, typeA ); + const b = typeof bNode !== 'undefined' ? bNode.build( builder, typeB ) : null; + + const outputLength = builder.getTypeLength( output ); + const fnOpSnippet = builder.getFunctionOperator( op ); + + if ( output !== 'void' ) { + + if ( op === '<' && outputLength > 1 ) { + + if ( builder.useComparisonMethod ) { + + return builder.format( `${ builder.getMethod( 'lessThan', output ) }( ${ a }, ${ b } )`, type, output ); + + } else { + + return builder.format( `( ${ a } < ${ b } )`, type, output ); + + } + + } else if ( op === '<=' && outputLength > 1 ) { + + if ( builder.useComparisonMethod ) { + + return builder.format( `${ builder.getMethod( 'lessThanEqual', output ) }( ${ a }, ${ b } )`, type, output ); + + } else { + + return builder.format( `( ${ a } <= ${ b } )`, type, output ); + + } + + } else if ( op === '>' && outputLength > 1 ) { + + if ( builder.useComparisonMethod ) { + + return builder.format( `${ builder.getMethod( 'greaterThan', output ) }( ${ a }, ${ b } )`, type, output ); + + } else { + + return builder.format( `( ${ a } > ${ b } )`, type, output ); + + } + + } else if ( op === '>=' && outputLength > 1 ) { + + if ( builder.useComparisonMethod ) { + + return builder.format( `${ builder.getMethod( 'greaterThanEqual', output ) }( ${ a }, ${ b } )`, type, output ); + + } else { + + return builder.format( `( ${ a } >= ${ b } )`, type, output ); + + } + + } else if ( op === '!' || op === '~' ) { + + return builder.format( `(${op}${a})`, typeA, output ); + + } else if ( fnOpSnippet ) { + + return builder.format( `${ fnOpSnippet }( ${ a }, ${ b } )`, type, output ); + + } else { + + return builder.format( `( ${ a } ${ op } ${ b } )`, type, output ); + + } + + } else if ( typeA !== 'void' ) { + + if ( fnOpSnippet ) { + + return builder.format( `${ fnOpSnippet }( ${ a }, ${ b } )`, type, output ); + + } else { + + return builder.format( `${ a } ${ op } ${ b }`, type, output ); + + } + + } + + } + + serialize( data ) { + + super.serialize( data ); + + data.op = this.op; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.op = data.op; + + } + +} + +const add = /*@__PURE__*/ nodeProxy( OperatorNode, '+' ); +const sub = /*@__PURE__*/ nodeProxy( OperatorNode, '-' ); +const mul = /*@__PURE__*/ nodeProxy( OperatorNode, '*' ); +const div = /*@__PURE__*/ nodeProxy( OperatorNode, '/' ); +const modInt = /*@__PURE__*/ nodeProxy( OperatorNode, '%' ); +const equal = /*@__PURE__*/ nodeProxy( OperatorNode, '==' ); +const notEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '!=' ); +const lessThan = /*@__PURE__*/ nodeProxy( OperatorNode, '<' ); +const greaterThan = /*@__PURE__*/ nodeProxy( OperatorNode, '>' ); +const lessThanEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '<=' ); +const greaterThanEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '>=' ); +const and = /*@__PURE__*/ nodeProxy( OperatorNode, '&&' ); +const or = /*@__PURE__*/ nodeProxy( OperatorNode, '||' ); +const not = /*@__PURE__*/ nodeProxy( OperatorNode, '!' ); +const xor = /*@__PURE__*/ nodeProxy( OperatorNode, '^^' ); +const bitAnd = /*@__PURE__*/ nodeProxy( OperatorNode, '&' ); +const bitNot = /*@__PURE__*/ nodeProxy( OperatorNode, '~' ); +const bitOr = /*@__PURE__*/ nodeProxy( OperatorNode, '|' ); +const bitXor = /*@__PURE__*/ nodeProxy( OperatorNode, '^' ); +const shiftLeft = /*@__PURE__*/ nodeProxy( OperatorNode, '<<' ); +const shiftRight = /*@__PURE__*/ nodeProxy( OperatorNode, '>>' ); + +addMethodChaining( 'add', add ); +addMethodChaining( 'sub', sub ); +addMethodChaining( 'mul', mul ); +addMethodChaining( 'div', div ); +addMethodChaining( 'modInt', modInt ); +addMethodChaining( 'equal', equal ); +addMethodChaining( 'notEqual', notEqual ); +addMethodChaining( 'lessThan', lessThan ); +addMethodChaining( 'greaterThan', greaterThan ); +addMethodChaining( 'lessThanEqual', lessThanEqual ); +addMethodChaining( 'greaterThanEqual', greaterThanEqual ); +addMethodChaining( 'and', and ); +addMethodChaining( 'or', or ); +addMethodChaining( 'not', not ); +addMethodChaining( 'xor', xor ); +addMethodChaining( 'bitAnd', bitAnd ); +addMethodChaining( 'bitNot', bitNot ); +addMethodChaining( 'bitOr', bitOr ); +addMethodChaining( 'bitXor', bitXor ); +addMethodChaining( 'shiftLeft', shiftLeft ); +addMethodChaining( 'shiftRight', shiftRight ); + + +const remainder = ( ...params ) => { // @deprecated, r168 + + console.warn( 'TSL.OperatorNode: .remainder() has been renamed to .modInt().' ); + return modInt( ...params ); + +}; + +addMethodChaining( 'remainder', remainder ); + +class MathNode extends TempNode { + + static get type() { + + return 'MathNode'; + + } + + constructor( method, aNode, bNode = null, cNode = null ) { + + super(); + + this.method = method; + + this.aNode = aNode; + this.bNode = bNode; + this.cNode = cNode; + + } + + getInputType( builder ) { + + const aType = this.aNode.getNodeType( builder ); + const bType = this.bNode ? this.bNode.getNodeType( builder ) : null; + const cType = this.cNode ? this.cNode.getNodeType( builder ) : null; + + const aLen = builder.isMatrix( aType ) ? 0 : builder.getTypeLength( aType ); + const bLen = builder.isMatrix( bType ) ? 0 : builder.getTypeLength( bType ); + const cLen = builder.isMatrix( cType ) ? 0 : builder.getTypeLength( cType ); + + if ( aLen > bLen && aLen > cLen ) { + + return aType; + + } else if ( bLen > cLen ) { + + return bType; + + } else if ( cLen > aLen ) { + + return cType; + + } + + return aType; + + } + + getNodeType( builder ) { + + const method = this.method; + + if ( method === MathNode.LENGTH || method === MathNode.DISTANCE || method === MathNode.DOT ) { + + return 'float'; + + } else if ( method === MathNode.CROSS ) { + + return 'vec3'; + + } else if ( method === MathNode.ALL ) { + + return 'bool'; + + } else if ( method === MathNode.EQUALS ) { + + return builder.changeComponentType( this.aNode.getNodeType( builder ), 'bool' ); + + } else if ( method === MathNode.MOD ) { + + return this.aNode.getNodeType( builder ); + + } else { + + return this.getInputType( builder ); + + } + + } + + generate( builder, output ) { + + const method = this.method; + + const type = this.getNodeType( builder ); + const inputType = this.getInputType( builder ); + + const a = this.aNode; + const b = this.bNode; + const c = this.cNode; + + const isWebGL = builder.renderer.isWebGLRenderer === true; + + if ( method === MathNode.TRANSFORM_DIRECTION ) { + + // dir can be either a direction vector or a normal vector + // upper-left 3x3 of matrix is assumed to be orthogonal + + let tA = a; + let tB = b; + + if ( builder.isMatrix( tA.getNodeType( builder ) ) ) { + + tB = vec4( vec3( tB ), 0.0 ); + + } else { + + tA = vec4( vec3( tA ), 0.0 ); + + } + + const mulNode = mul( tA, tB ).xyz; + + return normalize( mulNode ).build( builder, output ); + + } else if ( method === MathNode.NEGATE ) { + + return builder.format( '( - ' + a.build( builder, inputType ) + ' )', type, output ); + + } else if ( method === MathNode.ONE_MINUS ) { + + return sub( 1.0, a ).build( builder, output ); + + } else if ( method === MathNode.RECIPROCAL ) { + + return div( 1.0, a ).build( builder, output ); + + } else if ( method === MathNode.DIFFERENCE ) { + + return abs( sub( a, b ) ).build( builder, output ); + + } else { + + const params = []; + + if ( method === MathNode.CROSS || method === MathNode.MOD ) { + + params.push( + a.build( builder, type ), + b.build( builder, type ) + ); + + } else if ( isWebGL && method === MathNode.STEP ) { + + params.push( + a.build( builder, builder.getTypeLength( a.getNodeType( builder ) ) === 1 ? 'float' : inputType ), + b.build( builder, inputType ) + ); + + } else if ( ( isWebGL && ( method === MathNode.MIN || method === MathNode.MAX ) ) || method === MathNode.MOD ) { + + params.push( + a.build( builder, inputType ), + b.build( builder, builder.getTypeLength( b.getNodeType( builder ) ) === 1 ? 'float' : inputType ) + ); + + } else if ( method === MathNode.REFRACT ) { + + params.push( + a.build( builder, inputType ), + b.build( builder, inputType ), + c.build( builder, 'float' ) + ); + + } else if ( method === MathNode.MIX ) { + + params.push( + a.build( builder, inputType ), + b.build( builder, inputType ), + c.build( builder, builder.getTypeLength( c.getNodeType( builder ) ) === 1 ? 'float' : inputType ) + ); + + } else { + + params.push( a.build( builder, inputType ) ); + if ( b !== null ) params.push( b.build( builder, inputType ) ); + if ( c !== null ) params.push( c.build( builder, inputType ) ); + + } + + return builder.format( `${ builder.getMethod( method, type ) }( ${params.join( ', ' )} )`, type, output ); + + } + + } + + serialize( data ) { + + super.serialize( data ); + + data.method = this.method; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.method = data.method; + + } + +} + +// 1 input + +MathNode.ALL = 'all'; +MathNode.ANY = 'any'; +MathNode.EQUALS = 'equals'; + +MathNode.RADIANS = 'radians'; +MathNode.DEGREES = 'degrees'; +MathNode.EXP = 'exp'; +MathNode.EXP2 = 'exp2'; +MathNode.LOG = 'log'; +MathNode.LOG2 = 'log2'; +MathNode.SQRT = 'sqrt'; +MathNode.INVERSE_SQRT = 'inversesqrt'; +MathNode.FLOOR = 'floor'; +MathNode.CEIL = 'ceil'; +MathNode.NORMALIZE = 'normalize'; +MathNode.FRACT = 'fract'; +MathNode.SIN = 'sin'; +MathNode.COS = 'cos'; +MathNode.TAN = 'tan'; +MathNode.ASIN = 'asin'; +MathNode.ACOS = 'acos'; +MathNode.ATAN = 'atan'; +MathNode.ABS = 'abs'; +MathNode.SIGN = 'sign'; +MathNode.LENGTH = 'length'; +MathNode.NEGATE = 'negate'; +MathNode.ONE_MINUS = 'oneMinus'; +MathNode.DFDX = 'dFdx'; +MathNode.DFDY = 'dFdy'; +MathNode.ROUND = 'round'; +MathNode.RECIPROCAL = 'reciprocal'; +MathNode.TRUNC = 'trunc'; +MathNode.FWIDTH = 'fwidth'; +MathNode.BITCAST = 'bitcast'; +MathNode.TRANSPOSE = 'transpose'; + +// 2 inputs + +MathNode.ATAN2 = 'atan2'; +MathNode.MIN = 'min'; +MathNode.MAX = 'max'; +MathNode.MOD = 'mod'; +MathNode.STEP = 'step'; +MathNode.REFLECT = 'reflect'; +MathNode.DISTANCE = 'distance'; +MathNode.DIFFERENCE = 'difference'; +MathNode.DOT = 'dot'; +MathNode.CROSS = 'cross'; +MathNode.POW = 'pow'; +MathNode.TRANSFORM_DIRECTION = 'transformDirection'; + +// 3 inputs + +MathNode.MIX = 'mix'; +MathNode.CLAMP = 'clamp'; +MathNode.REFRACT = 'refract'; +MathNode.SMOOTHSTEP = 'smoothstep'; +MathNode.FACEFORWARD = 'faceforward'; + +const EPSILON = /*@__PURE__*/ float( 1e-6 ); +const INFINITY = /*@__PURE__*/ float( 1e6 ); +const PI = /*@__PURE__*/ float( Math.PI ); +const PI2 = /*@__PURE__*/ float( Math.PI * 2 ); + +const all = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ALL ); +const any = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ANY ); +const equals = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EQUALS ); + +const radians = /*@__PURE__*/ nodeProxy( MathNode, MathNode.RADIANS ); +const degrees = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DEGREES ); +const exp = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EXP ); +const exp2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EXP2 ); +const log = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LOG ); +const log2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LOG2 ); +const sqrt = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SQRT ); +const inverseSqrt = /*@__PURE__*/ nodeProxy( MathNode, MathNode.INVERSE_SQRT ); +const floor = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FLOOR ); +const ceil = /*@__PURE__*/ nodeProxy( MathNode, MathNode.CEIL ); +const normalize = /*@__PURE__*/ nodeProxy( MathNode, MathNode.NORMALIZE ); +const fract = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FRACT ); +const sin = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SIN ); +const cos = /*@__PURE__*/ nodeProxy( MathNode, MathNode.COS ); +const tan = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TAN ); +const asin = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ASIN ); +const acos = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ACOS ); +const atan = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ATAN ); +const abs = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ABS ); +const sign = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SIGN ); +const length = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LENGTH ); +const negate = /*@__PURE__*/ nodeProxy( MathNode, MathNode.NEGATE ); +const oneMinus = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ONE_MINUS ); +const dFdx = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DFDX ); +const dFdy = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DFDY ); +const round = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ROUND ); +const reciprocal = /*@__PURE__*/ nodeProxy( MathNode, MathNode.RECIPROCAL ); +const trunc = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRUNC ); +const fwidth = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FWIDTH ); +const bitcast = /*@__PURE__*/ nodeProxy( MathNode, MathNode.BITCAST ); +const transpose = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRANSPOSE ); + +const atan2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ATAN2 ); +const min$1 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MIN ); +const max$1 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MAX ); +const mod = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MOD ); +const step = /*@__PURE__*/ nodeProxy( MathNode, MathNode.STEP ); +const reflect = /*@__PURE__*/ nodeProxy( MathNode, MathNode.REFLECT ); +const distance = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DISTANCE ); +const difference = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DIFFERENCE ); +const dot = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DOT ); +const cross = /*@__PURE__*/ nodeProxy( MathNode, MathNode.CROSS ); +const pow = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW ); +const pow2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 2 ); +const pow3 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 3 ); +const pow4 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 4 ); +const transformDirection = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRANSFORM_DIRECTION ); + +const cbrt = ( a ) => mul( sign( a ), pow( abs( a ), 1.0 / 3.0 ) ); +const lengthSq = ( a ) => dot( a, a ); +const mix = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MIX ); +const clamp = ( value, low = 0, high = 1 ) => nodeObject( new MathNode( MathNode.CLAMP, nodeObject( value ), nodeObject( low ), nodeObject( high ) ) ); +const saturate = ( value ) => clamp( value ); +const refract = /*@__PURE__*/ nodeProxy( MathNode, MathNode.REFRACT ); +const smoothstep = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SMOOTHSTEP ); +const faceForward = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FACEFORWARD ); + +const rand = /*@__PURE__*/ Fn( ( [ uv ] ) => { + + const a = 12.9898, b = 78.233, c = 43758.5453; + const dt = dot( uv.xy, vec2( a, b ) ), sn = mod( dt, PI ); + + return fract( sin( sn ).mul( c ) ); + +} ); + +const mixElement = ( t, e1, e2 ) => mix( e1, e2, t ); +const smoothstepElement = ( x, low, high ) => smoothstep( low, high, x ); + +addMethodChaining( 'all', all ); +addMethodChaining( 'any', any ); +addMethodChaining( 'equals', equals ); + +addMethodChaining( 'radians', radians ); +addMethodChaining( 'degrees', degrees ); +addMethodChaining( 'exp', exp ); +addMethodChaining( 'exp2', exp2 ); +addMethodChaining( 'log', log ); +addMethodChaining( 'log2', log2 ); +addMethodChaining( 'sqrt', sqrt ); +addMethodChaining( 'inverseSqrt', inverseSqrt ); +addMethodChaining( 'floor', floor ); +addMethodChaining( 'ceil', ceil ); +addMethodChaining( 'normalize', normalize ); +addMethodChaining( 'fract', fract ); +addMethodChaining( 'sin', sin ); +addMethodChaining( 'cos', cos ); +addMethodChaining( 'tan', tan ); +addMethodChaining( 'asin', asin ); +addMethodChaining( 'acos', acos ); +addMethodChaining( 'atan', atan ); +addMethodChaining( 'abs', abs ); +addMethodChaining( 'sign', sign ); +addMethodChaining( 'length', length ); +addMethodChaining( 'lengthSq', lengthSq ); +addMethodChaining( 'negate', negate ); +addMethodChaining( 'oneMinus', oneMinus ); +addMethodChaining( 'dFdx', dFdx ); +addMethodChaining( 'dFdy', dFdy ); +addMethodChaining( 'round', round ); +addMethodChaining( 'reciprocal', reciprocal ); +addMethodChaining( 'trunc', trunc ); +addMethodChaining( 'fwidth', fwidth ); +addMethodChaining( 'atan2', atan2 ); +addMethodChaining( 'min', min$1 ); +addMethodChaining( 'max', max$1 ); +addMethodChaining( 'mod', mod ); +addMethodChaining( 'step', step ); +addMethodChaining( 'reflect', reflect ); +addMethodChaining( 'distance', distance ); +addMethodChaining( 'dot', dot ); +addMethodChaining( 'cross', cross ); +addMethodChaining( 'pow', pow ); +addMethodChaining( 'pow2', pow2 ); +addMethodChaining( 'pow3', pow3 ); +addMethodChaining( 'pow4', pow4 ); +addMethodChaining( 'transformDirection', transformDirection ); +addMethodChaining( 'mix', mixElement ); +addMethodChaining( 'clamp', clamp ); +addMethodChaining( 'refract', refract ); +addMethodChaining( 'smoothstep', smoothstepElement ); +addMethodChaining( 'faceForward', faceForward ); +addMethodChaining( 'difference', difference ); +addMethodChaining( 'saturate', saturate ); +addMethodChaining( 'cbrt', cbrt ); +addMethodChaining( 'transpose', transpose ); +addMethodChaining( 'rand', rand ); + +class ConditionalNode extends Node { + + static get type() { + + return 'ConditionalNode'; + + } + + constructor( condNode, ifNode, elseNode = null ) { + + super(); + + this.condNode = condNode; + + this.ifNode = ifNode; + this.elseNode = elseNode; + + } + + getNodeType( builder ) { + + const ifType = this.ifNode.getNodeType( builder ); + + if ( this.elseNode !== null ) { + + const elseType = this.elseNode.getNodeType( builder ); + + if ( builder.getTypeLength( elseType ) > builder.getTypeLength( ifType ) ) { + + return elseType; + + } + + } + + return ifType; + + } + + setup( builder ) { + + const condNode = this.condNode.cache(); + const ifNode = this.ifNode.cache(); + const elseNode = this.elseNode ? this.elseNode.cache() : null; + + // + + const currentNodeBlock = builder.context.nodeBlock; + + builder.getDataFromNode( ifNode ).parentNodeBlock = currentNodeBlock; + if ( elseNode !== null ) builder.getDataFromNode( elseNode ).parentNodeBlock = currentNodeBlock; + + // + + const properties = builder.getNodeProperties( this ); + properties.condNode = condNode; + properties.ifNode = ifNode.context( { nodeBlock: ifNode } ); + properties.elseNode = elseNode ? elseNode.context( { nodeBlock: elseNode } ) : null; + + } + + generate( builder, output ) { + + const type = this.getNodeType( builder ); + + const nodeData = builder.getDataFromNode( this ); + + if ( nodeData.nodeProperty !== undefined ) { + + return nodeData.nodeProperty; + + } + + const { condNode, ifNode, elseNode } = builder.getNodeProperties( this ); + + const needsOutput = output !== 'void'; + const nodeProperty = needsOutput ? property( type ).build( builder ) : ''; + + nodeData.nodeProperty = nodeProperty; + + const nodeSnippet = condNode.build( builder, 'bool' ); + + builder.addFlowCode( `\n${ builder.tab }if ( ${ nodeSnippet } ) {\n\n` ).addFlowTab(); + + let ifSnippet = ifNode.build( builder, type ); + + if ( ifSnippet ) { + + if ( needsOutput ) { + + ifSnippet = nodeProperty + ' = ' + ifSnippet + ';'; + + } else { + + ifSnippet = 'return ' + ifSnippet + ';'; + + } + + } + + builder.removeFlowTab().addFlowCode( builder.tab + '\t' + ifSnippet + '\n\n' + builder.tab + '}' ); + + if ( elseNode !== null ) { + + builder.addFlowCode( ' else {\n\n' ).addFlowTab(); + + let elseSnippet = elseNode.build( builder, type ); + + if ( elseSnippet ) { + + if ( needsOutput ) { + + elseSnippet = nodeProperty + ' = ' + elseSnippet + ';'; + + } else { + + elseSnippet = 'return ' + elseSnippet + ';'; + + } + + } + + builder.removeFlowTab().addFlowCode( builder.tab + '\t' + elseSnippet + '\n\n' + builder.tab + '}\n\n' ); + + } else { + + builder.addFlowCode( '\n\n' ); + + } + + return builder.format( nodeProperty, type, output ); + + } + +} + +const select = /*@__PURE__*/ nodeProxy( ConditionalNode ); + +addMethodChaining( 'select', select ); + +// + +const cond = ( ...params ) => { // @deprecated, r168 + + console.warn( 'TSL.ConditionalNode: cond() has been renamed to select().' ); + return select( ...params ); + +}; + +addMethodChaining( 'cond', cond ); + +class ContextNode extends Node { + + static get type() { + + return 'ContextNode'; + + } + + constructor( node, value = {} ) { + + super(); + + this.isContextNode = true; + + this.node = node; + this.value = value; + + } + + getScope() { + + return this.node.getScope(); + + } + + getNodeType( builder ) { + + return this.node.getNodeType( builder ); + + } + + analyze( builder ) { + + this.node.build( builder ); + + } + + setup( builder ) { + + const previousContext = builder.getContext(); + + builder.setContext( { ...builder.context, ...this.value } ); + + const node = this.node.build( builder ); + + builder.setContext( previousContext ); + + return node; + + } + + generate( builder, output ) { + + const previousContext = builder.getContext(); + + builder.setContext( { ...builder.context, ...this.value } ); + + const snippet = this.node.build( builder, output ); + + builder.setContext( previousContext ); + + return snippet; + + } + +} + +const context = /*@__PURE__*/ nodeProxy( ContextNode ); +const label = ( node, name ) => context( node, { label: name } ); + +addMethodChaining( 'context', context ); +addMethodChaining( 'label', label ); + +class VarNode extends Node { + + static get type() { + + return 'VarNode'; + + } + + constructor( node, name = null ) { + + super(); + + this.node = node; + this.name = name; + + this.global = true; + + this.isVarNode = true; + + } + + getHash( builder ) { + + return this.name || super.getHash( builder ); + + } + + getNodeType( builder ) { + + return this.node.getNodeType( builder ); + + } + + generate( builder ) { + + const { node, name } = this; + + const nodeVar = builder.getVarFromNode( this, name, builder.getVectorType( this.getNodeType( builder ) ) ); + + const propertyName = builder.getPropertyName( nodeVar ); + + const snippet = node.build( builder, nodeVar.type ); + + builder.addLineFlowCode( `${propertyName} = ${snippet}`, this ); + + return propertyName; + + } + +} + +const temp = /*@__PURE__*/ nodeProxy( VarNode ); + +addMethodChaining( 'temp', temp ); // @TODO: Will be removed in the future +addMethodChaining( 'toVar', ( ...params ) => temp( ...params ).append() ); + +class VaryingNode extends Node { + + static get type() { + + return 'VaryingNode'; + + } + + constructor( node, name = null ) { + + super(); + + this.node = node; + this.name = name; + + this.isVaryingNode = true; + + } + + isGlobal() { + + return true; + + } + + getHash( builder ) { + + return this.name || super.getHash( builder ); + + } + + getNodeType( builder ) { + + // VaryingNode is auto type + + return this.node.getNodeType( builder ); + + } + + setupVarying( builder ) { + + const properties = builder.getNodeProperties( this ); + + let varying = properties.varying; + + if ( varying === undefined ) { + + const name = this.name; + const type = this.getNodeType( builder ); + + properties.varying = varying = builder.getVaryingFromNode( this, name, type ); + properties.node = this.node; + + } + + // this property can be used to check if the varying can be optimized for a variable + varying.needsInterpolation || ( varying.needsInterpolation = ( builder.shaderStage === 'fragment' ) ); + + return varying; + + } + + setup( builder ) { + + this.setupVarying( builder ); + + } + + analyze( builder ) { + + this.setupVarying( builder ); + + return this.node.analyze( builder ); + + } + + generate( builder ) { + + const properties = builder.getNodeProperties( this ); + const varying = this.setupVarying( builder ); + + if ( properties.propertyName === undefined ) { + + const type = this.getNodeType( builder ); + const propertyName = builder.getPropertyName( varying, NodeShaderStage.VERTEX ); + + // force node run in vertex stage + builder.flowNodeFromShaderStage( NodeShaderStage.VERTEX, this.node, type, propertyName ); + + properties.propertyName = propertyName; + + } + + return builder.getPropertyName( varying ); + + } + +} + +const varying = /*@__PURE__*/ nodeProxy( VaryingNode ); + +addMethodChaining( 'varying', varying ); + +const WORKING_COLOR_SPACE = 'WorkingColorSpace'; +const OUTPUT_COLOR_SPACE = 'OutputColorSpace'; + +function getColorSpaceName( colorSpace ) { + + let method = null; + + if ( colorSpace === LinearSRGBColorSpace ) { + + method = 'Linear'; + + } else if ( colorSpace === SRGBColorSpace ) { + + method = 'sRGB'; + + } + + return method; + +} + +function getColorSpaceMethod( source, target ) { + + return getColorSpaceName( source ) + 'To' + getColorSpaceName( target ); + +} + +class ColorSpaceNode extends TempNode { + + static get type() { + + return 'ColorSpaceNode'; + + } + + constructor( colorNode, source, target ) { + + super( 'vec4' ); + + this.colorNode = colorNode; + this.source = source; + this.target = target; + + } + + getColorSpace( builder, colorSpace ) { + + if ( colorSpace === WORKING_COLOR_SPACE ) { + + return ColorManagement.workingColorSpace; + + } else if ( colorSpace === OUTPUT_COLOR_SPACE ) { + + return builder.context.outputColorSpace || builder.renderer.outputColorSpace; + + } + + return colorSpace; + + } + + setup( builder ) { + + const { renderer } = builder; + const { colorNode } = this; + + const source = this.getColorSpace( builder, this.source ); + const target = this.getColorSpace( builder, this.target ); + + if ( source === target ) return colorNode; + + const colorSpace = getColorSpaceMethod( source, target ); + + let outputNode = null; + + const colorSpaceFn = renderer.nodes.library.getColorSpaceFunction( colorSpace ); + + if ( colorSpaceFn !== null ) { + + outputNode = vec4( colorSpaceFn( colorNode.rgb ), colorNode.a ); + + } else { + + console.error( 'ColorSpaceNode: Unsupported Color Space configuration.', colorSpace ); + + outputNode = colorNode; + + } + + return outputNode; + + } + +} + +const toOutputColorSpace = ( node ) => nodeObject( new ColorSpaceNode( nodeObject( node ), WORKING_COLOR_SPACE, OUTPUT_COLOR_SPACE ) ); +const toWorkingColorSpace = ( node ) => nodeObject( new ColorSpaceNode( nodeObject( node ), OUTPUT_COLOR_SPACE, WORKING_COLOR_SPACE ) ); + +const workingToColorSpace = ( node, colorSpace ) => nodeObject( new ColorSpaceNode( nodeObject( node ), WORKING_COLOR_SPACE, colorSpace ) ); +const colorSpaceToWorking = ( node, colorSpace ) => nodeObject( new ColorSpaceNode( nodeObject( node ), colorSpace, WORKING_COLOR_SPACE ) ); + +addMethodChaining( 'toOutputColorSpace', toOutputColorSpace ); +addMethodChaining( 'toWorkingColorSpace', toWorkingColorSpace ); + +addMethodChaining( 'workingToColorSpace', workingToColorSpace ); +addMethodChaining( 'colorSpaceToWorking', colorSpaceToWorking ); + +let ReferenceElementNode$1 = class ReferenceElementNode extends ArrayElementNode { + + static get type() { + + return 'ReferenceElementNode'; + + } + + constructor( referenceNode, indexNode ) { + + super( referenceNode, indexNode ); + + this.referenceNode = referenceNode; + + this.isReferenceElementNode = true; + + } + + getNodeType() { + + return this.referenceNode.uniformType; + + } + + generate( builder ) { + + const snippet = super.generate( builder ); + const arrayType = this.referenceNode.getNodeType(); + const elementType = this.getNodeType(); + + return builder.format( snippet, arrayType, elementType ); + + } + +}; + +class ReferenceBaseNode extends Node { + + static get type() { + + return 'ReferenceBaseNode'; + + } + + constructor( property, uniformType, object = null, count = null ) { + + super(); + + this.property = property; + this.uniformType = uniformType; + this.object = object; + this.count = count; + + this.properties = property.split( '.' ); + this.reference = object; + this.node = null; + this.group = null; + + this.updateType = NodeUpdateType.OBJECT; + + } + + setGroup( group ) { + + this.group = group; + + return this; + + } + + element( indexNode ) { + + return nodeObject( new ReferenceElementNode$1( this, nodeObject( indexNode ) ) ); + + } + + setNodeType( uniformType ) { + + const node = uniform( null, uniformType ).getSelf(); + + if ( this.group !== null ) { + + node.setGroup( this.group ); + + } + + this.node = node; + + } + + getNodeType( builder ) { + + if ( this.node === null ) { + + this.updateReference( builder ); + this.updateValue(); + + } + + return this.node.getNodeType( builder ); + + } + + getValueFromReference( object = this.reference ) { + + const { properties } = this; + + let value = object[ properties[ 0 ] ]; + + for ( let i = 1; i < properties.length; i ++ ) { + + value = value[ properties[ i ] ]; + + } + + return value; + + } + + updateReference( state ) { + + this.reference = this.object !== null ? this.object : state.object; + + return this.reference; + + } + + setup() { + + this.updateValue(); + + return this.node; + + } + + update( /*frame*/ ) { + + this.updateValue(); + + } + + updateValue() { + + if ( this.node === null ) this.setNodeType( this.uniformType ); + + const value = this.getValueFromReference(); + + if ( Array.isArray( value ) ) { + + this.node.array = value; + + } else { + + this.node.value = value; + + } + + } + +} + +const reference$1 = ( name, type, object ) => nodeObject( new ReferenceBaseNode( name, type, object ) ); + +class RendererReferenceNode extends ReferenceBaseNode { + + static get type() { + + return 'RendererReferenceNode'; + + } + + constructor( property, inputType, renderer = null ) { + + super( property, inputType, renderer ); + + this.renderer = renderer; + + this.setGroup( renderGroup ); + + } + + updateReference( state ) { + + this.reference = this.renderer !== null ? this.renderer : state.renderer; + + return this.reference; + + } + +} + +const rendererReference = ( name, type, renderer ) => nodeObject( new RendererReferenceNode( name, type, renderer ) ); + +class ToneMappingNode extends TempNode { + + static get type() { + + return 'ToneMappingNode'; + + } + + constructor( toneMapping, exposureNode = toneMappingExposure, colorNode = null ) { + + super( 'vec3' ); + + this.toneMapping = toneMapping; + + this.exposureNode = exposureNode; + this.colorNode = colorNode; + + } + + getCacheKey() { + + return hash$1( super.getCacheKey(), this.toneMapping ); + + } + + setup( builder ) { + + const colorNode = this.colorNode || builder.context.color; + const toneMapping = this.toneMapping; + + if ( toneMapping === NoToneMapping ) return colorNode; + + let outputNode = null; + + const toneMappingFn = builder.renderer.nodes.library.getToneMappingFunction( toneMapping ); + + if ( toneMappingFn !== null ) { + + outputNode = vec4( toneMappingFn( colorNode.rgb, this.exposureNode ), colorNode.a ); + + } else { + + console.error( 'ToneMappingNode: Unsupported Tone Mapping configuration.', toneMapping ); + + outputNode = colorNode; + + } + + return outputNode; + + } + +} + +const toneMapping = ( mapping, exposure, color ) => nodeObject( new ToneMappingNode( mapping, nodeObject( exposure ), nodeObject( color ) ) ); +const toneMappingExposure = /*@__PURE__*/ rendererReference( 'toneMappingExposure', 'float' ); + +addMethodChaining( 'toneMapping', ( color, mapping, exposure ) => toneMapping( mapping, exposure, color ) ); + +class BufferAttributeNode extends InputNode { + + static get type() { + + return 'BufferAttributeNode'; + + } + + constructor( value, bufferType = null, bufferStride = 0, bufferOffset = 0 ) { + + super( value, bufferType ); + + this.isBufferNode = true; + + this.bufferType = bufferType; + this.bufferStride = bufferStride; + this.bufferOffset = bufferOffset; + + this.usage = StaticDrawUsage; + this.instanced = false; + + this.attribute = null; + + this.global = true; + + if ( value && value.isBufferAttribute === true ) { + + this.attribute = value; + this.usage = value.usage; + this.instanced = value.isInstancedBufferAttribute; + + } + + } + + getHash( builder ) { + + if ( this.bufferStride === 0 && this.bufferOffset === 0 ) { + + let bufferData = builder.globalCache.getData( this.value ); + + if ( bufferData === undefined ) { + + bufferData = { + node: this + }; + + builder.globalCache.setData( this.value, bufferData ); + + } + + return bufferData.node.uuid; + + } + + return this.uuid; + + } + + getNodeType( builder ) { + + if ( this.bufferType === null ) { + + this.bufferType = builder.getTypeFromAttribute( this.attribute ); + + } + + return this.bufferType; + + } + + setup( builder ) { + + if ( this.attribute !== null ) return; + + const type = this.getNodeType( builder ); + const array = this.value; + const itemSize = builder.getTypeLength( type ); + const stride = this.bufferStride || itemSize; + const offset = this.bufferOffset; + + const buffer = array.isInterleavedBuffer === true ? array : new InterleavedBuffer( array, stride ); + const bufferAttribute = new InterleavedBufferAttribute( buffer, itemSize, offset ); + + buffer.setUsage( this.usage ); + + this.attribute = bufferAttribute; + this.attribute.isInstancedBufferAttribute = this.instanced; // @TODO: Add a possible: InstancedInterleavedBufferAttribute + + } + + generate( builder ) { + + const nodeType = this.getNodeType( builder ); + + const nodeAttribute = builder.getBufferAttributeFromNode( this, nodeType ); + const propertyName = builder.getPropertyName( nodeAttribute ); + + let output = null; + + if ( builder.shaderStage === 'vertex' || builder.shaderStage === 'compute' ) { + + this.name = propertyName; + + output = propertyName; + + } else { + + const nodeVarying = varying( this ); + + output = nodeVarying.build( builder, nodeType ); + + } + + return output; + + } + + getInputType( /*builder*/ ) { + + return 'bufferAttribute'; + + } + + setUsage( value ) { + + this.usage = value; + + if ( this.attribute && this.attribute.isBufferAttribute === true ) { + + this.attribute.usage = value; + + } + + return this; + + } + + setInstanced( value ) { + + this.instanced = value; + + return this; + + } + +} + +const bufferAttribute = ( array, type, stride, offset ) => nodeObject( new BufferAttributeNode( array, type, stride, offset ) ); +const dynamicBufferAttribute = ( array, type, stride, offset ) => bufferAttribute( array, type, stride, offset ).setUsage( DynamicDrawUsage ); + +const instancedBufferAttribute = ( array, type, stride, offset ) => bufferAttribute( array, type, stride, offset ).setInstanced( true ); +const instancedDynamicBufferAttribute = ( array, type, stride, offset ) => dynamicBufferAttribute( array, type, stride, offset ).setInstanced( true ); + +addMethodChaining( 'toAttribute', ( bufferNode ) => bufferAttribute( bufferNode.value ) ); + +class ComputeNode extends Node { + + static get type() { + + return 'ComputeNode'; + + } + + constructor( computeNode, count, workgroupSize = [ 64 ] ) { + + super( 'void' ); + + this.isComputeNode = true; + + this.computeNode = computeNode; + + this.count = count; + this.workgroupSize = workgroupSize; + this.dispatchCount = 0; + + this.version = 1; + this.updateBeforeType = NodeUpdateType.OBJECT; + + this.updateDispatchCount(); + + } + + dispose() { + + this.dispatchEvent( { type: 'dispose' } ); + + } + + set needsUpdate( value ) { + + if ( value === true ) this.version ++; + + } + + updateDispatchCount() { + + const { count, workgroupSize } = this; + + let size = workgroupSize[ 0 ]; + + for ( let i = 1; i < workgroupSize.length; i ++ ) + size *= workgroupSize[ i ]; + + this.dispatchCount = Math.ceil( count / size ); + + } + + onInit() { } + + updateBefore( { renderer } ) { + + renderer.compute( this ); + + } + + generate( builder ) { + + const { shaderStage } = builder; + + if ( shaderStage === 'compute' ) { + + const snippet = this.computeNode.build( builder, 'void' ); + + if ( snippet !== '' ) { + + builder.addLineFlowCode( snippet, this ); + + } + + } + + } + +} + +const compute = ( node, count, workgroupSize ) => nodeObject( new ComputeNode( nodeObject( node ), count, workgroupSize ) ); + +addMethodChaining( 'compute', compute ); + +class CacheNode extends Node { + + static get type() { + + return 'CacheNode'; + + } + + constructor( node, parent = true ) { + + super(); + + this.node = node; + this.parent = parent; + + this.isCacheNode = true; + + } + + getNodeType( builder ) { + + return this.node.getNodeType( builder ); + + } + + build( builder, ...params ) { + + const previousCache = builder.getCache(); + const cache = builder.getCacheFromNode( this, this.parent ); + + builder.setCache( cache ); + + const data = this.node.build( builder, ...params ); + + builder.setCache( previousCache ); + + return data; + + } + +} + +const cache = ( node, ...params ) => nodeObject( new CacheNode( nodeObject( node ), ...params ) ); + +addMethodChaining( 'cache', cache ); + +class BypassNode extends Node { + + static get type() { + + return 'BypassNode'; + + } + + constructor( returnNode, callNode ) { + + super(); + + this.isBypassNode = true; + + this.outputNode = returnNode; + this.callNode = callNode; + + } + + getNodeType( builder ) { + + return this.outputNode.getNodeType( builder ); + + } + + generate( builder ) { + + const snippet = this.callNode.build( builder, 'void' ); + + if ( snippet !== '' ) { + + builder.addLineFlowCode( snippet, this ); + + } + + return this.outputNode.build( builder ); + + } + +} + +const bypass = /*@__PURE__*/ nodeProxy( BypassNode ); + +addMethodChaining( 'bypass', bypass ); + +class RemapNode extends Node { + + static get type() { + + return 'RemapNode'; + + } + + constructor( node, inLowNode, inHighNode, outLowNode = float( 0 ), outHighNode = float( 1 ) ) { + + super(); + + this.node = node; + this.inLowNode = inLowNode; + this.inHighNode = inHighNode; + this.outLowNode = outLowNode; + this.outHighNode = outHighNode; + + this.doClamp = true; + + } + + setup() { + + const { node, inLowNode, inHighNode, outLowNode, outHighNode, doClamp } = this; + + let t = node.sub( inLowNode ).div( inHighNode.sub( inLowNode ) ); + + if ( doClamp === true ) t = t.clamp(); + + return t.mul( outHighNode.sub( outLowNode ) ).add( outLowNode ); + + } + +} + +const remap = /*@__PURE__*/ nodeProxy( RemapNode, null, null, { doClamp: false } ); +const remapClamp = /*@__PURE__*/ nodeProxy( RemapNode ); + +addMethodChaining( 'remap', remap ); +addMethodChaining( 'remapClamp', remapClamp ); + +class ExpressionNode extends Node { + + static get type() { + + return 'ExpressionNode'; + + } + + constructor( snippet = '', nodeType = 'void' ) { + + super( nodeType ); + + this.snippet = snippet; + + } + + generate( builder, output ) { + + const type = this.getNodeType( builder ); + const snippet = this.snippet; + + if ( type === 'void' ) { + + builder.addLineFlowCode( snippet, this ); + + } else { + + return builder.format( `( ${ snippet } )`, type, output ); + + } + + } + +} + +const expression = /*@__PURE__*/ nodeProxy( ExpressionNode ); + +const Discard = ( conditional ) => ( conditional ? select( conditional, expression( 'discard' ) ) : expression( 'discard' ) ).append(); +const Return = () => expression( 'return' ).append(); + +addMethodChaining( 'discard', Discard ); + +class RenderOutputNode extends TempNode { + + static get type() { + + return 'RenderOutputNode'; + + } + + constructor( colorNode, toneMapping, outputColorSpace ) { + + super( 'vec4' ); + + this.colorNode = colorNode; + this.toneMapping = toneMapping; + this.outputColorSpace = outputColorSpace; + + this.isRenderOutput = true; + + } + + setup( { context } ) { + + let outputNode = this.colorNode || context.color; + + // tone mapping + + const toneMapping = ( this.toneMapping !== null ? this.toneMapping : context.toneMapping ) || NoToneMapping; + const outputColorSpace = ( this.outputColorSpace !== null ? this.outputColorSpace : context.outputColorSpace ) || NoColorSpace; + + if ( toneMapping !== NoToneMapping ) { + + outputNode = outputNode.toneMapping( toneMapping ); + + } + + // working to output color space + + if ( outputColorSpace !== NoColorSpace && outputColorSpace !== ColorManagement.workingColorSpace ) { + + outputNode = outputNode.workingToColorSpace( outputColorSpace ); + + } + + return outputNode; + + } + +} + +const renderOutput = ( color, toneMapping = null, outputColorSpace = null ) => nodeObject( new RenderOutputNode( nodeObject( color ), toneMapping, outputColorSpace ) ); + +addMethodChaining( 'renderOutput', renderOutput ); + +// Non-PURE exports list, side-effects are required here. +// TSL Base Syntax + + +function addNodeElement( name/*, nodeElement*/ ) { + + console.warn( 'THREE.TSLBase: AddNodeElement has been removed in favor of tree-shaking. Trying add', name ); + +} + +class AttributeNode extends Node { + + static get type() { + + return 'AttributeNode'; + + } + + constructor( attributeName, nodeType = null ) { + + super( nodeType ); + + this.global = true; + + this._attributeName = attributeName; + + } + + getHash( builder ) { + + return this.getAttributeName( builder ); + + } + + getNodeType( builder ) { + + let nodeType = this.nodeType; + + if ( nodeType === null ) { + + const attributeName = this.getAttributeName( builder ); + + if ( builder.hasGeometryAttribute( attributeName ) ) { + + const attribute = builder.geometry.getAttribute( attributeName ); + + nodeType = builder.getTypeFromAttribute( attribute ); + + } else { + + nodeType = 'float'; + + } + + } + + return nodeType; + + } + + setAttributeName( attributeName ) { + + this._attributeName = attributeName; + + return this; + + } + + getAttributeName( /*builder*/ ) { + + return this._attributeName; + + } + + generate( builder ) { + + const attributeName = this.getAttributeName( builder ); + const nodeType = this.getNodeType( builder ); + const geometryAttribute = builder.hasGeometryAttribute( attributeName ); + + if ( geometryAttribute === true ) { + + const attribute = builder.geometry.getAttribute( attributeName ); + const attributeType = builder.getTypeFromAttribute( attribute ); + + const nodeAttribute = builder.getAttribute( attributeName, attributeType ); + + if ( builder.shaderStage === 'vertex' ) { + + return builder.format( nodeAttribute.name, attributeType, nodeType ); + + } else { + + const nodeVarying = varying( this ); + + return nodeVarying.build( builder, nodeType ); + + } + + } else { + + console.warn( `AttributeNode: Vertex attribute "${ attributeName }" not found on geometry.` ); + + return builder.generateConst( nodeType ); + + } + + } + + serialize( data ) { + + super.serialize( data ); + + data.global = this.global; + data._attributeName = this._attributeName; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.global = data.global; + this._attributeName = data._attributeName; + + } + +} + +const attribute = ( name, nodeType ) => nodeObject( new AttributeNode( name, nodeType ) ); + +const uv = ( index ) => attribute( 'uv' + ( index > 0 ? index : '' ), 'vec2' ); + +class TextureSizeNode extends Node { + + static get type() { + + return 'TextureSizeNode'; + + } + + constructor( textureNode, levelNode = null ) { + + super( 'uvec2' ); + + this.isTextureSizeNode = true; + + this.textureNode = textureNode; + this.levelNode = levelNode; + + } + + generate( builder, output ) { + + const textureProperty = this.textureNode.build( builder, 'property' ); + const level = this.levelNode === null ? '0' : this.levelNode.build( builder, 'int' ); + + return builder.format( `${ builder.getMethod( 'textureDimensions' ) }( ${ textureProperty }, ${ level } )`, this.getNodeType( builder ), output ); + + } + +} + +const textureSize = /*@__PURE__*/ nodeProxy( TextureSizeNode ); + +class MaxMipLevelNode extends UniformNode { + + static get type() { + + return 'MaxMipLevelNode'; + + } + + constructor( textureNode ) { + + super( 0 ); + + this._textureNode = textureNode; + + this.updateType = NodeUpdateType.FRAME; + + } + + get textureNode() { + + return this._textureNode; + + } + + get texture() { + + return this._textureNode.value; + + } + + update() { + + const texture = this.texture; + const images = texture.images; + const image = ( images && images.length > 0 ) ? ( ( images[ 0 ] && images[ 0 ].image ) || images[ 0 ] ) : texture.image; + + if ( image && image.width !== undefined ) { + + const { width, height } = image; + + this.value = Math.log2( Math.max( width, height ) ); + + } + + } + +} + +const maxMipLevel = /*@__PURE__*/ nodeProxy( MaxMipLevelNode ); + +class TextureNode extends UniformNode { + + static get type() { + + return 'TextureNode'; + + } + + constructor( value, uvNode = null, levelNode = null, biasNode = null ) { + + super( value ); + + this.isTextureNode = true; + + this.uvNode = uvNode; + this.levelNode = levelNode; + this.biasNode = biasNode; + this.compareNode = null; + this.depthNode = null; + this.gradNode = null; + + this.sampler = true; + this.updateMatrix = false; + this.updateType = NodeUpdateType.NONE; + + this.referenceNode = null; + + this._value = value; + this._matrixUniform = null; + + this.setUpdateMatrix( uvNode === null ); + + } + + set value( value ) { + + if ( this.referenceNode ) { + + this.referenceNode.value = value; + + } else { + + this._value = value; + + } + + } + + get value() { + + return this.referenceNode ? this.referenceNode.value : this._value; + + } + + getUniformHash( /*builder*/ ) { + + return this.value.uuid; + + } + + getNodeType( /*builder*/ ) { + + if ( this.value.isDepthTexture === true ) return 'float'; + + if ( this.value.type === UnsignedIntType ) { + + return 'uvec4'; + + } else if ( this.value.type === IntType ) { + + return 'ivec4'; + + } + + return 'vec4'; + + } + + getInputType( /*builder*/ ) { + + return 'texture'; + + } + + getDefaultUV() { + + return uv( this.value.channel ); + + } + + updateReference( /*state*/ ) { + + return this.value; + + } + + getTransformedUV( uvNode ) { + + if ( this._matrixUniform === null ) this._matrixUniform = uniform( this.value.matrix ); + + return this._matrixUniform.mul( vec3( uvNode, 1 ) ).xy; + + } + + setUpdateMatrix( value ) { + + this.updateMatrix = value; + this.updateType = value ? NodeUpdateType.FRAME : NodeUpdateType.NONE; + + return this; + + } + + setupUV( builder, uvNode ) { + + const texture = this.value; + + if ( builder.isFlipY() && ( texture.isRenderTargetTexture === true || texture.isFramebufferTexture === true || texture.isDepthTexture === true ) ) { + + if ( this.sampler ) { + + uvNode = uvNode.flipY(); + + } else { + + uvNode = uvNode.setY( int( textureSize( this, this.levelNode ).y ).sub( uvNode.y ).sub( 1 ) ); + + } + + } + + return uvNode; + + } + + setup( builder ) { + + const properties = builder.getNodeProperties( this ); + properties.referenceNode = this.referenceNode; + + // + + let uvNode = this.uvNode; + + if ( ( uvNode === null || builder.context.forceUVContext === true ) && builder.context.getUV ) { + + uvNode = builder.context.getUV( this ); + + } + + if ( ! uvNode ) uvNode = this.getDefaultUV(); + + if ( this.updateMatrix === true ) { + + uvNode = this.getTransformedUV( uvNode ); + + } + + uvNode = this.setupUV( builder, uvNode ); + + // + + let levelNode = this.levelNode; + + if ( levelNode === null && builder.context.getTextureLevel ) { + + levelNode = builder.context.getTextureLevel( this ); + + } + + // + + properties.uvNode = uvNode; + properties.levelNode = levelNode; + properties.biasNode = this.biasNode; + properties.compareNode = this.compareNode; + properties.gradNode = this.gradNode; + properties.depthNode = this.depthNode; + + } + + generateUV( builder, uvNode ) { + + return uvNode.build( builder, this.sampler === true ? 'vec2' : 'ivec2' ); + + } + + generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet ) { + + const texture = this.value; + + let snippet; + + if ( levelSnippet ) { + + snippet = builder.generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet ); + + } else if ( biasSnippet ) { + + snippet = builder.generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet ); + + } else if ( gradSnippet ) { + + snippet = builder.generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet ); + + } else if ( compareSnippet ) { + + snippet = builder.generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet ); + + } else if ( this.sampler === false ) { + + snippet = builder.generateTextureLoad( texture, textureProperty, uvSnippet, depthSnippet ); + + } else { + + snippet = builder.generateTexture( texture, textureProperty, uvSnippet, depthSnippet ); + + } + + return snippet; + + } + + generate( builder, output ) { + + const properties = builder.getNodeProperties( this ); + + const texture = this.value; + + if ( ! texture || texture.isTexture !== true ) { + + throw new Error( 'TextureNode: Need a three.js texture.' ); + + } + + const textureProperty = super.generate( builder, 'property' ); + + if ( output === 'sampler' ) { + + return textureProperty + '_sampler'; + + } else if ( builder.isReference( output ) ) { + + return textureProperty; + + } else { + + const nodeData = builder.getDataFromNode( this ); + + let propertyName = nodeData.propertyName; + + if ( propertyName === undefined ) { + + const { uvNode, levelNode, biasNode, compareNode, depthNode, gradNode } = properties; + + const uvSnippet = this.generateUV( builder, uvNode ); + const levelSnippet = levelNode ? levelNode.build( builder, 'float' ) : null; + const biasSnippet = biasNode ? biasNode.build( builder, 'float' ) : null; + const depthSnippet = depthNode ? depthNode.build( builder, 'int' ) : null; + const compareSnippet = compareNode ? compareNode.build( builder, 'float' ) : null; + const gradSnippet = gradNode ? [ gradNode[ 0 ].build( builder, 'vec2' ), gradNode[ 1 ].build( builder, 'vec2' ) ] : null; + + const nodeVar = builder.getVarFromNode( this ); + + propertyName = builder.getPropertyName( nodeVar ); + + const snippet = this.generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet ); + + builder.addLineFlowCode( `${propertyName} = ${snippet}`, this ); + + nodeData.snippet = snippet; + nodeData.propertyName = propertyName; + + } + + let snippet = propertyName; + const nodeType = this.getNodeType( builder ); + + if ( builder.needsToWorkingColorSpace( texture ) ) { + + snippet = colorSpaceToWorking( expression( snippet, nodeType ), texture.colorSpace ).setup( builder ).build( builder, nodeType ); + + } + + return builder.format( snippet, nodeType, output ); + + } + + } + + setSampler( value ) { + + this.sampler = value; + + return this; + + } + + getSampler() { + + return this.sampler; + + } + + // @TODO: Move to TSL + + uv( uvNode ) { + + const textureNode = this.clone(); + textureNode.uvNode = nodeObject( uvNode ); + textureNode.referenceNode = this.getSelf(); + + return nodeObject( textureNode ); + + } + + blur( amountNode ) { + + const textureNode = this.clone(); + textureNode.biasNode = nodeObject( amountNode ).mul( maxMipLevel( textureNode ) ); + textureNode.referenceNode = this.getSelf(); + + return nodeObject( textureNode ); + + } + + level( levelNode ) { + + const textureNode = this.clone(); + textureNode.levelNode = nodeObject( levelNode ); + textureNode.referenceNode = this.getSelf(); + + return nodeObject( textureNode ); + + } + + size( levelNode ) { + + return textureSize( this, levelNode ); + + } + + bias( biasNode ) { + + const textureNode = this.clone(); + textureNode.biasNode = nodeObject( biasNode ); + textureNode.referenceNode = this.getSelf(); + + return nodeObject( textureNode ); + + } + + compare( compareNode ) { + + const textureNode = this.clone(); + textureNode.compareNode = nodeObject( compareNode ); + textureNode.referenceNode = this.getSelf(); + + return nodeObject( textureNode ); + + } + + grad( gradNodeX, gradNodeY ) { + + const textureNode = this.clone(); + textureNode.gradNode = [ nodeObject( gradNodeX ), nodeObject( gradNodeY ) ]; + textureNode.referenceNode = this.getSelf(); + + return nodeObject( textureNode ); + + } + + depth( depthNode ) { + + const textureNode = this.clone(); + textureNode.depthNode = nodeObject( depthNode ); + textureNode.referenceNode = this.getSelf(); + + return nodeObject( textureNode ); + + } + + // -- + + serialize( data ) { + + super.serialize( data ); + + data.value = this.value.toJSON( data.meta ).uuid; + data.sampler = this.sampler; + data.updateMatrix = this.updateMatrix; + data.updateType = this.updateType; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.value = data.meta.textures[ data.value ]; + this.sampler = data.sampler; + this.updateMatrix = data.updateMatrix; + this.updateType = data.updateType; + + } + + update() { + + const texture = this.value; + const matrixUniform = this._matrixUniform; + + if ( matrixUniform !== null ) matrixUniform.value = texture.matrix; + + if ( texture.matrixAutoUpdate === true ) { + + texture.updateMatrix(); + + } + + } + + clone() { + + const newNode = new this.constructor( this.value, this.uvNode, this.levelNode, this.biasNode ); + newNode.sampler = this.sampler; + + return newNode; + + } + +} + +const texture = /*@__PURE__*/ nodeProxy( TextureNode ); +const textureLoad = ( ...params ) => texture( ...params ).setSampler( false ); + +//export const textureLevel = ( value, uv, level ) => texture( value, uv ).level( level ); + +const sampler = ( aTexture ) => ( aTexture.isNode === true ? aTexture : texture( aTexture ) ).convert( 'sampler' ); + +const cameraNear = /*@__PURE__*/ uniform( 'float' ).label( 'cameraNear' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.near ); +const cameraFar = /*@__PURE__*/ uniform( 'float' ).label( 'cameraFar' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.far ); +const cameraLogDepth = /*@__PURE__*/ uniform( 'float' ).label( 'cameraLogDepth' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); +const cameraProjectionMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraProjectionMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.projectionMatrix ); +const cameraProjectionMatrixInverse = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraProjectionMatrixInverse' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.projectionMatrixInverse ); +const cameraViewMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraViewMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.matrixWorldInverse ); +const cameraWorldMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraWorldMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.matrixWorld ); +const cameraNormalMatrix = /*@__PURE__*/ uniform( 'mat3' ).label( 'cameraNormalMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.normalMatrix ); +const cameraPosition = /*@__PURE__*/ uniform( new Vector3() ).label( 'cameraPosition' ).setGroup( renderGroup ).onRenderUpdate( ( { camera }, self ) => self.value.setFromMatrixPosition( camera.matrixWorld ) ); + +class Object3DNode extends Node { + + static get type() { + + return 'Object3DNode'; + + } + + constructor( scope, object3d = null ) { + + super(); + + this.scope = scope; + this.object3d = object3d; + + this.updateType = NodeUpdateType.OBJECT; + + this._uniformNode = new UniformNode( null ); + + } + + getNodeType() { + + const scope = this.scope; + + if ( scope === Object3DNode.WORLD_MATRIX ) { + + return 'mat4'; + + } else if ( scope === Object3DNode.POSITION || scope === Object3DNode.VIEW_POSITION || scope === Object3DNode.DIRECTION || scope === Object3DNode.SCALE ) { + + return 'vec3'; + + } + + } + + update( frame ) { + + const object = this.object3d; + const uniformNode = this._uniformNode; + const scope = this.scope; + + if ( scope === Object3DNode.WORLD_MATRIX ) { + + uniformNode.value = object.matrixWorld; + + } else if ( scope === Object3DNode.POSITION ) { + + uniformNode.value = uniformNode.value || new Vector3(); + + uniformNode.value.setFromMatrixPosition( object.matrixWorld ); + + } else if ( scope === Object3DNode.SCALE ) { + + uniformNode.value = uniformNode.value || new Vector3(); + + uniformNode.value.setFromMatrixScale( object.matrixWorld ); + + } else if ( scope === Object3DNode.DIRECTION ) { + + uniformNode.value = uniformNode.value || new Vector3(); + + object.getWorldDirection( uniformNode.value ); + + } else if ( scope === Object3DNode.VIEW_POSITION ) { + + const camera = frame.camera; + + uniformNode.value = uniformNode.value || new Vector3(); + uniformNode.value.setFromMatrixPosition( object.matrixWorld ); + + uniformNode.value.applyMatrix4( camera.matrixWorldInverse ); + + } + + } + + generate( builder ) { + + const scope = this.scope; + + if ( scope === Object3DNode.WORLD_MATRIX ) { + + this._uniformNode.nodeType = 'mat4'; + + } else if ( scope === Object3DNode.POSITION || scope === Object3DNode.VIEW_POSITION || scope === Object3DNode.DIRECTION || scope === Object3DNode.SCALE ) { + + this._uniformNode.nodeType = 'vec3'; + + } + + return this._uniformNode.build( builder ); + + } + + serialize( data ) { + + super.serialize( data ); + + data.scope = this.scope; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.scope = data.scope; + + } + +} + +Object3DNode.WORLD_MATRIX = 'worldMatrix'; +Object3DNode.POSITION = 'position'; +Object3DNode.SCALE = 'scale'; +Object3DNode.VIEW_POSITION = 'viewPosition'; +Object3DNode.DIRECTION = 'direction'; + +const objectDirection = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.DIRECTION ); +const objectWorldMatrix = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.WORLD_MATRIX ); +const objectPosition = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.POSITION ); +const objectScale = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.SCALE ); +const objectViewPosition = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.VIEW_POSITION ); + +class ModelNode extends Object3DNode { + + static get type() { + + return 'ModelNode'; + + } + + constructor( scope ) { + + super( scope ); + + } + + update( frame ) { + + this.object3d = frame.object; + + super.update( frame ); + + } + +} + +const modelDirection = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.DIRECTION ); +const modelWorldMatrix = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.WORLD_MATRIX ); +const modelPosition = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.POSITION ); +const modelScale = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.SCALE ); +const modelViewPosition = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.VIEW_POSITION ); +const modelNormalMatrix = /*@__PURE__*/ uniform( new Matrix3() ).onObjectUpdate( ( { object }, self ) => self.value.getNormalMatrix( object.matrixWorld ) ); +const modelWorldMatrixInverse = /*@__PURE__*/ uniform( new Matrix4() ).onObjectUpdate( ( { object }, self ) => self.value.copy( object.matrixWorld ).invert() ); +const modelViewMatrix = /*@__PURE__*/ cameraViewMatrix.mul( modelWorldMatrix ).toVar( 'modelViewMatrix' ); + +const highPrecisionModelViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { + + builder.context.isHighPrecisionModelViewMatrix = true; + + return uniform( 'mat4' ).onObjectUpdate( ( { object, camera } ) => { + + return object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + + } ); + +} ).once() )().toVar( 'highPrecisionModelViewMatrix' ); + +const highPrecisionModelNormalViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { + + const isHighPrecisionModelViewMatrix = builder.context.isHighPrecisionModelViewMatrix; + + return uniform( 'mat3' ).onObjectUpdate( ( { object, camera } ) => { + + if ( isHighPrecisionModelViewMatrix !== true ) { + + object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + + } + + return object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); + + } ); + +} ).once() )().toVar( 'highPrecisionModelNormalMatrix' ); + +const positionGeometry = /*@__PURE__*/ attribute( 'position', 'vec3' ); +const positionLocal = /*@__PURE__*/ positionGeometry.varying( 'positionLocal' ); +const positionPrevious = /*@__PURE__*/ positionGeometry.varying( 'positionPrevious' ); +const positionWorld = /*@__PURE__*/ modelWorldMatrix.mul( positionLocal ).xyz.varying( 'v_positionWorld' ); +const positionWorldDirection = /*@__PURE__*/ positionLocal.transformDirection( modelWorldMatrix ).varying( 'v_positionWorldDirection' ).normalize().toVar( 'positionWorldDirection' ); +const positionView = /*@__PURE__*/ modelViewMatrix.mul( positionLocal ).xyz.varying( 'v_positionView' ); +const positionViewDirection = /*@__PURE__*/ positionView.negate().varying( 'v_positionViewDirection' ).normalize().toVar( 'positionViewDirection' ); + +class FrontFacingNode extends Node { + + static get type() { + + return 'FrontFacingNode'; + + } + + constructor() { + + super( 'bool' ); + + this.isFrontFacingNode = true; + + } + + generate( builder ) { + + const { renderer, material } = builder; + + if ( renderer.coordinateSystem === WebGLCoordinateSystem ) { + + if ( material.side === BackSide ) { + + return 'false'; + + } + + } + + return builder.getFrontFacing(); + + } + +} + +const frontFacing = /*@__PURE__*/ nodeImmutable( FrontFacingNode ); +const faceDirection = /*@__PURE__*/ float( frontFacing ).mul( 2.0 ).sub( 1.0 ); + +const normalGeometry = /*@__PURE__*/ attribute( 'normal', 'vec3' ); + +const normalLocal = /*@__PURE__*/ ( Fn( ( builder ) => { + + if ( builder.geometry.hasAttribute( 'normal' ) === false ) { + + console.warn( 'TSL.NormalNode: Vertex attribute "normal" not found on geometry.' ); + + return vec3( 0, 1, 0 ); + + } + + return normalGeometry; + +}, 'vec3' ).once() )().toVar( 'normalLocal' ); + +const normalFlat = /*@__PURE__*/ positionView.dFdx().cross( positionView.dFdy() ).normalize().toVar( 'normalFlat' ); + +const normalView = /*@__PURE__*/ ( Fn( ( builder ) => { + + let node; + + if ( builder.material.flatShading === true ) { + + node = normalFlat; + + } else { + + node = varying( transformNormalToView( normalLocal ), 'v_normalView' ).normalize(); + + } + + return node; + +}, 'vec3' ).once() )().toVar( 'normalView' ); + +const normalWorld = /*@__PURE__*/ varying( normalView.transformDirection( cameraViewMatrix ), 'v_normalWorld' ).normalize().toVar( 'normalWorld' ); + +const transformedNormalView = /*@__PURE__*/ ( Fn( ( builder ) => { + + return builder.context.setupNormal(); + +}, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedNormalView' ); + + +const transformedNormalWorld = /*@__PURE__*/ transformedNormalView.transformDirection( cameraViewMatrix ).toVar( 'transformedNormalWorld' ); + +const transformedClearcoatNormalView = /*@__PURE__*/ ( Fn( ( builder ) => { + + return builder.context.setupClearcoatNormal(); + +}, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedClearcoatNormalView' ); + +const transformNormal = /*@__PURE__*/ Fn( ( [ normal, matrix = modelWorldMatrix ] ) => { + + const m = mat3( matrix ); + + const transformedNormal = normal.div( vec3( m[ 0 ].dot( m[ 0 ] ), m[ 1 ].dot( m[ 1 ] ), m[ 2 ].dot( m[ 2 ] ) ) ); + + return m.mul( transformedNormal ).xyz; + +} ); + +const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) => { + + const modelNormalViewMatrix = builder.renderer.nodes.modelNormalViewMatrix; + + if ( modelNormalViewMatrix !== null ) { + + return modelNormalViewMatrix.transformDirection( normal ); + + } + + // + + const transformedNormal = modelNormalMatrix.mul( normal ); + + return cameraViewMatrix.transformDirection( transformedNormal ); + +} ); + +const materialRefractionRatio = /*@__PURE__*/ uniform( 0 ).onReference( ( { material } ) => material ).onRenderUpdate( ( { material } ) => material.refractionRatio ); + +const reflectView = /*@__PURE__*/ positionViewDirection.negate().reflect( transformedNormalView ); +const refractView = /*@__PURE__*/ positionViewDirection.negate().refract( transformedNormalView, materialRefractionRatio ); + +const reflectVector = /*@__PURE__*/ reflectView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' ); +const refractVector = /*@__PURE__*/ refractView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' ); + +class CubeTextureNode extends TextureNode { + + static get type() { + + return 'CubeTextureNode'; + + } + + constructor( value, uvNode = null, levelNode = null, biasNode = null ) { + + super( value, uvNode, levelNode, biasNode ); + + this.isCubeTextureNode = true; + + } + + getInputType( /*builder*/ ) { + + return 'cubeTexture'; + + } + + getDefaultUV() { + + const texture = this.value; + + if ( texture.mapping === CubeReflectionMapping ) { + + return reflectVector; + + } else if ( texture.mapping === CubeRefractionMapping ) { + + return refractVector; + + } else { + + console.error( 'THREE.CubeTextureNode: Mapping "%s" not supported.', texture.mapping ); + + return vec3( 0, 0, 0 ); + + } + + } + + setUpdateMatrix( /*updateMatrix*/ ) { } // Ignore .updateMatrix for CubeTextureNode + + setupUV( builder, uvNode ) { + + const texture = this.value; + + if ( builder.renderer.coordinateSystem === WebGPUCoordinateSystem || ! texture.isRenderTargetTexture ) { + + return vec3( uvNode.x.negate(), uvNode.yz ); + + } else { + + return uvNode; + + } + + } + + generateUV( builder, cubeUV ) { + + return cubeUV.build( builder, 'vec3' ); + + } + +} + +const cubeTexture = /*@__PURE__*/ nodeProxy( CubeTextureNode ); + +class BufferNode extends UniformNode { + + static get type() { + + return 'BufferNode'; + + } + + constructor( value, bufferType, bufferCount = 0 ) { + + super( value, bufferType ); + + this.isBufferNode = true; + + this.bufferType = bufferType; + this.bufferCount = bufferCount; + + } + + getElementType( builder ) { + + return this.getNodeType( builder ); + + } + + getInputType( /*builder*/ ) { + + return 'buffer'; + + } + +} + +const buffer = ( value, type, count ) => nodeObject( new BufferNode( value, type, count ) ); + +class UniformArrayElementNode extends ArrayElementNode { + + static get type() { + + return 'UniformArrayElementNode'; + + } + + constructor( arrayBuffer, indexNode ) { + + super( arrayBuffer, indexNode ); + + this.isArrayBufferElementNode = true; + + } + + generate( builder ) { + + const snippet = super.generate( builder ); + const type = this.getNodeType(); + + return builder.format( snippet, 'vec4', type ); + + } + +} + +class UniformArrayNode extends BufferNode { + + static get type() { + + return 'UniformArrayNode'; + + } + + constructor( value, elementType = null ) { + + super( null, 'vec4' ); + + this.array = value; + this.elementType = elementType; + + this._elementType = null; + this._elementLength = 0; + + this.updateType = NodeUpdateType.RENDER; + + this.isArrayBufferNode = true; + + } + + getElementType() { + + return this.elementType || this._elementType; + + } + + getElementLength() { + + return this._elementLength; + + } + + update( /*frame*/ ) { + + const { array, value } = this; + + const elementLength = this.getElementLength(); + const elementType = this.getElementType(); + + if ( elementLength === 1 ) { + + for ( let i = 0; i < array.length; i ++ ) { + + const index = i * 4; + + value[ index ] = array[ i ]; + + } + + } else if ( elementType === 'color' ) { + + for ( let i = 0; i < array.length; i ++ ) { + + const index = i * 4; + const vector = array[ i ]; + + value[ index ] = vector.r; + value[ index + 1 ] = vector.g; + value[ index + 2 ] = vector.b || 0; + //value[ index + 3 ] = vector.a || 0; + + } + + } else { + + for ( let i = 0; i < array.length; i ++ ) { + + const index = i * 4; + const vector = array[ i ]; + + value[ index ] = vector.x; + value[ index + 1 ] = vector.y; + value[ index + 2 ] = vector.z || 0; + value[ index + 3 ] = vector.w || 0; + + } + + } + + } + + setup( builder ) { + + const length = this.array.length; + + this._elementType = this.elementType === null ? getValueType( this.array[ 0 ] ) : this.elementType; + this._elementLength = builder.getTypeLength( this._elementType ); + + let arrayType = Float32Array; + + if ( this._elementType.charAt( 0 ) === 'i' ) arrayType = Int32Array; + else if ( this._elementType.charAt( 0 ) === 'u' ) arrayType = Uint32Array; + + this.value = new arrayType( length * 4 ); + this.bufferCount = length; + this.bufferType = builder.changeComponentType( 'vec4', builder.getComponentType( this._elementType ) ); + + return super.setup( builder ); + + } + + element( indexNode ) { + + return nodeObject( new UniformArrayElementNode( this, nodeObject( indexNode ) ) ); + + } + +} + +const uniformArray = ( values, nodeType ) => nodeObject( new UniformArrayNode( values, nodeType ) ); + +// + +const uniforms = ( values, nodeType ) => { // @deprecated, r168 + + console.warn( 'TSL.UniformArrayNode: uniforms() has been renamed to uniformArray().' ); + return nodeObject( new UniformArrayNode( values, nodeType ) ); + +}; + +class ReferenceElementNode extends ArrayElementNode { + + static get type() { + + return 'ReferenceElementNode'; + + } + + constructor( referenceNode, indexNode ) { + + super( referenceNode, indexNode ); + + this.referenceNode = referenceNode; + + this.isReferenceElementNode = true; + + } + + getNodeType() { + + return this.referenceNode.uniformType; + + } + + generate( builder ) { + + const snippet = super.generate( builder ); + const arrayType = this.referenceNode.getNodeType(); + const elementType = this.getNodeType(); + + return builder.format( snippet, arrayType, elementType ); + + } + +} + +// TODO: Extends this from ReferenceBaseNode +class ReferenceNode extends Node { + + static get type() { + + return 'ReferenceNode'; + + } + + constructor( property, uniformType, object = null, count = null ) { + + super(); + + this.property = property; + this.uniformType = uniformType; + this.object = object; + this.count = count; + + this.properties = property.split( '.' ); + this.reference = object; + this.node = null; + this.group = null; + this.name = null; + + this.updateType = NodeUpdateType.OBJECT; + + } + + element( indexNode ) { + + return nodeObject( new ReferenceElementNode( this, nodeObject( indexNode ) ) ); + + } + + setGroup( group ) { + + this.group = group; + + return this; + + } + + label( name ) { + + this.name = name; + + return this; + + } + + setNodeType( uniformType ) { + + let node = null; + + if ( this.count !== null ) { + + node = buffer( null, uniformType, this.count ); + + } else if ( Array.isArray( this.getValueFromReference() ) ) { + + node = uniformArray( null, uniformType ); + + } else if ( uniformType === 'texture' ) { + + node = texture( null ); + + } else if ( uniformType === 'cubeTexture' ) { + + node = cubeTexture( null ); + + } else { + + node = uniform( null, uniformType ); + + } + + if ( this.group !== null ) { + + node.setGroup( this.group ); + + } + + if ( this.name !== null ) node.label( this.name ); + + this.node = node.getSelf(); + + } + + getNodeType( builder ) { + + if ( this.node === null ) { + + this.updateReference( builder ); + this.updateValue(); + + } + + return this.node.getNodeType( builder ); + + } + + getValueFromReference( object = this.reference ) { + + const { properties } = this; + + let value = object[ properties[ 0 ] ]; + + for ( let i = 1; i < properties.length; i ++ ) { + + value = value[ properties[ i ] ]; + + } + + return value; + + } + + updateReference( state ) { + + this.reference = this.object !== null ? this.object : state.object; + + return this.reference; + + } + + setup() { + + this.updateValue(); + + return this.node; + + } + + update( /*frame*/ ) { + + this.updateValue(); + + } + + updateValue() { + + if ( this.node === null ) this.setNodeType( this.uniformType ); + + const value = this.getValueFromReference(); + + if ( Array.isArray( value ) ) { + + this.node.array = value; + + } else { + + this.node.value = value; + + } + + } + +} + +const reference = ( name, type, object ) => nodeObject( new ReferenceNode( name, type, object ) ); +const referenceBuffer = ( name, type, count, object ) => nodeObject( new ReferenceNode( name, type, object, count ) ); + +class MaterialReferenceNode extends ReferenceNode { + + static get type() { + + return 'MaterialReferenceNode'; + + } + + constructor( property, inputType, material = null ) { + + super( property, inputType, material ); + + this.material = material; + + //this.updateType = NodeUpdateType.RENDER; + + this.isMaterialReferenceNode = true; + + } + + /*setNodeType( node ) { + + super.setNodeType( node ); + + this.node.groupNode = renderGroup; + + }*/ + + updateReference( state ) { + + this.reference = this.material !== null ? this.material : state.material; + + return this.reference; + + } + +} + +const materialReference = ( name, type, material ) => nodeObject( new MaterialReferenceNode( name, type, material ) ); + +const tangentGeometry = /*@__PURE__*/ Fn( ( builder ) => { + + if ( builder.geometry.hasAttribute( 'tangent' ) === false ) { + + builder.geometry.computeTangents(); + + } + + return attribute( 'tangent', 'vec4' ); + +} )(); + +const tangentLocal = /*@__PURE__*/ tangentGeometry.xyz.toVar( 'tangentLocal' ); +const tangentView = /*@__PURE__*/ modelViewMatrix.mul( vec4( tangentLocal, 0 ) ).xyz.varying( 'v_tangentView' ).normalize().toVar( 'tangentView' ); +const tangentWorld = /*@__PURE__*/ tangentView.transformDirection( cameraViewMatrix ).varying( 'v_tangentWorld' ).normalize().toVar( 'tangentWorld' ); +const transformedTangentView = /*@__PURE__*/ tangentView.toVar( 'transformedTangentView' ); +const transformedTangentWorld = /*@__PURE__*/ transformedTangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedTangentWorld' ); + +const getBitangent = ( crossNormalTangent ) => crossNormalTangent.mul( tangentGeometry.w ).xyz; + +const bitangentGeometry = /*@__PURE__*/ varying( getBitangent( normalGeometry.cross( tangentGeometry ) ), 'v_bitangentGeometry' ).normalize().toVar( 'bitangentGeometry' ); +const bitangentLocal = /*@__PURE__*/ varying( getBitangent( normalLocal.cross( tangentLocal ) ), 'v_bitangentLocal' ).normalize().toVar( 'bitangentLocal' ); +const bitangentView = /*@__PURE__*/ varying( getBitangent( normalView.cross( tangentView ) ), 'v_bitangentView' ).normalize().toVar( 'bitangentView' ); +const bitangentWorld = /*@__PURE__*/ varying( getBitangent( normalWorld.cross( tangentWorld ) ), 'v_bitangentWorld' ).normalize().toVar( 'bitangentWorld' ); +const transformedBitangentView = /*@__PURE__*/ getBitangent( transformedNormalView.cross( transformedTangentView ) ).normalize().toVar( 'transformedBitangentView' ); +const transformedBitangentWorld = /*@__PURE__*/ transformedBitangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedBitangentWorld' ); + +const TBNViewMatrix = /*@__PURE__*/ mat3( tangentView, bitangentView, normalView ); + +const parallaxDirection = /*@__PURE__*/ positionViewDirection.mul( TBNViewMatrix )/*.normalize()*/; +const parallaxUV = ( uv, scale ) => uv.sub( parallaxDirection.mul( scale ) ); + +const transformedBentNormalView = /*@__PURE__*/ ( () => { + + // https://google.github.io/filament/Filament.md.html#lighting/imagebasedlights/anisotropy + + let bentNormal = anisotropyB.cross( positionViewDirection ); + bentNormal = bentNormal.cross( anisotropyB ).normalize(); + bentNormal = mix( bentNormal, transformedNormalView, anisotropy.mul( roughness.oneMinus() ).oneMinus().pow2().pow2() ).normalize(); + + return bentNormal; + + +} )(); + +// Normal Mapping Without Precomputed Tangents +// http://www.thetenthplanet.de/archives/1180 + +const perturbNormal2Arb = /*@__PURE__*/ Fn( ( inputs ) => { + + const { eye_pos, surf_norm, mapN, uv } = inputs; + + const q0 = eye_pos.dFdx(); + const q1 = eye_pos.dFdy(); + const st0 = uv.dFdx(); + const st1 = uv.dFdy(); + + const N = surf_norm; // normalized + + const q1perp = q1.cross( N ); + const q0perp = N.cross( q0 ); + + const T = q1perp.mul( st0.x ).add( q0perp.mul( st1.x ) ); + const B = q1perp.mul( st0.y ).add( q0perp.mul( st1.y ) ); + + const det = T.dot( T ).max( B.dot( B ) ); + const scale = faceDirection.mul( det.inverseSqrt() ); + + return add( T.mul( mapN.x, scale ), B.mul( mapN.y, scale ), N.mul( mapN.z ) ).normalize(); + +} ); + +class NormalMapNode extends TempNode { + + static get type() { + + return 'NormalMapNode'; + + } + + constructor( node, scaleNode = null ) { + + super( 'vec3' ); + + this.node = node; + this.scaleNode = scaleNode; + + this.normalMapType = TangentSpaceNormalMap; + + } + + setup( builder ) { + + const { normalMapType, scaleNode } = this; + + let normalMap = this.node.mul( 2.0 ).sub( 1.0 ); + + if ( scaleNode !== null ) { + + normalMap = vec3( normalMap.xy.mul( scaleNode ), normalMap.z ); + + } + + let outputNode = null; + + if ( normalMapType === ObjectSpaceNormalMap ) { + + outputNode = transformNormalToView( normalMap ); + + } else if ( normalMapType === TangentSpaceNormalMap ) { + + const tangent = builder.hasGeometryAttribute( 'tangent' ); + + if ( tangent === true ) { + + outputNode = TBNViewMatrix.mul( normalMap ).normalize(); + + } else { + + outputNode = perturbNormal2Arb( { + eye_pos: positionView, + surf_norm: normalView, + mapN: normalMap, + uv: uv() + } ); + + } + + } + + return outputNode; + + } + +} + +const normalMap = /*@__PURE__*/ nodeProxy( NormalMapNode ); + +// Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen +// https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf + +const dHdxy_fwd = Fn( ( { textureNode, bumpScale } ) => { + + // It's used to preserve the same TextureNode instance + const sampleTexture = ( callback ) => textureNode.cache().context( { getUV: ( texNode ) => callback( texNode.uvNode || uv() ), forceUVContext: true } ); + + const Hll = float( sampleTexture( ( uvNode ) => uvNode ) ); + + return vec2( + float( sampleTexture( ( uvNode ) => uvNode.add( uvNode.dFdx() ) ) ).sub( Hll ), + float( sampleTexture( ( uvNode ) => uvNode.add( uvNode.dFdy() ) ) ).sub( Hll ) + ).mul( bumpScale ); + +} ); + +// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2) + +const perturbNormalArb = Fn( ( inputs ) => { + + const { surf_pos, surf_norm, dHdxy } = inputs; + + // normalize is done to ensure that the bump map looks the same regardless of the texture's scale + const vSigmaX = surf_pos.dFdx().normalize(); + const vSigmaY = surf_pos.dFdy().normalize(); + const vN = surf_norm; // normalized + + const R1 = vSigmaY.cross( vN ); + const R2 = vN.cross( vSigmaX ); + + const fDet = vSigmaX.dot( R1 ).mul( faceDirection ); + + const vGrad = fDet.sign().mul( dHdxy.x.mul( R1 ).add( dHdxy.y.mul( R2 ) ) ); + + return fDet.abs().mul( surf_norm ).sub( vGrad ).normalize(); + +} ); + +class BumpMapNode extends TempNode { + + static get type() { + + return 'BumpMapNode'; + + } + + constructor( textureNode, scaleNode = null ) { + + super( 'vec3' ); + + this.textureNode = textureNode; + this.scaleNode = scaleNode; + + } + + setup() { + + const bumpScale = this.scaleNode !== null ? this.scaleNode : 1; + const dHdxy = dHdxy_fwd( { textureNode: this.textureNode, bumpScale } ); + + return perturbNormalArb( { + surf_pos: positionView, + surf_norm: normalView, + dHdxy + } ); + + } + +} + +const bumpMap = /*@__PURE__*/ nodeProxy( BumpMapNode ); + +const _propertyCache = new Map(); + +class MaterialNode extends Node { + + static get type() { + + return 'MaterialNode'; + + } + + constructor( scope ) { + + super(); + + this.scope = scope; + + } + + getCache( property, type ) { + + let node = _propertyCache.get( property ); + + if ( node === undefined ) { + + node = materialReference( property, type ); + + _propertyCache.set( property, node ); + + } + + return node; + + } + + getFloat( property ) { + + return this.getCache( property, 'float' ); + + } + + getColor( property ) { + + return this.getCache( property, 'color' ); + + } + + getTexture( property ) { + + return this.getCache( property === 'map' ? 'map' : property + 'Map', 'texture' ); + + } + + setup( builder ) { + + const material = builder.context.material; + const scope = this.scope; + + let node = null; + + if ( scope === MaterialNode.COLOR ) { + + const colorNode = material.color !== undefined ? this.getColor( scope ) : vec3(); + + if ( material.map && material.map.isTexture === true ) { + + node = colorNode.mul( this.getTexture( 'map' ) ); + + } else { + + node = colorNode; + + } + + } else if ( scope === MaterialNode.OPACITY ) { + + const opacityNode = this.getFloat( scope ); + + if ( material.alphaMap && material.alphaMap.isTexture === true ) { + + node = opacityNode.mul( this.getTexture( 'alpha' ) ); + + } else { + + node = opacityNode; + + } + + } else if ( scope === MaterialNode.SPECULAR_STRENGTH ) { + + if ( material.specularMap && material.specularMap.isTexture === true ) { + + node = this.getTexture( 'specular' ).r; + + } else { + + node = float( 1 ); + + } + + } else if ( scope === MaterialNode.SPECULAR_INTENSITY ) { + + const specularIntensity = this.getFloat( scope ); + + if ( material.specularMap ) { + + node = specularIntensity.mul( this.getTexture( scope ).a ); + + } else { + + node = specularIntensity; + + } + + } else if ( scope === MaterialNode.SPECULAR_COLOR ) { + + const specularColorNode = this.getColor( scope ); + + if ( material.specularColorMap && material.specularColorMap.isTexture === true ) { + + node = specularColorNode.mul( this.getTexture( scope ).rgb ); + + } else { + + node = specularColorNode; + + } + + } else if ( scope === MaterialNode.ROUGHNESS ) { // TODO: cleanup similar branches + + const roughnessNode = this.getFloat( scope ); + + if ( material.roughnessMap && material.roughnessMap.isTexture === true ) { + + node = roughnessNode.mul( this.getTexture( scope ).g ); + + } else { + + node = roughnessNode; + + } + + } else if ( scope === MaterialNode.METALNESS ) { + + const metalnessNode = this.getFloat( scope ); + + if ( material.metalnessMap && material.metalnessMap.isTexture === true ) { + + node = metalnessNode.mul( this.getTexture( scope ).b ); + + } else { + + node = metalnessNode; + + } + + } else if ( scope === MaterialNode.EMISSIVE ) { + + const emissiveIntensityNode = this.getFloat( 'emissiveIntensity' ); + const emissiveNode = this.getColor( scope ).mul( emissiveIntensityNode ); + + if ( material.emissiveMap && material.emissiveMap.isTexture === true ) { + + node = emissiveNode.mul( this.getTexture( scope ) ); + + } else { + + node = emissiveNode; + + } + + } else if ( scope === MaterialNode.NORMAL ) { + + if ( material.normalMap ) { + + node = normalMap( this.getTexture( 'normal' ), this.getCache( 'normalScale', 'vec2' ) ); + node.normalMapType = material.normalMapType; + + } else if ( material.bumpMap ) { + + node = bumpMap( this.getTexture( 'bump' ).r, this.getFloat( 'bumpScale' ) ); + + } else { + + node = normalView; + + } + + } else if ( scope === MaterialNode.CLEARCOAT ) { + + const clearcoatNode = this.getFloat( scope ); + + if ( material.clearcoatMap && material.clearcoatMap.isTexture === true ) { + + node = clearcoatNode.mul( this.getTexture( scope ).r ); + + } else { + + node = clearcoatNode; + + } + + } else if ( scope === MaterialNode.CLEARCOAT_ROUGHNESS ) { + + const clearcoatRoughnessNode = this.getFloat( scope ); + + if ( material.clearcoatRoughnessMap && material.clearcoatRoughnessMap.isTexture === true ) { + + node = clearcoatRoughnessNode.mul( this.getTexture( scope ).r ); + + } else { + + node = clearcoatRoughnessNode; + + } + + } else if ( scope === MaterialNode.CLEARCOAT_NORMAL ) { + + if ( material.clearcoatNormalMap ) { + + node = normalMap( this.getTexture( scope ), this.getCache( scope + 'Scale', 'vec2' ) ); + + } else { + + node = normalView; + + } + + } else if ( scope === MaterialNode.SHEEN ) { + + const sheenNode = this.getColor( 'sheenColor' ).mul( this.getFloat( 'sheen' ) ); // Move this mul() to CPU + + if ( material.sheenColorMap && material.sheenColorMap.isTexture === true ) { + + node = sheenNode.mul( this.getTexture( 'sheenColor' ).rgb ); + + } else { + + node = sheenNode; + + } + + } else if ( scope === MaterialNode.SHEEN_ROUGHNESS ) { + + const sheenRoughnessNode = this.getFloat( scope ); + + if ( material.sheenRoughnessMap && material.sheenRoughnessMap.isTexture === true ) { + + node = sheenRoughnessNode.mul( this.getTexture( scope ).a ); + + } else { + + node = sheenRoughnessNode; + + } + + node = node.clamp( 0.07, 1.0 ); + + } else if ( scope === MaterialNode.ANISOTROPY ) { + + if ( material.anisotropyMap && material.anisotropyMap.isTexture === true ) { + + const anisotropyPolar = this.getTexture( scope ); + const anisotropyMat = mat2( materialAnisotropyVector.x, materialAnisotropyVector.y, materialAnisotropyVector.y.negate(), materialAnisotropyVector.x ); + + node = anisotropyMat.mul( anisotropyPolar.rg.mul( 2.0 ).sub( vec2( 1.0 ) ).normalize().mul( anisotropyPolar.b ) ); + + } else { + + node = materialAnisotropyVector; + + } + + } else if ( scope === MaterialNode.IRIDESCENCE_THICKNESS ) { + + const iridescenceThicknessMaximum = reference( '1', 'float', material.iridescenceThicknessRange ); + + if ( material.iridescenceThicknessMap ) { + + const iridescenceThicknessMinimum = reference( '0', 'float', material.iridescenceThicknessRange ); + + node = iridescenceThicknessMaximum.sub( iridescenceThicknessMinimum ).mul( this.getTexture( scope ).g ).add( iridescenceThicknessMinimum ); + + } else { + + node = iridescenceThicknessMaximum; + + } + + } else if ( scope === MaterialNode.TRANSMISSION ) { + + const transmissionNode = this.getFloat( scope ); + + if ( material.transmissionMap ) { + + node = transmissionNode.mul( this.getTexture( scope ).r ); + + } else { + + node = transmissionNode; + + } + + } else if ( scope === MaterialNode.THICKNESS ) { + + const thicknessNode = this.getFloat( scope ); + + if ( material.thicknessMap ) { + + node = thicknessNode.mul( this.getTexture( scope ).g ); + + } else { + + node = thicknessNode; + + } + + } else if ( scope === MaterialNode.IOR ) { + + node = this.getFloat( scope ); + + } else if ( scope === MaterialNode.LIGHT_MAP ) { + + node = this.getTexture( scope ).rgb.mul( this.getFloat( 'lightMapIntensity' ) ); + + } else if ( scope === MaterialNode.AO_MAP ) { + + node = this.getTexture( scope ).r.sub( 1.0 ).mul( this.getFloat( 'aoMapIntensity' ) ).add( 1.0 ); + + } else { + + const outputType = this.getNodeType( builder ); + + node = this.getCache( scope, outputType ); + + } + + return node; + + } + +} + +MaterialNode.ALPHA_TEST = 'alphaTest'; +MaterialNode.COLOR = 'color'; +MaterialNode.OPACITY = 'opacity'; +MaterialNode.SHININESS = 'shininess'; +MaterialNode.SPECULAR = 'specular'; +MaterialNode.SPECULAR_STRENGTH = 'specularStrength'; +MaterialNode.SPECULAR_INTENSITY = 'specularIntensity'; +MaterialNode.SPECULAR_COLOR = 'specularColor'; +MaterialNode.REFLECTIVITY = 'reflectivity'; +MaterialNode.ROUGHNESS = 'roughness'; +MaterialNode.METALNESS = 'metalness'; +MaterialNode.NORMAL = 'normal'; +MaterialNode.CLEARCOAT = 'clearcoat'; +MaterialNode.CLEARCOAT_ROUGHNESS = 'clearcoatRoughness'; +MaterialNode.CLEARCOAT_NORMAL = 'clearcoatNormal'; +MaterialNode.EMISSIVE = 'emissive'; +MaterialNode.ROTATION = 'rotation'; +MaterialNode.SHEEN = 'sheen'; +MaterialNode.SHEEN_ROUGHNESS = 'sheenRoughness'; +MaterialNode.ANISOTROPY = 'anisotropy'; +MaterialNode.IRIDESCENCE = 'iridescence'; +MaterialNode.IRIDESCENCE_IOR = 'iridescenceIOR'; +MaterialNode.IRIDESCENCE_THICKNESS = 'iridescenceThickness'; +MaterialNode.IOR = 'ior'; +MaterialNode.TRANSMISSION = 'transmission'; +MaterialNode.THICKNESS = 'thickness'; +MaterialNode.ATTENUATION_DISTANCE = 'attenuationDistance'; +MaterialNode.ATTENUATION_COLOR = 'attenuationColor'; +MaterialNode.LINE_SCALE = 'scale'; +MaterialNode.LINE_DASH_SIZE = 'dashSize'; +MaterialNode.LINE_GAP_SIZE = 'gapSize'; +MaterialNode.LINE_WIDTH = 'linewidth'; +MaterialNode.LINE_DASH_OFFSET = 'dashOffset'; +MaterialNode.POINT_WIDTH = 'pointWidth'; +MaterialNode.DISPERSION = 'dispersion'; +MaterialNode.LIGHT_MAP = 'light'; +MaterialNode.AO_MAP = 'ao'; + +const materialAlphaTest = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ALPHA_TEST ); +const materialColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.COLOR ); +const materialShininess = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHININESS ); +const materialEmissive = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.EMISSIVE ); +const materialOpacity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.OPACITY ); +const materialSpecular = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR ); + +const materialSpecularIntensity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_INTENSITY ); +const materialSpecularColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_COLOR ); + +const materialSpecularStrength = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_STRENGTH ); +const materialReflectivity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.REFLECTIVITY ); +const materialRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ROUGHNESS ); +const materialMetalness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.METALNESS ); +const materialNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.NORMAL ).context( { getUV: null } ); +const materialClearcoat = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT ); +const materialClearcoatRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_ROUGHNESS ); +const materialClearcoatNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_NORMAL ).context( { getUV: null } ); +const materialRotation = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ROTATION ); +const materialSheen = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHEEN ); +const materialSheenRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHEEN_ROUGHNESS ); +const materialAnisotropy = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ANISOTROPY ); +const materialIridescence = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE ); +const materialIridescenceIOR = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_IOR ); +const materialIridescenceThickness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_THICKNESS ); +const materialTransmission = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.TRANSMISSION ); +const materialThickness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.THICKNESS ); +const materialIOR = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IOR ); +const materialAttenuationDistance = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_DISTANCE ); +const materialAttenuationColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_COLOR ); +const materialLineScale = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_SCALE ); +const materialLineDashSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_SIZE ); +const materialLineGapSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_GAP_SIZE ); +const materialLineWidth = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_WIDTH ); +const materialLineDashOffset = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_OFFSET ); +const materialPointWidth = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.POINT_WIDTH ); +const materialDispersion = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.DISPERSION ); +const materialLightMap = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LIGHT_MAP ); +const materialAOMap = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.AO_MAP ); +const materialAnisotropyVector = /*@__PURE__*/ uniform( new Vector2() ).onReference( function ( frame ) { + + return frame.material; + +} ).onRenderUpdate( function ( { material } ) { + + this.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) ); + +} ); + +class ModelViewProjectionNode extends TempNode { + + static get type() { + + return 'ModelViewProjectionNode'; + + } + + constructor( positionNode = null ) { + + super( 'vec4' ); + + this.positionNode = positionNode; + + } + + setup( builder ) { + + if ( builder.shaderStage === 'fragment' ) { + + return varying( builder.context.mvp ); + + } + + const position = this.positionNode || positionLocal; + const viewMatrix = builder.renderer.nodes.modelViewMatrix || modelViewMatrix; + + return cameraProjectionMatrix.mul( viewMatrix ).mul( position ); + + } + +} + +const modelViewProjection = /*@__PURE__*/ nodeProxy( ModelViewProjectionNode ); + +class IndexNode extends Node { + + static get type() { + + return 'IndexNode'; + + } + + constructor( scope ) { + + super( 'uint' ); + + this.scope = scope; + + this.isInstanceIndexNode = true; + + } + + generate( builder ) { + + const nodeType = this.getNodeType( builder ); + const scope = this.scope; + + let propertyName; + + if ( scope === IndexNode.VERTEX ) { + + // The index of a vertex within a mesh. + propertyName = builder.getVertexIndex(); + + } else if ( scope === IndexNode.INSTANCE ) { + + // The index of either a mesh instance or an invocation of a compute shader. + propertyName = builder.getInstanceIndex(); + + } else if ( scope === IndexNode.DRAW ) { + + // The index of a draw call. + propertyName = builder.getDrawIndex(); + + } else if ( scope === IndexNode.INVOCATION_LOCAL ) { + + // The index of a compute invocation within the scope of a workgroup load. + propertyName = builder.getInvocationLocalIndex(); + + } else if ( scope === IndexNode.INVOCATION_SUBGROUP ) { + + // The index of a compute invocation within the scope of a subgroup. + propertyName = builder.getInvocationSubgroupIndex(); + + } else if ( scope === IndexNode.SUBGROUP ) { + + // The index of the subgroup the current compute invocation belongs to. + propertyName = builder.getSubgroupIndex(); + + } else { + + throw new Error( 'THREE.IndexNode: Unknown scope: ' + scope ); + + } + + let output; + + if ( builder.shaderStage === 'vertex' || builder.shaderStage === 'compute' ) { + + output = propertyName; + + } else { + + const nodeVarying = varying( this ); + + output = nodeVarying.build( builder, nodeType ); + + } + + return output; + + } + +} + +IndexNode.VERTEX = 'vertex'; +IndexNode.INSTANCE = 'instance'; +IndexNode.SUBGROUP = 'subgroup'; +IndexNode.INVOCATION_LOCAL = 'invocationLocal'; +IndexNode.INVOCATION_SUBGROUP = 'invocationSubgroup'; +IndexNode.DRAW = 'draw'; + +const vertexIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.VERTEX ); +const instanceIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INSTANCE ); +const subgroupIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.SUBGROUP ); +const invocationSubgroupIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INVOCATION_SUBGROUP ); +const invocationLocalIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INVOCATION_LOCAL ); +const drawIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.DRAW ); + +class InstanceNode extends Node { + + static get type() { + + return 'InstanceNode'; + + } + + constructor( instanceMesh ) { + + super( 'void' ); + + this.instanceMesh = instanceMesh; + + this.instanceMatrixNode = null; + + this.instanceColorNode = null; + + this.updateType = NodeUpdateType.FRAME; + + this.buffer = null; + this.bufferColor = null; + + } + + setup( builder ) { + + let instanceMatrixNode = this.instanceMatrixNode; + let instanceColorNode = this.instanceColorNode; + + const instanceMesh = this.instanceMesh; + + if ( instanceMatrixNode === null ) { + + const instanceAttribute = instanceMesh.instanceMatrix; + + // Both WebGPU and WebGL backends have UBO max limited to 64kb. Matrix count number bigger than 1000 ( 16 * 4 * 1000 = 64kb ) will fallback to attribute. + + if ( instanceMesh.count <= 1000 ) { + + instanceMatrixNode = buffer( instanceAttribute.array, 'mat4', Math.max( instanceMesh.count, 1 ) ).element( instanceIndex ); + + } else { + + const buffer = new InstancedInterleavedBuffer( instanceAttribute.array, 16, 1 ); + + this.buffer = buffer; + + const bufferFn = instanceAttribute.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute; + + const instanceBuffers = [ + // F.Signature -> bufferAttribute( array, type, stride, offset ) + bufferFn( buffer, 'vec4', 16, 0 ), + bufferFn( buffer, 'vec4', 16, 4 ), + bufferFn( buffer, 'vec4', 16, 8 ), + bufferFn( buffer, 'vec4', 16, 12 ) + ]; + + instanceMatrixNode = mat4( ...instanceBuffers ); + + } + + this.instanceMatrixNode = instanceMatrixNode; + + } + + const instanceColorAttribute = instanceMesh.instanceColor; + + if ( instanceColorAttribute && instanceColorNode === null ) { + + const buffer = new InstancedBufferAttribute( instanceColorAttribute.array, 3 ); + + const bufferFn = instanceColorAttribute.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute; + + this.bufferColor = buffer; + + instanceColorNode = vec3( bufferFn( buffer, 'vec3', 3, 0 ) ); + + this.instanceColorNode = instanceColorNode; + + } + + // POSITION + + const instancePosition = instanceMatrixNode.mul( positionLocal ).xyz; + positionLocal.assign( instancePosition ); + + // NORMAL + + if ( builder.hasGeometryAttribute( 'normal' ) ) { + + const instanceNormal = transformNormal( normalLocal, instanceMatrixNode ); + + // ASSIGNS + + normalLocal.assign( instanceNormal ); + + } + + // COLOR + + if ( this.instanceColorNode !== null ) { + + varyingProperty( 'vec3', 'vInstanceColor' ).assign( this.instanceColorNode ); + + } + + } + + update( /*frame*/ ) { + + if ( this.instanceMesh.instanceMatrix.usage !== DynamicDrawUsage && this.buffer != null && this.instanceMesh.instanceMatrix.version !== this.buffer.version ) { + + this.buffer.version = this.instanceMesh.instanceMatrix.version; + + } + + if ( this.instanceMesh.instanceColor && this.instanceMesh.instanceColor.usage !== DynamicDrawUsage && this.bufferColor != null && this.instanceMesh.instanceColor.version !== this.bufferColor.version ) { + + this.bufferColor.version = this.instanceMesh.instanceColor.version; + + } + + } + +} + +const instance = /*@__PURE__*/ nodeProxy( InstanceNode ); + +class BatchNode extends Node { + + static get type() { + + return 'BatchNode'; + + } + + constructor( batchMesh ) { + + super( 'void' ); + + this.batchMesh = batchMesh; + + + this.batchingIdNode = null; + + } + + setup( builder ) { + + // POSITION + + if ( this.batchingIdNode === null ) { + + if ( builder.getDrawIndex() === null ) { + + this.batchingIdNode = instanceIndex; + + } else { + + this.batchingIdNode = drawIndex; + + } + + } + + const getIndirectIndex = Fn( ( [ id ] ) => { + + const size = textureSize( textureLoad( this.batchMesh._indirectTexture ), 0 ); + const x = int( id ).modInt( int( size ) ); + const y = int( id ).div( int( size ) ); + return textureLoad( this.batchMesh._indirectTexture, ivec2( x, y ) ).x; + + } ).setLayout( { + name: 'getIndirectIndex', + type: 'uint', + inputs: [ + { name: 'id', type: 'int' } + ] + } ); + + const indirectId = getIndirectIndex( int( this.batchingIdNode ) ); + + const matricesTexture = this.batchMesh._matricesTexture; + + const size = textureSize( textureLoad( matricesTexture ), 0 ); + const j = float( indirectId ).mul( 4 ).toInt().toVar(); + + const x = j.modInt( size ); + const y = j.div( int( size ) ); + const batchingMatrix = mat4( + textureLoad( matricesTexture, ivec2( x, y ) ), + textureLoad( matricesTexture, ivec2( x.add( 1 ), y ) ), + textureLoad( matricesTexture, ivec2( x.add( 2 ), y ) ), + textureLoad( matricesTexture, ivec2( x.add( 3 ), y ) ) + ); + + + const colorsTexture = this.batchMesh._colorsTexture; + + if ( colorsTexture !== null ) { + + const getBatchingColor = Fn( ( [ id ] ) => { + + const size = textureSize( textureLoad( colorsTexture ), 0 ).x; + const j = id; + const x = j.modInt( size ); + const y = j.div( size ); + return textureLoad( colorsTexture, ivec2( x, y ) ).rgb; + + } ).setLayout( { + name: 'getBatchingColor', + type: 'vec3', + inputs: [ + { name: 'id', type: 'int' } + ] + } ); + + const color = getBatchingColor( indirectId ); + + varyingProperty( 'vec3', 'vBatchColor' ).assign( color ); + + } + + const bm = mat3( batchingMatrix ); + + positionLocal.assign( batchingMatrix.mul( positionLocal ) ); + + const transformedNormal = normalLocal.div( vec3( bm[ 0 ].dot( bm[ 0 ] ), bm[ 1 ].dot( bm[ 1 ] ), bm[ 2 ].dot( bm[ 2 ] ) ) ); + + const batchingNormal = bm.mul( transformedNormal ).xyz; + + normalLocal.assign( batchingNormal ); + + if ( builder.hasGeometryAttribute( 'tangent' ) ) { + + tangentLocal.mulAssign( bm ); + + } + + } + +} + +const batch = /*@__PURE__*/ nodeProxy( BatchNode ); + +const _frameId = new WeakMap(); + +class SkinningNode extends Node { + + static get type() { + + return 'SkinningNode'; + + } + + constructor( skinnedMesh, useReference = false ) { + + super( 'void' ); + + this.skinnedMesh = skinnedMesh; + this.useReference = useReference; + + this.updateType = NodeUpdateType.OBJECT; + + // + + this.skinIndexNode = attribute( 'skinIndex', 'uvec4' ); + this.skinWeightNode = attribute( 'skinWeight', 'vec4' ); + + let bindMatrixNode, bindMatrixInverseNode, boneMatricesNode; + + if ( useReference ) { + + bindMatrixNode = reference( 'bindMatrix', 'mat4' ); + bindMatrixInverseNode = reference( 'bindMatrixInverse', 'mat4' ); + boneMatricesNode = referenceBuffer( 'skeleton.boneMatrices', 'mat4', skinnedMesh.skeleton.bones.length ); + + } else { + + bindMatrixNode = uniform( skinnedMesh.bindMatrix, 'mat4' ); + bindMatrixInverseNode = uniform( skinnedMesh.bindMatrixInverse, 'mat4' ); + boneMatricesNode = buffer( skinnedMesh.skeleton.boneMatrices, 'mat4', skinnedMesh.skeleton.bones.length ); + + } + + this.bindMatrixNode = bindMatrixNode; + this.bindMatrixInverseNode = bindMatrixInverseNode; + this.boneMatricesNode = boneMatricesNode; + this.previousBoneMatricesNode = null; + + } + + getSkinnedPosition( boneMatrices = this.boneMatricesNode, position = positionLocal ) { + + const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; + + const boneMatX = boneMatrices.element( skinIndexNode.x ); + const boneMatY = boneMatrices.element( skinIndexNode.y ); + const boneMatZ = boneMatrices.element( skinIndexNode.z ); + const boneMatW = boneMatrices.element( skinIndexNode.w ); + + // POSITION + + const skinVertex = bindMatrixNode.mul( position ); + + const skinned = add( + boneMatX.mul( skinWeightNode.x ).mul( skinVertex ), + boneMatY.mul( skinWeightNode.y ).mul( skinVertex ), + boneMatZ.mul( skinWeightNode.z ).mul( skinVertex ), + boneMatW.mul( skinWeightNode.w ).mul( skinVertex ) + ); + + return bindMatrixInverseNode.mul( skinned ).xyz; + + } + + getSkinnedNormal( boneMatrices = this.boneMatricesNode, normal = normalLocal ) { + + const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; + + const boneMatX = boneMatrices.element( skinIndexNode.x ); + const boneMatY = boneMatrices.element( skinIndexNode.y ); + const boneMatZ = boneMatrices.element( skinIndexNode.z ); + const boneMatW = boneMatrices.element( skinIndexNode.w ); + + // NORMAL + + let skinMatrix = add( + skinWeightNode.x.mul( boneMatX ), + skinWeightNode.y.mul( boneMatY ), + skinWeightNode.z.mul( boneMatZ ), + skinWeightNode.w.mul( boneMatW ) + ); + + skinMatrix = bindMatrixInverseNode.mul( skinMatrix ).mul( bindMatrixNode ); + + return skinMatrix.transformDirection( normal ).xyz; + + } + + getPreviousSkinnedPosition( builder ) { + + const skinnedMesh = builder.object; + + if ( this.previousBoneMatricesNode === null ) { + + skinnedMesh.skeleton.previousBoneMatrices = new Float32Array( skinnedMesh.skeleton.boneMatrices ); + + this.previousBoneMatricesNode = referenceBuffer( 'skeleton.previousBoneMatrices', 'mat4', skinnedMesh.skeleton.bones.length ); + + } + + return this.getSkinnedPosition( this.previousBoneMatricesNode, positionPrevious ); + + } + + needsPreviousBoneMatrices( builder ) { + + const mrt = builder.renderer.getMRT(); + + return mrt && mrt.has( 'velocity' ); + + } + + setup( builder ) { + + if ( this.needsPreviousBoneMatrices( builder ) ) { + + positionPrevious.assign( this.getPreviousSkinnedPosition( builder ) ); + + } + + const skinPosition = this.getSkinnedPosition(); + + + positionLocal.assign( skinPosition ); + + if ( builder.hasGeometryAttribute( 'normal' ) ) { + + const skinNormal = this.getSkinnedNormal(); + + normalLocal.assign( skinNormal ); + + if ( builder.hasGeometryAttribute( 'tangent' ) ) { + + tangentLocal.assign( skinNormal ); + + } + + } + + } + + generate( builder, output ) { + + if ( output !== 'void' ) { + + return positionLocal.build( builder, output ); + + } + + } + + update( frame ) { + + const object = this.useReference ? frame.object : this.skinnedMesh; + const skeleton = object.skeleton; + + if ( _frameId.get( skeleton ) === frame.frameId ) return; + + _frameId.set( skeleton, frame.frameId ); + + if ( this.previousBoneMatricesNode !== null ) skeleton.previousBoneMatrices.set( skeleton.boneMatrices ); + + skeleton.update(); + + } + +} + +const skinning = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh ) ); +const skinningReference = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh, true ) ); + +class LoopNode extends Node { + + static get type() { + + return 'LoopNode'; + + } + + constructor( params = [] ) { + + super(); + + this.params = params; + + } + + getVarName( index ) { + + return String.fromCharCode( 'i'.charCodeAt() + index ); + + } + + getProperties( builder ) { + + const properties = builder.getNodeProperties( this ); + + if ( properties.stackNode !== undefined ) return properties; + + // + + const inputs = {}; + + for ( let i = 0, l = this.params.length - 1; i < l; i ++ ) { + + const param = this.params[ i ]; + + const name = ( param.isNode !== true && param.name ) || this.getVarName( i ); + const type = ( param.isNode !== true && param.type ) || 'int'; + + inputs[ name ] = expression( name, type ); + + } + + const stack = builder.addStack(); // TODO: cache() it + + properties.returnsNode = this.params[ this.params.length - 1 ]( inputs, stack, builder ); + properties.stackNode = stack; + + builder.removeStack(); + + return properties; + + } + + getNodeType( builder ) { + + const { returnsNode } = this.getProperties( builder ); + + return returnsNode ? returnsNode.getNodeType( builder ) : 'void'; + + } + + setup( builder ) { + + // setup properties + + this.getProperties( builder ); + + } + + generate( builder ) { + + const properties = this.getProperties( builder ); + + const params = this.params; + const stackNode = properties.stackNode; + + for ( let i = 0, l = params.length - 1; i < l; i ++ ) { + + const param = params[ i ]; + + let start = null, end = null, name = null, type = null, condition = null, update = null; + + if ( param.isNode ) { + + type = 'int'; + name = this.getVarName( i ); + start = '0'; + end = param.build( builder, type ); + condition = '<'; + + } else { + + type = param.type || 'int'; + name = param.name || this.getVarName( i ); + start = param.start; + end = param.end; + condition = param.condition; + update = param.update; + + if ( typeof start === 'number' ) start = start.toString(); + else if ( start && start.isNode ) start = start.build( builder, type ); + + if ( typeof end === 'number' ) end = end.toString(); + else if ( end && end.isNode ) end = end.build( builder, type ); + + if ( start !== undefined && end === undefined ) { + + start = start + ' - 1'; + end = '0'; + condition = '>='; + + } else if ( end !== undefined && start === undefined ) { + + start = '0'; + condition = '<'; + + } + + if ( condition === undefined ) { + + if ( Number( start ) > Number( end ) ) { + + condition = '>='; + + } else { + + condition = '<'; + + } + + } + + } + + const internalParam = { start, end, condition }; + + // + + const startSnippet = internalParam.start; + const endSnippet = internalParam.end; + + let declarationSnippet = ''; + let conditionalSnippet = ''; + let updateSnippet = ''; + + if ( ! update ) { + + if ( type === 'int' || type === 'uint' ) { + + if ( condition.includes( '<' ) ) update = '++'; + else update = '--'; + + } else { + + if ( condition.includes( '<' ) ) update = '+= 1.'; + else update = '-= 1.'; + + } + + } + + declarationSnippet += builder.getVar( type, name ) + ' = ' + startSnippet; + + conditionalSnippet += name + ' ' + condition + ' ' + endSnippet; + updateSnippet += name + ' ' + update; + + const forSnippet = `for ( ${ declarationSnippet }; ${ conditionalSnippet }; ${ updateSnippet } )`; + + builder.addFlowCode( ( i === 0 ? '\n' : '' ) + builder.tab + forSnippet + ' {\n\n' ).addFlowTab(); + + } + + const stackSnippet = stackNode.build( builder, 'void' ); + + const returnsSnippet = properties.returnsNode ? properties.returnsNode.build( builder ) : ''; + + builder.removeFlowTab().addFlowCode( '\n' + builder.tab + stackSnippet ); + + for ( let i = 0, l = this.params.length - 1; i < l; i ++ ) { + + builder.addFlowCode( ( i === 0 ? '' : builder.tab ) + '}\n\n' ).removeFlowTab(); + + } + + builder.addFlowTab(); + + return returnsSnippet; + + } + +} + +const Loop = ( ...params ) => nodeObject( new LoopNode( nodeArray( params, 'int' ) ) ).append(); +const Continue = () => expression( 'continue' ).append(); +const Break = () => expression( 'break' ).append(); + +// + +const loop = ( ...params ) => { // @deprecated, r168 + + console.warn( 'TSL.LoopNode: loop() has been renamed to Loop().' ); + return Loop( ...params ); + +}; + +const _morphTextures = /*@__PURE__*/ new WeakMap(); +const _morphVec4 = /*@__PURE__*/ new Vector4(); + +const getMorph = /*@__PURE__*/ Fn( ( { bufferMap, influence, stride, width, depth, offset } ) => { + + const texelIndex = int( vertexIndex ).mul( stride ).add( offset ); + + const y = texelIndex.div( width ); + const x = texelIndex.sub( y.mul( width ) ); + + const bufferAttrib = textureLoad( bufferMap, ivec2( x, y ) ).depth( depth ); + + return bufferAttrib.mul( influence ); + +} ); + +function getEntry( geometry ) { + + const hasMorphPosition = geometry.morphAttributes.position !== undefined; + const hasMorphNormals = geometry.morphAttributes.normal !== undefined; + const hasMorphColors = geometry.morphAttributes.color !== undefined; + + // instead of using attributes, the WebGL 2 code path encodes morph targets + // into an array of data textures. Each layer represents a single morph target. + + const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; + const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; + + let entry = _morphTextures.get( geometry ); + + if ( entry === undefined || entry.count !== morphTargetsCount ) { + + if ( entry !== undefined ) entry.texture.dispose(); + + const morphTargets = geometry.morphAttributes.position || []; + const morphNormals = geometry.morphAttributes.normal || []; + const morphColors = geometry.morphAttributes.color || []; + + let vertexDataCount = 0; + + if ( hasMorphPosition === true ) vertexDataCount = 1; + if ( hasMorphNormals === true ) vertexDataCount = 2; + if ( hasMorphColors === true ) vertexDataCount = 3; + + let width = geometry.attributes.position.count * vertexDataCount; + let height = 1; + + const maxTextureSize = 4096; // @TODO: Use 'capabilities.maxTextureSize' + + if ( width > maxTextureSize ) { + + height = Math.ceil( width / maxTextureSize ); + width = maxTextureSize; + + } + + const buffer = new Float32Array( width * height * 4 * morphTargetsCount ); + + const bufferTexture = new DataArrayTexture( buffer, width, height, morphTargetsCount ); + bufferTexture.type = FloatType; + bufferTexture.needsUpdate = true; + + // fill buffer + + const vertexDataStride = vertexDataCount * 4; + + for ( let i = 0; i < morphTargetsCount; i ++ ) { + + const morphTarget = morphTargets[ i ]; + const morphNormal = morphNormals[ i ]; + const morphColor = morphColors[ i ]; + + const offset = width * height * 4 * i; + + for ( let j = 0; j < morphTarget.count; j ++ ) { + + const stride = j * vertexDataStride; + + if ( hasMorphPosition === true ) { + + _morphVec4.fromBufferAttribute( morphTarget, j ); + + buffer[ offset + stride + 0 ] = _morphVec4.x; + buffer[ offset + stride + 1 ] = _morphVec4.y; + buffer[ offset + stride + 2 ] = _morphVec4.z; + buffer[ offset + stride + 3 ] = 0; + + } + + if ( hasMorphNormals === true ) { + + _morphVec4.fromBufferAttribute( morphNormal, j ); + + buffer[ offset + stride + 4 ] = _morphVec4.x; + buffer[ offset + stride + 5 ] = _morphVec4.y; + buffer[ offset + stride + 6 ] = _morphVec4.z; + buffer[ offset + stride + 7 ] = 0; + + } + + if ( hasMorphColors === true ) { + + _morphVec4.fromBufferAttribute( morphColor, j ); + + buffer[ offset + stride + 8 ] = _morphVec4.x; + buffer[ offset + stride + 9 ] = _morphVec4.y; + buffer[ offset + stride + 10 ] = _morphVec4.z; + buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? _morphVec4.w : 1; + + } + + } + + } + + entry = { + count: morphTargetsCount, + texture: bufferTexture, + stride: vertexDataCount, + size: new Vector2( width, height ) + }; + + _morphTextures.set( geometry, entry ); + + function disposeTexture() { + + bufferTexture.dispose(); + + _morphTextures.delete( geometry ); + + geometry.removeEventListener( 'dispose', disposeTexture ); + + } + + geometry.addEventListener( 'dispose', disposeTexture ); + + } + + return entry; + +} + + +class MorphNode extends Node { + + static get type() { + + return 'MorphNode'; + + } + + constructor( mesh ) { + + super( 'void' ); + + this.mesh = mesh; + this.morphBaseInfluence = uniform( 1 ); + + this.updateType = NodeUpdateType.OBJECT; + + } + + setup( builder ) { + + const { geometry } = builder; + + const hasMorphPosition = geometry.morphAttributes.position !== undefined; + const hasMorphNormals = geometry.hasAttribute( 'normal' ) && geometry.morphAttributes.normal !== undefined; + + const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; + const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; + + // nodes + + const { texture: bufferMap, stride, size } = getEntry( geometry ); + + if ( hasMorphPosition === true ) positionLocal.mulAssign( this.morphBaseInfluence ); + if ( hasMorphNormals === true ) normalLocal.mulAssign( this.morphBaseInfluence ); + + const width = int( size.width ); + + Loop( morphTargetsCount, ( { i } ) => { + + const influence = float( 0 ).toVar(); + + if ( this.mesh.count > 1 && ( this.mesh.morphTexture !== null && this.mesh.morphTexture !== undefined ) ) { + + influence.assign( textureLoad( this.mesh.morphTexture, ivec2( int( i ).add( 1 ), int( instanceIndex ) ) ).r ); + + } else { + + influence.assign( reference( 'morphTargetInfluences', 'float' ).element( i ).toVar() ); + + } + + if ( hasMorphPosition === true ) { + + positionLocal.addAssign( getMorph( { + bufferMap, + influence, + stride, + width, + depth: i, + offset: int( 0 ) + } ) ); + + } + + if ( hasMorphNormals === true ) { + + normalLocal.addAssign( getMorph( { + bufferMap, + influence, + stride, + width, + depth: i, + offset: int( 1 ) + } ) ); + + } + + } ); + + } + + update() { + + const morphBaseInfluence = this.morphBaseInfluence; + + if ( this.mesh.geometry.morphTargetsRelative ) { + + morphBaseInfluence.value = 1; + + } else { + + morphBaseInfluence.value = 1 - this.mesh.morphTargetInfluences.reduce( ( a, b ) => a + b, 0 ); + + } + + } + +} + +const morphReference = /*@__PURE__*/ nodeProxy( MorphNode ); + +const sortLights = ( lights ) => { + + return lights.sort( ( a, b ) => a.id - b.id ); + +}; + +const getLightNodeById = ( id, lightNodes ) => { + + for ( const lightNode of lightNodes ) { + + if ( lightNode.isAnalyticLightNode && lightNode.light.id === id ) { + + return lightNode; + + } + + } + + return null; + +}; + +const _lightsNodeRef = /*@__PURE__*/ new WeakMap(); + +class LightsNode extends Node { + + static get type() { + + return 'LightsNode'; + + } + + constructor( lights = [] ) { + + super( 'vec3' ); + + this.totalDiffuseNode = vec3().toVar( 'totalDiffuse' ); + this.totalSpecularNode = vec3().toVar( 'totalSpecular' ); + + this.outgoingLightNode = vec3().toVar( 'outgoingLight' ); + + this._lights = lights; + + this._lightNodes = null; + this._lightNodesHash = null; + + this.global = true; + + } + + getHash( builder ) { + + if ( this._lightNodesHash === null ) { + + if ( this._lightNodes === null ) this.setupLightsNode( builder ); + + const hash = []; + + for ( const lightNode of this._lightNodes ) { + + hash.push( lightNode.getHash() ); + + } + + this._lightNodesHash = 'lights-' + hash.join( ',' ); + + } + + return this._lightNodesHash; + + } + + analyze( builder ) { + + const properties = builder.getDataFromNode( this ); + + for ( const node of properties.nodes ) { + + node.build( builder ); + + } + + } + + setupLightsNode( builder ) { + + const lightNodes = []; + + const previousLightNodes = this._lightNodes; + + const lights = sortLights( this._lights ); + const nodeLibrary = builder.renderer.nodes.library; + + for ( const light of lights ) { + + if ( light.isNode ) { + + lightNodes.push( nodeObject( light ) ); + + } else { + + let lightNode = null; + + if ( previousLightNodes !== null ) { + + lightNode = getLightNodeById( light.id, previousLightNodes ); // resuse existing light node + + } + + if ( lightNode === null ) { + + const lightNodeClass = nodeLibrary.getLightNodeClass( light.constructor ); + + if ( lightNodeClass === null ) { + + console.warn( `LightsNode.setupNodeLights: Light node not found for ${ light.constructor.name }` ); + continue; + + } + + let lightNode = null; + + if ( ! _lightsNodeRef.has( light ) ) { + + lightNode = new lightNodeClass( light ); + _lightsNodeRef.set( light, lightNode ); + + } else { + + lightNode = _lightsNodeRef.get( light ); + + } + + lightNodes.push( lightNode ); + + } + + } + + } + + this._lightNodes = lightNodes; + + } + + setup( builder ) { + + if ( this._lightNodes === null ) this.setupLightsNode( builder ); + + const context = builder.context; + const lightingModel = context.lightingModel; + + let outgoingLightNode = this.outgoingLightNode; + + if ( lightingModel ) { + + const { _lightNodes, totalDiffuseNode, totalSpecularNode } = this; + + context.outgoingLight = outgoingLightNode; + + const stack = builder.addStack(); + + // + + const properties = builder.getDataFromNode( this ); + properties.nodes = stack.nodes; + + // + + lightingModel.start( context, stack, builder ); + + // lights + + for ( const lightNode of _lightNodes ) { + + lightNode.build( builder ); + + } + + // + + lightingModel.indirect( context, stack, builder ); + + // + + const { backdrop, backdropAlpha } = context; + const { directDiffuse, directSpecular, indirectDiffuse, indirectSpecular } = context.reflectedLight; + + let totalDiffuse = directDiffuse.add( indirectDiffuse ); + + if ( backdrop !== null ) { + + if ( backdropAlpha !== null ) { + + totalDiffuse = vec3( backdropAlpha.mix( totalDiffuse, backdrop ) ); + + } else { + + totalDiffuse = vec3( backdrop ); + + } + + context.material.transparent = true; + + } + + totalDiffuseNode.assign( totalDiffuse ); + totalSpecularNode.assign( directSpecular.add( indirectSpecular ) ); + + outgoingLightNode.assign( totalDiffuseNode.add( totalSpecularNode ) ); + + // + + lightingModel.finish( context, stack, builder ); + + // + + outgoingLightNode = outgoingLightNode.bypass( builder.removeStack() ); + + } + + return outgoingLightNode; + + } + + setLights( lights ) { + + this._lights = lights; + + this._lightNodes = null; + this._lightNodesHash = null; + + return this; + + } + + getLights() { + + return this._lights; + + } + +} + +const lights = /*@__PURE__*/ nodeProxy( LightsNode ); + +class LightingNode extends Node { + + static get type() { + + return 'LightingNode'; + + } + + constructor() { + + super( 'vec3' ); + + this.isLightingNode = true; + + } + + generate( /*builder*/ ) { + + console.warn( 'Abstract function.' ); + + } + +} + +class AONode extends LightingNode { + + static get type() { + + return 'AONode'; + + } + + constructor( aoNode = null ) { + + super(); + + this.aoNode = aoNode; + + } + + setup( builder ) { + + builder.context.ambientOcclusion.mulAssign( this.aoNode ); + + } + +} + +class LightingContextNode extends ContextNode { + + static get type() { + + return 'LightingContextNode'; + + } + + constructor( node, lightingModel = null, backdropNode = null, backdropAlphaNode = null ) { + + super( node ); + + this.lightingModel = lightingModel; + this.backdropNode = backdropNode; + this.backdropAlphaNode = backdropAlphaNode; + + this._value = null; + + } + + getContext() { + + const { backdropNode, backdropAlphaNode } = this; + + const directDiffuse = vec3().toVar( 'directDiffuse' ), + directSpecular = vec3().toVar( 'directSpecular' ), + indirectDiffuse = vec3().toVar( 'indirectDiffuse' ), + indirectSpecular = vec3().toVar( 'indirectSpecular' ); + + const reflectedLight = { + directDiffuse, + directSpecular, + indirectDiffuse, + indirectSpecular + }; + + const context = { + radiance: vec3().toVar( 'radiance' ), + irradiance: vec3().toVar( 'irradiance' ), + iblIrradiance: vec3().toVar( 'iblIrradiance' ), + ambientOcclusion: float( 1 ).toVar( 'ambientOcclusion' ), + reflectedLight, + backdrop: backdropNode, + backdropAlpha: backdropAlphaNode + }; + + return context; + + } + + setup( builder ) { + + this.value = this._value || ( this._value = this.getContext() ); + this.value.lightingModel = this.lightingModel || builder.context.lightingModel; + + return super.setup( builder ); + + } + +} + +const lightingContext = /*@__PURE__*/ nodeProxy( LightingContextNode ); + +class IrradianceNode extends LightingNode { + + static get type() { + + return 'IrradianceNode'; + + } + + constructor( node ) { + + super(); + + this.node = node; + + } + + setup( builder ) { + + builder.context.irradiance.addAssign( this.node ); + + } + +} + +let screenSizeVec, viewportVec; + +class ScreenNode extends Node { + + static get type() { + + return 'ScreenNode'; + + } + + constructor( scope ) { + + super(); + + this.scope = scope; + + this.isViewportNode = true; + + } + + getNodeType() { + + if ( this.scope === ScreenNode.VIEWPORT ) return 'vec4'; + else return 'vec2'; + + } + + getUpdateType() { + + let updateType = NodeUpdateType.NONE; + + if ( this.scope === ScreenNode.SIZE || this.scope === ScreenNode.VIEWPORT ) { + + updateType = NodeUpdateType.RENDER; + + } + + this.updateType = updateType; + + return updateType; + + } + + update( { renderer } ) { + + const renderTarget = renderer.getRenderTarget(); + + if ( this.scope === ScreenNode.VIEWPORT ) { + + if ( renderTarget !== null ) { + + viewportVec.copy( renderTarget.viewport ); + + } else { + + renderer.getViewport( viewportVec ); + + viewportVec.multiplyScalar( renderer.getPixelRatio() ); + + } + + } else { + + if ( renderTarget !== null ) { + + screenSizeVec.width = renderTarget.width; + screenSizeVec.height = renderTarget.height; + + } else { + + renderer.getDrawingBufferSize( screenSizeVec ); + + } + + } + + } + + setup( /*builder*/ ) { + + const scope = this.scope; + + let output = null; + + if ( scope === ScreenNode.SIZE ) { + + output = uniform( screenSizeVec || ( screenSizeVec = new Vector2() ) ); + + } else if ( scope === ScreenNode.VIEWPORT ) { + + output = uniform( viewportVec || ( viewportVec = new Vector4() ) ); + + } else { + + output = vec2( screenCoordinate.div( screenSize ) ); + + } + + return output; + + } + + generate( builder ) { + + if ( this.scope === ScreenNode.COORDINATE ) { + + let coord = builder.getFragCoord(); + + if ( builder.isFlipY() ) { + + // follow webgpu standards + + const size = builder.getNodeProperties( screenSize ).outputNode.build( builder ); + + coord = `${ builder.getType( 'vec2' ) }( ${ coord }.x, ${ size }.y - ${ coord }.y )`; + + } + + return coord; + + } + + return super.generate( builder ); + + } + +} + +ScreenNode.COORDINATE = 'coordinate'; +ScreenNode.VIEWPORT = 'viewport'; +ScreenNode.SIZE = 'size'; +ScreenNode.UV = 'uv'; + +// Screen + +const screenUV = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.UV ); +const screenSize = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.SIZE ); +const screenCoordinate = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.COORDINATE ); + +// Viewport + +const viewport = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.VIEWPORT ); +const viewportSize = viewport.zw; +const viewportCoordinate = /*@__PURE__*/ screenCoordinate.sub( viewport.xy ); +const viewportUV = /*@__PURE__*/ viewportCoordinate.div( viewportSize ); + +// Deprecated + +const viewportResolution = /*@__PURE__*/ ( Fn( () => { // @deprecated, r169 + + console.warn( 'TSL.ViewportNode: "viewportResolution" is deprecated. Use "screenSize" instead.' ); + + return screenSize; + +}, 'vec2' ).once() )(); + +const viewportTopLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 + + console.warn( 'TSL.ViewportNode: "viewportTopLeft" is deprecated. Use "screenUV" instead.' ); + + return screenUV; + +}, 'vec2' ).once() )(); + +const viewportBottomLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 + + console.warn( 'TSL.ViewportNode: "viewportBottomLeft" is deprecated. Use "screenUV.flipY()" instead.' ); + + return screenUV.flipY(); + +}, 'vec2' ).once() )(); + +const _size$a = /*@__PURE__*/ new Vector2(); + +class ViewportTextureNode extends TextureNode { + + static get type() { + + return 'ViewportTextureNode'; + + } + + constructor( uvNode = screenUV, levelNode = null, framebufferTexture = null ) { + + if ( framebufferTexture === null ) { + + framebufferTexture = new FramebufferTexture(); + framebufferTexture.minFilter = LinearMipmapLinearFilter; + + } + + super( framebufferTexture, uvNode, levelNode ); + + this.generateMipmaps = false; + + this.isOutputTextureNode = true; + + this.updateBeforeType = NodeUpdateType.FRAME; + + } + + updateBefore( frame ) { + + const renderer = frame.renderer; + renderer.getDrawingBufferSize( _size$a ); + + // + + const framebufferTexture = this.value; + + if ( framebufferTexture.image.width !== _size$a.width || framebufferTexture.image.height !== _size$a.height ) { + + framebufferTexture.image.width = _size$a.width; + framebufferTexture.image.height = _size$a.height; + framebufferTexture.needsUpdate = true; + + } + + // + + const currentGenerateMipmaps = framebufferTexture.generateMipmaps; + framebufferTexture.generateMipmaps = this.generateMipmaps; + + renderer.copyFramebufferToTexture( framebufferTexture ); + + framebufferTexture.generateMipmaps = currentGenerateMipmaps; + + } + + clone() { + + const viewportTextureNode = new this.constructor( this.uvNode, this.levelNode, this.value ); + viewportTextureNode.generateMipmaps = this.generateMipmaps; + + return viewportTextureNode; + + } + +} + +const viewportTexture = /*@__PURE__*/ nodeProxy( ViewportTextureNode ); +const viewportMipTexture = /*@__PURE__*/ nodeProxy( ViewportTextureNode, null, null, { generateMipmaps: true } ); + +let sharedDepthbuffer = null; + +class ViewportDepthTextureNode extends ViewportTextureNode { + + static get type() { + + return 'ViewportDepthTextureNode'; + + } + + constructor( uvNode = screenUV, levelNode = null ) { + + if ( sharedDepthbuffer === null ) { + + sharedDepthbuffer = new DepthTexture(); + + } + + super( uvNode, levelNode, sharedDepthbuffer ); + + } + +} + +const viewportDepthTexture = /*@__PURE__*/ nodeProxy( ViewportDepthTextureNode ); + +class ViewportDepthNode extends Node { + + static get type() { + + return 'ViewportDepthNode'; + + } + + constructor( scope, valueNode = null ) { + + super( 'float' ); + + this.scope = scope; + this.valueNode = valueNode; + + this.isViewportDepthNode = true; + + } + + generate( builder ) { + + const { scope } = this; + + if ( scope === ViewportDepthNode.DEPTH_BASE ) { + + return builder.getFragDepth(); + + } + + return super.generate( builder ); + + } + + setup( { camera } ) { + + const { scope } = this; + const value = this.valueNode; + + let node = null; + + if ( scope === ViewportDepthNode.DEPTH_BASE ) { + + if ( value !== null ) { + + node = depthBase().assign( value ); + + } + + } else if ( scope === ViewportDepthNode.DEPTH ) { + + if ( camera.isPerspectiveCamera ) { + + node = viewZToPerspectiveDepth( positionView.z, cameraNear, cameraFar ); + + } else { + + node = viewZToOrthographicDepth( positionView.z, cameraNear, cameraFar ); + + } + + } else if ( scope === ViewportDepthNode.LINEAR_DEPTH ) { + + if ( value !== null ) { + + if ( camera.isPerspectiveCamera ) { + + const viewZ = perspectiveDepthToViewZ( value, cameraNear, cameraFar ); + + node = viewZToOrthographicDepth( viewZ, cameraNear, cameraFar ); + + } else { + + node = value; + + } + + } else { + + node = viewZToOrthographicDepth( positionView.z, cameraNear, cameraFar ); + + } + + } + + return node; + + } + +} + +ViewportDepthNode.DEPTH_BASE = 'depthBase'; +ViewportDepthNode.DEPTH = 'depth'; +ViewportDepthNode.LINEAR_DEPTH = 'linearDepth'; + +// NOTE: viewZ, the z-coordinate in camera space, is negative for points in front of the camera + +// -near maps to 0; -far maps to 1 +const viewZToOrthographicDepth = ( viewZ, near, far ) => viewZ.add( near ).div( near.sub( far ) ); + +// maps orthographic depth in [ 0, 1 ] to viewZ +const orthographicDepthToViewZ = ( depth, near, far ) => near.sub( far ).mul( depth ).sub( near ); + +// NOTE: https://twitter.com/gonnavis/status/1377183786949959682 + +// -near maps to 0; -far maps to 1 +const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ ).mul( far ).div( far.sub( near ).mul( viewZ ) ); + +// maps perspective depth in [ 0, 1 ] to viewZ +const perspectiveDepthToViewZ = ( depth, near, far ) => near.mul( far ).div( far.sub( near ).mul( depth ).sub( far ) ); + +const depthBase = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.DEPTH_BASE ); + +const depth = /*@__PURE__*/ nodeImmutable( ViewportDepthNode, ViewportDepthNode.DEPTH ); +const linearDepth = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.LINEAR_DEPTH ); +const viewportLinearDepth = /*@__PURE__*/ linearDepth( viewportDepthTexture() ); + +depth.assign = ( value ) => depthBase( value ); + +class ClippingNode extends Node { + + static get type() { + + return 'ClippingNode'; + + } + + constructor( scope = ClippingNode.DEFAULT ) { + + super(); + + this.scope = scope; + + } + + setup( builder ) { + + super.setup( builder ); + + const clippingContext = builder.clippingContext; + const { localClipIntersection, localClippingCount, globalClippingCount } = clippingContext; + + const numClippingPlanes = globalClippingCount + localClippingCount; + const numUnionClippingPlanes = localClipIntersection ? numClippingPlanes - localClippingCount : numClippingPlanes; + + if ( this.scope === ClippingNode.ALPHA_TO_COVERAGE ) { + + return this.setupAlphaToCoverage( clippingContext.planes, numClippingPlanes, numUnionClippingPlanes ); + + } else { + + return this.setupDefault( clippingContext.planes, numClippingPlanes, numUnionClippingPlanes ); + + } + + } + + setupAlphaToCoverage( planes, numClippingPlanes, numUnionClippingPlanes ) { + + return Fn( () => { + + const clippingPlanes = uniformArray( planes ); + + const distanceToPlane = property( 'float', 'distanceToPlane' ); + const distanceGradient = property( 'float', 'distanceToGradient' ); + + const clipOpacity = property( 'float', 'clipOpacity' ); + + clipOpacity.assign( 1 ); + + let plane; + + Loop( numUnionClippingPlanes, ( { i } ) => { + + plane = clippingPlanes.element( i ); + + distanceToPlane.assign( positionView.dot( plane.xyz ).negate().add( plane.w ) ); + distanceGradient.assign( distanceToPlane.fwidth().div( 2.0 ) ); + + clipOpacity.mulAssign( smoothstep( distanceGradient.negate(), distanceGradient, distanceToPlane ) ); + + clipOpacity.equal( 0.0 ).discard(); + + } ); + + if ( numUnionClippingPlanes < numClippingPlanes ) { + + const unionClipOpacity = property( 'float', 'unionclipOpacity' ); + + unionClipOpacity.assign( 1 ); + + Loop( { start: numUnionClippingPlanes, end: numClippingPlanes }, ( { i } ) => { + + plane = clippingPlanes.element( i ); + + distanceToPlane.assign( positionView.dot( plane.xyz ).negate().add( plane.w ) ); + distanceGradient.assign( distanceToPlane.fwidth().div( 2.0 ) ); + + unionClipOpacity.mulAssign( smoothstep( distanceGradient.negate(), distanceGradient, distanceToPlane ).oneMinus() ); + + } ); + + clipOpacity.mulAssign( unionClipOpacity.oneMinus() ); + + } + + diffuseColor.a.mulAssign( clipOpacity ); + + diffuseColor.a.equal( 0.0 ).discard(); + + } )(); + + } + + setupDefault( planes, numClippingPlanes, numUnionClippingPlanes ) { + + return Fn( () => { + + const clippingPlanes = uniformArray( planes ); + + let plane; + + Loop( numUnionClippingPlanes, ( { i } ) => { + + plane = clippingPlanes.element( i ); + positionView.dot( plane.xyz ).greaterThan( plane.w ).discard(); + + } ); + + if ( numUnionClippingPlanes < numClippingPlanes ) { + + const clipped = property( 'bool', 'clipped' ); + + clipped.assign( true ); + + Loop( { start: numUnionClippingPlanes, end: numClippingPlanes }, ( { i } ) => { + + plane = clippingPlanes.element( i ); + clipped.assign( positionView.dot( plane.xyz ).greaterThan( plane.w ).and( clipped ) ); + + } ); + + clipped.discard(); + + } + + } )(); + + } + +} + +ClippingNode.ALPHA_TO_COVERAGE = 'alphaToCoverage'; +ClippingNode.DEFAULT = 'default'; + +const clipping = () => nodeObject( new ClippingNode() ); + +const clippingAlpha = () => nodeObject( new ClippingNode( ClippingNode.ALPHA_TO_COVERAGE ) ); + +class NodeMaterial extends Material { + + static get type() { + + return 'NodeMaterial'; + + } + + constructor() { + + super(); + + this.isNodeMaterial = true; + + this.type = this.constructor.type; + + this.forceSinglePass = false; + + this.fog = true; + this.lights = false; + + this.lightsNode = null; + this.envNode = null; + this.aoNode = null; + + this.colorNode = null; + this.normalNode = null; + this.opacityNode = null; + this.backdropNode = null; + this.backdropAlphaNode = null; + this.alphaTestNode = null; + + this.positionNode = null; + + this.depthNode = null; + this.shadowNode = null; + this.shadowPositionNode = null; + + this.outputNode = null; + this.mrtNode = null; + + this.fragmentNode = null; + this.vertexNode = null; + + } + + customProgramCacheKey() { + + return this.type + getCacheKey$1( this ); + + } + + build( builder ) { + + this.setup( builder ); + + } + + setupObserver( builder ) { + + return new NodeMaterialObserver( builder ); + + } + + setup( builder ) { + + builder.context.setupNormal = () => this.setupNormal( builder ); + + // < VERTEX STAGE > + + builder.addStack(); + + builder.stack.outputNode = this.vertexNode || this.setupPosition( builder ); + + builder.addFlow( 'vertex', builder.removeStack() ); + + // < FRAGMENT STAGE > + + builder.addStack(); + + let resultNode; + + const clippingNode = this.setupClipping( builder ); + + if ( this.depthWrite === true ) this.setupDepth( builder ); + + if ( this.fragmentNode === null ) { + + this.setupDiffuseColor( builder ); + this.setupVariants( builder ); + + const outgoingLightNode = this.setupLighting( builder ); + + if ( clippingNode !== null ) builder.stack.add( clippingNode ); + + // force unsigned floats - useful for RenderTargets + + const basicOutput = vec4( outgoingLightNode, diffuseColor.a ).max( 0 ); + + resultNode = this.setupOutput( builder, basicOutput ); + + // OUTPUT NODE + + output.assign( resultNode ); + + // + + if ( this.outputNode !== null ) resultNode = this.outputNode; + + // MRT + + const renderTarget = builder.renderer.getRenderTarget(); + + if ( renderTarget !== null ) { + + const mrt = builder.renderer.getMRT(); + const materialMRT = this.mrtNode; + + if ( mrt !== null ) { + + resultNode = mrt; + + if ( materialMRT !== null ) { + + resultNode = mrt.merge( materialMRT ); + + } + + } else if ( materialMRT !== null ) { + + resultNode = materialMRT; + + } + + } + + } else { + + let fragmentNode = this.fragmentNode; + + if ( fragmentNode.isOutputStructNode !== true ) { + + fragmentNode = vec4( fragmentNode ); + + } + + resultNode = this.setupOutput( builder, fragmentNode ); + + } + + builder.stack.outputNode = resultNode; + + builder.addFlow( 'fragment', builder.removeStack() ); + + // < MONITOR > + + builder.monitor = this.setupObserver( builder ); + + } + + setupClipping( builder ) { + + if ( builder.clippingContext === null ) return null; + + const { globalClippingCount, localClippingCount } = builder.clippingContext; + + let result = null; + + if ( globalClippingCount || localClippingCount ) { + + const samples = builder.renderer.samples; + + if ( this.alphaToCoverage && samples > 1 ) { + + // to be added to flow when the color/alpha value has been determined + result = clippingAlpha(); + + } else { + + builder.stack.add( clipping() ); + + } + + } + + return result; + + } + + setupDepth( builder ) { + + const { renderer } = builder; + + // Depth + + let depthNode = this.depthNode; + + if ( depthNode === null ) { + + const mrt = renderer.getMRT(); + + if ( mrt && mrt.has( 'depth' ) ) { + + depthNode = mrt.get( 'depth' ); + + } else if ( renderer.logarithmicDepthBuffer === true ) { + + const fragDepth = modelViewProjection().w.add( 1 ); + + depthNode = fragDepth.log2().mul( cameraLogDepth ).mul( 0.5 ); + + } + + } + + if ( depthNode !== null ) { + + depth.assign( depthNode ).append(); + + } + + } + + setupPosition( builder ) { + + const { object } = builder; + const geometry = object.geometry; + + builder.addStack(); + + // Vertex + + if ( geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color ) { + + morphReference( object ).append(); + + } + + if ( object.isSkinnedMesh === true ) { + + skinningReference( object ).append(); + + } + + if ( this.displacementMap ) { + + const displacementMap = materialReference( 'displacementMap', 'texture' ); + const displacementScale = materialReference( 'displacementScale', 'float' ); + const displacementBias = materialReference( 'displacementBias', 'float' ); + + positionLocal.addAssign( normalLocal.normalize().mul( ( displacementMap.x.mul( displacementScale ).add( displacementBias ) ) ) ); + + } + + if ( object.isBatchedMesh ) { + + batch( object ).append(); + + } + + if ( ( object.instanceMatrix && object.instanceMatrix.isInstancedBufferAttribute === true ) ) { + + instance( object ).append(); + + } + + if ( this.positionNode !== null ) { + + positionLocal.assign( this.positionNode ); + + } + + const mvp = modelViewProjection(); + + builder.context.vertex = builder.removeStack(); + builder.context.mvp = mvp; + + return mvp; + + } + + setupDiffuseColor( { object, geometry } ) { + + let colorNode = this.colorNode ? vec4( this.colorNode ) : materialColor; + + // VERTEX COLORS + + if ( this.vertexColors === true && geometry.hasAttribute( 'color' ) ) { + + colorNode = vec4( colorNode.xyz.mul( attribute( 'color', 'vec3' ) ), colorNode.a ); + + } + + // Instanced colors + + if ( object.instanceColor ) { + + const instanceColor = varyingProperty( 'vec3', 'vInstanceColor' ); + + colorNode = instanceColor.mul( colorNode ); + + } + + if ( object.isBatchedMesh && object._colorsTexture ) { + + const batchColor = varyingProperty( 'vec3', 'vBatchColor' ); + + colorNode = batchColor.mul( colorNode ); + + } + + + // COLOR + + diffuseColor.assign( colorNode ); + + // OPACITY + + const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity; + diffuseColor.a.assign( diffuseColor.a.mul( opacityNode ) ); + + // ALPHA TEST + + if ( this.alphaTestNode !== null || this.alphaTest > 0 ) { + + const alphaTestNode = this.alphaTestNode !== null ? float( this.alphaTestNode ) : materialAlphaTest; + + diffuseColor.a.lessThanEqual( alphaTestNode ).discard(); + + } + + if ( this.transparent === false && this.blending === NormalBlending && this.alphaToCoverage === false ) { + + diffuseColor.a.assign( 1.0 ); + + } + + } + + setupVariants( /*builder*/ ) { + + // Interface function. + + } + + setupOutgoingLight() { + + return ( this.lights === true ) ? vec3( 0 ) : diffuseColor.rgb; + + } + + setupNormal() { + + return this.normalNode ? vec3( this.normalNode ) : materialNormal; + + } + + setupEnvironment( /*builder*/ ) { + + let node = null; + + if ( this.envNode ) { + + node = this.envNode; + + } else if ( this.envMap ) { + + node = this.envMap.isCubeTexture ? materialReference( 'envMap', 'cubeTexture' ) : materialReference( 'envMap', 'texture' ); + + } + + return node; + + } + + setupLightMap( builder ) { + + let node = null; + + if ( builder.material.lightMap ) { + + node = new IrradianceNode( materialLightMap ); + + } + + return node; + + } + + setupLights( builder ) { + + const materialLightsNode = []; + + // + + const envNode = this.setupEnvironment( builder ); + + if ( envNode && envNode.isLightingNode ) { + + materialLightsNode.push( envNode ); + + } + + const lightMapNode = this.setupLightMap( builder ); + + if ( lightMapNode && lightMapNode.isLightingNode ) { + + materialLightsNode.push( lightMapNode ); + + } + + if ( this.aoNode !== null || builder.material.aoMap ) { + + const aoNode = this.aoNode !== null ? this.aoNode : materialAOMap; + + materialLightsNode.push( new AONode( aoNode ) ); + + } + + let lightsN = this.lightsNode || builder.lightsNode; + + if ( materialLightsNode.length > 0 ) { + + lightsN = lights( [ ...lightsN.getLights(), ...materialLightsNode ] ); + + } + + return lightsN; + + } + + setupLightingModel( /*builder*/ ) { + + // Interface function. + + } + + setupLighting( builder ) { + + const { material } = builder; + const { backdropNode, backdropAlphaNode, emissiveNode } = this; + + // OUTGOING LIGHT + + const lights = this.lights === true || this.lightsNode !== null; + + const lightsNode = lights ? this.setupLights( builder ) : null; + + let outgoingLightNode = this.setupOutgoingLight( builder ); + + if ( lightsNode && lightsNode.getScope().getLights().length > 0 ) { + + const lightingModel = this.setupLightingModel( builder ); + + outgoingLightNode = lightingContext( lightsNode, lightingModel, backdropNode, backdropAlphaNode ); + + } else if ( backdropNode !== null ) { + + outgoingLightNode = vec3( backdropAlphaNode !== null ? mix( outgoingLightNode, backdropNode, backdropAlphaNode ) : backdropNode ); + + } + + // EMISSIVE + + if ( ( emissiveNode && emissiveNode.isNode === true ) || ( material.emissive && material.emissive.isColor === true ) ) { + + emissive.assign( vec3( emissiveNode ? emissiveNode : materialEmissive ) ); + + outgoingLightNode = outgoingLightNode.add( emissive ); + + } + + return outgoingLightNode; + + } + + setupOutput( builder, outputNode ) { + + // FOG + + if ( this.fog === true ) { + + const fogNode = builder.fogNode; + + if ( fogNode ) outputNode = vec4( fogNode.mix( outputNode.rgb, fogNode.colorNode ), outputNode.a ); + + } + + return outputNode; + + } + + setDefaultValues( material ) { + + // This approach is to reuse the native refreshUniforms* + // and turn available the use of features like transmission and environment in core + + for ( const property in material ) { + + const value = material[ property ]; + + if ( this[ property ] === undefined ) { + + this[ property ] = value; + + if ( value && value.clone ) this[ property ] = value.clone(); + + } + + } + + const descriptors = Object.getOwnPropertyDescriptors( material.constructor.prototype ); + + for ( const key in descriptors ) { + + if ( Object.getOwnPropertyDescriptor( this.constructor.prototype, key ) === undefined && + descriptors[ key ].get !== undefined ) { + + Object.defineProperty( this.constructor.prototype, key, descriptors[ key ] ); + + } + + } + + } + + toJSON( meta ) { + + const isRoot = ( meta === undefined || typeof meta === 'string' ); + + if ( isRoot ) { + + meta = { + textures: {}, + images: {}, + nodes: {} + }; + + } + + const data = Material.prototype.toJSON.call( this, meta ); + const nodeChildren = getNodeChildren( this ); + + data.inputNodes = {}; + + for ( const { property, childNode } of nodeChildren ) { + + data.inputNodes[ property ] = childNode.toJSON( meta ).uuid; + + } + + // TODO: Copied from Object3D.toJSON + + function extractFromCache( cache ) { + + const values = []; + + for ( const key in cache ) { + + const data = cache[ key ]; + delete data.metadata; + values.push( data ); + + } + + return values; + + } + + if ( isRoot ) { + + const textures = extractFromCache( meta.textures ); + const images = extractFromCache( meta.images ); + const nodes = extractFromCache( meta.nodes ); + + if ( textures.length > 0 ) data.textures = textures; + if ( images.length > 0 ) data.images = images; + if ( nodes.length > 0 ) data.nodes = nodes; + + } + + return data; + + } + + copy( source ) { + + this.lightsNode = source.lightsNode; + this.envNode = source.envNode; + + this.colorNode = source.colorNode; + this.normalNode = source.normalNode; + this.opacityNode = source.opacityNode; + this.backdropNode = source.backdropNode; + this.backdropAlphaNode = source.backdropAlphaNode; + this.alphaTestNode = source.alphaTestNode; + + this.positionNode = source.positionNode; + + this.depthNode = source.depthNode; + this.shadowNode = source.shadowNode; + this.shadowPositionNode = source.shadowPositionNode; + + this.outputNode = source.outputNode; + this.mrtNode = source.mrtNode; + + this.fragmentNode = source.fragmentNode; + this.vertexNode = source.vertexNode; + + return super.copy( source ); + + } + +} + +const _defaultValues$e = /*@__PURE__*/ new PointsMaterial(); + +class InstancedPointsNodeMaterial extends NodeMaterial { + + static get type() { + + return 'InstancedPointsNodeMaterial'; + + } + + constructor( params = {} ) { + + super(); + + this.lights = false; + + this.useAlphaToCoverage = true; + + this.useColor = params.vertexColors; + + this.pointWidth = 1; + + this.pointColorNode = null; + + this.pointWidthNode = null; + + this.setDefaultValues( _defaultValues$e ); + + this.setValues( params ); + + } + + setup( builder ) { + + this.setupShaders( builder ); + + super.setup( builder ); + + } + + setupShaders( { renderer } ) { + + const useAlphaToCoverage = this.alphaToCoverage; + const useColor = this.useColor; + + this.vertexNode = Fn( () => { + + const instancePosition = attribute( 'instancePosition' ).xyz; + + // camera space + const mvPos = vec4( modelViewMatrix.mul( vec4( instancePosition, 1.0 ) ) ); + + const aspect = viewport.z.div( viewport.w ); + + // clip space + const clipPos = cameraProjectionMatrix.mul( mvPos ); + + // offset in ndc space + const offset = positionGeometry.xy.toVar(); + + offset.mulAssign( this.pointWidthNode ? this.pointWidthNode : materialPointWidth ); + + offset.assign( offset.div( viewport.z ) ); + offset.y.assign( offset.y.mul( aspect ) ); + + // back to clip space + offset.assign( offset.mul( clipPos.w ) ); + + //clipPos.xy += offset; + clipPos.addAssign( vec4( offset, 0, 0 ) ); + + return clipPos; + + } )(); + + this.fragmentNode = Fn( () => { + + const alpha = float( 1 ).toVar(); + + const len2 = lengthSq( uv().mul( 2 ).sub( 1 ) ); + + if ( useAlphaToCoverage && renderer.samples > 1 ) { + + const dlen = float( len2.fwidth() ).toVar(); + + alpha.assign( smoothstep( dlen.oneMinus(), dlen.add( 1 ), len2 ).oneMinus() ); + + } else { + + len2.greaterThan( 1.0 ).discard(); + + } + + let pointColorNode; + + if ( this.pointColorNode ) { + + pointColorNode = this.pointColorNode; + + } else { + + if ( useColor ) { + + const instanceColor = attribute( 'instanceColor' ); + + pointColorNode = instanceColor.mul( materialColor ); + + } else { + + pointColorNode = materialColor; + + } + + } + + alpha.mulAssign( materialOpacity ); + + return vec4( pointColorNode, alpha ); + + } )(); + + } + + get alphaToCoverage() { + + return this.useAlphaToCoverage; + + } + + set alphaToCoverage( value ) { + + if ( this.useAlphaToCoverage !== value ) { + + this.useAlphaToCoverage = value; + this.needsUpdate = true; + + } + + } + +} + +const _defaultValues$d = /*@__PURE__*/ new LineBasicMaterial(); + +class LineBasicNodeMaterial extends NodeMaterial { + + static get type() { + + return 'LineBasicNodeMaterial'; + + } + + constructor( parameters ) { + + super(); + + this.isLineBasicNodeMaterial = true; + + this.lights = false; + + this.setDefaultValues( _defaultValues$d ); + + this.setValues( parameters ); + + } + +} + +const _defaultValues$c = /*@__PURE__*/ new LineDashedMaterial(); + +class LineDashedNodeMaterial extends NodeMaterial { + + static get type() { + + return 'LineDashedNodeMaterial'; + + } + + constructor( parameters ) { + + super(); + + this.isLineDashedNodeMaterial = true; + + this.lights = false; + + this.setDefaultValues( _defaultValues$c ); + + this.offsetNode = null; + this.dashScaleNode = null; + this.dashSizeNode = null; + this.gapSizeNode = null; + + this.setValues( parameters ); + + } + + setupVariants() { + + const offsetNode = this.offsetNode; + const dashScaleNode = this.dashScaleNode ? float( this.dashScaleNode ) : materialLineScale; + const dashSizeNode = this.dashSizeNode ? float( this.dashSizeNode ) : materialLineDashSize; + const gapSizeNode = this.dashSizeNode ? float( this.dashGapNode ) : materialLineGapSize; + + dashSize.assign( dashSizeNode ); + gapSize.assign( gapSizeNode ); + + const vLineDistance = varying( attribute( 'lineDistance' ).mul( dashScaleNode ) ); + const vLineDistanceOffset = offsetNode ? vLineDistance.add( offsetNode ) : vLineDistance; + + vLineDistanceOffset.mod( dashSize.add( gapSize ) ).greaterThan( dashSize ).discard(); + + } + +} + +const _defaultValues$b = /*@__PURE__*/ new LineDashedMaterial(); + +class Line2NodeMaterial extends NodeMaterial { + + static get type() { + + return 'Line2NodeMaterial'; + + } + + constructor( params = {} ) { + + super(); + + this.lights = false; + + this.setDefaultValues( _defaultValues$b ); + + this.useAlphaToCoverage = true; + this.useColor = params.vertexColors; + this.useDash = params.dashed; + this.useWorldUnits = false; + + this.dashOffset = 0; + this.lineWidth = 1; + + this.lineColorNode = null; + + this.offsetNode = null; + this.dashScaleNode = null; + this.dashSizeNode = null; + this.gapSizeNode = null; + + this.setValues( params ); + + } + + setup( builder ) { + + this.setupShaders( builder ); + + super.setup( builder ); + + } + + setupShaders( { renderer } ) { + + const useAlphaToCoverage = this.alphaToCoverage; + const useColor = this.useColor; + const useDash = this.dashed; + const useWorldUnits = this.worldUnits; + + const trimSegment = Fn( ( { start, end } ) => { + + const a = cameraProjectionMatrix.element( 2 ).element( 2 ); // 3nd entry in 3th column + const b = cameraProjectionMatrix.element( 3 ).element( 2 ); // 3nd entry in 4th column + const nearEstimate = b.mul( - 0.5 ).div( a ); + + const alpha = nearEstimate.sub( start.z ).div( end.z.sub( start.z ) ); + + return vec4( mix( start.xyz, end.xyz, alpha ), end.w ); + + } ).setLayout( { + name: 'trimSegment', + type: 'vec4', + inputs: [ + { name: 'start', type: 'vec4' }, + { name: 'end', type: 'vec4' } + ] + } ); + + this.vertexNode = Fn( () => { + + const instanceStart = attribute( 'instanceStart' ); + const instanceEnd = attribute( 'instanceEnd' ); + + // camera space + + const start = vec4( modelViewMatrix.mul( vec4( instanceStart, 1.0 ) ) ).toVar( 'start' ); + const end = vec4( modelViewMatrix.mul( vec4( instanceEnd, 1.0 ) ) ).toVar( 'end' ); + + if ( useWorldUnits ) { + + varyingProperty( 'vec3', 'worldStart' ).assign( start.xyz ); + varyingProperty( 'vec3', 'worldEnd' ).assign( end.xyz ); + + } + + const aspect = viewport.z.div( viewport.w ); + + // special case for perspective projection, and segments that terminate either in, or behind, the camera plane + // clearly the gpu firmware has a way of addressing this issue when projecting into ndc space + // but we need to perform ndc-space calculations in the shader, so we must address this issue directly + // perhaps there is a more elegant solution -- WestLangley + + const perspective = cameraProjectionMatrix.element( 2 ).element( 3 ).equal( - 1.0 ); // 4th entry in the 3rd column + + If( perspective, () => { + + If( start.z.lessThan( 0.0 ).and( end.z.greaterThan( 0.0 ) ), () => { + + end.assign( trimSegment( { start: start, end: end } ) ); + + } ).ElseIf( end.z.lessThan( 0.0 ).and( start.z.greaterThanEqual( 0.0 ) ), () => { + + start.assign( trimSegment( { start: end, end: start } ) ); + + } ); + + } ); + + // clip space + const clipStart = cameraProjectionMatrix.mul( start ); + const clipEnd = cameraProjectionMatrix.mul( end ); + + // ndc space + const ndcStart = clipStart.xyz.div( clipStart.w ); + const ndcEnd = clipEnd.xyz.div( clipEnd.w ); + + // direction + const dir = ndcEnd.xy.sub( ndcStart.xy ).toVar(); + + // account for clip-space aspect ratio + dir.x.assign( dir.x.mul( aspect ) ); + dir.assign( dir.normalize() ); + + const clip = vec4().toVar(); + + if ( useWorldUnits ) { + + // get the offset direction as perpendicular to the view vector + + const worldDir = end.xyz.sub( start.xyz ).normalize(); + const tmpFwd = mix( start.xyz, end.xyz, 0.5 ).normalize(); + const worldUp = worldDir.cross( tmpFwd ).normalize(); + const worldFwd = worldDir.cross( worldUp ); + + const worldPos = varyingProperty( 'vec4', 'worldPos' ); + + worldPos.assign( positionGeometry.y.lessThan( 0.5 ).select( start, end ) ); + + // height offset + const hw = materialLineWidth.mul( 0.5 ); + worldPos.addAssign( vec4( positionGeometry.x.lessThan( 0.0 ).select( worldUp.mul( hw ), worldUp.mul( hw ).negate() ), 0 ) ); + + // don't extend the line if we're rendering dashes because we + // won't be rendering the endcaps + if ( ! useDash ) { + + // cap extension + worldPos.addAssign( vec4( positionGeometry.y.lessThan( 0.5 ).select( worldDir.mul( hw ).negate(), worldDir.mul( hw ) ), 0 ) ); + + // add width to the box + worldPos.addAssign( vec4( worldFwd.mul( hw ), 0 ) ); + + // endcaps + If( positionGeometry.y.greaterThan( 1.0 ).or( positionGeometry.y.lessThan( 0.0 ) ), () => { + + worldPos.subAssign( vec4( worldFwd.mul( 2.0 ).mul( hw ), 0 ) ); + + } ); + + } + + // project the worldpos + clip.assign( cameraProjectionMatrix.mul( worldPos ) ); + + // shift the depth of the projected points so the line + // segments overlap neatly + const clipPose = vec3().toVar(); + + clipPose.assign( positionGeometry.y.lessThan( 0.5 ).select( ndcStart, ndcEnd ) ); + clip.z.assign( clipPose.z.mul( clip.w ) ); + + } else { + + const offset = vec2( dir.y, dir.x.negate() ).toVar( 'offset' ); + + // undo aspect ratio adjustment + dir.x.assign( dir.x.div( aspect ) ); + offset.x.assign( offset.x.div( aspect ) ); + + // sign flip + offset.assign( positionGeometry.x.lessThan( 0.0 ).select( offset.negate(), offset ) ); + + // endcaps + If( positionGeometry.y.lessThan( 0.0 ), () => { + + offset.assign( offset.sub( dir ) ); + + } ).ElseIf( positionGeometry.y.greaterThan( 1.0 ), () => { + + offset.assign( offset.add( dir ) ); + + } ); + + // adjust for linewidth + offset.assign( offset.mul( materialLineWidth ) ); + + // adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ... + offset.assign( offset.div( viewport.w ) ); + + // select end + clip.assign( positionGeometry.y.lessThan( 0.5 ).select( clipStart, clipEnd ) ); + + // back to clip space + offset.assign( offset.mul( clip.w ) ); + + clip.assign( clip.add( vec4( offset, 0, 0 ) ) ); + + } + + return clip; + + } )(); + + const closestLineToLine = Fn( ( { p1, p2, p3, p4 } ) => { + + const p13 = p1.sub( p3 ); + const p43 = p4.sub( p3 ); + + const p21 = p2.sub( p1 ); + + const d1343 = p13.dot( p43 ); + const d4321 = p43.dot( p21 ); + const d1321 = p13.dot( p21 ); + const d4343 = p43.dot( p43 ); + const d2121 = p21.dot( p21 ); + + const denom = d2121.mul( d4343 ).sub( d4321.mul( d4321 ) ); + const numer = d1343.mul( d4321 ).sub( d1321.mul( d4343 ) ); + + const mua = numer.div( denom ).clamp(); + const mub = d1343.add( d4321.mul( mua ) ).div( d4343 ).clamp(); + + return vec2( mua, mub ); + + } ); + + this.fragmentNode = Fn( () => { + + const vUv = uv(); + + if ( useDash ) { + + const offsetNode = this.offsetNode ? float( this.offsetNodeNode ) : materialLineDashOffset; + const dashScaleNode = this.dashScaleNode ? float( this.dashScaleNode ) : materialLineScale; + const dashSizeNode = this.dashSizeNode ? float( this.dashSizeNode ) : materialLineDashSize; + const gapSizeNode = this.dashSizeNode ? float( this.dashGapNode ) : materialLineGapSize; + + dashSize.assign( dashSizeNode ); + gapSize.assign( gapSizeNode ); + + const instanceDistanceStart = attribute( 'instanceDistanceStart' ); + const instanceDistanceEnd = attribute( 'instanceDistanceEnd' ); + + const lineDistance = positionGeometry.y.lessThan( 0.5 ).select( dashScaleNode.mul( instanceDistanceStart ), materialLineScale.mul( instanceDistanceEnd ) ); + + const vLineDistance = varying( lineDistance.add( materialLineDashOffset ) ); + const vLineDistanceOffset = offsetNode ? vLineDistance.add( offsetNode ) : vLineDistance; + + vUv.y.lessThan( - 1.0 ).or( vUv.y.greaterThan( 1.0 ) ).discard(); // discard endcaps + vLineDistanceOffset.mod( dashSize.add( gapSize ) ).greaterThan( dashSize ).discard(); // todo - FIX + + } + + const alpha = float( 1 ).toVar( 'alpha' ); + + if ( useWorldUnits ) { + + const worldStart = varyingProperty( 'vec3', 'worldStart' ); + const worldEnd = varyingProperty( 'vec3', 'worldEnd' ); + + // Find the closest points on the view ray and the line segment + const rayEnd = varyingProperty( 'vec4', 'worldPos' ).xyz.normalize().mul( 1e5 ); + const lineDir = worldEnd.sub( worldStart ); + const params = closestLineToLine( { p1: worldStart, p2: worldEnd, p3: vec3( 0.0, 0.0, 0.0 ), p4: rayEnd } ); + + const p1 = worldStart.add( lineDir.mul( params.x ) ); + const p2 = rayEnd.mul( params.y ); + const delta = p1.sub( p2 ); + const len = delta.length(); + const norm = len.div( materialLineWidth ); + + if ( ! useDash ) { + + if ( useAlphaToCoverage && renderer.samples > 1 ) { + + const dnorm = norm.fwidth(); + alpha.assign( smoothstep( dnorm.negate().add( 0.5 ), dnorm.add( 0.5 ), norm ).oneMinus() ); + + } else { + + norm.greaterThan( 0.5 ).discard(); + + } + + } + + } else { + + // round endcaps + + if ( useAlphaToCoverage && renderer.samples > 1 ) { + + const a = vUv.x; + const b = vUv.y.greaterThan( 0.0 ).select( vUv.y.sub( 1.0 ), vUv.y.add( 1.0 ) ); + + const len2 = a.mul( a ).add( b.mul( b ) ); + + const dlen = float( len2.fwidth() ).toVar( 'dlen' ); + + If( vUv.y.abs().greaterThan( 1.0 ), () => { + + alpha.assign( smoothstep( dlen.oneMinus(), dlen.add( 1 ), len2 ).oneMinus() ); + + } ); + + } else { + + If( vUv.y.abs().greaterThan( 1.0 ), () => { + + const a = vUv.x; + const b = vUv.y.greaterThan( 0.0 ).select( vUv.y.sub( 1.0 ), vUv.y.add( 1.0 ) ); + const len2 = a.mul( a ).add( b.mul( b ) ); + + len2.greaterThan( 1.0 ).discard(); + + } ); + + } + + } + + let lineColorNode; + + if ( this.lineColorNode ) { + + lineColorNode = this.lineColorNode; + + } else { + + if ( useColor ) { + + const instanceColorStart = attribute( 'instanceColorStart' ); + const instanceColorEnd = attribute( 'instanceColorEnd' ); + + const instanceColor = positionGeometry.y.lessThan( 0.5 ).select( instanceColorStart, instanceColorEnd ); + + lineColorNode = instanceColor.mul( materialColor ); + + } else { + + lineColorNode = materialColor; + + } + + } + + return vec4( lineColorNode, alpha ); + + } )(); + + } + + + get worldUnits() { + + return this.useWorldUnits; + + } + + set worldUnits( value ) { + + if ( this.useWorldUnits !== value ) { + + this.useWorldUnits = value; + this.needsUpdate = true; + + } + + } + + + get dashed() { + + return this.useDash; + + } + + set dashed( value ) { + + if ( this.useDash !== value ) { + + this.useDash = value; + this.needsUpdate = true; + + } + + } + + + get alphaToCoverage() { + + return this.useAlphaToCoverage; + + } + + set alphaToCoverage( value ) { + + if ( this.useAlphaToCoverage !== value ) { + + this.useAlphaToCoverage = value; + this.needsUpdate = true; + + } + + } + +} + +const directionToColor = ( node ) => nodeObject( node ).mul( 0.5 ).add( 0.5 ); +const colorToDirection = ( node ) => nodeObject( node ).mul( 2.0 ).sub( 1 ); + +const _defaultValues$a = /*@__PURE__*/ new MeshNormalMaterial(); + +class MeshNormalNodeMaterial extends NodeMaterial { + + static get type() { + + return 'MeshNormalNodeMaterial'; + + } + + constructor( parameters ) { + + super(); + + this.lights = false; + + this.isMeshNormalNodeMaterial = true; + + this.setDefaultValues( _defaultValues$a ); + + this.setValues( parameters ); + + } + + setupDiffuseColor() { + + const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity; + + diffuseColor.assign( vec4( directionToColor( transformedNormalView ), opacityNode ) ); + + } + +} + +class EquirectUVNode extends TempNode { + + static get type() { + + return 'EquirectUVNode'; + + } + + constructor( dirNode = positionWorldDirection ) { + + super( 'vec2' ); + + this.dirNode = dirNode; + + } + + setup() { + + const dir = this.dirNode; + + const u = dir.z.atan2( dir.x ).mul( 1 / ( Math.PI * 2 ) ).add( 0.5 ); + const v = dir.y.clamp( - 1.0, 1.0 ).asin().mul( 1 / Math.PI ).add( 0.5 ); + + return vec2( u, v ); + + } + +} + +const equirectUV = /*@__PURE__*/ nodeProxy( EquirectUVNode ); + +// @TODO: Consider rename WebGLCubeRenderTarget to just CubeRenderTarget + +class CubeRenderTarget extends WebGLCubeRenderTarget { + + constructor( size = 1, options = {} ) { + + super( size, options ); + + this.isCubeRenderTarget = true; + + } + + fromEquirectangularTexture( renderer, texture$1 ) { + + const currentMinFilter = texture$1.minFilter; + const currentGenerateMipmaps = texture$1.generateMipmaps; + + texture$1.generateMipmaps = true; + + this.texture.type = texture$1.type; + this.texture.colorSpace = texture$1.colorSpace; + + this.texture.generateMipmaps = texture$1.generateMipmaps; + this.texture.minFilter = texture$1.minFilter; + this.texture.magFilter = texture$1.magFilter; + + const geometry = new BoxGeometry( 5, 5, 5 ); + + const uvNode = equirectUV( positionWorldDirection ); + + const material = new NodeMaterial(); + material.colorNode = texture( texture$1, uvNode, 0 ); + material.side = BackSide; + material.blending = NoBlending; + + const mesh = new Mesh( geometry, material ); + + const scene = new Scene(); + scene.add( mesh ); + + // Avoid blurred poles + if ( texture$1.minFilter === LinearMipmapLinearFilter ) texture$1.minFilter = LinearFilter; + + const camera = new CubeCamera( 1, 10, this ); + + const currentMRT = renderer.getMRT(); + renderer.setMRT( null ); + + camera.update( renderer, scene ); + + renderer.setMRT( currentMRT ); + + texture$1.minFilter = currentMinFilter; + texture$1.currentGenerateMipmaps = currentGenerateMipmaps; + + mesh.geometry.dispose(); + mesh.material.dispose(); + + return this; + + } + +} + +const _cache$1 = new WeakMap(); + +class CubeMapNode extends TempNode { + + static get type() { + + return 'CubeMapNode'; + + } + + constructor( envNode ) { + + super( 'vec3' ); + + this.envNode = envNode; + + this._cubeTexture = null; + this._cubeTextureNode = cubeTexture(); + + const defaultTexture = new CubeTexture(); + defaultTexture.isRenderTargetTexture = true; + + this._defaultTexture = defaultTexture; + + this.updateBeforeType = NodeUpdateType.RENDER; + + } + + updateBefore( frame ) { + + const { renderer, material } = frame; + + const envNode = this.envNode; + + if ( envNode.isTextureNode || envNode.isMaterialReferenceNode ) { + + const texture = ( envNode.isTextureNode ) ? envNode.value : material[ envNode.property ]; + + if ( texture && texture.isTexture ) { + + const mapping = texture.mapping; + + if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) { + + // check for converted cubemap map + + if ( _cache$1.has( texture ) ) { + + const cubeMap = _cache$1.get( texture ); + + mapTextureMapping( cubeMap, texture.mapping ); + this._cubeTexture = cubeMap; + + } else { + + // create cube map from equirectangular map + + const image = texture.image; + + if ( isEquirectangularMapReady$1( image ) ) { + + const renderTarget = new CubeRenderTarget( image.height ); + renderTarget.fromEquirectangularTexture( renderer, texture ); + + mapTextureMapping( renderTarget.texture, texture.mapping ); + this._cubeTexture = renderTarget.texture; + + _cache$1.set( texture, renderTarget.texture ); + + texture.addEventListener( 'dispose', onTextureDispose ); + + } else { + + // default cube texture as fallback when equirectangular texture is not yet loaded + + this._cubeTexture = this._defaultTexture; + + } + + } + + // + + this._cubeTextureNode.value = this._cubeTexture; + + } else { + + // envNode already refers to a cube map + + this._cubeTextureNode = this.envNode; + + } + + } + + } + + } + + setup( builder ) { + + this.updateBefore( builder ); + + return this._cubeTextureNode; + + } + +} + +function isEquirectangularMapReady$1( image ) { + + if ( image === null || image === undefined ) return false; + + return image.height > 0; + +} + +function onTextureDispose( event ) { + + const texture = event.target; + + texture.removeEventListener( 'dispose', onTextureDispose ); + + const renderTarget = _cache$1.get( texture ); + + if ( renderTarget !== undefined ) { + + _cache$1.delete( texture ); + + renderTarget.dispose(); + + } + +} + +function mapTextureMapping( texture, mapping ) { + + if ( mapping === EquirectangularReflectionMapping ) { + + texture.mapping = CubeReflectionMapping; + + } else if ( mapping === EquirectangularRefractionMapping ) { + + texture.mapping = CubeRefractionMapping; + + } + +} + +const cubeMapNode = /*@__PURE__*/ nodeProxy( CubeMapNode ); + +class BasicEnvironmentNode extends LightingNode { + + static get type() { + + return 'BasicEnvironmentNode'; + + } + + constructor( envNode = null ) { + + super(); + + this.envNode = envNode; + + } + + setup( builder ) { + + // environment property is used in the finish() method of BasicLightingModel + + builder.context.environment = cubeMapNode( this.envNode ); + + } + +} + +class BasicLightMapNode extends LightingNode { + + static get type() { + + return 'BasicLightMapNode'; + + } + + constructor( lightMapNode = null ) { + + super(); + + this.lightMapNode = lightMapNode; + + } + + setup( builder ) { + + // irradianceLightMap property is used in the indirectDiffuse() method of BasicLightingModel + + const RECIPROCAL_PI = float( 1 / Math.PI ); + + builder.context.irradianceLightMap = this.lightMapNode.mul( RECIPROCAL_PI ); + + } + +} + +class LightingModel { + + start( /*input, stack, builder*/ ) { } + + finish( /*input, stack, builder*/ ) { } + + direct( /*input, stack, builder*/ ) { } + + directRectArea( /*input, stack, builder*/ ) {} + + indirect( /*input, stack, builder*/ ) { } + + ambientOcclusion( /*input, stack, builder*/ ) { } + +} + +class BasicLightingModel extends LightingModel { + + constructor() { + + super(); + + } + + indirect( context, stack, builder ) { + + const ambientOcclusion = context.ambientOcclusion; + const reflectedLight = context.reflectedLight; + const irradianceLightMap = builder.context.irradianceLightMap; + + reflectedLight.indirectDiffuse.assign( vec4( 0.0 ) ); + + // accumulation (baked indirect lighting only) + + if ( irradianceLightMap ) { + + reflectedLight.indirectDiffuse.addAssign( irradianceLightMap ); + + } else { + + reflectedLight.indirectDiffuse.addAssign( vec4( 1.0, 1.0, 1.0, 0.0 ) ); + + } + + // modulation + + reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion ); + + reflectedLight.indirectDiffuse.mulAssign( diffuseColor.rgb ); + + } + + finish( context, stack, builder ) { + + const material = builder.material; + const outgoingLight = context.outgoingLight; + const envNode = builder.context.environment; + + if ( envNode ) { + + switch ( material.combine ) { + + case MultiplyOperation: + outgoingLight.rgb.assign( mix( outgoingLight.rgb, outgoingLight.rgb.mul( envNode.rgb ), materialSpecularStrength.mul( materialReflectivity ) ) ); + break; + + case MixOperation: + outgoingLight.rgb.assign( mix( outgoingLight.rgb, envNode.rgb, materialSpecularStrength.mul( materialReflectivity ) ) ); + break; + + case AddOperation: + outgoingLight.rgb.addAssign( envNode.rgb.mul( materialSpecularStrength.mul( materialReflectivity ) ) ); + break; + + default: + console.warn( 'THREE.BasicLightingModel: Unsupported .combine value:', material.combine ); + break; + + } + + } + + } + +} + +const _defaultValues$9 = /*@__PURE__*/ new MeshBasicMaterial(); + +class MeshBasicNodeMaterial extends NodeMaterial { + + static get type() { + + return 'MeshBasicNodeMaterial'; + + } + + constructor( parameters ) { + + super(); + + this.isMeshBasicNodeMaterial = true; + + this.lights = true; + + this.setDefaultValues( _defaultValues$9 ); + + this.setValues( parameters ); + + } + + setupNormal() { + + return normalView; // see #28839 + + } + + setupEnvironment( builder ) { + + const envNode = super.setupEnvironment( builder ); + + return envNode ? new BasicEnvironmentNode( envNode ) : null; + + } + + setupLightMap( builder ) { + + let node = null; + + if ( builder.material.lightMap ) { + + node = new BasicLightMapNode( materialLightMap ); + + } + + return node; + + } + + setupOutgoingLight() { + + return diffuseColor.rgb; + + } + + setupLightingModel() { + + return new BasicLightingModel(); + + } + +} + +const F_Schlick = /*@__PURE__*/ Fn( ( { f0, f90, dotVH } ) => { + + // Original approximation by Christophe Schlick '94 + // float fresnel = pow( 1.0 - dotVH, 5.0 ); + + // Optimized variant (presented by Epic at SIGGRAPH '13) + // https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf + const fresnel = dotVH.mul( - 5.55473 ).sub( 6.98316 ).mul( dotVH ).exp2(); + + return f0.mul( fresnel.oneMinus() ).add( f90.mul( fresnel ) ); + +} ); // validated + +const BRDF_Lambert = /*@__PURE__*/ Fn( ( inputs ) => { + + return inputs.diffuseColor.mul( 1 / Math.PI ); // punctual light + +} ); // validated + +const G_BlinnPhong_Implicit = () => float( 0.25 ); + +const D_BlinnPhong = /*@__PURE__*/ Fn( ( { dotNH } ) => { + + return shininess.mul( float( 0.5 ) ).add( 1.0 ).mul( float( 1 / Math.PI ) ).mul( dotNH.pow( shininess ) ); + +} ); + +const BRDF_BlinnPhong = /*@__PURE__*/ Fn( ( { lightDirection } ) => { + + const halfDir = lightDirection.add( positionViewDirection ).normalize(); + + const dotNH = transformedNormalView.dot( halfDir ).clamp(); + const dotVH = positionViewDirection.dot( halfDir ).clamp(); + + const F = F_Schlick( { f0: specularColor, f90: 1.0, dotVH } ); + const G = G_BlinnPhong_Implicit(); + const D = D_BlinnPhong( { dotNH } ); + + return F.mul( G ).mul( D ); + +} ); + +class PhongLightingModel extends BasicLightingModel { + + constructor( specular = true ) { + + super(); + + this.specular = specular; + + } + + direct( { lightDirection, lightColor, reflectedLight } ) { + + const dotNL = transformedNormalView.dot( lightDirection ).clamp(); + const irradiance = dotNL.mul( lightColor ); + + reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) ); + + if ( this.specular === true ) { + + reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_BlinnPhong( { lightDirection } ) ).mul( materialSpecularStrength ) ); + + } + + } + + indirect( { ambientOcclusion, irradiance, reflectedLight } ) { + + reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) ); + + reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion ); + + } + +} + +const _defaultValues$8 = /*@__PURE__*/ new MeshLambertMaterial(); + +class MeshLambertNodeMaterial extends NodeMaterial { + + static get type() { + + return 'MeshLambertNodeMaterial'; + + } + + constructor( parameters ) { + + super(); + + this.isMeshLambertNodeMaterial = true; + + this.lights = true; + + this.setDefaultValues( _defaultValues$8 ); + + this.setValues( parameters ); + + } + + setupEnvironment( builder ) { + + const envNode = super.setupEnvironment( builder ); + + return envNode ? new BasicEnvironmentNode( envNode ) : null; + + } + + setupLightingModel( /*builder*/ ) { + + return new PhongLightingModel( false ); // ( specular ) -> force lambert + + } + +} + +const _defaultValues$7 = /*@__PURE__*/ new MeshPhongMaterial(); + +class MeshPhongNodeMaterial extends NodeMaterial { + + static get type() { + + return 'MeshPhongNodeMaterial'; + + } + + constructor( parameters ) { + + super(); + + this.isMeshPhongNodeMaterial = true; + + this.lights = true; + + this.shininessNode = null; + this.specularNode = null; + + this.setDefaultValues( _defaultValues$7 ); + + this.setValues( parameters ); + + } + + setupEnvironment( builder ) { + + const envNode = super.setupEnvironment( builder ); + + return envNode ? new BasicEnvironmentNode( envNode ) : null; + + } + + setupLightingModel( /*builder*/ ) { + + return new PhongLightingModel(); + + } + + setupVariants() { + + // SHININESS + + const shininessNode = ( this.shininessNode ? float( this.shininessNode ) : materialShininess ).max( 1e-4 ); // to prevent pow( 0.0, 0.0 ) + + shininess.assign( shininessNode ); + + // SPECULAR COLOR + + const specularNode = this.specularNode || materialSpecular; + + specularColor.assign( specularNode ); + + } + + copy( source ) { + + this.shininessNode = source.shininessNode; + this.specularNode = source.specularNode; + + return super.copy( source ); + + } + +} + +const getGeometryRoughness = /*@__PURE__*/ Fn( () => { + + const dxy = normalView.dFdx().abs().max( normalView.dFdy().abs() ); + const geometryRoughness = dxy.x.max( dxy.y ).max( dxy.z ); + + return geometryRoughness; + +} ); + +const getRoughness = /*@__PURE__*/ Fn( ( inputs ) => { + + const { roughness } = inputs; + + const geometryRoughness = getGeometryRoughness(); + + let roughnessFactor = roughness.max( 0.0525 ); // 0.0525 corresponds to the base mip of a 256 cubemap. + roughnessFactor = roughnessFactor.add( geometryRoughness ); + roughnessFactor = roughnessFactor.min( 1.0 ); + + return roughnessFactor; + +} ); + +// Moving Frostbite to Physically Based Rendering 3.0 - page 12, listing 2 +// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf +const V_GGX_SmithCorrelated = /*@__PURE__*/ Fn( ( { alpha, dotNL, dotNV } ) => { + + const a2 = alpha.pow2(); + + const gv = dotNL.mul( a2.add( a2.oneMinus().mul( dotNV.pow2() ) ).sqrt() ); + const gl = dotNV.mul( a2.add( a2.oneMinus().mul( dotNL.pow2() ) ).sqrt() ); + + return div( 0.5, gv.add( gl ).max( EPSILON ) ); + +} ).setLayout( { + name: 'V_GGX_SmithCorrelated', + type: 'float', + inputs: [ + { name: 'alpha', type: 'float' }, + { name: 'dotNL', type: 'float' }, + { name: 'dotNV', type: 'float' } + ] +} ); // validated + +// https://google.github.io/filament/Filament.md.html#materialsystem/anisotropicmodel/anisotropicspecularbrdf + +const V_GGX_SmithCorrelated_Anisotropic = /*@__PURE__*/ Fn( ( { alphaT, alphaB, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL } ) => { + + const gv = dotNL.mul( vec3( alphaT.mul( dotTV ), alphaB.mul( dotBV ), dotNV ).length() ); + const gl = dotNV.mul( vec3( alphaT.mul( dotTL ), alphaB.mul( dotBL ), dotNL ).length() ); + const v = div( 0.5, gv.add( gl ) ); + + return v.saturate(); + +} ).setLayout( { + name: 'V_GGX_SmithCorrelated_Anisotropic', + type: 'float', + inputs: [ + { name: 'alphaT', type: 'float', qualifier: 'in' }, + { name: 'alphaB', type: 'float', qualifier: 'in' }, + { name: 'dotTV', type: 'float', qualifier: 'in' }, + { name: 'dotBV', type: 'float', qualifier: 'in' }, + { name: 'dotTL', type: 'float', qualifier: 'in' }, + { name: 'dotBL', type: 'float', qualifier: 'in' }, + { name: 'dotNV', type: 'float', qualifier: 'in' }, + { name: 'dotNL', type: 'float', qualifier: 'in' } + ] +} ); + +// Microfacet Models for Refraction through Rough Surfaces - equation (33) +// http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html +// alpha is "roughness squared" in Disney’s reparameterization +const D_GGX = /*@__PURE__*/ Fn( ( { alpha, dotNH } ) => { + + const a2 = alpha.pow2(); + + const denom = dotNH.pow2().mul( a2.oneMinus() ).oneMinus(); // avoid alpha = 0 with dotNH = 1 + + return a2.div( denom.pow2() ).mul( 1 / Math.PI ); + +} ).setLayout( { + name: 'D_GGX', + type: 'float', + inputs: [ + { name: 'alpha', type: 'float' }, + { name: 'dotNH', type: 'float' } + ] +} ); // validated + +const RECIPROCAL_PI = /*@__PURE__*/ float( 1 / Math.PI ); + +// https://google.github.io/filament/Filament.md.html#materialsystem/anisotropicmodel/anisotropicspecularbrdf + +const D_GGX_Anisotropic = /*@__PURE__*/ Fn( ( { alphaT, alphaB, dotNH, dotTH, dotBH } ) => { + + const a2 = alphaT.mul( alphaB ); + const v = vec3( alphaB.mul( dotTH ), alphaT.mul( dotBH ), a2.mul( dotNH ) ); + const v2 = v.dot( v ); + const w2 = a2.div( v2 ); + + return RECIPROCAL_PI.mul( a2.mul( w2.pow2() ) ); + +} ).setLayout( { + name: 'D_GGX_Anisotropic', + type: 'float', + inputs: [ + { name: 'alphaT', type: 'float', qualifier: 'in' }, + { name: 'alphaB', type: 'float', qualifier: 'in' }, + { name: 'dotNH', type: 'float', qualifier: 'in' }, + { name: 'dotTH', type: 'float', qualifier: 'in' }, + { name: 'dotBH', type: 'float', qualifier: 'in' } + ] +} ); + +// GGX Distribution, Schlick Fresnel, GGX_SmithCorrelated Visibility +const BRDF_GGX = /*@__PURE__*/ Fn( ( inputs ) => { + + const { lightDirection, f0, f90, roughness, f, USE_IRIDESCENCE, USE_ANISOTROPY } = inputs; + + const normalView = inputs.normalView || transformedNormalView; + + const alpha = roughness.pow2(); // UE4's roughness + + const halfDir = lightDirection.add( positionViewDirection ).normalize(); + + const dotNL = normalView.dot( lightDirection ).clamp(); + const dotNV = normalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV + const dotNH = normalView.dot( halfDir ).clamp(); + const dotVH = positionViewDirection.dot( halfDir ).clamp(); + + let F = F_Schlick( { f0, f90, dotVH } ); + let V, D; + + if ( defined( USE_IRIDESCENCE ) ) { + + F = iridescence.mix( F, f ); + + } + + if ( defined( USE_ANISOTROPY ) ) { + + const dotTL = anisotropyT.dot( lightDirection ); + const dotTV = anisotropyT.dot( positionViewDirection ); + const dotTH = anisotropyT.dot( halfDir ); + const dotBL = anisotropyB.dot( lightDirection ); + const dotBV = anisotropyB.dot( positionViewDirection ); + const dotBH = anisotropyB.dot( halfDir ); + + V = V_GGX_SmithCorrelated_Anisotropic( { alphaT, alphaB: alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL } ); + D = D_GGX_Anisotropic( { alphaT, alphaB: alpha, dotNH, dotTH, dotBH } ); + + } else { + + V = V_GGX_SmithCorrelated( { alpha, dotNL, dotNV } ); + D = D_GGX( { alpha, dotNH } ); + + } + + return F.mul( V ).mul( D ); + +} ); // validated + +// Analytical approximation of the DFG LUT, one half of the +// split-sum approximation used in indirect specular lighting. +// via 'environmentBRDF' from "Physically Based Shading on Mobile" +// https://www.unrealengine.com/blog/physically-based-shading-on-mobile +const DFGApprox = /*@__PURE__*/ Fn( ( { roughness, dotNV } ) => { + + const c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 ); + + const c1 = vec4( 1, 0.0425, 1.04, - 0.04 ); + + const r = roughness.mul( c0 ).add( c1 ); + + const a004 = r.x.mul( r.x ).min( dotNV.mul( - 9.28 ).exp2() ).mul( r.x ).add( r.y ); + + const fab = vec2( - 1.04, 1.04 ).mul( a004 ).add( r.zw ); + + return fab; + +} ).setLayout( { + name: 'DFGApprox', + type: 'vec2', + inputs: [ + { name: 'roughness', type: 'float' }, + { name: 'dotNV', type: 'vec3' } + ] +} ); + +const EnvironmentBRDF = /*@__PURE__*/ Fn( ( inputs ) => { + + const { dotNV, specularColor, specularF90, roughness } = inputs; + + const fab = DFGApprox( { dotNV, roughness } ); + return specularColor.mul( fab.x ).add( specularF90.mul( fab.y ) ); + +} ); + +const Schlick_to_F0 = /*@__PURE__*/ Fn( ( { f, f90, dotVH } ) => { + + const x = dotVH.oneMinus().saturate(); + const x2 = x.mul( x ); + const x5 = x.mul( x2, x2 ).clamp( 0, .9999 ); + + return f.sub( vec3( f90 ).mul( x5 ) ).div( x5.oneMinus() ); + +} ).setLayout( { + name: 'Schlick_to_F0', + type: 'vec3', + inputs: [ + { name: 'f', type: 'vec3' }, + { name: 'f90', type: 'float' }, + { name: 'dotVH', type: 'float' } + ] +} ); + +// https://github.com/google/filament/blob/master/shaders/src/brdf.fs +const D_Charlie = /*@__PURE__*/ Fn( ( { roughness, dotNH } ) => { + + const alpha = roughness.pow2(); + + // Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF" + const invAlpha = float( 1.0 ).div( alpha ); + const cos2h = dotNH.pow2(); + const sin2h = cos2h.oneMinus().max( 0.0078125 ); // 2^(-14/2), so sin2h^2 > 0 in fp16 + + return float( 2.0 ).add( invAlpha ).mul( sin2h.pow( invAlpha.mul( 0.5 ) ) ).div( 2.0 * Math.PI ); + +} ).setLayout( { + name: 'D_Charlie', + type: 'float', + inputs: [ + { name: 'roughness', type: 'float' }, + { name: 'dotNH', type: 'float' } + ] +} ); + +// https://github.com/google/filament/blob/master/shaders/src/brdf.fs +const V_Neubelt = /*@__PURE__*/ Fn( ( { dotNV, dotNL } ) => { + + // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886" + return float( 1.0 ).div( float( 4.0 ).mul( dotNL.add( dotNV ).sub( dotNL.mul( dotNV ) ) ) ); + +} ).setLayout( { + name: 'V_Neubelt', + type: 'float', + inputs: [ + { name: 'dotNV', type: 'float' }, + { name: 'dotNL', type: 'float' } + ] +} ); + +const BRDF_Sheen = /*@__PURE__*/ Fn( ( { lightDirection } ) => { + + const halfDir = lightDirection.add( positionViewDirection ).normalize(); + + const dotNL = transformedNormalView.dot( lightDirection ).clamp(); + const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); + const dotNH = transformedNormalView.dot( halfDir ).clamp(); + + const D = D_Charlie( { roughness: sheenRoughness, dotNH } ); + const V = V_Neubelt( { dotNV, dotNL } ); + + return sheen.mul( D ).mul( V ); + +} ); + +// Rect Area Light + +// Real-Time Polygonal-Light Shading with Linearly Transformed Cosines +// by Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt +// code: https://github.com/selfshadow/ltc_code/ + +const LTC_Uv = /*@__PURE__*/ Fn( ( { N, V, roughness } ) => { + + const LUT_SIZE = 64.0; + const LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE; + const LUT_BIAS = 0.5 / LUT_SIZE; + + const dotNV = N.dot( V ).saturate(); + + // texture parameterized by sqrt( GGX alpha ) and sqrt( 1 - cos( theta ) ) + const uv = vec2( roughness, dotNV.oneMinus().sqrt() ); + + uv.assign( uv.mul( LUT_SCALE ).add( LUT_BIAS ) ); + + return uv; + +} ).setLayout( { + name: 'LTC_Uv', + type: 'vec2', + inputs: [ + { name: 'N', type: 'vec3' }, + { name: 'V', type: 'vec3' }, + { name: 'roughness', type: 'float' } + ] +} ); + +const LTC_ClippedSphereFormFactor = /*@__PURE__*/ Fn( ( { f } ) => { + + // Real-Time Area Lighting: a Journey from Research to Production (p.102) + // An approximation of the form factor of a horizon-clipped rectangle. + + const l = f.length(); + + return max$1( l.mul( l ).add( f.z ).div( l.add( 1.0 ) ), 0 ); + +} ).setLayout( { + name: 'LTC_ClippedSphereFormFactor', + type: 'float', + inputs: [ + { name: 'f', type: 'vec3' } + ] +} ); + +const LTC_EdgeVectorFormFactor = /*@__PURE__*/ Fn( ( { v1, v2 } ) => { + + const x = v1.dot( v2 ); + const y = x.abs().toVar(); + + // rational polynomial approximation to theta / sin( theta ) / 2PI + const a = y.mul( 0.0145206 ).add( 0.4965155 ).mul( y ).add( 0.8543985 ).toVar(); + const b = y.add( 4.1616724 ).mul( y ).add( 3.4175940 ).toVar(); + const v = a.div( b ); + + const theta_sintheta = x.greaterThan( 0.0 ).select( v, max$1( x.mul( x ).oneMinus(), 1e-7 ).inverseSqrt().mul( 0.5 ).sub( v ) ); + + return v1.cross( v2 ).mul( theta_sintheta ); + +} ).setLayout( { + name: 'LTC_EdgeVectorFormFactor', + type: 'vec3', + inputs: [ + { name: 'v1', type: 'vec3' }, + { name: 'v2', type: 'vec3' } + ] +} ); + +const LTC_Evaluate = /*@__PURE__*/ Fn( ( { N, V, P, mInv, p0, p1, p2, p3 } ) => { + + // bail if point is on back side of plane of light + // assumes ccw winding order of light vertices + const v1 = p1.sub( p0 ).toVar(); + const v2 = p3.sub( p0 ).toVar(); + + const lightNormal = v1.cross( v2 ); + const result = vec3().toVar(); + + If( lightNormal.dot( P.sub( p0 ) ).greaterThanEqual( 0.0 ), () => { + + // construct orthonormal basis around N + const T1 = V.sub( N.mul( V.dot( N ) ) ).normalize(); + const T2 = N.cross( T1 ).negate(); // negated from paper; possibly due to a different handedness of world coordinate system + + // compute transform + const mat = mInv.mul( mat3( T1, T2, N ).transpose() ).toVar(); + + // transform rect + // & project rect onto sphere + const coords0 = mat.mul( p0.sub( P ) ).normalize().toVar(); + const coords1 = mat.mul( p1.sub( P ) ).normalize().toVar(); + const coords2 = mat.mul( p2.sub( P ) ).normalize().toVar(); + const coords3 = mat.mul( p3.sub( P ) ).normalize().toVar(); + + // calculate vector form factor + const vectorFormFactor = vec3( 0 ).toVar(); + vectorFormFactor.addAssign( LTC_EdgeVectorFormFactor( { v1: coords0, v2: coords1 } ) ); + vectorFormFactor.addAssign( LTC_EdgeVectorFormFactor( { v1: coords1, v2: coords2 } ) ); + vectorFormFactor.addAssign( LTC_EdgeVectorFormFactor( { v1: coords2, v2: coords3 } ) ); + vectorFormFactor.addAssign( LTC_EdgeVectorFormFactor( { v1: coords3, v2: coords0 } ) ); + + // adjust for horizon clipping + result.assign( vec3( LTC_ClippedSphereFormFactor( { f: vectorFormFactor } ) ) ); + + } ); + + return result; + +} ).setLayout( { + name: 'LTC_Evaluate', + type: 'vec3', + inputs: [ + { name: 'N', type: 'vec3' }, + { name: 'V', type: 'vec3' }, + { name: 'P', type: 'vec3' }, + { name: 'mInv', type: 'mat3' }, + { name: 'p0', type: 'vec3' }, + { name: 'p1', type: 'vec3' }, + { name: 'p2', type: 'vec3' }, + { name: 'p3', type: 'vec3' } + ] +} ); + +// Mipped Bicubic Texture Filtering by N8 +// https://www.shadertoy.com/view/Dl2SDW + +const bC = 1.0 / 6.0; + +const w0 = ( a ) => mul( bC, mul( a, mul( a, a.negate().add( 3.0 ) ).sub( 3.0 ) ).add( 1.0 ) ); + +const w1 = ( a ) => mul( bC, mul( a, mul( a, mul( 3.0, a ).sub( 6.0 ) ) ).add( 4.0 ) ); + +const w2 = ( a ) => mul( bC, mul( a, mul( a, mul( - 3.0, a ).add( 3.0 ) ).add( 3.0 ) ).add( 1.0 ) ); + +const w3 = ( a ) => mul( bC, pow( a, 3 ) ); + +const g0 = ( a ) => w0( a ).add( w1( a ) ); + +const g1 = ( a ) => w2( a ).add( w3( a ) ); + +// h0 and h1 are the two offset functions +const h0 = ( a ) => add( - 1.0, w1( a ).div( w0( a ).add( w1( a ) ) ) ); + +const h1 = ( a ) => add( 1.0, w3( a ).div( w2( a ).add( w3( a ) ) ) ); + +const bicubic = ( textureNode, texelSize, lod ) => { + + const uv = textureNode.uvNode; + const uvScaled = mul( uv, texelSize.zw ).add( 0.5 ); + + const iuv = floor( uvScaled ); + const fuv = fract( uvScaled ); + + const g0x = g0( fuv.x ); + const g1x = g1( fuv.x ); + const h0x = h0( fuv.x ); + const h1x = h1( fuv.x ); + const h0y = h0( fuv.y ); + const h1y = h1( fuv.y ); + + const p0 = vec2( iuv.x.add( h0x ), iuv.y.add( h0y ) ).sub( 0.5 ).mul( texelSize.xy ); + const p1 = vec2( iuv.x.add( h1x ), iuv.y.add( h0y ) ).sub( 0.5 ).mul( texelSize.xy ); + const p2 = vec2( iuv.x.add( h0x ), iuv.y.add( h1y ) ).sub( 0.5 ).mul( texelSize.xy ); + const p3 = vec2( iuv.x.add( h1x ), iuv.y.add( h1y ) ).sub( 0.5 ).mul( texelSize.xy ); + + const a = g0( fuv.y ).mul( add( g0x.mul( textureNode.uv( p0 ).level( lod ) ), g1x.mul( textureNode.uv( p1 ).level( lod ) ) ) ); + const b = g1( fuv.y ).mul( add( g0x.mul( textureNode.uv( p2 ).level( lod ) ), g1x.mul( textureNode.uv( p3 ).level( lod ) ) ) ); + + return a.add( b ); + +}; + +const textureBicubic = /*@__PURE__*/ Fn( ( [ textureNode, lodNode = float( 3 ) ] ) => { + + const fLodSize = vec2( textureNode.size( int( lodNode ) ) ); + const cLodSize = vec2( textureNode.size( int( lodNode.add( 1.0 ) ) ) ); + const fLodSizeInv = div( 1.0, fLodSize ); + const cLodSizeInv = div( 1.0, cLodSize ); + const fSample = bicubic( textureNode, vec4( fLodSizeInv, fLodSize ), floor( lodNode ) ); + const cSample = bicubic( textureNode, vec4( cLodSizeInv, cLodSize ), ceil( lodNode ) ); + + return fract( lodNode ).mix( fSample, cSample ); + +} ); + +// +// Transmission +// + +const getVolumeTransmissionRay = /*@__PURE__*/ Fn( ( [ n, v, thickness, ior, modelMatrix ] ) => { + + // Direction of refracted light. + const refractionVector = vec3( refract( v.negate(), normalize( n ), div( 1.0, ior ) ) ); + + // Compute rotation-independant scaling of the model matrix. + const modelScale = vec3( + length( modelMatrix[ 0 ].xyz ), + length( modelMatrix[ 1 ].xyz ), + length( modelMatrix[ 2 ].xyz ) + ); + + // The thickness is specified in local space. + return normalize( refractionVector ).mul( thickness.mul( modelScale ) ); + +} ).setLayout( { + name: 'getVolumeTransmissionRay', + type: 'vec3', + inputs: [ + { name: 'n', type: 'vec3' }, + { name: 'v', type: 'vec3' }, + { name: 'thickness', type: 'float' }, + { name: 'ior', type: 'float' }, + { name: 'modelMatrix', type: 'mat4' } + ] +} ); + +const applyIorToRoughness = /*@__PURE__*/ Fn( ( [ roughness, ior ] ) => { + + // Scale roughness with IOR so that an IOR of 1.0 results in no microfacet refraction and + // an IOR of 1.5 results in the default amount of microfacet refraction. + return roughness.mul( clamp( ior.mul( 2.0 ).sub( 2.0 ), 0.0, 1.0 ) ); + +} ).setLayout( { + name: 'applyIorToRoughness', + type: 'float', + inputs: [ + { name: 'roughness', type: 'float' }, + { name: 'ior', type: 'float' } + ] +} ); + +const singleViewportMipTexture = /*@__PURE__*/ viewportMipTexture(); + +const getTransmissionSample = /*@__PURE__*/ Fn( ( [ fragCoord, roughness, ior ] ) => { + + const transmissionSample = singleViewportMipTexture.uv( fragCoord ); + //const transmissionSample = viewportMipTexture( fragCoord ); + + const lod = log2( float( screenSize.x ) ).mul( applyIorToRoughness( roughness, ior ) ); + + return textureBicubic( transmissionSample, lod ); + +} ); + +const volumeAttenuation = /*@__PURE__*/ Fn( ( [ transmissionDistance, attenuationColor, attenuationDistance ] ) => { + + If( attenuationDistance.notEqual( 0 ), () => { + + // Compute light attenuation using Beer's law. + const attenuationCoefficient = log( attenuationColor ).negate().div( attenuationDistance ); + const transmittance = exp( attenuationCoefficient.negate().mul( transmissionDistance ) ); + + return transmittance; + + } ); + + // Attenuation distance is +∞, i.e. the transmitted color is not attenuated at all. + return vec3( 1.0 ); + +} ).setLayout( { + name: 'volumeAttenuation', + type: 'vec3', + inputs: [ + { name: 'transmissionDistance', type: 'float' }, + { name: 'attenuationColor', type: 'vec3' }, + { name: 'attenuationDistance', type: 'float' } + ] +} ); + +const getIBLVolumeRefraction = /*@__PURE__*/ Fn( ( [ n, v, roughness, diffuseColor, specularColor, specularF90, position, modelMatrix, viewMatrix, projMatrix, ior, thickness, attenuationColor, attenuationDistance, dispersion ] ) => { + + let transmittedLight, transmittance; + + if ( dispersion ) { + + transmittedLight = vec4().toVar(); + transmittance = vec3().toVar(); + + const halfSpread = ior.sub( 1.0 ).mul( dispersion.mul( 0.025 ) ); + const iors = vec3( ior.sub( halfSpread ), ior, ior.add( halfSpread ) ); + + Loop( { start: 0, end: 3 }, ( { i } ) => { + + const ior = iors.element( i ); + + const transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix ); + const refractedRayExit = position.add( transmissionRay ); + + // Project refracted vector on the framebuffer, while mapping to normalized device coordinates. + const ndcPos = projMatrix.mul( viewMatrix.mul( vec4( refractedRayExit, 1.0 ) ) ); + const refractionCoords = vec2( ndcPos.xy.div( ndcPos.w ) ).toVar(); + refractionCoords.addAssign( 1.0 ); + refractionCoords.divAssign( 2.0 ); + refractionCoords.assign( vec2( refractionCoords.x, refractionCoords.y.oneMinus() ) ); // webgpu + + // Sample framebuffer to get pixel the refracted ray hits. + const transmissionSample = getTransmissionSample( refractionCoords, roughness, ior ); + + transmittedLight.element( i ).assign( transmissionSample.element( i ) ); + transmittedLight.a.addAssign( transmissionSample.a ); + + transmittance.element( i ).assign( diffuseColor.element( i ).mul( volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ).element( i ) ) ); + + } ); + + transmittedLight.a.divAssign( 3.0 ); + + } else { + + const transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix ); + const refractedRayExit = position.add( transmissionRay ); + + // Project refracted vector on the framebuffer, while mapping to normalized device coordinates. + const ndcPos = projMatrix.mul( viewMatrix.mul( vec4( refractedRayExit, 1.0 ) ) ); + const refractionCoords = vec2( ndcPos.xy.div( ndcPos.w ) ).toVar(); + refractionCoords.addAssign( 1.0 ); + refractionCoords.divAssign( 2.0 ); + refractionCoords.assign( vec2( refractionCoords.x, refractionCoords.y.oneMinus() ) ); // webgpu + + // Sample framebuffer to get pixel the refracted ray hits. + transmittedLight = getTransmissionSample( refractionCoords, roughness, ior ); + transmittance = diffuseColor.mul( volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ) ); + + } + + const attenuatedColor = transmittance.rgb.mul( transmittedLight.rgb ); + const dotNV = n.dot( v ).clamp(); + + // Get the specular component. + const F = vec3( EnvironmentBRDF( { // n, v, specularColor, specularF90, roughness + dotNV, + specularColor, + specularF90, + roughness + } ) ); + + // As less light is transmitted, the opacity should be increased. This simple approximation does a decent job + // of modulating a CSS background, and has no effect when the buffer is opaque, due to a solid object or clear color. + const transmittanceFactor = transmittance.r.add( transmittance.g, transmittance.b ).div( 3.0 ); + + return vec4( F.oneMinus().mul( attenuatedColor ), transmittedLight.a.oneMinus().mul( transmittanceFactor ).oneMinus() ); + +} ); + +// +// Iridescence +// + +// XYZ to linear-sRGB color space +const XYZ_TO_REC709 = /*@__PURE__*/ mat3( + 3.2404542, - 0.9692660, 0.0556434, + - 1.5371385, 1.8760108, - 0.2040259, + - 0.4985314, 0.0415560, 1.0572252 +); + +// Assume air interface for top +// Note: We don't handle the case fresnel0 == 1 +const Fresnel0ToIor = ( fresnel0 ) => { + + const sqrtF0 = fresnel0.sqrt(); + return vec3( 1.0 ).add( sqrtF0 ).div( vec3( 1.0 ).sub( sqrtF0 ) ); + +}; + +// ior is a value between 1.0 and 3.0. 1.0 is air interface +const IorToFresnel0 = ( transmittedIor, incidentIor ) => { + + return transmittedIor.sub( incidentIor ).div( transmittedIor.add( incidentIor ) ).pow2(); + +}; + +// Fresnel equations for dielectric/dielectric interfaces. +// Ref: https://belcour.github.io/blog/research/2017/05/01/brdf-thin-film.html +// Evaluation XYZ sensitivity curves in Fourier space +const evalSensitivity = ( OPD, shift ) => { + + const phase = OPD.mul( 2.0 * Math.PI * 1.0e-9 ); + const val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 ); + const pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 ); + const VAR = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 ); + + const x = float( 9.7470e-14 * Math.sqrt( 2.0 * Math.PI * 4.5282e+09 ) ).mul( phase.mul( 2.2399e+06 ).add( shift.x ).cos() ).mul( phase.pow2().mul( - 4.5282e+09 ).exp() ); + + let xyz = val.mul( VAR.mul( 2.0 * Math.PI ).sqrt() ).mul( pos.mul( phase ).add( shift ).cos() ).mul( phase.pow2().negate().mul( VAR ).exp() ); + xyz = vec3( xyz.x.add( x ), xyz.y, xyz.z ).div( 1.0685e-7 ); + + const rgb = XYZ_TO_REC709.mul( xyz ); + + return rgb; + +}; + +const evalIridescence = /*@__PURE__*/ Fn( ( { outsideIOR, eta2, cosTheta1, thinFilmThickness, baseF0 } ) => { + + // Force iridescenceIOR -> outsideIOR when thinFilmThickness -> 0.0 + const iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) ); + // Evaluate the cosTheta on the base layer (Snell law) + const sinTheta2Sq = outsideIOR.div( iridescenceIOR ).pow2().mul( float( 1 ).sub( cosTheta1.pow2() ) ); + + // Handle TIR: + const cosTheta2Sq = float( 1 ).sub( sinTheta2Sq ); + /*if ( cosTheta2Sq < 0.0 ) { + + return vec3( 1.0 ); + + }*/ + + const cosTheta2 = cosTheta2Sq.sqrt(); + + // First interface + const R0 = IorToFresnel0( iridescenceIOR, outsideIOR ); + const R12 = F_Schlick( { f0: R0, f90: 1.0, dotVH: cosTheta1 } ); + //const R21 = R12; + const T121 = R12.oneMinus(); + const phi12 = iridescenceIOR.lessThan( outsideIOR ).select( Math.PI, 0.0 ); + const phi21 = float( Math.PI ).sub( phi12 ); + + // Second interface + const baseIOR = Fresnel0ToIor( baseF0.clamp( 0.0, 0.9999 ) ); // guard against 1.0 + const R1 = IorToFresnel0( baseIOR, iridescenceIOR.toVec3() ); + const R23 = F_Schlick( { f0: R1, f90: 1.0, dotVH: cosTheta2 } ); + const phi23 = vec3( + baseIOR.x.lessThan( iridescenceIOR ).select( Math.PI, 0.0 ), + baseIOR.y.lessThan( iridescenceIOR ).select( Math.PI, 0.0 ), + baseIOR.z.lessThan( iridescenceIOR ).select( Math.PI, 0.0 ) + ); + + // Phase shift + const OPD = iridescenceIOR.mul( thinFilmThickness, cosTheta2, 2.0 ); + const phi = vec3( phi21 ).add( phi23 ); + + // Compound terms + const R123 = R12.mul( R23 ).clamp( 1e-5, 0.9999 ); + const r123 = R123.sqrt(); + const Rs = T121.pow2().mul( R23 ).div( vec3( 1.0 ).sub( R123 ) ); + + // Reflectance term for m = 0 (DC term amplitude) + const C0 = R12.add( Rs ); + let I = C0; + + // Reflectance term for m > 0 (pairs of diracs) + let Cm = Rs.sub( T121 ); + for ( let m = 1; m <= 2; ++ m ) { + + Cm = Cm.mul( r123 ); + const Sm = evalSensitivity( float( m ).mul( OPD ), float( m ).mul( phi ) ).mul( 2.0 ); + I = I.add( Cm.mul( Sm ) ); + + } + + // Since out of gamut colors might be produced, negative color values are clamped to 0. + return I.max( vec3( 0.0 ) ); + +} ).setLayout( { + name: 'evalIridescence', + type: 'vec3', + inputs: [ + { name: 'outsideIOR', type: 'float' }, + { name: 'eta2', type: 'float' }, + { name: 'cosTheta1', type: 'float' }, + { name: 'thinFilmThickness', type: 'float' }, + { name: 'baseF0', type: 'vec3' } + ] +} ); + +// +// Sheen +// + +// This is a curve-fit approxmation to the "Charlie sheen" BRDF integrated over the hemisphere from +// Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF". The analysis can be found +// in the Sheen section of https://drive.google.com/file/d/1T0D1VSyR4AllqIJTQAraEIzjlb5h4FKH/view?usp=sharing +const IBLSheenBRDF = /*@__PURE__*/ Fn( ( { normal, viewDir, roughness } ) => { + + const dotNV = normal.dot( viewDir ).saturate(); + + const r2 = roughness.pow2(); + + const a = select( + roughness.lessThan( 0.25 ), + float( - 339.2 ).mul( r2 ).add( float( 161.4 ).mul( roughness ) ).sub( 25.9 ), + float( - 8.48 ).mul( r2 ).add( float( 14.3 ).mul( roughness ) ).sub( 9.95 ) + ); + + const b = select( + roughness.lessThan( 0.25 ), + float( 44.0 ).mul( r2 ).sub( float( 23.7 ).mul( roughness ) ).add( 3.26 ), + float( 1.97 ).mul( r2 ).sub( float( 3.27 ).mul( roughness ) ).add( 0.72 ) + ); + + const DG = select( roughness.lessThan( 0.25 ), 0.0, float( 0.1 ).mul( roughness ).sub( 0.025 ) ).add( a.mul( dotNV ).add( b ).exp() ); + + return DG.mul( 1.0 / Math.PI ).saturate(); + +} ); + +const clearcoatF0 = vec3( 0.04 ); +const clearcoatF90 = float( 1 ); + +// + +class PhysicalLightingModel extends LightingModel { + + constructor( clearcoat = false, sheen = false, iridescence = false, anisotropy = false, transmission = false, dispersion = false ) { + + super(); + + this.clearcoat = clearcoat; + this.sheen = sheen; + this.iridescence = iridescence; + this.anisotropy = anisotropy; + this.transmission = transmission; + this.dispersion = dispersion; + + this.clearcoatRadiance = null; + this.clearcoatSpecularDirect = null; + this.clearcoatSpecularIndirect = null; + this.sheenSpecularDirect = null; + this.sheenSpecularIndirect = null; + this.iridescenceFresnel = null; + this.iridescenceF0 = null; + + } + + start( context ) { + + if ( this.clearcoat === true ) { + + this.clearcoatRadiance = vec3().toVar( 'clearcoatRadiance' ); + this.clearcoatSpecularDirect = vec3().toVar( 'clearcoatSpecularDirect' ); + this.clearcoatSpecularIndirect = vec3().toVar( 'clearcoatSpecularIndirect' ); + + } + + if ( this.sheen === true ) { + + this.sheenSpecularDirect = vec3().toVar( 'sheenSpecularDirect' ); + this.sheenSpecularIndirect = vec3().toVar( 'sheenSpecularIndirect' ); + + } + + if ( this.iridescence === true ) { + + const dotNVi = transformedNormalView.dot( positionViewDirection ).clamp(); + + this.iridescenceFresnel = evalIridescence( { + outsideIOR: float( 1.0 ), + eta2: iridescenceIOR, + cosTheta1: dotNVi, + thinFilmThickness: iridescenceThickness, + baseF0: specularColor + } ); + + this.iridescenceF0 = Schlick_to_F0( { f: this.iridescenceFresnel, f90: 1.0, dotVH: dotNVi } ); + + } + + if ( this.transmission === true ) { + + const position = positionWorld; + const v = cameraPosition.sub( positionWorld ).normalize(); // TODO: Create Node for this, same issue in MaterialX + const n = transformedNormalWorld; + + context.backdrop = getIBLVolumeRefraction( + n, + v, + roughness, + diffuseColor, + specularColor, + specularF90, // specularF90 + position, // positionWorld + modelWorldMatrix, // modelMatrix + cameraViewMatrix, // viewMatrix + cameraProjectionMatrix, // projMatrix + ior, + thickness, + attenuationColor, + attenuationDistance, + this.dispersion ? dispersion : null + ); + + context.backdropAlpha = transmission; + + diffuseColor.a.mulAssign( mix( 1, context.backdrop.a, transmission ) ); + + } + + } + + // Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting" + // Approximates multiscattering in order to preserve energy. + // http://www.jcgt.org/published/0008/01/03/ + + computeMultiscattering( singleScatter, multiScatter, specularF90 ) { + + const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV + + const fab = DFGApprox( { roughness, dotNV } ); + + const Fr = this.iridescenceF0 ? iridescence.mix( specularColor, this.iridescenceF0 ) : specularColor; + + const FssEss = Fr.mul( fab.x ).add( specularF90.mul( fab.y ) ); + + const Ess = fab.x.add( fab.y ); + const Ems = Ess.oneMinus(); + + const Favg = specularColor.add( specularColor.oneMinus().mul( 0.047619 ) ); // 1/21 + const Fms = FssEss.mul( Favg ).div( Ems.mul( Favg ).oneMinus() ); + + singleScatter.addAssign( FssEss ); + multiScatter.addAssign( Fms.mul( Ems ) ); + + } + + direct( { lightDirection, lightColor, reflectedLight } ) { + + const dotNL = transformedNormalView.dot( lightDirection ).clamp(); + const irradiance = dotNL.mul( lightColor ); + + if ( this.sheen === true ) { + + this.sheenSpecularDirect.addAssign( irradiance.mul( BRDF_Sheen( { lightDirection } ) ) ); + + } + + if ( this.clearcoat === true ) { + + const dotNLcc = transformedClearcoatNormalView.dot( lightDirection ).clamp(); + const ccIrradiance = dotNLcc.mul( lightColor ); + + this.clearcoatSpecularDirect.addAssign( ccIrradiance.mul( BRDF_GGX( { lightDirection, f0: clearcoatF0, f90: clearcoatF90, roughness: clearcoatRoughness, normalView: transformedClearcoatNormalView } ) ) ); + + } + + reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) ); + + reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_GGX( { lightDirection, f0: specularColor, f90: 1, roughness, iridescence: this.iridescence, f: this.iridescenceFresnel, USE_IRIDESCENCE: this.iridescence, USE_ANISOTROPY: this.anisotropy } ) ) ); + + } + + directRectArea( { lightColor, lightPosition, halfWidth, halfHeight, reflectedLight, ltc_1, ltc_2 } ) { + + const p0 = lightPosition.add( halfWidth ).sub( halfHeight ); // counterclockwise; light shines in local neg z direction + const p1 = lightPosition.sub( halfWidth ).sub( halfHeight ); + const p2 = lightPosition.sub( halfWidth ).add( halfHeight ); + const p3 = lightPosition.add( halfWidth ).add( halfHeight ); + + const N = transformedNormalView; + const V = positionViewDirection; + const P = positionView.toVar(); + + const uv = LTC_Uv( { N, V, roughness } ); + + const t1 = ltc_1.uv( uv ).toVar(); + const t2 = ltc_2.uv( uv ).toVar(); + + const mInv = mat3( + vec3( t1.x, 0, t1.y ), + vec3( 0, 1, 0 ), + vec3( t1.z, 0, t1.w ) + ).toVar(); + + // LTC Fresnel Approximation by Stephen Hill + // http://blog.selfshadow.com/publications/s2016-advances/s2016_ltc_fresnel.pdf + const fresnel = specularColor.mul( t2.x ).add( specularColor.oneMinus().mul( t2.y ) ).toVar(); + + reflectedLight.directSpecular.addAssign( lightColor.mul( fresnel ).mul( LTC_Evaluate( { N, V, P, mInv, p0, p1, p2, p3 } ) ) ); + + reflectedLight.directDiffuse.addAssign( lightColor.mul( diffuseColor ).mul( LTC_Evaluate( { N, V, P, mInv: mat3( 1, 0, 0, 0, 1, 0, 0, 0, 1 ), p0, p1, p2, p3 } ) ) ); + + } + + indirect( context, stack, builder ) { + + this.indirectDiffuse( context, stack, builder ); + this.indirectSpecular( context, stack, builder ); + this.ambientOcclusion( context, stack, builder ); + + } + + indirectDiffuse( { irradiance, reflectedLight } ) { + + reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) ); + + } + + indirectSpecular( { radiance, iblIrradiance, reflectedLight } ) { + + if ( this.sheen === true ) { + + this.sheenSpecularIndirect.addAssign( iblIrradiance.mul( + sheen, + IBLSheenBRDF( { + normal: transformedNormalView, + viewDir: positionViewDirection, + roughness: sheenRoughness + } ) + ) ); + + } + + if ( this.clearcoat === true ) { + + const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp(); + + const clearcoatEnv = EnvironmentBRDF( { + dotNV: dotNVcc, + specularColor: clearcoatF0, + specularF90: clearcoatF90, + roughness: clearcoatRoughness + } ); + + this.clearcoatSpecularIndirect.addAssign( this.clearcoatRadiance.mul( clearcoatEnv ) ); + + } + + // Both indirect specular and indirect diffuse light accumulate here + + const singleScattering = vec3().toVar( 'singleScattering' ); + const multiScattering = vec3().toVar( 'multiScattering' ); + const cosineWeightedIrradiance = iblIrradiance.mul( 1 / Math.PI ); + + this.computeMultiscattering( singleScattering, multiScattering, specularF90 ); + + const totalScattering = singleScattering.add( multiScattering ); + + const diffuse = diffuseColor.mul( totalScattering.r.max( totalScattering.g ).max( totalScattering.b ).oneMinus() ); + + reflectedLight.indirectSpecular.addAssign( radiance.mul( singleScattering ) ); + reflectedLight.indirectSpecular.addAssign( multiScattering.mul( cosineWeightedIrradiance ) ); + + reflectedLight.indirectDiffuse.addAssign( diffuse.mul( cosineWeightedIrradiance ) ); + + } + + ambientOcclusion( { ambientOcclusion, reflectedLight } ) { + + const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV + + const aoNV = dotNV.add( ambientOcclusion ); + const aoExp = roughness.mul( - 16.0 ).oneMinus().negate().exp2(); + + const aoNode = ambientOcclusion.sub( aoNV.pow( aoExp ).oneMinus() ).clamp(); + + if ( this.clearcoat === true ) { + + this.clearcoatSpecularIndirect.mulAssign( ambientOcclusion ); + + } + + if ( this.sheen === true ) { + + this.sheenSpecularIndirect.mulAssign( ambientOcclusion ); + + } + + reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion ); + reflectedLight.indirectSpecular.mulAssign( aoNode ); + + } + + finish( context ) { + + const { outgoingLight } = context; + + if ( this.clearcoat === true ) { + + const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp(); + + const Fcc = F_Schlick( { + dotVH: dotNVcc, + f0: clearcoatF0, + f90: clearcoatF90 + } ); + + const clearcoatLight = outgoingLight.mul( clearcoat.mul( Fcc ).oneMinus() ).add( this.clearcoatSpecularDirect.add( this.clearcoatSpecularIndirect ).mul( clearcoat ) ); + + outgoingLight.assign( clearcoatLight ); + + } + + if ( this.sheen === true ) { + + const sheenEnergyComp = sheen.r.max( sheen.g ).max( sheen.b ).mul( 0.157 ).oneMinus(); + const sheenLight = outgoingLight.mul( sheenEnergyComp ).add( this.sheenSpecularDirect, this.sheenSpecularIndirect ); + + outgoingLight.assign( sheenLight ); + + } + + } + +} + +// These defines must match with PMREMGenerator + +const cubeUV_r0 = /*@__PURE__*/ float( 1.0 ); +const cubeUV_m0 = /*@__PURE__*/ float( - 2.0 ); +const cubeUV_r1 = /*@__PURE__*/ float( 0.8 ); +const cubeUV_m1 = /*@__PURE__*/ float( - 1.0 ); +const cubeUV_r4 = /*@__PURE__*/ float( 0.4 ); +const cubeUV_m4 = /*@__PURE__*/ float( 2.0 ); +const cubeUV_r5 = /*@__PURE__*/ float( 0.305 ); +const cubeUV_m5 = /*@__PURE__*/ float( 3.0 ); +const cubeUV_r6 = /*@__PURE__*/ float( 0.21 ); +const cubeUV_m6 = /*@__PURE__*/ float( 4.0 ); + +const cubeUV_minMipLevel = /*@__PURE__*/ float( 4.0 ); +const cubeUV_minTileSize = /*@__PURE__*/ float( 16.0 ); + +// These shader functions convert between the UV coordinates of a single face of +// a cubemap, the 0-5 integer index of a cube face, and the direction vector for +// sampling a textureCube (not generally normalized ). + +const getFace = /*@__PURE__*/ Fn( ( [ direction ] ) => { + + const absDirection = vec3( abs( direction ) ).toVar(); + const face = float( - 1.0 ).toVar(); + + If( absDirection.x.greaterThan( absDirection.z ), () => { + + If( absDirection.x.greaterThan( absDirection.y ), () => { + + face.assign( select( direction.x.greaterThan( 0.0 ), 0.0, 3.0 ) ); + + } ).Else( () => { + + face.assign( select( direction.y.greaterThan( 0.0 ), 1.0, 4.0 ) ); + + } ); + + } ).Else( () => { + + If( absDirection.z.greaterThan( absDirection.y ), () => { + + face.assign( select( direction.z.greaterThan( 0.0 ), 2.0, 5.0 ) ); + + } ).Else( () => { + + face.assign( select( direction.y.greaterThan( 0.0 ), 1.0, 4.0 ) ); + + } ); + + } ); + + return face; + +} ).setLayout( { + name: 'getFace', + type: 'float', + inputs: [ + { name: 'direction', type: 'vec3' } + ] +} ); + +// RH coordinate system; PMREM face-indexing convention +const getUV = /*@__PURE__*/ Fn( ( [ direction, face ] ) => { + + const uv = vec2().toVar(); + + If( face.equal( 0.0 ), () => { + + uv.assign( vec2( direction.z, direction.y ).div( abs( direction.x ) ) ); // pos x + + } ).ElseIf( face.equal( 1.0 ), () => { + + uv.assign( vec2( direction.x.negate(), direction.z.negate() ).div( abs( direction.y ) ) ); // pos y + + } ).ElseIf( face.equal( 2.0 ), () => { + + uv.assign( vec2( direction.x.negate(), direction.y ).div( abs( direction.z ) ) ); // pos z + + } ).ElseIf( face.equal( 3.0 ), () => { + + uv.assign( vec2( direction.z.negate(), direction.y ).div( abs( direction.x ) ) ); // neg x + + } ).ElseIf( face.equal( 4.0 ), () => { + + uv.assign( vec2( direction.x.negate(), direction.z ).div( abs( direction.y ) ) ); // neg y + + } ).Else( () => { + + uv.assign( vec2( direction.x, direction.y ).div( abs( direction.z ) ) ); // neg z + + } ); + + return mul( 0.5, uv.add( 1.0 ) ); + +} ).setLayout( { + name: 'getUV', + type: 'vec2', + inputs: [ + { name: 'direction', type: 'vec3' }, + { name: 'face', type: 'float' } + ] +} ); + +const roughnessToMip = /*@__PURE__*/ Fn( ( [ roughness ] ) => { + + const mip = float( 0.0 ).toVar(); + + If( roughness.greaterThanEqual( cubeUV_r1 ), () => { + + mip.assign( cubeUV_r0.sub( roughness ).mul( cubeUV_m1.sub( cubeUV_m0 ) ).div( cubeUV_r0.sub( cubeUV_r1 ) ).add( cubeUV_m0 ) ); + + } ).ElseIf( roughness.greaterThanEqual( cubeUV_r4 ), () => { + + mip.assign( cubeUV_r1.sub( roughness ).mul( cubeUV_m4.sub( cubeUV_m1 ) ).div( cubeUV_r1.sub( cubeUV_r4 ) ).add( cubeUV_m1 ) ); + + } ).ElseIf( roughness.greaterThanEqual( cubeUV_r5 ), () => { + + mip.assign( cubeUV_r4.sub( roughness ).mul( cubeUV_m5.sub( cubeUV_m4 ) ).div( cubeUV_r4.sub( cubeUV_r5 ) ).add( cubeUV_m4 ) ); + + } ).ElseIf( roughness.greaterThanEqual( cubeUV_r6 ), () => { + + mip.assign( cubeUV_r5.sub( roughness ).mul( cubeUV_m6.sub( cubeUV_m5 ) ).div( cubeUV_r5.sub( cubeUV_r6 ) ).add( cubeUV_m5 ) ); + + } ).Else( () => { + + mip.assign( float( - 2.0 ).mul( log2( mul( 1.16, roughness ) ) ) ); // 1.16 = 1.79^0.25 + + } ); + + return mip; + +} ).setLayout( { + name: 'roughnessToMip', + type: 'float', + inputs: [ + { name: 'roughness', type: 'float' } + ] +} ); + +// RH coordinate system; PMREM face-indexing convention +const getDirection = /*@__PURE__*/ Fn( ( [ uv_immutable, face ] ) => { + + const uv = uv_immutable.toVar(); + uv.assign( mul( 2.0, uv ).sub( 1.0 ) ); + const direction = vec3( uv, 1.0 ).toVar(); + + If( face.equal( 0.0 ), () => { + + direction.assign( direction.zyx ); // ( 1, v, u ) pos x + + } ).ElseIf( face.equal( 1.0 ), () => { + + direction.assign( direction.xzy ); + direction.xz.mulAssign( - 1.0 ); // ( -u, 1, -v ) pos y + + } ).ElseIf( face.equal( 2.0 ), () => { + + direction.x.mulAssign( - 1.0 ); // ( -u, v, 1 ) pos z + + } ).ElseIf( face.equal( 3.0 ), () => { + + direction.assign( direction.zyx ); + direction.xz.mulAssign( - 1.0 ); // ( -1, v, -u ) neg x + + } ).ElseIf( face.equal( 4.0 ), () => { + + direction.assign( direction.xzy ); + direction.xy.mulAssign( - 1.0 ); // ( -u, -1, v ) neg y + + } ).ElseIf( face.equal( 5.0 ), () => { + + direction.z.mulAssign( - 1.0 ); // ( u, v, -1 ) neg zS + + } ); + + return direction; + +} ).setLayout( { + name: 'getDirection', + type: 'vec3', + inputs: [ + { name: 'uv', type: 'vec2' }, + { name: 'face', type: 'float' } + ] +} ); + +// + +const textureCubeUV = /*@__PURE__*/ Fn( ( [ envMap, sampleDir_immutable, roughness_immutable, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ] ) => { + + const roughness = float( roughness_immutable ); + const sampleDir = vec3( sampleDir_immutable ); + + const mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP ); + const mipF = fract( mip ); + const mipInt = floor( mip ); + const color0 = vec3( bilinearCubeUV( envMap, sampleDir, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ) ).toVar(); + + If( mipF.notEqual( 0.0 ), () => { + + const color1 = vec3( bilinearCubeUV( envMap, sampleDir, mipInt.add( 1.0 ), CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ) ).toVar(); + + color0.assign( mix( color0, color1, mipF ) ); + + } ); + + return color0; + +} ); + +const bilinearCubeUV = /*@__PURE__*/ Fn( ( [ envMap, direction_immutable, mipInt_immutable, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ] ) => { + + const mipInt = float( mipInt_immutable ).toVar(); + const direction = vec3( direction_immutable ); + const face = float( getFace( direction ) ).toVar(); + const filterInt = float( max$1( cubeUV_minMipLevel.sub( mipInt ), 0.0 ) ).toVar(); + mipInt.assign( max$1( mipInt, cubeUV_minMipLevel ) ); + const faceSize = float( exp2( mipInt ) ).toVar(); + const uv = vec2( getUV( direction, face ).mul( faceSize.sub( 2.0 ) ).add( 1.0 ) ).toVar(); + + If( face.greaterThan( 2.0 ), () => { + + uv.y.addAssign( faceSize ); + face.subAssign( 3.0 ); + + } ); + + uv.x.addAssign( face.mul( faceSize ) ); + uv.x.addAssign( filterInt.mul( mul( 3.0, cubeUV_minTileSize ) ) ); + uv.y.addAssign( mul( 4.0, exp2( CUBEUV_MAX_MIP ).sub( faceSize ) ) ); + uv.x.mulAssign( CUBEUV_TEXEL_WIDTH ); + uv.y.mulAssign( CUBEUV_TEXEL_HEIGHT ); + + return envMap.uv( uv ).grad( vec2(), vec2() ); // disable anisotropic filtering + +} ); + +const getSample = /*@__PURE__*/ Fn( ( { envMap, mipInt, outputDirection, theta, axis, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) => { + + const cosTheta = cos( theta ); + + // Rodrigues' axis-angle rotation + const sampleDirection = outputDirection.mul( cosTheta ) + .add( axis.cross( outputDirection ).mul( sin( theta ) ) ) + .add( axis.mul( axis.dot( outputDirection ).mul( cosTheta.oneMinus() ) ) ); + + return bilinearCubeUV( envMap, sampleDirection, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ); + +} ); + +const blur = /*@__PURE__*/ Fn( ( { n, latitudinal, poleAxis, outputDirection, weights, samples, dTheta, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) => { + + const axis = vec3( select( latitudinal, poleAxis, cross( poleAxis, outputDirection ) ) ).toVar(); + + If( all( axis.equals( vec3( 0.0 ) ) ), () => { + + axis.assign( vec3( outputDirection.z, 0.0, outputDirection.x.negate() ) ); + + } ); + + axis.assign( normalize( axis ) ); + + const gl_FragColor = vec3().toVar(); + gl_FragColor.addAssign( weights.element( int( 0 ) ).mul( getSample( { theta: 0.0, axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) ) ); + + Loop( { start: int( 1 ), end: n }, ( { i } ) => { + + If( i.greaterThanEqual( samples ), () => { + + Break(); + + } ); + + const theta = float( dTheta.mul( float( i ) ) ).toVar(); + gl_FragColor.addAssign( weights.element( i ).mul( getSample( { theta: theta.mul( - 1.0 ), axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) ) ); + gl_FragColor.addAssign( weights.element( i ).mul( getSample( { theta, axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) ) ); + + } ); + + return vec4( gl_FragColor, 1 ); + +} ); + +let _generator = null; + +const _cache = new WeakMap(); + +function _generateCubeUVSize( imageHeight ) { + + const maxMip = Math.log2( imageHeight ) - 2; + + const texelHeight = 1.0 / imageHeight; + + const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) ); + + return { texelWidth, texelHeight, maxMip }; + +} + +function _getPMREMFromTexture( texture ) { + + let cacheTexture = _cache.get( texture ); + + const pmremVersion = cacheTexture !== undefined ? cacheTexture.pmremVersion : - 1; + + if ( pmremVersion !== texture.pmremVersion ) { + + const image = texture.image; + + if ( texture.isCubeTexture ) { + + if ( isCubeMapReady( image ) ) { + + cacheTexture = _generator.fromCubemap( texture, cacheTexture ); + + } else { + + return null; + + } + + + } else { + + if ( isEquirectangularMapReady( image ) ) { + + cacheTexture = _generator.fromEquirectangular( texture, cacheTexture ); + + } else { + + return null; + + } + + } + + cacheTexture.pmremVersion = texture.pmremVersion; + + _cache.set( texture, cacheTexture ); + + } + + return cacheTexture.texture; + +} + +class PMREMNode extends TempNode { + + static get type() { + + return 'PMREMNode'; + + } + + constructor( value, uvNode = null, levelNode = null ) { + + super( 'vec3' ); + + this._value = value; + this._pmrem = null; + + this.uvNode = uvNode; + this.levelNode = levelNode; + + this._generator = null; + + const defaultTexture = new Texture(); + defaultTexture.isRenderTargetTexture = true; + + this._texture = texture( defaultTexture ); + + this._width = uniform( 0 ); + this._height = uniform( 0 ); + this._maxMip = uniform( 0 ); + + this.updateBeforeType = NodeUpdateType.RENDER; + + } + + set value( value ) { + + this._value = value; + this._pmrem = null; + + } + + get value() { + + return this._value; + + } + + updateFromTexture( texture ) { + + const cubeUVSize = _generateCubeUVSize( texture.image.height ); + + this._texture.value = texture; + this._width.value = cubeUVSize.texelWidth; + this._height.value = cubeUVSize.texelHeight; + this._maxMip.value = cubeUVSize.maxMip; + + } + + updateBefore() { + + let pmrem = this._pmrem; + + const pmremVersion = pmrem ? pmrem.pmremVersion : - 1; + const texture = this._value; + + if ( pmremVersion !== texture.pmremVersion ) { + + if ( texture.isPMREMTexture === true ) { + + pmrem = texture; + + } else { + + pmrem = _getPMREMFromTexture( texture ); + + } + + if ( pmrem !== null ) { + + this._pmrem = pmrem; + + this.updateFromTexture( pmrem ); + + } + + } + + } + + setup( builder ) { + + if ( _generator === null ) { + + _generator = builder.createPMREMGenerator(); + + } + + // + + this.updateBefore( builder ); + + // + + let uvNode = this.uvNode; + + if ( uvNode === null && builder.context.getUV ) { + + uvNode = builder.context.getUV( this ); + + } + + // + + const texture = this.value; + + if ( builder.renderer.coordinateSystem === WebGLCoordinateSystem && texture.isPMREMTexture !== true && texture.isRenderTargetTexture === true ) { + + uvNode = vec3( uvNode.x.negate(), uvNode.yz ); + + } + + // + + let levelNode = this.levelNode; + + if ( levelNode === null && builder.context.getTextureLevel ) { + + levelNode = builder.context.getTextureLevel( this ); + + } + + // + + return textureCubeUV( this._texture, uvNode, levelNode, this._width, this._height, this._maxMip ); + + } + +} + +function isCubeMapReady( image ) { + + if ( image === null || image === undefined ) return false; + + let count = 0; + const length = 6; + + for ( let i = 0; i < length; i ++ ) { + + if ( image[ i ] !== undefined ) count ++; + + } + + return count === length; + + +} + +function isEquirectangularMapReady( image ) { + + if ( image === null || image === undefined ) return false; + + return image.height > 0; + +} + +const pmremTexture = /*@__PURE__*/ nodeProxy( PMREMNode ); + +const _envNodeCache = new WeakMap(); + +class EnvironmentNode extends LightingNode { + + static get type() { + + return 'EnvironmentNode'; + + } + + constructor( envNode = null ) { + + super(); + + this.envNode = envNode; + + } + + setup( builder ) { + + const { material } = builder; + + let envNode = this.envNode; + + if ( envNode.isTextureNode || envNode.isMaterialReferenceNode ) { + + const value = ( envNode.isTextureNode ) ? envNode.value : material[ envNode.property ]; + + let cacheEnvNode = _envNodeCache.get( value ); + + if ( cacheEnvNode === undefined ) { + + cacheEnvNode = pmremTexture( value ); + + _envNodeCache.set( value, cacheEnvNode ); + + } + + envNode = cacheEnvNode; + + } + + // + + const envMap = material.envMap; + const intensity = envMap ? reference( 'envMapIntensity', 'float', builder.material ) : reference( 'environmentIntensity', 'float', builder.scene ); // @TODO: Add materialEnvIntensity in MaterialNode + + const useAnisotropy = material.useAnisotropy === true || material.anisotropy > 0; + const radianceNormalView = useAnisotropy ? transformedBentNormalView : transformedNormalView; + + const radiance = envNode.context( createRadianceContext( roughness, radianceNormalView ) ).mul( intensity ); + const irradiance = envNode.context( createIrradianceContext( transformedNormalWorld ) ).mul( Math.PI ).mul( intensity ); + + const isolateRadiance = cache( radiance ); + const isolateIrradiance = cache( irradiance ); + + // + + builder.context.radiance.addAssign( isolateRadiance ); + + builder.context.iblIrradiance.addAssign( isolateIrradiance ); + + // + + const clearcoatRadiance = builder.context.lightingModel.clearcoatRadiance; + + if ( clearcoatRadiance ) { + + const clearcoatRadianceContext = envNode.context( createRadianceContext( clearcoatRoughness, transformedClearcoatNormalView ) ).mul( intensity ); + const isolateClearcoatRadiance = cache( clearcoatRadianceContext ); + + clearcoatRadiance.addAssign( isolateClearcoatRadiance ); + + } + + } + +} + +const createRadianceContext = ( roughnessNode, normalViewNode ) => { + + let reflectVec = null; + + return { + getUV: () => { + + if ( reflectVec === null ) { + + reflectVec = positionViewDirection.negate().reflect( normalViewNode ); + + // Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane. + reflectVec = roughnessNode.mul( roughnessNode ).mix( reflectVec, normalViewNode ).normalize(); + + reflectVec = reflectVec.transformDirection( cameraViewMatrix ); + + } + + return reflectVec; + + }, + getTextureLevel: () => { + + return roughnessNode; + + } + }; + +}; + +const createIrradianceContext = ( normalWorldNode ) => { + + return { + getUV: () => { + + return normalWorldNode; + + }, + getTextureLevel: () => { + + return float( 1.0 ); + + } + }; + +}; + +const _defaultValues$6 = /*@__PURE__*/ new MeshStandardMaterial(); + +class MeshStandardNodeMaterial extends NodeMaterial { + + static get type() { + + return 'MeshStandardNodeMaterial'; + + } + + constructor( parameters ) { + + super(); + + this.isMeshStandardNodeMaterial = true; + + this.lights = true; + + this.emissiveNode = null; + + this.metalnessNode = null; + this.roughnessNode = null; + + this.setDefaultValues( _defaultValues$6 ); + + this.setValues( parameters ); + + } + + setupEnvironment( builder ) { + + let envNode = super.setupEnvironment( builder ); + + if ( envNode === null && builder.environmentNode ) { + + envNode = builder.environmentNode; + + } + + return envNode ? new EnvironmentNode( envNode ) : null; + + } + + setupLightingModel( /*builder*/ ) { + + return new PhysicalLightingModel(); + + } + + setupSpecular() { + + const specularColorNode = mix( vec3( 0.04 ), diffuseColor.rgb, metalness ); + + specularColor.assign( specularColorNode ); + specularF90.assign( 1.0 ); + + } + + setupVariants() { + + // METALNESS + + const metalnessNode = this.metalnessNode ? float( this.metalnessNode ) : materialMetalness; + + metalness.assign( metalnessNode ); + + // ROUGHNESS + + let roughnessNode = this.roughnessNode ? float( this.roughnessNode ) : materialRoughness; + roughnessNode = getRoughness( { roughness: roughnessNode } ); + + roughness.assign( roughnessNode ); + + // SPECULAR COLOR + + this.setupSpecular(); + + // DIFFUSE COLOR + + diffuseColor.assign( vec4( diffuseColor.rgb.mul( metalnessNode.oneMinus() ), diffuseColor.a ) ); + + } + + copy( source ) { + + this.emissiveNode = source.emissiveNode; + + this.metalnessNode = source.metalnessNode; + this.roughnessNode = source.roughnessNode; + + return super.copy( source ); + + } + +} + +const _defaultValues$5 = /*@__PURE__*/ new MeshPhysicalMaterial(); + +class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { + + static get type() { + + return 'MeshPhysicalNodeMaterial'; + + } + + constructor( parameters ) { + + super(); + + this.isMeshPhysicalNodeMaterial = true; + + this.clearcoatNode = null; + this.clearcoatRoughnessNode = null; + this.clearcoatNormalNode = null; + + this.sheenNode = null; + this.sheenRoughnessNode = null; + + this.iridescenceNode = null; + this.iridescenceIORNode = null; + this.iridescenceThicknessNode = null; + + this.specularIntensityNode = null; + this.specularColorNode = null; + + this.iorNode = null; + this.transmissionNode = null; + this.thicknessNode = null; + this.attenuationDistanceNode = null; + this.attenuationColorNode = null; + this.dispersionNode = null; + + this.anisotropyNode = null; + + this.setDefaultValues( _defaultValues$5 ); + + this.setValues( parameters ); + + } + + get useClearcoat() { + + return this.clearcoat > 0 || this.clearcoatNode !== null; + + } + + get useIridescence() { + + return this.iridescence > 0 || this.iridescenceNode !== null; + + } + + get useSheen() { + + return this.sheen > 0 || this.sheenNode !== null; + + } + + get useAnisotropy() { + + return this.anisotropy > 0 || this.anisotropyNode !== null; + + } + + get useTransmission() { + + return this.transmission > 0 || this.transmissionNode !== null; + + } + + get useDispersion() { + + return this.dispersion > 0 || this.dispersionNode !== null; + + } + + setupSpecular() { + + const iorNode = this.iorNode ? float( this.iorNode ) : materialIOR; + + ior.assign( iorNode ); + specularColor.assign( mix( min$1( pow2( ior.sub( 1.0 ).div( ior.add( 1.0 ) ) ).mul( materialSpecularColor ), vec3( 1.0 ) ).mul( materialSpecularIntensity ), diffuseColor.rgb, metalness ) ); + specularF90.assign( mix( materialSpecularIntensity, 1.0, metalness ) ); + + } + + setupLightingModel( /*builder*/ ) { + + return new PhysicalLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion ); + + } + + setupVariants( builder ) { + + super.setupVariants( builder ); + + // CLEARCOAT + + if ( this.useClearcoat ) { + + const clearcoatNode = this.clearcoatNode ? float( this.clearcoatNode ) : materialClearcoat; + const clearcoatRoughnessNode = this.clearcoatRoughnessNode ? float( this.clearcoatRoughnessNode ) : materialClearcoatRoughness; + + clearcoat.assign( clearcoatNode ); + clearcoatRoughness.assign( getRoughness( { roughness: clearcoatRoughnessNode } ) ); + + } + + // SHEEN + + if ( this.useSheen ) { + + const sheenNode = this.sheenNode ? vec3( this.sheenNode ) : materialSheen; + const sheenRoughnessNode = this.sheenRoughnessNode ? float( this.sheenRoughnessNode ) : materialSheenRoughness; + + sheen.assign( sheenNode ); + sheenRoughness.assign( sheenRoughnessNode ); + + } + + // IRIDESCENCE + + if ( this.useIridescence ) { + + const iridescenceNode = this.iridescenceNode ? float( this.iridescenceNode ) : materialIridescence; + const iridescenceIORNode = this.iridescenceIORNode ? float( this.iridescenceIORNode ) : materialIridescenceIOR; + const iridescenceThicknessNode = this.iridescenceThicknessNode ? float( this.iridescenceThicknessNode ) : materialIridescenceThickness; + + iridescence.assign( iridescenceNode ); + iridescenceIOR.assign( iridescenceIORNode ); + iridescenceThickness.assign( iridescenceThicknessNode ); + + } + + // ANISOTROPY + + if ( this.useAnisotropy ) { + + const anisotropyV = ( this.anisotropyNode ? vec2( this.anisotropyNode ) : materialAnisotropy ).toVar(); + + anisotropy.assign( anisotropyV.length() ); + + If( anisotropy.equal( 0.0 ), () => { + + anisotropyV.assign( vec2( 1.0, 0.0 ) ); + + } ).Else( () => { + + anisotropyV.divAssign( vec2( anisotropy ) ); + anisotropy.assign( anisotropy.saturate() ); + + } ); + + // Roughness along the anisotropy bitangent is the material roughness, while the tangent roughness increases with anisotropy. + alphaT.assign( anisotropy.pow2().mix( roughness.pow2(), 1.0 ) ); + + anisotropyT.assign( TBNViewMatrix[ 0 ].mul( anisotropyV.x ).add( TBNViewMatrix[ 1 ].mul( anisotropyV.y ) ) ); + anisotropyB.assign( TBNViewMatrix[ 1 ].mul( anisotropyV.x ).sub( TBNViewMatrix[ 0 ].mul( anisotropyV.y ) ) ); + + } + + // TRANSMISSION + + if ( this.useTransmission ) { + + const transmissionNode = this.transmissionNode ? float( this.transmissionNode ) : materialTransmission; + const thicknessNode = this.thicknessNode ? float( this.thicknessNode ) : materialThickness; + const attenuationDistanceNode = this.attenuationDistanceNode ? float( this.attenuationDistanceNode ) : materialAttenuationDistance; + const attenuationColorNode = this.attenuationColorNode ? vec3( this.attenuationColorNode ) : materialAttenuationColor; + + transmission.assign( transmissionNode ); + thickness.assign( thicknessNode ); + attenuationDistance.assign( attenuationDistanceNode ); + attenuationColor.assign( attenuationColorNode ); + + if ( this.useDispersion ) { + + const dispersionNode = this.dispersionNode ? float( this.dispersionNode ) : materialDispersion; + + dispersion.assign( dispersionNode ); + + } + + } + + } + + setupClearcoatNormal() { + + return this.clearcoatNormalNode ? vec3( this.clearcoatNormalNode ) : materialClearcoatNormal; + + } + + setup( builder ) { + + builder.context.setupClearcoatNormal = () => this.setupClearcoatNormal( builder ); + + super.setup( builder ); + + } + + copy( source ) { + + this.clearcoatNode = source.clearcoatNode; + this.clearcoatRoughnessNode = source.clearcoatRoughnessNode; + this.clearcoatNormalNode = source.clearcoatNormalNode; + + this.sheenNode = source.sheenNode; + this.sheenRoughnessNode = source.sheenRoughnessNode; + + this.iridescenceNode = source.iridescenceNode; + this.iridescenceIORNode = source.iridescenceIORNode; + this.iridescenceThicknessNode = source.iridescenceThicknessNode; + + this.specularIntensityNode = source.specularIntensityNode; + this.specularColorNode = source.specularColorNode; + + this.transmissionNode = source.transmissionNode; + this.thicknessNode = source.thicknessNode; + this.attenuationDistanceNode = source.attenuationDistanceNode; + this.attenuationColorNode = source.attenuationColorNode; + this.dispersionNode = source.dispersionNode; + + this.anisotropyNode = source.anisotropyNode; + + return super.copy( source ); + + } + +} + +class SSSLightingModel extends PhysicalLightingModel { + + constructor( useClearcoat, useSheen, useIridescence, useSSS ) { + + super( useClearcoat, useSheen, useIridescence ); + + this.useSSS = useSSS; + + } + + direct( { lightDirection, lightColor, reflectedLight }, stack, builder ) { + + if ( this.useSSS === true ) { + + const material = builder.material; + + const { thicknessColorNode, thicknessDistortionNode, thicknessAmbientNode, thicknessAttenuationNode, thicknessPowerNode, thicknessScaleNode } = material; + + const scatteringHalf = lightDirection.add( transformedNormalView.mul( thicknessDistortionNode ) ).normalize(); + const scatteringDot = float( positionViewDirection.dot( scatteringHalf.negate() ).saturate().pow( thicknessPowerNode ).mul( thicknessScaleNode ) ); + const scatteringIllu = vec3( scatteringDot.add( thicknessAmbientNode ).mul( thicknessColorNode ) ); + + reflectedLight.directDiffuse.addAssign( scatteringIllu.mul( thicknessAttenuationNode.mul( lightColor ) ) ); + + } + + super.direct( { lightDirection, lightColor, reflectedLight }, stack, builder ); + + } + +} + +class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial { + + static get type() { + + return 'MeshSSSNodeMaterial'; + + } + + constructor( parameters ) { + + super( parameters ); + + this.thicknessColorNode = null; + this.thicknessDistortionNode = float( 0.1 ); + this.thicknessAmbientNode = float( 0.0 ); + this.thicknessAttenuationNode = float( .1 ); + this.thicknessPowerNode = float( 2.0 ); + this.thicknessScaleNode = float( 10.0 ); + + } + + get useSSS() { + + return this.thicknessColorNode !== null; + + } + + setupLightingModel( /*builder*/ ) { + + return new SSSLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useSSS ); + + } + + copy( source ) { + + this.thicknessColorNode = source.thicknessColorNode; + this.thicknessDistortionNode = source.thicknessDistortionNode; + this.thicknessAmbientNode = source.thicknessAmbientNode; + this.thicknessAttenuationNode = source.thicknessAttenuationNode; + this.thicknessPowerNode = source.thicknessPowerNode; + this.thicknessScaleNode = source.thicknessScaleNode; + + return super.copy( source ); + + } + +} + +const getGradientIrradiance = /*@__PURE__*/ Fn( ( { normal, lightDirection, builder } ) => { + + // dotNL will be from -1.0 to 1.0 + const dotNL = normal.dot( lightDirection ); + const coord = vec2( dotNL.mul( 0.5 ).add( 0.5 ), 0.0 ); + + if ( builder.material.gradientMap ) { + + const gradientMap = materialReference( 'gradientMap', 'texture' ).context( { getUV: () => coord } ); + + return vec3( gradientMap.r ); + + } else { + + const fw = coord.fwidth().mul( 0.5 ); + + return mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( float( 0.7 ).sub( fw.x ), float( 0.7 ).add( fw.x ), coord.x ) ); + + } + +} ); + +class ToonLightingModel extends LightingModel { + + direct( { lightDirection, lightColor, reflectedLight }, stack, builder ) { + + const irradiance = getGradientIrradiance( { normal: normalGeometry, lightDirection, builder } ).mul( lightColor ); + + reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) ); + + } + + indirect( { ambientOcclusion, irradiance, reflectedLight } ) { + + reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) ); + + reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion ); + + } + +} + +const _defaultValues$4 = /*@__PURE__*/ new MeshToonMaterial(); + +class MeshToonNodeMaterial extends NodeMaterial { + + static get type() { + + return 'MeshToonNodeMaterial'; + + } + + constructor( parameters ) { + + super(); + + this.isMeshToonNodeMaterial = true; + + this.lights = true; + + this.setDefaultValues( _defaultValues$4 ); + + this.setValues( parameters ); + + } + + setupLightingModel( /*builder*/ ) { + + return new ToonLightingModel(); + + } + +} + +class MatcapUVNode extends TempNode { + + static get type() { + + return 'MatcapUVNode'; + + } + + constructor() { + + super( 'vec2' ); + + } + + setup() { + + const x = vec3( positionViewDirection.z, 0, positionViewDirection.x.negate() ).normalize(); + const y = positionViewDirection.cross( x ); + + return vec2( x.dot( transformedNormalView ), y.dot( transformedNormalView ) ).mul( 0.495 ).add( 0.5 ); // 0.495 to remove artifacts caused by undersized matcap disks + + } + +} + +const matcapUV = /*@__PURE__*/ nodeImmutable( MatcapUVNode ); + +const _defaultValues$3 = /*@__PURE__*/ new MeshMatcapMaterial(); + +class MeshMatcapNodeMaterial extends NodeMaterial { + + static get type() { + + return 'MeshMatcapNodeMaterial'; + + } + + constructor( parameters ) { + + super(); + + this.lights = false; + + this.isMeshMatcapNodeMaterial = true; + + this.setDefaultValues( _defaultValues$3 ); + + this.setValues( parameters ); + + } + + setupVariants( builder ) { + + const uv = matcapUV; + + let matcapColor; + + if ( builder.material.matcap ) { + + matcapColor = materialReference( 'matcap', 'texture' ).context( { getUV: () => uv } ); + + } else { + + matcapColor = vec3( mix( 0.2, 0.8, uv.y ) ); // default if matcap is missing + + } + + diffuseColor.rgb.mulAssign( matcapColor.rgb ); + + } + +} + +const _defaultValues$2 = /*@__PURE__*/ new PointsMaterial(); + +class PointsNodeMaterial extends NodeMaterial { + + static get type() { + + return 'PointsNodeMaterial'; + + } + + constructor( parameters ) { + + super(); + + this.isPointsNodeMaterial = true; + + this.lights = false; + this.transparent = true; + + this.sizeNode = null; + + this.setDefaultValues( _defaultValues$2 ); + + this.setValues( parameters ); + + } + + copy( source ) { + + this.sizeNode = source.sizeNode; + + return super.copy( source ); + + } + +} + +class RotateNode extends TempNode { + + static get type() { + + return 'RotateNode'; + + } + + constructor( positionNode, rotationNode ) { + + super(); + + this.positionNode = positionNode; + this.rotationNode = rotationNode; + + } + + getNodeType( builder ) { + + return this.positionNode.getNodeType( builder ); + + } + + setup( builder ) { + + const { rotationNode, positionNode } = this; + + const nodeType = this.getNodeType( builder ); + + if ( nodeType === 'vec2' ) { + + const cosAngle = rotationNode.cos(); + const sinAngle = rotationNode.sin(); + + const rotationMatrix = mat2( + cosAngle, sinAngle, + sinAngle.negate(), cosAngle + ); + + return rotationMatrix.mul( positionNode ); + + } else { + + const rotation = rotationNode; + const rotationXMatrix = mat4( vec4( 1.0, 0.0, 0.0, 0.0 ), vec4( 0.0, cos( rotation.x ), sin( rotation.x ).negate(), 0.0 ), vec4( 0.0, sin( rotation.x ), cos( rotation.x ), 0.0 ), vec4( 0.0, 0.0, 0.0, 1.0 ) ); + const rotationYMatrix = mat4( vec4( cos( rotation.y ), 0.0, sin( rotation.y ), 0.0 ), vec4( 0.0, 1.0, 0.0, 0.0 ), vec4( sin( rotation.y ).negate(), 0.0, cos( rotation.y ), 0.0 ), vec4( 0.0, 0.0, 0.0, 1.0 ) ); + const rotationZMatrix = mat4( vec4( cos( rotation.z ), sin( rotation.z ).negate(), 0.0, 0.0 ), vec4( sin( rotation.z ), cos( rotation.z ), 0.0, 0.0 ), vec4( 0.0, 0.0, 1.0, 0.0 ), vec4( 0.0, 0.0, 0.0, 1.0 ) ); + + return rotationXMatrix.mul( rotationYMatrix ).mul( rotationZMatrix ).mul( vec4( positionNode, 1.0 ) ).xyz; + + } + + } + +} + +const rotate = /*@__PURE__*/ nodeProxy( RotateNode ); + +const _defaultValues$1 = /*@__PURE__*/ new SpriteMaterial(); + +class SpriteNodeMaterial extends NodeMaterial { + + static get type() { + + return 'SpriteNodeMaterial'; + + } + + constructor( parameters ) { + + super(); + + this.isSpriteNodeMaterial = true; + + this.lights = false; + this._useSizeAttenuation = true; + + this.positionNode = null; + this.rotationNode = null; + this.scaleNode = null; + + this.setDefaultValues( _defaultValues$1 ); + + this.setValues( parameters ); + + } + + setupPosition( { object, camera, context } ) { + + const sizeAttenuation = this.sizeAttenuation; + + // < VERTEX STAGE > + + const { positionNode, rotationNode, scaleNode } = this; + + const vertex = positionLocal; + + let mvPosition = modelViewMatrix.mul( vec3( positionNode || 0 ) ); + + let scale = vec2( modelWorldMatrix[ 0 ].xyz.length(), modelWorldMatrix[ 1 ].xyz.length() ); + + if ( scaleNode !== null ) { + + scale = scale.mul( scaleNode ); + + } + + + if ( ! sizeAttenuation && camera.isPerspectiveCamera ) { + + scale = scale.mul( mvPosition.z.negate() ); + + } + + let alignedPosition = vertex.xy; + + if ( object.center && object.center.isVector2 === true ) { + + const center = reference$1( 'center', 'vec2' ); + + alignedPosition = alignedPosition.sub( center.sub( 0.5 ) ); + + } + + alignedPosition = alignedPosition.mul( scale ); + + const rotation = float( rotationNode || materialRotation ); + + const rotatedPosition = rotate( alignedPosition, rotation ); + + mvPosition = vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw ); + + const modelViewProjection = cameraProjectionMatrix.mul( mvPosition ); + + context.vertex = vertex; + + return modelViewProjection; + + } + + copy( source ) { + + this.positionNode = source.positionNode; + this.rotationNode = source.rotationNode; + this.scaleNode = source.scaleNode; + + return super.copy( source ); + + } + + get sizeAttenuation() { + + return this._useSizeAttenuation; + + } + + set sizeAttenuation( value ) { + + if ( this._useSizeAttenuation !== value ) { + + this._useSizeAttenuation = value; + this.needsUpdate = true; + + } + + } + +} + +class ShadowMaskModel extends LightingModel { + + constructor() { + + super(); + + this.shadowNode = float( 1 ).toVar( 'shadowMask' ); + + } + + direct( { shadowMask } ) { + + this.shadowNode.mulAssign( shadowMask ); + + } + + finish( context ) { + + diffuseColor.a.mulAssign( this.shadowNode.oneMinus() ); + + context.outgoingLight.rgb.assign( diffuseColor.rgb ); // TODO: Optimize LightsNode to avoid this assignment + + } + +} + +const _defaultValues = /*@__PURE__*/ new ShadowMaterial(); + +class ShadowNodeMaterial extends NodeMaterial { + + static get type() { + + return 'ShadowNodeMaterial'; + + } + + constructor( parameters ) { + + super(); + + this.isShadowNodeMaterial = true; + + this.lights = true; + + this.setDefaultValues( _defaultValues ); + + this.setValues( parameters ); + + } + + setupLightingModel( /*builder*/ ) { + + return new ShadowMaskModel(); + + } + +} + +const normal = Fn( ( { texture, uv } ) => { + + const epsilon = 0.0001; + + const ret = vec3().toVar(); + + If( uv.x.lessThan( epsilon ), () => { + + ret.assign( vec3( 1, 0, 0 ) ); + + } ).ElseIf( uv.y.lessThan( epsilon ), () => { + + ret.assign( vec3( 0, 1, 0 ) ); + + } ).ElseIf( uv.z.lessThan( epsilon ), () => { + + ret.assign( vec3( 0, 0, 1 ) ); + + } ).ElseIf( uv.x.greaterThan( 1 - epsilon ), () => { + + ret.assign( vec3( - 1, 0, 0 ) ); + + } ).ElseIf( uv.y.greaterThan( 1 - epsilon ), () => { + + ret.assign( vec3( 0, - 1, 0 ) ); + + } ).ElseIf( uv.z.greaterThan( 1 - epsilon ), () => { + + ret.assign( vec3( 0, 0, - 1 ) ); + + } ).Else( () => { + + const step = 0.01; + + const x = texture.uv( uv.add( vec3( - step, 0.0, 0.0 ) ) ).r.sub( texture.uv( uv.add( vec3( step, 0.0, 0.0 ) ) ).r ); + const y = texture.uv( uv.add( vec3( 0.0, - step, 0.0 ) ) ).r.sub( texture.uv( uv.add( vec3( 0.0, step, 0.0 ) ) ).r ); + const z = texture.uv( uv.add( vec3( 0.0, 0.0, - step ) ) ).r.sub( texture.uv( uv.add( vec3( 0.0, 0.0, step ) ) ).r ); + + ret.assign( vec3( x, y, z ) ); + + } ); + + return ret.normalize(); + +} ); + + +class Texture3DNode extends TextureNode { + + static get type() { + + return 'Texture3DNode'; + + } + + constructor( value, uvNode = null, levelNode = null ) { + + super( value, uvNode, levelNode ); + + this.isTexture3DNode = true; + + } + + getInputType( /*builder*/ ) { + + return 'texture3D'; + + } + + getDefaultUV() { + + return vec3( 0.5, 0.5, 0.5 ); + + } + + setUpdateMatrix( /*updateMatrix*/ ) { } // Ignore .updateMatrix for 3d TextureNode + + setupUV( builder, uvNode ) { + + return uvNode; + + } + + generateUV( builder, uvNode ) { + + return uvNode.build( builder, 'vec3' ); + + } + + normal( uvNode ) { + + return normal( { texture: this, uv: uvNode } ); + + } + +} + +const texture3D = /*@__PURE__*/ nodeProxy( Texture3DNode ); + +class VolumeNodeMaterial extends NodeMaterial { + + static get type() { + + return 'VolumeNodeMaterial'; + + } + + constructor( params = {} ) { + + super(); + + this.lights = false; + this.isVolumeNodeMaterial = true; + this.testNode = null; + + this.setValues( params ); + + } + + setup( builder ) { + + const map = texture3D( this.map, null, 0 ); + + const hitBox = Fn( ( { orig, dir } ) => { + + const box_min = vec3( - 0.5 ); + const box_max = vec3( 0.5 ); + + const inv_dir = dir.reciprocal(); + + const tmin_tmp = box_min.sub( orig ).mul( inv_dir ); + const tmax_tmp = box_max.sub( orig ).mul( inv_dir ); + + const tmin = min$1( tmin_tmp, tmax_tmp ); + const tmax = max$1( tmin_tmp, tmax_tmp ); + + const t0 = max$1( tmin.x, max$1( tmin.y, tmin.z ) ); + const t1 = min$1( tmax.x, min$1( tmax.y, tmax.z ) ); + + return vec2( t0, t1 ); + + } ); + + this.fragmentNode = Fn( () => { + + const vOrigin = varying( vec3( modelWorldMatrixInverse.mul( vec4( cameraPosition, 1.0 ) ) ) ); + const vDirection = varying( positionGeometry.sub( vOrigin ) ); + + const rayDir = vDirection.normalize(); + const bounds = vec2( hitBox( { orig: vOrigin, dir: rayDir } ) ).toVar(); + + bounds.x.greaterThan( bounds.y ).discard(); + + bounds.assign( vec2( max$1( bounds.x, 0.0 ), bounds.y ) ); + + const p = vec3( vOrigin.add( bounds.x.mul( rayDir ) ) ).toVar(); + const inc = vec3( rayDir.abs().reciprocal() ).toVar(); + const delta = float( min$1( inc.x, min$1( inc.y, inc.z ) ) ).toVar( 'delta' ); // used 'delta' name in loop + + delta.divAssign( materialReference( 'steps', 'float' ) ); + + const ac = vec4( materialReference( 'base', 'color' ), 0.0 ).toVar(); + + Loop( { type: 'float', start: bounds.x, end: bounds.y, update: '+= delta' }, () => { + + const d = property( 'float', 'd' ).assign( map.uv( p.add( 0.5 ) ).r ); + + if ( this.testNode !== null ) { + + this.testNode( { map: map, mapValue: d, probe: p, finalColor: ac } ).append(); + + } else { + + // default to show surface of mesh + ac.a.assign( 1 ); + Break(); + + } + + p.addAssign( rayDir.mul( delta ) ); + + } ); + + ac.a.equal( 0 ).discard(); + + return vec4( ac ); + + } )(); + + super.setup( builder ); + + } + +} + +class Animation { + + constructor( nodes, info ) { + + this.nodes = nodes; + this.info = info; + + this.animationLoop = null; + this.requestId = null; + + this._init(); + + } + + _init() { + + const update = ( time, frame ) => { + + this.requestId = self.requestAnimationFrame( update ); + + if ( this.info.autoReset === true ) this.info.reset(); + + this.nodes.nodeFrame.update(); + + this.info.frame = this.nodes.nodeFrame.frameId; + + if ( this.animationLoop !== null ) this.animationLoop( time, frame ); + + }; + + update(); + + } + + dispose() { + + self.cancelAnimationFrame( this.requestId ); + this.requestId = null; + + } + + setAnimationLoop( callback ) { + + this.animationLoop = callback; + + } + +} + +class ChainMap { + + constructor() { + + this.weakMap = new WeakMap(); + + } + + get( keys ) { + + let map = this.weakMap; + + for ( let i = 0; i < keys.length; i ++ ) { + + map = map.get( keys[ i ] ); + + if ( map === undefined ) return undefined; + + } + + return map.get( keys[ keys.length - 1 ] ); + + } + + set( keys, value ) { + + let map = this.weakMap; + + for ( let i = 0; i < keys.length; i ++ ) { + + const key = keys[ i ]; + + if ( map.has( key ) === false ) map.set( key, new WeakMap() ); + + map = map.get( key ); + + } + + return map.set( keys[ keys.length - 1 ], value ); + + } + + delete( keys ) { + + let map = this.weakMap; + + for ( let i = 0; i < keys.length; i ++ ) { + + map = map.get( keys[ i ] ); + + if ( map === undefined ) return false; + + } + + return map.delete( keys[ keys.length - 1 ] ); + + } + +} + +const _plane = /*@__PURE__*/ new Plane(); + +class ClippingContext { + + constructor() { + + this.version = 0; + + this.globalClippingCount = 0; + + this.localClippingCount = 0; + this.localClippingEnabled = false; + this.localClipIntersection = false; + + this.planes = []; + + this.parentVersion = 0; + this.viewNormalMatrix = new Matrix3(); + this.cacheKey = 0; + + } + + projectPlanes( source, offset ) { + + const l = source.length; + const planes = this.planes; + + for ( let i = 0; i < l; i ++ ) { + + _plane.copy( source[ i ] ).applyMatrix4( this.viewMatrix, this.viewNormalMatrix ); + + const v = planes[ offset + i ]; + const normal = _plane.normal; + + v.x = - normal.x; + v.y = - normal.y; + v.z = - normal.z; + v.w = _plane.constant; + + } + + } + + updateGlobal( renderer, camera ) { + + const rendererClippingPlanes = renderer.clippingPlanes; + this.viewMatrix = camera.matrixWorldInverse; + + this.viewNormalMatrix.getNormalMatrix( this.viewMatrix ); + + let update = false; + + if ( Array.isArray( rendererClippingPlanes ) && rendererClippingPlanes.length !== 0 ) { + + const l = rendererClippingPlanes.length; + + if ( l !== this.globalClippingCount ) { + + const planes = []; + + for ( let i = 0; i < l; i ++ ) { + + planes.push( new Vector4() ); + + } + + this.globalClippingCount = l; + this.planes = planes; + + update = true; + + } + + this.projectPlanes( rendererClippingPlanes, 0 ); + + } else if ( this.globalClippingCount !== 0 ) { + + this.globalClippingCount = 0; + this.planes = []; + update = true; + + } + + if ( renderer.localClippingEnabled !== this.localClippingEnabled ) { + + this.localClippingEnabled = renderer.localClippingEnabled; + update = true; + + } + + if ( update ) { + + this.version ++; + this.cacheKey = hash$1( this.globalClippingCount, this.localClippingEnabled === true ? 1 : 0 ); + + } + + } + + update( parent, material ) { + + let update = false; + + if ( this !== parent && parent.version !== this.parentVersion ) { + + this.globalClippingCount = material.isShadowNodeMaterial ? 0 : parent.globalClippingCount; + this.localClippingEnabled = parent.localClippingEnabled; + this.planes = Array.from( parent.planes ); + this.parentVersion = parent.version; + this.viewMatrix = parent.viewMatrix; + this.viewNormalMatrix = parent.viewNormalMatrix; + + update = true; + + } + + if ( this.localClippingEnabled ) { + + const localClippingPlanes = material.clippingPlanes; + + if ( ( Array.isArray( localClippingPlanes ) && localClippingPlanes.length !== 0 ) ) { + + const l = localClippingPlanes.length; + const planes = this.planes; + const offset = this.globalClippingCount; + + if ( update || l !== this.localClippingCount ) { + + planes.length = offset + l; + + for ( let i = 0; i < l; i ++ ) { + + planes[ offset + i ] = new Vector4(); + + } + + this.localClippingCount = l; + update = true; + + } + + this.projectPlanes( localClippingPlanes, offset ); + + + } else if ( this.localClippingCount !== 0 ) { + + this.localClippingCount = 0; + update = true; + + } + + if ( this.localClipIntersection !== material.clipIntersection ) { + + this.localClipIntersection = material.clipIntersection; + update = true; + + } + + } + + if ( update ) { + + this.version += parent.version; + this.cacheKey = hash$1( parent.cacheKey, this.localClippingCount, this.localClipIntersection === true ? 1 : 0 ); + + } + + } + +} + +let _id$7 = 0; + +function getKeys( obj ) { + + const keys = Object.keys( obj ); + + let proto = Object.getPrototypeOf( obj ); + + while ( proto ) { + + const descriptors = Object.getOwnPropertyDescriptors( proto ); + + for ( const key in descriptors ) { + + if ( descriptors[ key ] !== undefined ) { + + const descriptor = descriptors[ key ]; + + if ( descriptor && typeof descriptor.get === 'function' ) { + + keys.push( key ); + + } + + } + + } + + proto = Object.getPrototypeOf( proto ); + + } + + return keys; + +} + +class RenderObject { + + constructor( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext ) { + + this._nodes = nodes; + this._geometries = geometries; + + this.id = _id$7 ++; + + this.renderer = renderer; + this.object = object; + this.material = material; + this.scene = scene; + this.camera = camera; + this.lightsNode = lightsNode; + this.context = renderContext; + + this.geometry = object.geometry; + this.version = material.version; + + this.drawRange = null; + + this.attributes = null; + this.pipeline = null; + this.vertexBuffers = null; + this.drawParams = null; + + this.bundle = null; + + this.updateClipping( renderContext.clippingContext ); + + this.clippingContextVersion = this.clippingContext.version; + + this.initialNodesCacheKey = this.getDynamicCacheKey(); + this.initialCacheKey = this.getCacheKey(); + + this._nodeBuilderState = null; + this._bindings = null; + this._monitor = null; + + this.onDispose = null; + + this.isRenderObject = true; + + this.onMaterialDispose = () => { + + this.dispose(); + + }; + + this.material.addEventListener( 'dispose', this.onMaterialDispose ); + + } + + updateClipping( parent ) { + + const material = this.material; + + let clippingContext = this.clippingContext; + + if ( Array.isArray( material.clippingPlanes ) ) { + + if ( clippingContext === parent || ! clippingContext ) { + + clippingContext = new ClippingContext(); + this.clippingContext = clippingContext; + + } + + clippingContext.update( parent, material ); + + } else if ( this.clippingContext !== parent ) { + + this.clippingContext = parent; + + } + + } + + get clippingNeedsUpdate() { + + if ( this.clippingContext.version === this.clippingContextVersion ) return false; + + this.clippingContextVersion = this.clippingContext.version; + + return true; + + } + + getNodeBuilderState() { + + return this._nodeBuilderState || ( this._nodeBuilderState = this._nodes.getForRender( this ) ); + + } + + getMonitor() { + + return this._monitor || ( this._monitor = this.getNodeBuilderState().monitor ); + + } + + getBindings() { + + return this._bindings || ( this._bindings = this.getNodeBuilderState().createBindings() ); + + } + + getIndex() { + + return this._geometries.getIndex( this ); + + } + + getChainArray() { + + return [ this.object, this.material, this.context, this.lightsNode ]; + + } + + getAttributes() { + + if ( this.attributes !== null ) return this.attributes; + + const nodeAttributes = this.getNodeBuilderState().nodeAttributes; + const geometry = this.geometry; + + const attributes = []; + const vertexBuffers = new Set(); + + for ( const nodeAttribute of nodeAttributes ) { + + const attribute = nodeAttribute.node && nodeAttribute.node.attribute ? nodeAttribute.node.attribute : geometry.getAttribute( nodeAttribute.name ); + + if ( attribute === undefined ) continue; + + attributes.push( attribute ); + + const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute; + vertexBuffers.add( bufferAttribute ); + + } + + this.attributes = attributes; + this.vertexBuffers = Array.from( vertexBuffers.values() ); + + return attributes; + + } + + getVertexBuffers() { + + if ( this.vertexBuffers === null ) this.getAttributes(); + + return this.vertexBuffers; + + } + + getDrawParameters() { + + const { object, material, geometry, group, drawRange } = this; + + const drawParams = this.drawParams || ( this.drawParams = { + vertexCount: 0, + firstVertex: 0, + instanceCount: 0, + firstInstance: 0 + } ); + + const index = this.getIndex(); + const hasIndex = ( index !== null ); + const instanceCount = geometry.isInstancedBufferGeometry ? geometry.instanceCount : ( object.count > 1 ? object.count : 1 ); + + if ( instanceCount === 0 ) return null; + + drawParams.instanceCount = instanceCount; + + if ( object.isBatchedMesh === true ) return drawParams; + + let rangeFactor = 1; + + if ( material.wireframe === true && ! object.isPoints && ! object.isLineSegments && ! object.isLine && ! object.isLineLoop ) { + + rangeFactor = 2; + + } + + let firstVertex = drawRange.start * rangeFactor; + let lastVertex = ( drawRange.start + drawRange.count ) * rangeFactor; + + if ( group !== null ) { + + firstVertex = Math.max( firstVertex, group.start * rangeFactor ); + lastVertex = Math.min( lastVertex, ( group.start + group.count ) * rangeFactor ); + + } + + const itemCount = hasIndex === true ? index.count : geometry.attributes.position.count; + + firstVertex = Math.max( firstVertex, 0 ); + lastVertex = Math.min( lastVertex, itemCount ); + + const count = lastVertex - firstVertex; + + if ( count < 0 || count === Infinity ) return null; + + drawParams.vertexCount = count; + drawParams.firstVertex = firstVertex; + + return drawParams; + + } + + getGeometryCacheKey() { + + const { geometry } = this; + + let cacheKey = ''; + + for ( const name of Object.keys( geometry.attributes ).sort() ) { + + const attribute = geometry.attributes[ name ]; + + cacheKey += name + ','; + + if ( attribute.data ) cacheKey += attribute.data.stride + ','; + if ( attribute.offset ) cacheKey += attribute.offset + ','; + if ( attribute.itemSize ) cacheKey += attribute.itemSize + ','; + if ( attribute.normalized ) cacheKey += 'n,'; + + } + + if ( geometry.index ) { + + cacheKey += 'index,'; + + } + + return cacheKey; + + } + + getMaterialCacheKey() { + + const { object, material } = this; + + let cacheKey = material.customProgramCacheKey(); + + for ( const property of getKeys( material ) ) { + + if ( /^(is[A-Z]|_)|^(visible|version|uuid|name|opacity|userData)$/.test( property ) ) continue; + + const value = material[ property ]; + + let valueKey; + + if ( value !== null ) { + + // some material values require a formatting + + const type = typeof value; + + if ( type === 'number' ) { + + valueKey = value !== 0 ? '1' : '0'; // Convert to on/off, important for clearcoat, transmission, etc + + } else if ( type === 'object' ) { + + valueKey = '{'; + + if ( value.isTexture ) { + + valueKey += value.mapping; + + } + + valueKey += '}'; + + } else { + + valueKey = String( value ); + + } + + } else { + + valueKey = String( value ); + + } + + cacheKey += /*property + ':' +*/ valueKey + ','; + + } + + cacheKey += this.clippingContext.cacheKey + ','; + + if ( object.geometry ) { + + cacheKey += this.getGeometryCacheKey(); + + } + + if ( object.skeleton ) { + + cacheKey += object.skeleton.bones.length + ','; + + } + + if ( object.morphTargetInfluences ) { + + cacheKey += object.morphTargetInfluences.length + ','; + + } + + if ( object.isBatchedMesh ) { + + cacheKey += object._matricesTexture.uuid + ','; + + if ( object._colorsTexture !== null ) { + + cacheKey += object._colorsTexture.uuid + ','; + + } + + } + + if ( object.count > 1 ) { + + // TODO: https://github.com/mrdoob/three.js/pull/29066#issuecomment-2269400850 + + cacheKey += object.uuid + ','; + + } + + return hashString( cacheKey ); + + } + + get needsUpdate() { + + return /*this.object.static !== true &&*/ ( this.initialNodesCacheKey !== this.getDynamicCacheKey() || this.clippingNeedsUpdate ); + + } + + getDynamicCacheKey() { + + // Environment Nodes Cache Key + + let cacheKey = this._nodes.getCacheKey( this.scene, this.lightsNode ); + + if ( this.object.receiveShadow ) { + + cacheKey += 1; + + } + + return cacheKey; + + } + + getCacheKey() { + + return this.getMaterialCacheKey() + this.getDynamicCacheKey(); + + } + + dispose() { + + this.material.removeEventListener( 'dispose', this.onMaterialDispose ); + + this.onDispose(); + + } + +} + +const chainArray = []; + +class RenderObjects { + + constructor( renderer, nodes, geometries, pipelines, bindings, info ) { + + this.renderer = renderer; + this.nodes = nodes; + this.geometries = geometries; + this.pipelines = pipelines; + this.bindings = bindings; + this.info = info; + + this.chainMaps = {}; + + } + + get( object, material, scene, camera, lightsNode, renderContext, passId ) { + + const chainMap = this.getChainMap( passId ); + + // reuse chainArray + chainArray[ 0 ] = object; + chainArray[ 1 ] = material; + chainArray[ 2 ] = renderContext; + chainArray[ 3 ] = lightsNode; + + let renderObject = chainMap.get( chainArray ); + + if ( renderObject === undefined ) { + + renderObject = this.createRenderObject( this.nodes, this.geometries, this.renderer, object, material, scene, camera, lightsNode, renderContext, passId ); + + chainMap.set( chainArray, renderObject ); + + } else { + + renderObject.updateClipping( renderContext.clippingContext ); + + if ( renderObject.version !== material.version || renderObject.needsUpdate ) { + + if ( renderObject.initialCacheKey !== renderObject.getCacheKey() ) { + + renderObject.dispose(); + + renderObject = this.get( object, material, scene, camera, lightsNode, renderContext, passId ); + + } else { + + renderObject.version = material.version; + + } + + } + + } + + return renderObject; + + } + + getChainMap( passId = 'default' ) { + + return this.chainMaps[ passId ] || ( this.chainMaps[ passId ] = new ChainMap() ); + + } + + dispose() { + + this.chainMaps = {}; + + } + + createRenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, passId ) { + + const chainMap = this.getChainMap( passId ); + + const renderObject = new RenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext ); + + renderObject.onDispose = () => { + + this.pipelines.delete( renderObject ); + this.bindings.delete( renderObject ); + this.nodes.delete( renderObject ); + + chainMap.delete( renderObject.getChainArray() ); + + }; + + return renderObject; + + } + + +} + +class DataMap { + + constructor() { + + this.data = new WeakMap(); + + } + + get( object ) { + + let map = this.data.get( object ); + + if ( map === undefined ) { + + map = {}; + this.data.set( object, map ); + + } + + return map; + + } + + delete( object ) { + + let map; + + if ( this.data.has( object ) ) { + + map = this.data.get( object ); + + this.data.delete( object ); + + } + + return map; + + } + + has( object ) { + + return this.data.has( object ); + + } + + dispose() { + + this.data = new WeakMap(); + + } + +} + +const AttributeType = { + VERTEX: 1, + INDEX: 2, + STORAGE: 4 +}; + +// size of a chunk in bytes (STD140 layout) + +const GPU_CHUNK_BYTES = 16; + +// @TODO: Move to src/constants.js + +const BlendColorFactor = 211; +const OneMinusBlendColorFactor = 212; + +class Attributes extends DataMap { + + constructor( backend ) { + + super(); + + this.backend = backend; + + } + + delete( attribute ) { + + const attributeData = super.delete( attribute ); + + if ( attributeData !== undefined ) { + + this.backend.destroyAttribute( attribute ); + + } + + return attributeData; + + } + + update( attribute, type ) { + + const data = this.get( attribute ); + + if ( data.version === undefined ) { + + if ( type === AttributeType.VERTEX ) { + + this.backend.createAttribute( attribute ); + + } else if ( type === AttributeType.INDEX ) { + + this.backend.createIndexAttribute( attribute ); + + } else if ( type === AttributeType.STORAGE ) { + + this.backend.createStorageAttribute( attribute ); + + } + + data.version = this._getBufferAttribute( attribute ).version; + + } else { + + const bufferAttribute = this._getBufferAttribute( attribute ); + + if ( data.version < bufferAttribute.version || bufferAttribute.usage === DynamicDrawUsage ) { + + this.backend.updateAttribute( attribute ); + + data.version = bufferAttribute.version; + + } + + } + + } + + _getBufferAttribute( attribute ) { + + if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; + + return attribute; + + } + +} + +function arrayNeedsUint32( array ) { + + // assumes larger values usually on last + + for ( let i = array.length - 1; i >= 0; -- i ) { + + if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 + + } + + return false; + +} + +function getWireframeVersion( geometry ) { + + return ( geometry.index !== null ) ? geometry.index.version : geometry.attributes.position.version; + +} + +function getWireframeIndex( geometry ) { + + const indices = []; + + const geometryIndex = geometry.index; + const geometryPosition = geometry.attributes.position; + + if ( geometryIndex !== null ) { + + const array = geometryIndex.array; + + for ( let i = 0, l = array.length; i < l; i += 3 ) { + + const a = array[ i + 0 ]; + const b = array[ i + 1 ]; + const c = array[ i + 2 ]; + + indices.push( a, b, b, c, c, a ); + + } + + } else { + + const array = geometryPosition.array; + + for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { + + const a = i + 0; + const b = i + 1; + const c = i + 2; + + indices.push( a, b, b, c, c, a ); + + } + + } + + const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); + attribute.version = getWireframeVersion( geometry ); + + return attribute; + +} + +class Geometries extends DataMap { + + constructor( attributes, info ) { + + super(); + + this.attributes = attributes; + this.info = info; + + this.wireframes = new WeakMap(); + + this.attributeCall = new WeakMap(); + + } + + has( renderObject ) { + + const geometry = renderObject.geometry; + + return super.has( geometry ) && this.get( geometry ).initialized === true; + + } + + updateForRender( renderObject ) { + + if ( this.has( renderObject ) === false ) this.initGeometry( renderObject ); + + this.updateAttributes( renderObject ); + + } + + initGeometry( renderObject ) { + + const geometry = renderObject.geometry; + const geometryData = this.get( geometry ); + + geometryData.initialized = true; + + this.info.memory.geometries ++; + + const onDispose = () => { + + this.info.memory.geometries --; + + const index = geometry.index; + const geometryAttributes = renderObject.getAttributes(); + + if ( index !== null ) { + + this.attributes.delete( index ); + + } + + for ( const geometryAttribute of geometryAttributes ) { + + this.attributes.delete( geometryAttribute ); + + } + + const wireframeAttribute = this.wireframes.get( geometry ); + + if ( wireframeAttribute !== undefined ) { + + this.attributes.delete( wireframeAttribute ); + + } + + geometry.removeEventListener( 'dispose', onDispose ); + + }; + + geometry.addEventListener( 'dispose', onDispose ); + + } + + updateAttributes( renderObject ) { + + const attributes = renderObject.getAttributes(); + + for ( const attribute of attributes ) { + + if ( attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute ) { + + this.updateAttribute( attribute, AttributeType.STORAGE ); + + } else { + + this.updateAttribute( attribute, AttributeType.VERTEX ); + + } + + } + + const index = this.getIndex( renderObject ); + + if ( index !== null ) { + + this.updateAttribute( index, AttributeType.INDEX ); + + } + + } + + updateAttribute( attribute, type ) { + + const callId = this.info.render.calls; + + if ( ! attribute.isInterleavedBufferAttribute ) { + + if ( this.attributeCall.get( attribute ) !== callId ) { + + this.attributes.update( attribute, type ); + + this.attributeCall.set( attribute, callId ); + + } + + } else { + + if ( this.attributeCall.get( attribute ) === undefined ) { + + this.attributes.update( attribute, type ); + + this.attributeCall.set( attribute, callId ); + + } else if ( this.attributeCall.get( attribute.data ) !== callId ) { + + this.attributes.update( attribute, type ); + + this.attributeCall.set( attribute.data, callId ); + + this.attributeCall.set( attribute, callId ); + + } + + } + + } + + getIndex( renderObject ) { + + const { geometry, material } = renderObject; + + let index = geometry.index; + + if ( material.wireframe === true ) { + + const wireframes = this.wireframes; + + let wireframeAttribute = wireframes.get( geometry ); + + if ( wireframeAttribute === undefined ) { + + wireframeAttribute = getWireframeIndex( geometry ); + + wireframes.set( geometry, wireframeAttribute ); + + } else if ( wireframeAttribute.version !== getWireframeVersion( geometry ) ) { + + this.attributes.delete( wireframeAttribute ); + + wireframeAttribute = getWireframeIndex( geometry ); + + wireframes.set( geometry, wireframeAttribute ); + + } + + index = wireframeAttribute; + + } + + return index; + + } + +} + +class Info { + + constructor() { + + this.autoReset = true; + + this.frame = 0; + this.calls = 0; + + this.render = { + calls: 0, + frameCalls: 0, + drawCalls: 0, + triangles: 0, + points: 0, + lines: 0, + timestamp: 0, + previousFrameCalls: 0, + timestampCalls: 0 + }; + + this.compute = { + calls: 0, + frameCalls: 0, + timestamp: 0, + previousFrameCalls: 0, + timestampCalls: 0 + }; + + this.memory = { + geometries: 0, + textures: 0 + }; + + } + + update( object, count, instanceCount ) { + + this.render.drawCalls ++; + + if ( object.isMesh || object.isSprite ) { + + this.render.triangles += instanceCount * ( count / 3 ); + + } else if ( object.isPoints ) { + + this.render.points += instanceCount * count; + + } else if ( object.isLineSegments ) { + + this.render.lines += instanceCount * ( count / 2 ); + + } else if ( object.isLine ) { + + this.render.lines += instanceCount * ( count - 1 ); + + } else { + + console.error( 'THREE.WebGPUInfo: Unknown object type.' ); + + } + + } + + updateTimestamp( type, time ) { + + if ( this[ type ].timestampCalls === 0 ) { + + this[ type ].timestamp = 0; + + } + + + this[ type ].timestamp += time; + + this[ type ].timestampCalls ++; + + + if ( this[ type ].timestampCalls >= this[ type ].previousFrameCalls ) { + + this[ type ].timestampCalls = 0; + + } + + + } + + reset() { + + const previousRenderFrameCalls = this.render.frameCalls; + this.render.previousFrameCalls = previousRenderFrameCalls; + + const previousComputeFrameCalls = this.compute.frameCalls; + this.compute.previousFrameCalls = previousComputeFrameCalls; + + + this.render.drawCalls = 0; + this.render.frameCalls = 0; + this.compute.frameCalls = 0; + + this.render.triangles = 0; + this.render.points = 0; + this.render.lines = 0; + + + } + + dispose() { + + this.reset(); + + this.calls = 0; + + this.render.calls = 0; + this.compute.calls = 0; + + this.render.timestamp = 0; + this.compute.timestamp = 0; + this.memory.geometries = 0; + this.memory.textures = 0; + + } + +} + +class Pipeline { + + constructor( cacheKey ) { + + this.cacheKey = cacheKey; + + this.usedTimes = 0; + + } + +} + +class RenderPipeline extends Pipeline { + + constructor( cacheKey, vertexProgram, fragmentProgram ) { + + super( cacheKey ); + + this.vertexProgram = vertexProgram; + this.fragmentProgram = fragmentProgram; + + } + +} + +class ComputePipeline extends Pipeline { + + constructor( cacheKey, computeProgram ) { + + super( cacheKey ); + + this.computeProgram = computeProgram; + + this.isComputePipeline = true; + + } + +} + +let _id$6 = 0; + +class ProgrammableStage { + + constructor( code, type, transforms = null, attributes = null ) { + + this.id = _id$6 ++; + + this.code = code; + this.stage = type; + this.transforms = transforms; + this.attributes = attributes; + + this.usedTimes = 0; + + } + +} + +class Pipelines extends DataMap { + + constructor( backend, nodes ) { + + super(); + + this.backend = backend; + this.nodes = nodes; + + this.bindings = null; // set by the bindings + + this.caches = new Map(); + this.programs = { + vertex: new Map(), + fragment: new Map(), + compute: new Map() + }; + + } + + getForCompute( computeNode, bindings ) { + + const { backend } = this; + + const data = this.get( computeNode ); + + if ( this._needsComputeUpdate( computeNode ) ) { + + const previousPipeline = data.pipeline; + + if ( previousPipeline ) { + + previousPipeline.usedTimes --; + previousPipeline.computeProgram.usedTimes --; + + } + + // get shader + + const nodeBuilderState = this.nodes.getForCompute( computeNode ); + + // programmable stage + + let stageCompute = this.programs.compute.get( nodeBuilderState.computeShader ); + + if ( stageCompute === undefined ) { + + if ( previousPipeline && previousPipeline.computeProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.computeProgram ); + + stageCompute = new ProgrammableStage( nodeBuilderState.computeShader, 'compute', nodeBuilderState.transforms, nodeBuilderState.nodeAttributes ); + this.programs.compute.set( nodeBuilderState.computeShader, stageCompute ); + + backend.createProgram( stageCompute ); + + } + + // determine compute pipeline + + const cacheKey = this._getComputeCacheKey( computeNode, stageCompute ); + + let pipeline = this.caches.get( cacheKey ); + + if ( pipeline === undefined ) { + + if ( previousPipeline && previousPipeline.usedTimes === 0 ) this._releasePipeline( previousPipeline ); + + pipeline = this._getComputePipeline( computeNode, stageCompute, cacheKey, bindings ); + + } + + // keep track of all used times + + pipeline.usedTimes ++; + stageCompute.usedTimes ++; + + // + + data.version = computeNode.version; + data.pipeline = pipeline; + + } + + return data.pipeline; + + } + + getForRender( renderObject, promises = null ) { + + const { backend } = this; + + const data = this.get( renderObject ); + + if ( this._needsRenderUpdate( renderObject ) ) { + + const previousPipeline = data.pipeline; + + if ( previousPipeline ) { + + previousPipeline.usedTimes --; + previousPipeline.vertexProgram.usedTimes --; + previousPipeline.fragmentProgram.usedTimes --; + + } + + // get shader + + const nodeBuilderState = renderObject.getNodeBuilderState(); + + // programmable stages + + let stageVertex = this.programs.vertex.get( nodeBuilderState.vertexShader ); + + if ( stageVertex === undefined ) { + + if ( previousPipeline && previousPipeline.vertexProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.vertexProgram ); + + stageVertex = new ProgrammableStage( nodeBuilderState.vertexShader, 'vertex' ); + this.programs.vertex.set( nodeBuilderState.vertexShader, stageVertex ); + + backend.createProgram( stageVertex ); + + } + + let stageFragment = this.programs.fragment.get( nodeBuilderState.fragmentShader ); + + if ( stageFragment === undefined ) { + + if ( previousPipeline && previousPipeline.fragmentProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.fragmentProgram ); + + stageFragment = new ProgrammableStage( nodeBuilderState.fragmentShader, 'fragment' ); + this.programs.fragment.set( nodeBuilderState.fragmentShader, stageFragment ); + + backend.createProgram( stageFragment ); + + } + + // determine render pipeline + + const cacheKey = this._getRenderCacheKey( renderObject, stageVertex, stageFragment ); + + let pipeline = this.caches.get( cacheKey ); + + if ( pipeline === undefined ) { + + if ( previousPipeline && previousPipeline.usedTimes === 0 ) this._releasePipeline( previousPipeline ); + + pipeline = this._getRenderPipeline( renderObject, stageVertex, stageFragment, cacheKey, promises ); + + } else { + + renderObject.pipeline = pipeline; + + } + + // keep track of all used times + + pipeline.usedTimes ++; + stageVertex.usedTimes ++; + stageFragment.usedTimes ++; + + // + + data.pipeline = pipeline; + + } + + return data.pipeline; + + } + + delete( object ) { + + const pipeline = this.get( object ).pipeline; + + if ( pipeline ) { + + // pipeline + + pipeline.usedTimes --; + + if ( pipeline.usedTimes === 0 ) this._releasePipeline( pipeline ); + + // programs + + if ( pipeline.isComputePipeline ) { + + pipeline.computeProgram.usedTimes --; + + if ( pipeline.computeProgram.usedTimes === 0 ) this._releaseProgram( pipeline.computeProgram ); + + } else { + + pipeline.fragmentProgram.usedTimes --; + pipeline.vertexProgram.usedTimes --; + + if ( pipeline.vertexProgram.usedTimes === 0 ) this._releaseProgram( pipeline.vertexProgram ); + if ( pipeline.fragmentProgram.usedTimes === 0 ) this._releaseProgram( pipeline.fragmentProgram ); + + } + + } + + return super.delete( object ); + + } + + dispose() { + + super.dispose(); + + this.caches = new Map(); + this.programs = { + vertex: new Map(), + fragment: new Map(), + compute: new Map() + }; + + } + + updateForRender( renderObject ) { + + this.getForRender( renderObject ); + + } + + _getComputePipeline( computeNode, stageCompute, cacheKey, bindings ) { + + // check for existing pipeline + + cacheKey = cacheKey || this._getComputeCacheKey( computeNode, stageCompute ); + + let pipeline = this.caches.get( cacheKey ); + + if ( pipeline === undefined ) { + + pipeline = new ComputePipeline( cacheKey, stageCompute ); + + this.caches.set( cacheKey, pipeline ); + + this.backend.createComputePipeline( pipeline, bindings ); + + } + + return pipeline; + + } + + _getRenderPipeline( renderObject, stageVertex, stageFragment, cacheKey, promises ) { + + // check for existing pipeline + + cacheKey = cacheKey || this._getRenderCacheKey( renderObject, stageVertex, stageFragment ); + + let pipeline = this.caches.get( cacheKey ); + + if ( pipeline === undefined ) { + + pipeline = new RenderPipeline( cacheKey, stageVertex, stageFragment ); + + this.caches.set( cacheKey, pipeline ); + + renderObject.pipeline = pipeline; + + this.backend.createRenderPipeline( renderObject, promises ); + + } + + return pipeline; + + } + + _getComputeCacheKey( computeNode, stageCompute ) { + + return computeNode.id + ',' + stageCompute.id; + + } + + _getRenderCacheKey( renderObject, stageVertex, stageFragment ) { + + return stageVertex.id + ',' + stageFragment.id + ',' + this.backend.getRenderCacheKey( renderObject ); + + } + + _releasePipeline( pipeline ) { + + this.caches.delete( pipeline.cacheKey ); + + } + + _releaseProgram( program ) { + + const code = program.code; + const stage = program.stage; + + this.programs[ stage ].delete( code ); + + } + + _needsComputeUpdate( computeNode ) { + + const data = this.get( computeNode ); + + return data.pipeline === undefined || data.version !== computeNode.version; + + } + + _needsRenderUpdate( renderObject ) { + + const data = this.get( renderObject ); + + return data.pipeline === undefined || this.backend.needsRenderUpdate( renderObject ); + + } + +} + +class Bindings extends DataMap { + + constructor( backend, nodes, textures, attributes, pipelines, info ) { + + super(); + + this.backend = backend; + this.textures = textures; + this.pipelines = pipelines; + this.attributes = attributes; + this.nodes = nodes; + this.info = info; + + this.pipelines.bindings = this; // assign bindings to pipelines + + } + + getForRender( renderObject ) { + + const bindings = renderObject.getBindings(); + + for ( const bindGroup of bindings ) { + + const groupData = this.get( bindGroup ); + + if ( groupData.bindGroup === undefined ) { + + // each object defines an array of bindings (ubos, textures, samplers etc.) + + this._init( bindGroup ); + + this.backend.createBindings( bindGroup, bindings ); + + groupData.bindGroup = bindGroup; + + } + + } + + return bindings; + + } + + getForCompute( computeNode ) { + + const bindings = this.nodes.getForCompute( computeNode ).bindings; + + for ( const bindGroup of bindings ) { + + const groupData = this.get( bindGroup ); + + if ( groupData.bindGroup === undefined ) { + + this._init( bindGroup ); + + this.backend.createBindings( bindGroup, bindings ); + + groupData.bindGroup = bindGroup; + + } + + } + + return bindings; + + } + + updateForCompute( computeNode ) { + + this._updateBindings( this.getForCompute( computeNode ) ); + + } + + updateForRender( renderObject ) { + + this._updateBindings( this.getForRender( renderObject ) ); + + } + + _updateBindings( bindings ) { + + for ( const bindGroup of bindings ) { + + this._update( bindGroup, bindings ); + + } + + } + + _init( bindGroup ) { + + for ( const binding of bindGroup.bindings ) { + + if ( binding.isSampledTexture ) { + + this.textures.updateTexture( binding.texture ); + + } else if ( binding.isStorageBuffer ) { + + const attribute = binding.attribute; + + this.attributes.update( attribute, AttributeType.STORAGE ); + + } + + } + + } + + _update( bindGroup, bindings ) { + + const { backend } = this; + + let needsBindingsUpdate = false; + + // iterate over all bindings and check if buffer updates or a new binding group is required + + for ( const binding of bindGroup.bindings ) { + + if ( binding.isNodeUniformsGroup ) { + + const updated = this.nodes.updateGroup( binding ); + + if ( ! updated ) continue; + + } + + if ( binding.isUniformBuffer ) { + + const updated = binding.update(); + + if ( updated ) { + + backend.updateBinding( binding ); + + } + + } else if ( binding.isSampler ) { + + binding.update(); + + } else if ( binding.isSampledTexture ) { + + if ( binding.needsBindingsUpdate( this.textures.get( binding.texture ).generation ) ) needsBindingsUpdate = true; + + const updated = binding.update(); + + const texture = binding.texture; + + if ( updated ) { + + this.textures.updateTexture( texture ); + + } + + const textureData = backend.get( texture ); + + if ( backend.isWebGPUBackend === true && textureData.texture === undefined && textureData.externalTexture === undefined ) { + + // TODO: Remove this once we found why updated === false isn't bound to a texture in the WebGPU backend + console.error( 'Bindings._update: binding should be available:', binding, updated, texture, binding.textureNode.value, needsBindingsUpdate ); + + this.textures.updateTexture( texture ); + needsBindingsUpdate = true; + + } + + if ( texture.isStorageTexture === true ) { + + const textureData = this.get( texture ); + + if ( binding.store === true ) { + + textureData.needsMipmap = true; + + } else if ( texture.generateMipmaps === true && this.textures.needsMipmaps( texture ) && textureData.needsMipmap === true ) { + + this.backend.generateMipmaps( texture ); + + textureData.needsMipmap = false; + + } + + } + + } + + } + + if ( needsBindingsUpdate === true ) { + + this.backend.updateBindings( bindGroup, bindings ); + + } + + } + +} + +class NodeAttribute { + + constructor( name, type, node = null ) { + + this.isNodeAttribute = true; + + this.name = name; + this.type = type; + this.node = node; + + } + +} + +class NodeUniform { + + constructor( name, type, node ) { + + this.isNodeUniform = true; + + this.name = name; + this.type = type; + this.node = node.getSelf(); + + } + + get value() { + + return this.node.value; + + } + + set value( val ) { + + this.node.value = val; + + } + + get id() { + + return this.node.id; + + } + + get groupNode() { + + return this.node.groupNode; + + } + +} + +class NodeVar { + + constructor( name, type ) { + + this.isNodeVar = true; + + this.name = name; + this.type = type; + + } + +} + +class NodeVarying extends NodeVar { + + constructor( name, type ) { + + super( name, type ); + + this.needsInterpolation = false; + + this.isNodeVarying = true; + + } + +} + +class NodeCode { + + constructor( name, type, code = '' ) { + + this.name = name; + this.type = type; + this.code = code; + + Object.defineProperty( this, 'isNodeCode', { value: true } ); + + } + +} + +let id$1 = 0; + +class NodeCache { + + constructor( parent = null ) { + + this.id = id$1 ++; + this.nodesData = new WeakMap(); + + this.parent = parent; + + } + + getData( node ) { + + let data = this.nodesData.get( node ); + + if ( data === undefined && this.parent !== null ) { + + data = this.parent.getData( node ); + + } + + return data; + + } + + setData( node, data ) { + + this.nodesData.set( node, data ); + + } + +} + +class ParameterNode extends PropertyNode { + + static get type() { + + return 'ParameterNode'; + + } + + constructor( nodeType, name = null ) { + + super( nodeType, name ); + + this.isParameterNode = true; + + } + + getHash() { + + return this.uuid; + + } + + generate() { + + return this.name; + + } + +} + +const parameter = ( type, name ) => nodeObject( new ParameterNode( type, name ) ); + +class CodeNode extends Node { + + static get type() { + + return 'CodeNode'; + + } + + constructor( code = '', includes = [], language = '' ) { + + super( 'code' ); + + this.isCodeNode = true; + + this.code = code; + this.language = language; + + this.includes = includes; + + } + + isGlobal() { + + return true; + + } + + setIncludes( includes ) { + + this.includes = includes; + + return this; + + } + + getIncludes( /*builder*/ ) { + + return this.includes; + + } + + generate( builder ) { + + const includes = this.getIncludes( builder ); + + for ( const include of includes ) { + + include.build( builder ); + + } + + const nodeCode = builder.getCodeFromNode( this, this.getNodeType( builder ) ); + nodeCode.code = this.code; + + return nodeCode.code; + + } + + serialize( data ) { + + super.serialize( data ); + + data.code = this.code; + data.language = this.language; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.code = data.code; + this.language = data.language; + + } + +} + +const code = /*@__PURE__*/ nodeProxy( CodeNode ); + +const js = ( src, includes ) => code( src, includes, 'js' ); +const wgsl = ( src, includes ) => code( src, includes, 'wgsl' ); +const glsl = ( src, includes ) => code( src, includes, 'glsl' ); + +class FunctionNode extends CodeNode { + + static get type() { + + return 'FunctionNode'; + + } + + constructor( code = '', includes = [], language = '' ) { + + super( code, includes, language ); + + } + + getNodeType( builder ) { + + return this.getNodeFunction( builder ).type; + + } + + getInputs( builder ) { + + return this.getNodeFunction( builder ).inputs; + + } + + getNodeFunction( builder ) { + + const nodeData = builder.getDataFromNode( this ); + + let nodeFunction = nodeData.nodeFunction; + + if ( nodeFunction === undefined ) { + + nodeFunction = builder.parser.parseFunction( this.code ); + + nodeData.nodeFunction = nodeFunction; + + } + + return nodeFunction; + + } + + generate( builder, output ) { + + super.generate( builder ); + + const nodeFunction = this.getNodeFunction( builder ); + + const name = nodeFunction.name; + const type = nodeFunction.type; + + const nodeCode = builder.getCodeFromNode( this, type ); + + if ( name !== '' ) { + + // use a custom property name + + nodeCode.name = name; + + } + + const propertyName = builder.getPropertyName( nodeCode ); + + const code = this.getNodeFunction( builder ).getCode( propertyName ); + + nodeCode.code = code + '\n'; + + if ( output === 'property' ) { + + return propertyName; + + } else { + + return builder.format( `${ propertyName }()`, type, output ); + + } + + } + +} + +const nativeFn = ( code, includes = [], language = '' ) => { + + for ( let i = 0; i < includes.length; i ++ ) { + + const include = includes[ i ]; + + // TSL Function: glslFn, wgslFn + + if ( typeof include === 'function' ) { + + includes[ i ] = include.functionNode; + + } + + } + + const functionNode = nodeObject( new FunctionNode( code, includes, language ) ); + + const fn = ( ...params ) => functionNode.call( ...params ); + fn.functionNode = functionNode; + + return fn; + +}; + +const glslFn = ( code, includes ) => nativeFn( code, includes, 'glsl' ); +const wgslFn = ( code, includes ) => nativeFn( code, includes, 'wgsl' ); + +class Uniform { + + constructor( name, value ) { + + this.name = name; + this.value = value; + + this.boundary = 0; // used to build the uniform buffer according to the STD140 layout + this.itemSize = 0; + + this.offset = 0; // this property is set by WebGPUUniformsGroup and marks the start position in the uniform buffer + + } + + setValue( value ) { + + this.value = value; + + } + + getValue() { + + return this.value; + + } + +} + +class NumberUniform extends Uniform { + + constructor( name, value = 0 ) { + + super( name, value ); + + this.isNumberUniform = true; + + this.boundary = 4; + this.itemSize = 1; + + } + +} + +class Vector2Uniform extends Uniform { + + constructor( name, value = new Vector2() ) { + + super( name, value ); + + this.isVector2Uniform = true; + + this.boundary = 8; + this.itemSize = 2; + + } + +} + +class Vector3Uniform extends Uniform { + + constructor( name, value = new Vector3() ) { + + super( name, value ); + + this.isVector3Uniform = true; + + this.boundary = 16; + this.itemSize = 3; + + } + +} + +class Vector4Uniform extends Uniform { + + constructor( name, value = new Vector4() ) { + + super( name, value ); + + this.isVector4Uniform = true; + + this.boundary = 16; + this.itemSize = 4; + + } + +} + +class ColorUniform extends Uniform { + + constructor( name, value = new Color() ) { + + super( name, value ); + + this.isColorUniform = true; + + this.boundary = 16; + this.itemSize = 3; + + } + +} + +class Matrix3Uniform extends Uniform { + + constructor( name, value = new Matrix3() ) { + + super( name, value ); + + this.isMatrix3Uniform = true; + + this.boundary = 48; + this.itemSize = 12; + + } + +} + +class Matrix4Uniform extends Uniform { + + constructor( name, value = new Matrix4() ) { + + super( name, value ); + + this.isMatrix4Uniform = true; + + this.boundary = 64; + this.itemSize = 16; + + } + +} + +class NumberNodeUniform extends NumberUniform { + + constructor( nodeUniform ) { + + super( nodeUniform.name, nodeUniform.value ); + + this.nodeUniform = nodeUniform; + + } + + getValue() { + + return this.nodeUniform.value; + + } + +} + +class Vector2NodeUniform extends Vector2Uniform { + + constructor( nodeUniform ) { + + super( nodeUniform.name, nodeUniform.value ); + + this.nodeUniform = nodeUniform; + + } + + getValue() { + + return this.nodeUniform.value; + + } + +} + +class Vector3NodeUniform extends Vector3Uniform { + + constructor( nodeUniform ) { + + super( nodeUniform.name, nodeUniform.value ); + + this.nodeUniform = nodeUniform; + + } + + getValue() { + + return this.nodeUniform.value; + + } + +} + +class Vector4NodeUniform extends Vector4Uniform { + + constructor( nodeUniform ) { + + super( nodeUniform.name, nodeUniform.value ); + + this.nodeUniform = nodeUniform; + + } + + getValue() { + + return this.nodeUniform.value; + + } + +} + +class ColorNodeUniform extends ColorUniform { + + constructor( nodeUniform ) { + + super( nodeUniform.name, nodeUniform.value ); + + this.nodeUniform = nodeUniform; + + } + + getValue() { + + return this.nodeUniform.value; + + } + +} + +class Matrix3NodeUniform extends Matrix3Uniform { + + constructor( nodeUniform ) { + + super( nodeUniform.name, nodeUniform.value ); + + this.nodeUniform = nodeUniform; + + } + + getValue() { + + return this.nodeUniform.value; + + } + +} + +class Matrix4NodeUniform extends Matrix4Uniform { + + constructor( nodeUniform ) { + + super( nodeUniform.name, nodeUniform.value ); + + this.nodeUniform = nodeUniform; + + } + + getValue() { + + return this.nodeUniform.value; + + } + +} + +class StackNode extends Node { + + static get type() { + + return 'StackNode'; + + } + + constructor( parent = null ) { + + super(); + + this.nodes = []; + this.outputNode = null; + + this.parent = parent; + + this._currentCond = null; + + this.isStackNode = true; + + } + + getNodeType( builder ) { + + return this.outputNode ? this.outputNode.getNodeType( builder ) : 'void'; + + } + + add( node ) { + + this.nodes.push( node ); + + return this; + + } + + If( boolNode, method ) { + + const methodNode = new ShaderNode( method ); + this._currentCond = select( boolNode, methodNode ); + + return this.add( this._currentCond ); + + } + + ElseIf( boolNode, method ) { + + const methodNode = new ShaderNode( method ); + const ifNode = select( boolNode, methodNode ); + + this._currentCond.elseNode = ifNode; + this._currentCond = ifNode; + + return this; + + } + + Else( method ) { + + this._currentCond.elseNode = new ShaderNode( method ); + + return this; + + } + + build( builder, ...params ) { + + const previousStack = getCurrentStack(); + + setCurrentStack( this ); + + for ( const node of this.nodes ) { + + node.build( builder, 'void' ); + + } + + setCurrentStack( previousStack ); + + return this.outputNode ? this.outputNode.build( builder, ...params ) : super.build( builder, ...params ); + + } + + // + + else( ...params ) { // @deprecated, r168 + + console.warn( 'TSL.StackNode: .else() has been renamed to .Else().' ); + return this.Else( ...params ); + + } + + elseif( ...params ) { // @deprecated, r168 + + console.warn( 'TSL.StackNode: .elseif() has been renamed to .ElseIf().' ); + return this.ElseIf( ...params ); + + } + +} + +const stack = /*@__PURE__*/ nodeProxy( StackNode ); + +const LOD_MIN = 4; + +// The standard deviations (radians) associated with the extra mips. These are +// chosen to approximate a Trowbridge-Reitz distribution function times the +// geometric shadowing function. These sigma values squared must match the +// variance #defines in cube_uv_reflection_fragment.glsl.js. +const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; + +// The maximum length of the blur for loop. Smaller sigmas will use fewer +// samples and exit early, but not recompile the shader. +const MAX_SAMPLES = 20; + +const _flatCamera = /*@__PURE__*/ new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); +const _cubeCamera = /*@__PURE__*/ new PerspectiveCamera( 90, 1 ); +const _clearColor$2 = /*@__PURE__*/ new Color(); +let _oldTarget = null; +let _oldActiveCubeFace = 0; +let _oldActiveMipmapLevel = 0; + +// Golden Ratio +const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; +const INV_PHI = 1 / PHI; + +// Vertices of a dodecahedron (except the opposites, which represent the +// same axis), used as axis directions evenly spread on a sphere. +const _axisDirections = [ + /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ), + /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ), + /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ), + /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ), + /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ), + /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ), + /*@__PURE__*/ new Vector3( - 1, 1, - 1 ), + /*@__PURE__*/ new Vector3( 1, 1, - 1 ), + /*@__PURE__*/ new Vector3( - 1, 1, 1 ), + /*@__PURE__*/ new Vector3( 1, 1, 1 ) +]; + +// + +// WebGPU Face indices +const _faceLib = [ + 3, 1, 5, + 0, 4, 2 +]; + +const direction = getDirection( uv(), attribute( 'faceIndex' ) ).normalize(); +const outputDirection = vec3( direction.x, direction.y.negate(), direction.z ); + +/** + * This class generates a Prefiltered, Mipmapped Radiance Environment Map + * (PMREM) from a cubeMap environment texture. This allows different levels of + * blur to be quickly accessed based on material roughness. It is packed into a + * special CubeUV format that allows us to perform custom interpolation so that + * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap + * chain, it only goes down to the LOD_MIN level (above), and then creates extra + * even more filtered 'mips' at the same LOD_MIN resolution, associated with + * higher roughness levels. In this way we maintain resolution to smoothly + * interpolate diffuse lighting while limiting sampling computation. + * + * Paper: Fast, Accurate Image-Based Lighting + * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view +*/ + +class PMREMGenerator { + + constructor( renderer ) { + + this._renderer = renderer; + this._pingPongRenderTarget = null; + + this._lodMax = 0; + this._cubeSize = 0; + this._lodPlanes = []; + this._sizeLods = []; + this._sigmas = []; + this._lodMeshes = []; + + this._blurMaterial = null; + this._cubemapMaterial = null; + this._equirectMaterial = null; + this._backgroundBox = null; + + } + + /** + * Generates a PMREM from a supplied Scene, which can be faster than using an + * image if networking bandwidth is low. Optional sigma specifies a blur radius + * in radians to be applied to the scene before PMREM generation. Optional near + * and far planes ensure the scene is rendered in its entirety (the cubeCamera + * is placed at the origin). + */ + fromScene( scene, sigma = 0, near = 0.1, far = 100 ) { + + _oldTarget = this._renderer.getRenderTarget(); + _oldActiveCubeFace = this._renderer.getActiveCubeFace(); + _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); + + this._setSize( 256 ); + + const cubeUVRenderTarget = this._allocateTargets(); + cubeUVRenderTarget.depthBuffer = true; + + this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget ); + + if ( sigma > 0 ) { + + this._blur( cubeUVRenderTarget, 0, 0, sigma ); + + } + + this._applyPMREM( cubeUVRenderTarget ); + + this._cleanup( cubeUVRenderTarget ); + + return cubeUVRenderTarget; + + } + + /** + * Generates a PMREM from an equirectangular texture, which can be either LDR + * or HDR. The ideal input image size is 1k (1024 x 512), + * as this matches best with the 256 x 256 cubemap output. + */ + fromEquirectangular( equirectangular, renderTarget = null ) { + + return this._fromTexture( equirectangular, renderTarget ); + + } + + /** + * Generates a PMREM from an cubemap texture, which can be either LDR + * or HDR. The ideal input cube size is 256 x 256, + * as this matches best with the 256 x 256 cubemap output. + */ + fromCubemap( cubemap, renderTarget = null ) { + + return this._fromTexture( cubemap, renderTarget ); + + } + + /** + * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during + * your texture's network fetch for increased concurrency. + */ + async compileCubemapShader() { + + if ( this._cubemapMaterial === null ) { + + this._cubemapMaterial = _getCubemapMaterial(); + await this._compileMaterial( this._cubemapMaterial ); + + } + + } + + /** + * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during + * your texture's network fetch for increased concurrency. + */ + async compileEquirectangularShader() { + + if ( this._equirectMaterial === null ) { + + this._equirectMaterial = _getEquirectMaterial(); + await this._compileMaterial( this._equirectMaterial ); + + } + + } + + /** + * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, + * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on + * one of them will cause any others to also become unusable. + */ + dispose() { + + this._dispose(); + + if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose(); + if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose(); + if ( this._backgroundBox !== null ) { + + this._backgroundBox.geometry.dispose(); + this._backgroundBox.material.dispose(); + + } + + } + + // private interface + + _setSize( cubeSize ) { + + this._lodMax = Math.floor( Math.log2( cubeSize ) ); + this._cubeSize = Math.pow( 2, this._lodMax ); + + } + + _dispose() { + + if ( this._blurMaterial !== null ) this._blurMaterial.dispose(); + + if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose(); + + for ( let i = 0; i < this._lodPlanes.length; i ++ ) { + + this._lodPlanes[ i ].dispose(); + + } + + } + + _cleanup( outputTarget ) { + + this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel ); + outputTarget.scissorTest = false; + _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); + + } + + _fromTexture( texture, renderTarget ) { + + if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) { + + this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) ); + + } else { // Equirectangular + + this._setSize( texture.image.width / 4 ); + + } + + _oldTarget = this._renderer.getRenderTarget(); + _oldActiveCubeFace = this._renderer.getActiveCubeFace(); + _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); + + const cubeUVRenderTarget = renderTarget || this._allocateTargets(); + this._textureToCubeUV( texture, cubeUVRenderTarget ); + this._applyPMREM( cubeUVRenderTarget ); + this._cleanup( cubeUVRenderTarget ); + + return cubeUVRenderTarget; + + } + + _allocateTargets() { + + const width = 3 * Math.max( this._cubeSize, 16 * 7 ); + const height = 4 * this._cubeSize; + + const params = { + magFilter: LinearFilter, + minFilter: LinearFilter, + generateMipmaps: false, + type: HalfFloatType, + format: RGBAFormat, + colorSpace: LinearSRGBColorSpace, + //depthBuffer: false + }; + + const cubeUVRenderTarget = _createRenderTarget( width, height, params ); + + if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) { + + if ( this._pingPongRenderTarget !== null ) { + + this._dispose(); + + } + + this._pingPongRenderTarget = _createRenderTarget( width, height, params ); + + const { _lodMax } = this; + ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas, lodMeshes: this._lodMeshes } = _createPlanes( _lodMax ) ); + + this._blurMaterial = _getBlurShader( _lodMax, width, height ); + + } + + return cubeUVRenderTarget; + + } + + async _compileMaterial( material ) { + + const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material ); + await this._renderer.compile( tmpMesh, _flatCamera ); + + } + + _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) { + + const cubeCamera = _cubeCamera; + cubeCamera.near = near; + cubeCamera.far = far; + + // px, py, pz, nx, ny, nz + const upSign = [ - 1, 1, - 1, - 1, - 1, - 1 ]; + const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ]; + + const renderer = this._renderer; + + const originalAutoClear = renderer.autoClear; + + renderer.getClearColor( _clearColor$2 ); + + renderer.autoClear = false; + + let backgroundBox = this._backgroundBox; + + if ( backgroundBox === null ) { + + const backgroundMaterial = new MeshBasicMaterial( { + name: 'PMREM.Background', + side: BackSide, + depthWrite: false, + depthTest: false + } ); + + backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial ); + + } + + let useSolidColor = false; + const background = scene.background; + + if ( background ) { + + if ( background.isColor ) { + + backgroundBox.material.color.copy( background ); + scene.background = null; + useSolidColor = true; + + } + + } else { + + backgroundBox.material.color.copy( _clearColor$2 ); + useSolidColor = true; + + } + + renderer.setRenderTarget( cubeUVRenderTarget ); + + renderer.clear(); + + if ( useSolidColor ) { + + renderer.render( backgroundBox, cubeCamera ); + + } + + for ( let i = 0; i < 6; i ++ ) { + + const col = i % 3; + + if ( col === 0 ) { + + cubeCamera.up.set( 0, upSign[ i ], 0 ); + cubeCamera.lookAt( forwardSign[ i ], 0, 0 ); + + } else if ( col === 1 ) { + + cubeCamera.up.set( 0, 0, upSign[ i ] ); + cubeCamera.lookAt( 0, forwardSign[ i ], 0 ); + + } else { + + cubeCamera.up.set( 0, upSign[ i ], 0 ); + cubeCamera.lookAt( 0, 0, forwardSign[ i ] ); + + } + + const size = this._cubeSize; + + _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size ); + + renderer.render( scene, cubeCamera ); + + } + + renderer.autoClear = originalAutoClear; + scene.background = background; + + } + + _textureToCubeUV( texture, cubeUVRenderTarget ) { + + const renderer = this._renderer; + + const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ); + + if ( isCubeTexture ) { + + if ( this._cubemapMaterial === null ) { + + this._cubemapMaterial = _getCubemapMaterial( texture ); + + } + + } else { + + if ( this._equirectMaterial === null ) { + + this._equirectMaterial = _getEquirectMaterial( texture ); + + } + + } + + const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial; + material.fragmentNode.value = texture; + + const mesh = this._lodMeshes[ 0 ]; + mesh.material = material; + + const size = this._cubeSize; + + _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size ); + + renderer.setRenderTarget( cubeUVRenderTarget ); + renderer.render( mesh, _flatCamera ); + + } + + _applyPMREM( cubeUVRenderTarget ) { + + const renderer = this._renderer; + const autoClear = renderer.autoClear; + renderer.autoClear = false; + const n = this._lodPlanes.length; + + for ( let i = 1; i < n; i ++ ) { + + const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] ); + + const poleAxis = _axisDirections[ ( n - i - 1 ) % _axisDirections.length ]; + + this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis ); + + } + + renderer.autoClear = autoClear; + + } + + /** + * This is a two-pass Gaussian blur for a cubemap. Normally this is done + * vertically and horizontally, but this breaks down on a cube. Here we apply + * the blur latitudinally (around the poles), and then longitudinally (towards + * the poles) to approximate the orthogonally-separable blur. It is least + * accurate at the poles, but still does a decent job. + */ + _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) { + + const pingPongRenderTarget = this._pingPongRenderTarget; + + this._halfBlur( + cubeUVRenderTarget, + pingPongRenderTarget, + lodIn, + lodOut, + sigma, + 'latitudinal', + poleAxis ); + + this._halfBlur( + pingPongRenderTarget, + cubeUVRenderTarget, + lodOut, + lodOut, + sigma, + 'longitudinal', + poleAxis ); + + } + + _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) { + + const renderer = this._renderer; + const blurMaterial = this._blurMaterial; + + if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) { + + console.error( 'blur direction must be either latitudinal or longitudinal!' ); + + } + + // Number of standard deviations at which to cut off the discrete approximation. + const STANDARD_DEVIATIONS = 3; + + const blurMesh = this._lodMeshes[ lodOut ]; + blurMesh.material = blurMaterial; + + const blurUniforms = blurMaterial.uniforms; + + const pixels = this._sizeLods[ lodIn ] - 1; + const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 ); + const sigmaPixels = sigmaRadians / radiansPerPixel; + const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES; + + if ( samples > MAX_SAMPLES ) { + + console.warn( `sigmaRadians, ${ + sigmaRadians}, is too large and will clip, as it requested ${ + samples} samples when the maximum is set to ${MAX_SAMPLES}` ); + + } + + const weights = []; + let sum = 0; + + for ( let i = 0; i < MAX_SAMPLES; ++ i ) { + + const x = i / sigmaPixels; + const weight = Math.exp( - x * x / 2 ); + weights.push( weight ); + + if ( i === 0 ) { + + sum += weight; + + } else if ( i < samples ) { + + sum += 2 * weight; + + } + + } + + for ( let i = 0; i < weights.length; i ++ ) { + + weights[ i ] = weights[ i ] / sum; + + } + + targetIn.texture.frame = ( targetIn.texture.frame || 0 ) + 1; + + blurUniforms.envMap.value = targetIn.texture; + blurUniforms.samples.value = samples; + blurUniforms.weights.array = weights; + blurUniforms.latitudinal.value = direction === 'latitudinal' ? 1 : 0; + + if ( poleAxis ) { + + blurUniforms.poleAxis.value = poleAxis; + + } + + const { _lodMax } = this; + blurUniforms.dTheta.value = radiansPerPixel; + blurUniforms.mipInt.value = _lodMax - lodIn; + + const outputSize = this._sizeLods[ lodOut ]; + const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 ); + const y = 4 * ( this._cubeSize - outputSize ); + + _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize ); + renderer.setRenderTarget( targetOut ); + renderer.render( blurMesh, _flatCamera ); + + } + +} + +function _createPlanes( lodMax ) { + + const lodPlanes = []; + const sizeLods = []; + const sigmas = []; + const lodMeshes = []; + + let lod = lodMax; + + const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; + + for ( let i = 0; i < totalLods; i ++ ) { + + const sizeLod = Math.pow( 2, lod ); + sizeLods.push( sizeLod ); + let sigma = 1.0 / sizeLod; + + if ( i > lodMax - LOD_MIN ) { + + sigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ]; + + } else if ( i === 0 ) { + + sigma = 0; + + } + + sigmas.push( sigma ); + + const texelSize = 1.0 / ( sizeLod - 2 ); + const min = - texelSize; + const max = 1 + texelSize; + const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ]; + + const cubeFaces = 6; + const vertices = 6; + const positionSize = 3; + const uvSize = 2; + const faceIndexSize = 1; + + const position = new Float32Array( positionSize * vertices * cubeFaces ); + const uv = new Float32Array( uvSize * vertices * cubeFaces ); + const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces ); + + for ( let face = 0; face < cubeFaces; face ++ ) { + + const x = ( face % 3 ) * 2 / 3 - 1; + const y = face > 2 ? 0 : - 1; + const coordinates = [ + x, y, 0, + x + 2 / 3, y, 0, + x + 2 / 3, y + 1, 0, + x, y, 0, + x + 2 / 3, y + 1, 0, + x, y + 1, 0 + ]; + + const faceIdx = _faceLib[ face ]; + position.set( coordinates, positionSize * vertices * faceIdx ); + uv.set( uv1, uvSize * vertices * faceIdx ); + const fill = [ faceIdx, faceIdx, faceIdx, faceIdx, faceIdx, faceIdx ]; + faceIndex.set( fill, faceIndexSize * vertices * faceIdx ); + + } + + const planes = new BufferGeometry(); + planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) ); + planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) ); + planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) ); + lodPlanes.push( planes ); + lodMeshes.push( new Mesh( planes, null ) ); + + if ( lod > LOD_MIN ) { + + lod --; + + } + + } + + return { lodPlanes, sizeLods, sigmas, lodMeshes }; + +} + +function _createRenderTarget( width, height, params ) { + + const cubeUVRenderTarget = new RenderTarget( width, height, params ); + cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; + cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; + cubeUVRenderTarget.texture.isPMREMTexture = true; + cubeUVRenderTarget.scissorTest = true; + return cubeUVRenderTarget; + +} + +function _setViewport( target, x, y, width, height ) { + + target.viewport.set( x, y, width, height ); + target.scissor.set( x, y, width, height ); + +} + +function _getMaterial( type ) { + + const material = new NodeMaterial(); + material.depthTest = false; + material.depthWrite = false; + material.blending = NoBlending; + material.name = `PMREM_${ type }`; + + return material; + +} + +function _getBlurShader( lodMax, width, height ) { + + const weights = uniformArray( new Array( MAX_SAMPLES ).fill( 0 ) ); + const poleAxis = uniform( new Vector3( 0, 1, 0 ) ); + const dTheta = uniform( 0 ); + const n = float( MAX_SAMPLES ); + const latitudinal = uniform( 0 ); // false, bool + const samples = uniform( 1 ); // int + const envMap = texture( null ); + const mipInt = uniform( 0 ); // int + const CUBEUV_TEXEL_WIDTH = float( 1 / width ); + const CUBEUV_TEXEL_HEIGHT = float( 1 / height ); + const CUBEUV_MAX_MIP = float( lodMax ); + + const materialUniforms = { + n, + latitudinal, + weights, + poleAxis, + outputDirection, + dTheta, + samples, + envMap, + mipInt, + CUBEUV_TEXEL_WIDTH, + CUBEUV_TEXEL_HEIGHT, + CUBEUV_MAX_MIP + }; + + const material = _getMaterial( 'blur' ); + material.uniforms = materialUniforms; // TODO: Move to outside of the material + material.fragmentNode = blur( { ...materialUniforms, latitudinal: latitudinal.equal( 1 ) } ); + + return material; + +} + +function _getCubemapMaterial( envTexture ) { + + const material = _getMaterial( 'cubemap' ); + material.fragmentNode = cubeTexture( envTexture, outputDirection ); + + return material; + +} + +function _getEquirectMaterial( envTexture ) { + + const material = _getMaterial( 'equirect' ); + material.fragmentNode = texture( envTexture, equirectUV( outputDirection ), 0 ); + + return material; + +} + +let _id$5 = 0; + +class BindGroup { + + constructor( name = '', bindings = [], index = 0, bindingsReference = [] ) { + + this.name = name; + this.bindings = bindings; + this.index = index; + this.bindingsReference = bindingsReference; + + this.id = _id$5 ++; + + } + +} + +const rendererCache = new WeakMap(); + +const typeFromLength = new Map( [ + [ 2, 'vec2' ], + [ 3, 'vec3' ], + [ 4, 'vec4' ], + [ 9, 'mat3' ], + [ 16, 'mat4' ] +] ); + +const typeFromArray = new Map( [ + [ Int8Array, 'int' ], + [ Int16Array, 'int' ], + [ Int32Array, 'int' ], + [ Uint8Array, 'uint' ], + [ Uint16Array, 'uint' ], + [ Uint32Array, 'uint' ], + [ Float32Array, 'float' ] +] ); + +const toFloat = ( value ) => { + + value = Number( value ); + + return value + ( value % 1 ? '' : '.0' ); + +}; + +class NodeBuilder { + + constructor( object, renderer, parser ) { + + this.object = object; + this.material = ( object && object.material ) || null; + this.geometry = ( object && object.geometry ) || null; + this.renderer = renderer; + this.parser = parser; + this.scene = null; + this.camera = null; + + this.nodes = []; + this.updateNodes = []; + this.updateBeforeNodes = []; + this.updateAfterNodes = []; + this.hashNodes = {}; + + this.monitor = null; + + this.lightsNode = null; + this.environmentNode = null; + this.fogNode = null; + + this.clippingContext = null; + + this.vertexShader = null; + this.fragmentShader = null; + this.computeShader = null; + + this.flowNodes = { vertex: [], fragment: [], compute: [] }; + this.flowCode = { vertex: '', fragment: '', compute: '' }; + this.uniforms = { vertex: [], fragment: [], compute: [], index: 0 }; + this.structs = { vertex: [], fragment: [], compute: [], index: 0 }; + this.bindings = { vertex: {}, fragment: {}, compute: {} }; + this.bindingsIndexes = {}; + this.bindGroups = null; + this.attributes = []; + this.bufferAttributes = []; + this.varyings = []; + this.codes = {}; + this.vars = {}; + this.flow = { code: '' }; + this.chaining = []; + this.stack = stack(); + this.stacks = []; + this.tab = '\t'; + + this.currentFunctionNode = null; + + this.context = { + material: this.material + }; + + this.cache = new NodeCache(); + this.globalCache = this.cache; + + this.flowsData = new WeakMap(); + + this.shaderStage = null; + this.buildStage = null; + + this.useComparisonMethod = false; + + } + + getBindGroupsCache() { + + let bindGroupsCache = rendererCache.get( this.renderer ); + + if ( bindGroupsCache === undefined ) { + + bindGroupsCache = new ChainMap(); + + rendererCache.set( this.renderer, bindGroupsCache ); + + } + + return bindGroupsCache; + + } + + createRenderTarget( width, height, options ) { + + return new RenderTarget( width, height, options ); + + } + + createCubeRenderTarget( size, options ) { + + return new CubeRenderTarget( size, options ); + + } + + createPMREMGenerator() { + + // TODO: Move Materials.js to outside of the Nodes.js in order to remove this function and improve tree-shaking support + + return new PMREMGenerator( this.renderer ); + + } + + includes( node ) { + + return this.nodes.includes( node ); + + } + + _getBindGroup( groupName, bindings ) { + + const bindGroupsCache = this.getBindGroupsCache(); + + // + + const bindingsArray = []; + + let sharedGroup = true; + + for ( const binding of bindings ) { + + bindingsArray.push( binding ); + + sharedGroup = sharedGroup && binding.groupNode.shared !== true; + + } + + // + + let bindGroup; + + if ( sharedGroup ) { + + bindGroup = bindGroupsCache.get( bindingsArray ); + + if ( bindGroup === undefined ) { + + bindGroup = new BindGroup( groupName, bindingsArray, this.bindingsIndexes[ groupName ].group, bindingsArray ); + + bindGroupsCache.set( bindingsArray, bindGroup ); + + } + + } else { + + bindGroup = new BindGroup( groupName, bindingsArray, this.bindingsIndexes[ groupName ].group, bindingsArray ); + + } + + return bindGroup; + + } + + getBindGroupArray( groupName, shaderStage ) { + + const bindings = this.bindings[ shaderStage ]; + + let bindGroup = bindings[ groupName ]; + + if ( bindGroup === undefined ) { + + if ( this.bindingsIndexes[ groupName ] === undefined ) { + + this.bindingsIndexes[ groupName ] = { binding: 0, group: Object.keys( this.bindingsIndexes ).length }; + + } + + bindings[ groupName ] = bindGroup = []; + + } + + return bindGroup; + + } + + getBindings() { + + let bindingsGroups = this.bindGroups; + + if ( bindingsGroups === null ) { + + const groups = {}; + const bindings = this.bindings; + + for ( const shaderStage of shaderStages ) { + + for ( const groupName in bindings[ shaderStage ] ) { + + const uniforms = bindings[ shaderStage ][ groupName ]; + + const groupUniforms = groups[ groupName ] || ( groups[ groupName ] = [] ); + groupUniforms.push( ...uniforms ); + + } + + } + + bindingsGroups = []; + + for ( const groupName in groups ) { + + const group = groups[ groupName ]; + + const bindingsGroup = this._getBindGroup( groupName, group ); + + bindingsGroups.push( bindingsGroup ); + + } + + this.bindGroups = bindingsGroups; + + } + + return bindingsGroups; + + } + + sortBindingGroups() { + + const bindingsGroups = this.getBindings(); + + bindingsGroups.sort( ( a, b ) => ( a.bindings[ 0 ].groupNode.order - b.bindings[ 0 ].groupNode.order ) ); + + for ( let i = 0; i < bindingsGroups.length; i ++ ) { + + const bindingGroup = bindingsGroups[ i ]; + this.bindingsIndexes[ bindingGroup.name ].group = i; + + bindingGroup.index = i; + + } + + } + + setHashNode( node, hash ) { + + this.hashNodes[ hash ] = node; + + } + + addNode( node ) { + + if ( this.nodes.includes( node ) === false ) { + + this.nodes.push( node ); + + this.setHashNode( node, node.getHash( this ) ); + + } + + } + + buildUpdateNodes() { + + for ( const node of this.nodes ) { + + const updateType = node.getUpdateType(); + const updateBeforeType = node.getUpdateBeforeType(); + const updateAfterType = node.getUpdateAfterType(); + + if ( updateType !== NodeUpdateType.NONE ) { + + this.updateNodes.push( node.getSelf() ); + + } + + if ( updateBeforeType !== NodeUpdateType.NONE ) { + + this.updateBeforeNodes.push( node.getSelf() ); + + } + + if ( updateAfterType !== NodeUpdateType.NONE ) { + + this.updateAfterNodes.push( node.getSelf() ); + + } + + } + + } + + get currentNode() { + + return this.chaining[ this.chaining.length - 1 ]; + + } + + isFilteredTexture( texture ) { + + return ( texture.magFilter === LinearFilter || texture.magFilter === LinearMipmapNearestFilter || texture.magFilter === NearestMipmapLinearFilter || texture.magFilter === LinearMipmapLinearFilter || + texture.minFilter === LinearFilter || texture.minFilter === LinearMipmapNearestFilter || texture.minFilter === NearestMipmapLinearFilter || texture.minFilter === LinearMipmapLinearFilter ); + + } + + addChain( node ) { + + /* + if ( this.chaining.indexOf( node ) !== - 1 ) { + + console.warn( 'Recursive node: ', node ); + + } + */ + + this.chaining.push( node ); + + } + + removeChain( node ) { + + const lastChain = this.chaining.pop(); + + if ( lastChain !== node ) { + + throw new Error( 'NodeBuilder: Invalid node chaining!' ); + + } + + } + + getMethod( method ) { + + return method; + + } + + getNodeFromHash( hash ) { + + return this.hashNodes[ hash ]; + + } + + addFlow( shaderStage, node ) { + + this.flowNodes[ shaderStage ].push( node ); + + return node; + + } + + setContext( context ) { + + this.context = context; + + } + + getContext() { + + return this.context; + + } + + getSharedContext() { + + ({ ...this.context }); + + return this.context; + + } + + setCache( cache ) { + + this.cache = cache; + + } + + getCache() { + + return this.cache; + + } + + getCacheFromNode( node, parent = true ) { + + const data = this.getDataFromNode( node ); + if ( data.cache === undefined ) data.cache = new NodeCache( parent ? this.getCache() : null ); + + return data.cache; + + } + + isAvailable( /*name*/ ) { + + return false; + + } + + getVertexIndex() { + + console.warn( 'Abstract function.' ); + + } + + getInstanceIndex() { + + console.warn( 'Abstract function.' ); + + } + + getDrawIndex() { + + console.warn( 'Abstract function.' ); + + } + + getFrontFacing() { + + console.warn( 'Abstract function.' ); + + } + + getFragCoord() { + + console.warn( 'Abstract function.' ); + + } + + isFlipY() { + + return false; + + } + + increaseUsage( node ) { + + const nodeData = this.getDataFromNode( node ); + nodeData.usageCount = nodeData.usageCount === undefined ? 1 : nodeData.usageCount + 1; + + return nodeData.usageCount; + + } + + generateTexture( /* texture, textureProperty, uvSnippet */ ) { + + console.warn( 'Abstract function.' ); + + } + + generateTextureLod( /* texture, textureProperty, uvSnippet, levelSnippet */ ) { + + console.warn( 'Abstract function.' ); + + } + + generateConst( type, value = null ) { + + if ( value === null ) { + + if ( type === 'float' || type === 'int' || type === 'uint' ) value = 0; + else if ( type === 'bool' ) value = false; + else if ( type === 'color' ) value = new Color(); + else if ( type === 'vec2' ) value = new Vector2(); + else if ( type === 'vec3' ) value = new Vector3(); + else if ( type === 'vec4' ) value = new Vector4(); + + } + + if ( type === 'float' ) return toFloat( value ); + if ( type === 'int' ) return `${ Math.round( value ) }`; + if ( type === 'uint' ) return value >= 0 ? `${ Math.round( value ) }u` : '0u'; + if ( type === 'bool' ) return value ? 'true' : 'false'; + if ( type === 'color' ) return `${ this.getType( 'vec3' ) }( ${ toFloat( value.r ) }, ${ toFloat( value.g ) }, ${ toFloat( value.b ) } )`; + + const typeLength = this.getTypeLength( type ); + + const componentType = this.getComponentType( type ); + + const generateConst = value => this.generateConst( componentType, value ); + + if ( typeLength === 2 ) { + + return `${ this.getType( type ) }( ${ generateConst( value.x ) }, ${ generateConst( value.y ) } )`; + + } else if ( typeLength === 3 ) { + + return `${ this.getType( type ) }( ${ generateConst( value.x ) }, ${ generateConst( value.y ) }, ${ generateConst( value.z ) } )`; + + } else if ( typeLength === 4 ) { + + return `${ this.getType( type ) }( ${ generateConst( value.x ) }, ${ generateConst( value.y ) }, ${ generateConst( value.z ) }, ${ generateConst( value.w ) } )`; + + } else if ( typeLength > 4 && value && ( value.isMatrix3 || value.isMatrix4 ) ) { + + return `${ this.getType( type ) }( ${ value.elements.map( generateConst ).join( ', ' ) } )`; + + } else if ( typeLength > 4 ) { + + return `${ this.getType( type ) }()`; + + } + + throw new Error( `NodeBuilder: Type '${type}' not found in generate constant attempt.` ); + + } + + getType( type ) { + + if ( type === 'color' ) return 'vec3'; + + return type; + + } + + hasGeometryAttribute( name ) { + + return this.geometry && this.geometry.getAttribute( name ) !== undefined; + + } + + getAttribute( name, type ) { + + const attributes = this.attributes; + + // find attribute + + for ( const attribute of attributes ) { + + if ( attribute.name === name ) { + + return attribute; + + } + + } + + // create a new if no exist + + const attribute = new NodeAttribute( name, type ); + + attributes.push( attribute ); + + return attribute; + + } + + getPropertyName( node/*, shaderStage*/ ) { + + return node.name; + + } + + isVector( type ) { + + return /vec\d/.test( type ); + + } + + isMatrix( type ) { + + return /mat\d/.test( type ); + + } + + isReference( type ) { + + return type === 'void' || type === 'property' || type === 'sampler' || type === 'texture' || type === 'cubeTexture' || type === 'storageTexture' || type === 'depthTexture' || type === 'texture3D'; + + } + + needsToWorkingColorSpace( /*texture*/ ) { + + return false; + + } + + getComponentTypeFromTexture( texture ) { + + const type = texture.type; + + if ( texture.isDataTexture ) { + + if ( type === IntType ) return 'int'; + if ( type === UnsignedIntType ) return 'uint'; + + } + + return 'float'; + + } + + getElementType( type ) { + + if ( type === 'mat2' ) return 'vec2'; + if ( type === 'mat3' ) return 'vec3'; + if ( type === 'mat4' ) return 'vec4'; + + return this.getComponentType( type ); + + } + + getComponentType( type ) { + + type = this.getVectorType( type ); + + if ( type === 'float' || type === 'bool' || type === 'int' || type === 'uint' ) return type; + + const componentType = /(b|i|u|)(vec|mat)([2-4])/.exec( type ); + + if ( componentType === null ) return null; + + if ( componentType[ 1 ] === 'b' ) return 'bool'; + if ( componentType[ 1 ] === 'i' ) return 'int'; + if ( componentType[ 1 ] === 'u' ) return 'uint'; + + return 'float'; + + } + + getVectorType( type ) { + + if ( type === 'color' ) return 'vec3'; + if ( type === 'texture' || type === 'cubeTexture' || type === 'storageTexture' || type === 'texture3D' ) return 'vec4'; + + return type; + + } + + getTypeFromLength( length, componentType = 'float' ) { + + if ( length === 1 ) return componentType; + + const baseType = typeFromLength.get( length ); + const prefix = componentType === 'float' ? '' : componentType[ 0 ]; + + return prefix + baseType; + + } + + getTypeFromArray( array ) { + + return typeFromArray.get( array.constructor ); + + } + + getTypeFromAttribute( attribute ) { + + let dataAttribute = attribute; + + if ( attribute.isInterleavedBufferAttribute ) dataAttribute = attribute.data; + + const array = dataAttribute.array; + const itemSize = attribute.itemSize; + const normalized = attribute.normalized; + + let arrayType; + + if ( ! ( attribute instanceof Float16BufferAttribute ) && normalized !== true ) { + + arrayType = this.getTypeFromArray( array ); + + } + + return this.getTypeFromLength( itemSize, arrayType ); + + } + + getTypeLength( type ) { + + const vecType = this.getVectorType( type ); + const vecNum = /vec([2-4])/.exec( vecType ); + + if ( vecNum !== null ) return Number( vecNum[ 1 ] ); + if ( vecType === 'float' || vecType === 'bool' || vecType === 'int' || vecType === 'uint' ) return 1; + if ( /mat2/.test( type ) === true ) return 4; + if ( /mat3/.test( type ) === true ) return 9; + if ( /mat4/.test( type ) === true ) return 16; + + return 0; + + } + + getVectorFromMatrix( type ) { + + return type.replace( 'mat', 'vec' ); + + } + + changeComponentType( type, newComponentType ) { + + return this.getTypeFromLength( this.getTypeLength( type ), newComponentType ); + + } + + getIntegerType( type ) { + + const componentType = this.getComponentType( type ); + + if ( componentType === 'int' || componentType === 'uint' ) return type; + + return this.changeComponentType( type, 'int' ); + + } + + addStack() { + + this.stack = stack( this.stack ); + + this.stacks.push( getCurrentStack() || this.stack ); + setCurrentStack( this.stack ); + + return this.stack; + + } + + removeStack() { + + const lastStack = this.stack; + this.stack = lastStack.parent; + + setCurrentStack( this.stacks.pop() ); + + return lastStack; + + } + + getDataFromNode( node, shaderStage = this.shaderStage, cache = null ) { + + cache = cache === null ? ( node.isGlobal( this ) ? this.globalCache : this.cache ) : cache; + + let nodeData = cache.getData( node ); + + if ( nodeData === undefined ) { + + nodeData = {}; + + cache.setData( node, nodeData ); + + } + + if ( nodeData[ shaderStage ] === undefined ) nodeData[ shaderStage ] = {}; + + return nodeData[ shaderStage ]; + + } + + getNodeProperties( node, shaderStage = 'any' ) { + + const nodeData = this.getDataFromNode( node, shaderStage ); + + return nodeData.properties || ( nodeData.properties = { outputNode: null } ); + + } + + getBufferAttributeFromNode( node, type ) { + + const nodeData = this.getDataFromNode( node ); + + let bufferAttribute = nodeData.bufferAttribute; + + if ( bufferAttribute === undefined ) { + + const index = this.uniforms.index ++; + + bufferAttribute = new NodeAttribute( 'nodeAttribute' + index, type, node ); + + this.bufferAttributes.push( bufferAttribute ); + + nodeData.bufferAttribute = bufferAttribute; + + } + + return bufferAttribute; + + } + + getStructTypeFromNode( node, shaderStage = this.shaderStage ) { + + const nodeData = this.getDataFromNode( node, shaderStage ); + + if ( nodeData.structType === undefined ) { + + const index = this.structs.index ++; + + node.name = `StructType${ index }`; + this.structs[ shaderStage ].push( node ); + + nodeData.structType = node; + + } + + return node; + + } + + getUniformFromNode( node, type, shaderStage = this.shaderStage, name = null ) { + + const nodeData = this.getDataFromNode( node, shaderStage, this.globalCache ); + + let nodeUniform = nodeData.uniform; + + if ( nodeUniform === undefined ) { + + const index = this.uniforms.index ++; + + nodeUniform = new NodeUniform( name || ( 'nodeUniform' + index ), type, node ); + + this.uniforms[ shaderStage ].push( nodeUniform ); + + nodeData.uniform = nodeUniform; + + } + + return nodeUniform; + + } + + getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage ) { + + const nodeData = this.getDataFromNode( node, shaderStage ); + + let nodeVar = nodeData.variable; + + if ( nodeVar === undefined ) { + + const vars = this.vars[ shaderStage ] || ( this.vars[ shaderStage ] = [] ); + + if ( name === null ) name = 'nodeVar' + vars.length; + + nodeVar = new NodeVar( name, type ); + + vars.push( nodeVar ); + + nodeData.variable = nodeVar; + + } + + return nodeVar; + + } + + getVaryingFromNode( node, name = null, type = node.getNodeType( this ) ) { + + const nodeData = this.getDataFromNode( node, 'any' ); + + let nodeVarying = nodeData.varying; + + if ( nodeVarying === undefined ) { + + const varyings = this.varyings; + const index = varyings.length; + + if ( name === null ) name = 'nodeVarying' + index; + + nodeVarying = new NodeVarying( name, type ); + + varyings.push( nodeVarying ); + + nodeData.varying = nodeVarying; + + } + + return nodeVarying; + + } + + getCodeFromNode( node, type, shaderStage = this.shaderStage ) { + + const nodeData = this.getDataFromNode( node ); + + let nodeCode = nodeData.code; + + if ( nodeCode === undefined ) { + + const codes = this.codes[ shaderStage ] || ( this.codes[ shaderStage ] = [] ); + const index = codes.length; + + nodeCode = new NodeCode( 'nodeCode' + index, type ); + + codes.push( nodeCode ); + + nodeData.code = nodeCode; + + } + + return nodeCode; + + } + + addFlowCodeHierarchy( node, nodeBlock ) { + + const { flowCodes, flowCodeBlock } = this.getDataFromNode( node ); + + let needsFlowCode = true; + let nodeBlockHierarchy = nodeBlock; + + while ( nodeBlockHierarchy ) { + + if ( flowCodeBlock.get( nodeBlockHierarchy ) === true ) { + + needsFlowCode = false; + break; + + } + + nodeBlockHierarchy = this.getDataFromNode( nodeBlockHierarchy ).parentNodeBlock; + + } + + if ( needsFlowCode ) { + + for ( const flowCode of flowCodes ) { + + this.addLineFlowCode( flowCode ); + + } + + } + + } + + addLineFlowCodeBlock( node, code, nodeBlock ) { + + const nodeData = this.getDataFromNode( node ); + const flowCodes = nodeData.flowCodes || ( nodeData.flowCodes = [] ); + const codeBlock = nodeData.flowCodeBlock || ( nodeData.flowCodeBlock = new WeakMap() ); + + flowCodes.push( code ); + codeBlock.set( nodeBlock, true ); + + } + + addLineFlowCode( code, node = null ) { + + if ( code === '' ) return this; + + if ( node !== null && this.context.nodeBlock ) { + + this.addLineFlowCodeBlock( node, code, this.context.nodeBlock ); + + } + + code = this.tab + code; + + if ( ! /;\s*$/.test( code ) ) { + + code = code + ';\n'; + + } + + this.flow.code += code; + + return this; + + } + + addFlowCode( code ) { + + this.flow.code += code; + + return this; + + } + + addFlowTab() { + + this.tab += '\t'; + + return this; + + } + + removeFlowTab() { + + this.tab = this.tab.slice( 0, - 1 ); + + return this; + + } + + getFlowData( node/*, shaderStage*/ ) { + + return this.flowsData.get( node ); + + } + + flowNode( node ) { + + const output = node.getNodeType( this ); + + const flowData = this.flowChildNode( node, output ); + + this.flowsData.set( node, flowData ); + + return flowData; + + } + + buildFunctionNode( shaderNode ) { + + const fn = new FunctionNode(); + + const previous = this.currentFunctionNode; + + this.currentFunctionNode = fn; + + fn.code = this.buildFunctionCode( shaderNode ); + + this.currentFunctionNode = previous; + + return fn; + + } + + flowShaderNode( shaderNode ) { + + const layout = shaderNode.layout; + + const inputs = { + [ Symbol.iterator ]() { + + let index = 0; + const values = Object.values( this ); + return { + next: () => ( { + value: values[ index ], + done: index ++ >= values.length + } ) + }; + + } + }; + + for ( const input of layout.inputs ) { + + inputs[ input.name ] = new ParameterNode( input.type, input.name ); + + } + + // + + shaderNode.layout = null; + + const callNode = shaderNode.call( inputs ); + const flowData = this.flowStagesNode( callNode, layout.type ); + + shaderNode.layout = layout; + + return flowData; + + } + + flowStagesNode( node, output = null ) { + + const previousFlow = this.flow; + const previousVars = this.vars; + const previousCache = this.cache; + const previousBuildStage = this.buildStage; + const previousStack = this.stack; + + const flow = { + code: '' + }; + + this.flow = flow; + this.vars = {}; + this.cache = new NodeCache(); + this.stack = stack(); + + for ( const buildStage of defaultBuildStages ) { + + this.setBuildStage( buildStage ); + + flow.result = node.build( this, output ); + + } + + flow.vars = this.getVars( this.shaderStage ); + + this.flow = previousFlow; + this.vars = previousVars; + this.cache = previousCache; + this.stack = previousStack; + + this.setBuildStage( previousBuildStage ); + + return flow; + + } + + getFunctionOperator() { + + return null; + + } + + flowChildNode( node, output = null ) { + + const previousFlow = this.flow; + + const flow = { + code: '' + }; + + this.flow = flow; + + flow.result = node.build( this, output ); + + this.flow = previousFlow; + + return flow; + + } + + flowNodeFromShaderStage( shaderStage, node, output = null, propertyName = null ) { + + const previousShaderStage = this.shaderStage; + + this.setShaderStage( shaderStage ); + + const flowData = this.flowChildNode( node, output ); + + if ( propertyName !== null ) { + + flowData.code += `${ this.tab + propertyName } = ${ flowData.result };\n`; + + } + + this.flowCode[ shaderStage ] = this.flowCode[ shaderStage ] + flowData.code; + + this.setShaderStage( previousShaderStage ); + + return flowData; + + } + + getAttributesArray() { + + return this.attributes.concat( this.bufferAttributes ); + + } + + getAttributes( /*shaderStage*/ ) { + + console.warn( 'Abstract function.' ); + + } + + getVaryings( /*shaderStage*/ ) { + + console.warn( 'Abstract function.' ); + + } + + getVar( type, name ) { + + return `${ this.getType( type ) } ${ name }`; + + } + + getVars( shaderStage ) { + + let snippet = ''; + + const vars = this.vars[ shaderStage ]; + + if ( vars !== undefined ) { + + for ( const variable of vars ) { + + snippet += `${ this.getVar( variable.type, variable.name ) }; `; + + } + + } + + return snippet; + + } + + getUniforms( /*shaderStage*/ ) { + + console.warn( 'Abstract function.' ); + + } + + getCodes( shaderStage ) { + + const codes = this.codes[ shaderStage ]; + + let code = ''; + + if ( codes !== undefined ) { + + for ( const nodeCode of codes ) { + + code += nodeCode.code + '\n'; + + } + + } + + return code; + + } + + getHash() { + + return this.vertexShader + this.fragmentShader + this.computeShader; + + } + + setShaderStage( shaderStage ) { + + this.shaderStage = shaderStage; + + } + + getShaderStage() { + + return this.shaderStage; + + } + + setBuildStage( buildStage ) { + + this.buildStage = buildStage; + + } + + getBuildStage() { + + return this.buildStage; + + } + + buildCode() { + + console.warn( 'Abstract function.' ); + + } + + build() { + + const { object, material, renderer } = this; + + if ( material !== null ) { + + let nodeMaterial = renderer.nodes.library.fromMaterial( material ); + + if ( nodeMaterial === null ) { + + console.error( `NodeMaterial: Material "${ material.type }" is not compatible.` ); + + nodeMaterial = new NodeMaterial(); + + } + + nodeMaterial.build( this ); + + } else { + + this.addFlow( 'compute', object ); + + } + + // setup() -> stage 1: create possible new nodes and returns an output reference node + // analyze() -> stage 2: analyze nodes to possible optimization and validation + // generate() -> stage 3: generate shader + + for ( const buildStage of defaultBuildStages ) { + + this.setBuildStage( buildStage ); + + if ( this.context.vertex && this.context.vertex.isNode ) { + + this.flowNodeFromShaderStage( 'vertex', this.context.vertex ); + + } + + for ( const shaderStage of shaderStages ) { + + this.setShaderStage( shaderStage ); + + const flowNodes = this.flowNodes[ shaderStage ]; + + for ( const node of flowNodes ) { + + if ( buildStage === 'generate' ) { + + this.flowNode( node ); + + } else { + + node.build( this ); + + } + + } + + } + + } + + this.setBuildStage( null ); + this.setShaderStage( null ); + + // stage 4: build code for a specific output + + this.buildCode(); + this.buildUpdateNodes(); + + return this; + + } + + getNodeUniform( uniformNode, type ) { + + if ( type === 'float' || type === 'int' || type === 'uint' ) return new NumberNodeUniform( uniformNode ); + if ( type === 'vec2' || type === 'ivec2' || type === 'uvec2' ) return new Vector2NodeUniform( uniformNode ); + if ( type === 'vec3' || type === 'ivec3' || type === 'uvec3' ) return new Vector3NodeUniform( uniformNode ); + if ( type === 'vec4' || type === 'ivec4' || type === 'uvec4' ) return new Vector4NodeUniform( uniformNode ); + if ( type === 'color' ) return new ColorNodeUniform( uniformNode ); + if ( type === 'mat3' ) return new Matrix3NodeUniform( uniformNode ); + if ( type === 'mat4' ) return new Matrix4NodeUniform( uniformNode ); + + throw new Error( `Uniform "${type}" not declared.` ); + + } + + createNodeMaterial( type = 'NodeMaterial' ) { // @deprecated, r168 + + throw new Error( `THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${ type }() instead.` ); + + } + + format( snippet, fromType, toType ) { + + fromType = this.getVectorType( fromType ); + toType = this.getVectorType( toType ); + + if ( fromType === toType || toType === null || this.isReference( toType ) ) { + + return snippet; + + } + + const fromTypeLength = this.getTypeLength( fromType ); + const toTypeLength = this.getTypeLength( toType ); + + if ( fromTypeLength === 16 && toTypeLength === 9 ) { + + return `${ this.getType( toType ) }(${ snippet }[0].xyz, ${ snippet }[1].xyz, ${ snippet }[2].xyz)`; + + } + + if ( fromTypeLength === 9 && toTypeLength === 4 ) { + + return `${ this.getType( toType ) }(${ snippet }[0].xy, ${ snippet }[1].xy)`; + + } + + + if ( fromTypeLength > 4 ) { // fromType is matrix-like + + // @TODO: ignore for now + + return snippet; + + } + + if ( toTypeLength > 4 || toTypeLength === 0 ) { // toType is matrix-like or unknown + + // @TODO: ignore for now + + return snippet; + + } + + if ( fromTypeLength === toTypeLength ) { + + return `${ this.getType( toType ) }( ${ snippet } )`; + + } + + if ( fromTypeLength > toTypeLength ) { + + return this.format( `${ snippet }.${ 'xyz'.slice( 0, toTypeLength ) }`, this.getTypeFromLength( toTypeLength, this.getComponentType( fromType ) ), toType ); + + } + + if ( toTypeLength === 4 && fromTypeLength > 1 ) { // toType is vec4-like + + return `${ this.getType( toType ) }( ${ this.format( snippet, fromType, 'vec3' ) }, 1.0 )`; + + } + + if ( fromTypeLength === 2 ) { // fromType is vec2-like and toType is vec3-like + + return `${ this.getType( toType ) }( ${ this.format( snippet, fromType, 'vec2' ) }, 0.0 )`; + + } + + if ( fromTypeLength === 1 && toTypeLength > 1 && fromType !== this.getComponentType( toType ) ) { // fromType is float-like + + // convert a number value to vector type, e.g: + // vec3( 1u ) -> vec3( float( 1u ) ) + + snippet = `${ this.getType( this.getComponentType( toType ) ) }( ${ snippet } )`; + + } + + return `${ this.getType( toType ) }( ${ snippet } )`; // fromType is float-like + + } + + getSignature() { + + return `// Three.js r${ REVISION } - Node System\n`; + + } + +} + +class NodeFrame { + + constructor() { + + this.time = 0; + this.deltaTime = 0; + + this.frameId = 0; + this.renderId = 0; + + this.startTime = null; + + this.updateMap = new WeakMap(); + this.updateBeforeMap = new WeakMap(); + this.updateAfterMap = new WeakMap(); + + this.renderer = null; + this.material = null; + this.camera = null; + this.object = null; + this.scene = null; + + } + + _getMaps( referenceMap, nodeRef ) { + + let maps = referenceMap.get( nodeRef ); + + if ( maps === undefined ) { + + maps = { + renderMap: new WeakMap(), + frameMap: new WeakMap() + }; + + referenceMap.set( nodeRef, maps ); + + } + + return maps; + + } + + updateBeforeNode( node ) { + + const updateType = node.getUpdateBeforeType(); + const reference = node.updateReference( this ); + + if ( updateType === NodeUpdateType.FRAME ) { + + const { frameMap } = this._getMaps( this.updateBeforeMap, reference ); + + if ( frameMap.get( reference ) !== this.frameId ) { + + if ( node.updateBefore( this ) !== false ) { + + frameMap.set( reference, this.frameId ); + + } + + } + + } else if ( updateType === NodeUpdateType.RENDER ) { + + const { renderMap } = this._getMaps( this.updateBeforeMap, reference ); + + if ( renderMap.get( reference ) !== this.renderId ) { + + if ( node.updateBefore( this ) !== false ) { + + renderMap.set( reference, this.renderId ); + + } + + } + + } else if ( updateType === NodeUpdateType.OBJECT ) { + + node.updateBefore( this ); + + } + + } + + updateAfterNode( node ) { + + const updateType = node.getUpdateAfterType(); + const reference = node.updateReference( this ); + + if ( updateType === NodeUpdateType.FRAME ) { + + const { frameMap } = this._getMaps( this.updateAfterMap, reference ); + + if ( frameMap.get( reference ) !== this.frameId ) { + + if ( node.updateAfter( this ) !== false ) { + + frameMap.set( reference, this.frameId ); + + } + + } + + } else if ( updateType === NodeUpdateType.RENDER ) { + + const { renderMap } = this._getMaps( this.updateAfterMap, reference ); + + if ( renderMap.get( reference ) !== this.renderId ) { + + if ( node.updateAfter( this ) !== false ) { + + renderMap.set( reference, this.renderId ); + + } + + } + + } else if ( updateType === NodeUpdateType.OBJECT ) { + + node.updateAfter( this ); + + } + + } + + updateNode( node ) { + + const updateType = node.getUpdateType(); + const reference = node.updateReference( this ); + + if ( updateType === NodeUpdateType.FRAME ) { + + const { frameMap } = this._getMaps( this.updateMap, reference ); + + if ( frameMap.get( reference ) !== this.frameId ) { + + if ( node.update( this ) !== false ) { + + frameMap.set( reference, this.frameId ); + + } + + } + + } else if ( updateType === NodeUpdateType.RENDER ) { + + const { renderMap } = this._getMaps( this.updateMap, reference ); + + if ( renderMap.get( reference ) !== this.renderId ) { + + if ( node.update( this ) !== false ) { + + renderMap.set( reference, this.renderId ); + + } + + } + + } else if ( updateType === NodeUpdateType.OBJECT ) { + + node.update( this ); + + } + + } + + update() { + + this.frameId ++; + + if ( this.lastTime === undefined ) this.lastTime = performance.now(); + + this.deltaTime = ( performance.now() - this.lastTime ) / 1000; + + this.lastTime = performance.now(); + + this.time += this.deltaTime; + + } + +} + +class NodeFunctionInput { + + constructor( type, name, count = null, qualifier = '', isConst = false ) { + + this.type = type; + this.name = name; + this.count = count; + this.qualifier = qualifier; + this.isConst = isConst; + + } + +} + +NodeFunctionInput.isNodeFunctionInput = true; + +class StructTypeNode extends Node { + + static get type() { + + return 'StructTypeNode'; + + } + + constructor( types ) { + + super(); + + this.types = types; + this.isStructTypeNode = true; + + } + + getMemberTypes() { + + return this.types; + + } + +} + +class OutputStructNode extends Node { + + static get type() { + + return 'OutputStructNode'; + + } + + constructor( ...members ) { + + super(); + + this.members = members; + + this.isOutputStructNode = true; + + } + + setup( builder ) { + + super.setup( builder ); + + const members = this.members; + const types = []; + + for ( let i = 0; i < members.length; i ++ ) { + + types.push( members[ i ].getNodeType( builder ) ); + + } + + this.nodeType = builder.getStructTypeFromNode( new StructTypeNode( types ) ).name; + + } + + generate( builder, output ) { + + const propertyName = builder.getOutputStructName(); + const members = this.members; + + const structPrefix = propertyName !== '' ? propertyName + '.' : ''; + + for ( let i = 0; i < members.length; i ++ ) { + + const snippet = members[ i ].build( builder, output ); + + builder.addLineFlowCode( `${ structPrefix }m${ i } = ${ snippet }`, this ); + + } + + return propertyName; + + } + +} + +const outputStruct = /*@__PURE__*/ nodeProxy( OutputStructNode ); + +function getTextureIndex( textures, name ) { + + for ( let i = 0; i < textures.length; i ++ ) { + + if ( textures[ i ].name === name ) { + + return i; + + } + + } + + return - 1; + +} + +class MRTNode extends OutputStructNode { + + static get type() { + + return 'MRTNode'; + + } + + constructor( outputNodes ) { + + super(); + + this.outputNodes = outputNodes; + + this.isMRTNode = true; + + } + + has( name ) { + + return this.outputNodes[ name ] !== undefined; + + } + + get( name ) { + + return this.outputNodes[ name ]; + + } + + merge( mrtNode ) { + + const outputs = { ...this.outputNodes, ...mrtNode.outputNodes }; + + return mrt( outputs ); + + } + + setup( builder ) { + + const outputNodes = this.outputNodes; + const mrt = builder.renderer.getRenderTarget(); + + const members = []; + + const textures = mrt.textures; + + for ( const name in outputNodes ) { + + const index = getTextureIndex( textures, name ); + + members[ index ] = vec4( outputNodes[ name ] ); + + } + + this.members = members; + + return super.setup( builder ); + + } + +} + +const mrt = /*@__PURE__*/ nodeProxy( MRTNode ); + +class FunctionOverloadingNode extends Node { + + static get type() { + + return 'FunctionOverloadingNode'; + + } + + constructor( functionNodes = [], ...parametersNodes ) { + + super(); + + this.functionNodes = functionNodes; + this.parametersNodes = parametersNodes; + + this._candidateFnCall = null; + + this.global = true; + + } + + getNodeType() { + + return this.functionNodes[ 0 ].shaderNode.layout.type; + + } + + setup( builder ) { + + const params = this.parametersNodes; + + let candidateFnCall = this._candidateFnCall; + + if ( candidateFnCall === null ) { + + let candidateFn = null; + let candidateScore = - 1; + + for ( const functionNode of this.functionNodes ) { + + const shaderNode = functionNode.shaderNode; + const layout = shaderNode.layout; + + if ( layout === null ) { + + throw new Error( 'FunctionOverloadingNode: FunctionNode must be a layout.' ); + + } + + const inputs = layout.inputs; + + if ( params.length === inputs.length ) { + + let score = 0; + + for ( let i = 0; i < params.length; i ++ ) { + + const param = params[ i ]; + const input = inputs[ i ]; + + if ( param.getNodeType( builder ) === input.type ) { + + score ++; + + } else { + + score = 0; + + } + + } + + if ( score > candidateScore ) { + + candidateFn = functionNode; + candidateScore = score; + + } + + } + + } + + this._candidateFnCall = candidateFnCall = candidateFn( ...params ); + + } + + return candidateFnCall; + + } + +} + +const overloadingBaseFn = /*@__PURE__*/ nodeProxy( FunctionOverloadingNode ); + +const overloadingFn = ( functionNodes ) => ( ...params ) => overloadingBaseFn( functionNodes, ...params ); + +class TimerNode extends UniformNode { + + static get type() { + + return 'TimerNode'; + + } + + constructor( scope = TimerNode.LOCAL, scale = 1, value = 0 ) { + + super( value ); + + this.scope = scope; + this.scale = scale; + + this.updateType = NodeUpdateType.FRAME; + + } + /* + @TODO: + getNodeType( builder ) { + + const scope = this.scope; + + if ( scope === TimerNode.FRAME ) { + + return 'uint'; + + } + + return 'float'; + + } +*/ + update( frame ) { + + const scope = this.scope; + const scale = this.scale; + + if ( scope === TimerNode.LOCAL ) { + + this.value += frame.deltaTime * scale; + + } else if ( scope === TimerNode.DELTA ) { + + this.value = frame.deltaTime * scale; + + } else if ( scope === TimerNode.FRAME ) { + + this.value = frame.frameId; + + } else { + + // global + + this.value = frame.time * scale; + + } + + } + + serialize( data ) { + + super.serialize( data ); + + data.scope = this.scope; + data.scale = this.scale; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.scope = data.scope; + this.scale = data.scale; + + } + +} + +TimerNode.LOCAL = 'local'; +TimerNode.GLOBAL = 'global'; +TimerNode.DELTA = 'delta'; +TimerNode.FRAME = 'frame'; + +// @TODO: add support to use node in timeScale +const timerLocal = ( timeScale, value = 0 ) => nodeObject( new TimerNode( TimerNode.LOCAL, timeScale, value ) ); +const timerGlobal = ( timeScale, value = 0 ) => nodeObject( new TimerNode( TimerNode.GLOBAL, timeScale, value ) ); +const timerDelta = ( timeScale, value = 0 ) => nodeObject( new TimerNode( TimerNode.DELTA, timeScale, value ) ); +const frameId = /*@__PURE__*/ nodeImmutable( TimerNode, TimerNode.FRAME ).toUint(); + +class OscNode extends Node { + + static get type() { + + return 'OscNode'; + + } + + constructor( method = OscNode.SINE, timeNode = timerLocal() ) { + + super(); + + this.method = method; + this.timeNode = timeNode; + + } + + getNodeType( builder ) { + + return this.timeNode.getNodeType( builder ); + + } + + setup() { + + const method = this.method; + const timeNode = nodeObject( this.timeNode ); + + let outputNode = null; + + if ( method === OscNode.SINE ) { + + outputNode = timeNode.add( 0.75 ).mul( Math.PI * 2 ).sin().mul( 0.5 ).add( 0.5 ); + + } else if ( method === OscNode.SQUARE ) { + + outputNode = timeNode.fract().round(); + + } else if ( method === OscNode.TRIANGLE ) { + + outputNode = timeNode.add( 0.5 ).fract().mul( 2 ).sub( 1 ).abs(); + + } else if ( method === OscNode.SAWTOOTH ) { + + outputNode = timeNode.fract(); + + } + + return outputNode; + + } + + serialize( data ) { + + super.serialize( data ); + + data.method = this.method; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.method = data.method; + + } + +} + +OscNode.SINE = 'sine'; +OscNode.SQUARE = 'square'; +OscNode.TRIANGLE = 'triangle'; +OscNode.SAWTOOTH = 'sawtooth'; + +const oscSine = /*@__PURE__*/ nodeProxy( OscNode, OscNode.SINE ); +const oscSquare = /*@__PURE__*/ nodeProxy( OscNode, OscNode.SQUARE ); +const oscTriangle = /*@__PURE__*/ nodeProxy( OscNode, OscNode.TRIANGLE ); +const oscSawtooth = /*@__PURE__*/ nodeProxy( OscNode, OscNode.SAWTOOTH ); + +class SpriteSheetUVNode extends Node { + + static get type() { + + return 'SpriteSheetUVNode'; + + } + + constructor( countNode, uvNode = uv(), frameNode = float( 0 ) ) { + + super( 'vec2' ); + + this.countNode = countNode; + this.uvNode = uvNode; + this.frameNode = frameNode; + + } + + setup() { + + const { frameNode, uvNode, countNode } = this; + + const { width, height } = countNode; + + const frameNum = frameNode.mod( width.mul( height ) ).floor(); + + const column = frameNum.mod( width ); + const row = height.sub( frameNum.add( 1 ).div( width ).ceil() ); + + const scale = countNode.reciprocal(); + const uvFrameOffset = vec2( column, row ); + + return uvNode.add( uvFrameOffset ).mul( scale ); + + } + +} + +const spritesheetUV = /*@__PURE__*/ nodeProxy( SpriteSheetUVNode ); + +class StorageArrayElementNode extends ArrayElementNode { + + static get type() { + + return 'StorageArrayElementNode'; + + } + + constructor( storageBufferNode, indexNode ) { + + super( storageBufferNode, indexNode ); + + this.isStorageArrayElementNode = true; + + } + + set storageBufferNode( value ) { + + this.node = value; + + } + + get storageBufferNode() { + + return this.node; + + } + + setup( builder ) { + + if ( builder.isAvailable( 'storageBuffer' ) === false ) { + + if ( this.node.bufferObject === true ) { + + builder.setupPBO( this.node ); + + } + + } + + return super.setup( builder ); + + } + + generate( builder, output ) { + + let snippet; + + const isAssignContext = builder.context.assign; + + // + + if ( builder.isAvailable( 'storageBuffer' ) === false ) { + + if ( this.node.bufferObject === true && isAssignContext !== true ) { + + snippet = builder.generatePBO( this ); + + } else { + + snippet = this.node.build( builder ); + + } + + } else { + + snippet = super.generate( builder ); + + } + + if ( isAssignContext !== true ) { + + const type = this.getNodeType( builder ); + + snippet = builder.format( snippet, type, output ); + + } + + return snippet; + + } + +} + +const storageElement = /*@__PURE__*/ nodeProxy( StorageArrayElementNode ); + +class TriplanarTexturesNode extends Node { + + static get type() { + + return 'TriplanarTexturesNode'; + + } + + constructor( textureXNode, textureYNode = null, textureZNode = null, scaleNode = float( 1 ), positionNode = positionLocal, normalNode = normalLocal ) { + + super( 'vec4' ); + + this.textureXNode = textureXNode; + this.textureYNode = textureYNode; + this.textureZNode = textureZNode; + + this.scaleNode = scaleNode; + + this.positionNode = positionNode; + this.normalNode = normalNode; + + } + + setup() { + + const { textureXNode, textureYNode, textureZNode, scaleNode, positionNode, normalNode } = this; + + // Ref: https://github.com/keijiro/StandardTriplanar + + // Blending factor of triplanar mapping + let bf = normalNode.abs().normalize(); + bf = bf.div( bf.dot( vec3( 1.0 ) ) ); + + // Triplanar mapping + const tx = positionNode.yz.mul( scaleNode ); + const ty = positionNode.zx.mul( scaleNode ); + const tz = positionNode.xy.mul( scaleNode ); + + // Base color + const textureX = textureXNode.value; + const textureY = textureYNode !== null ? textureYNode.value : textureX; + const textureZ = textureZNode !== null ? textureZNode.value : textureX; + + const cx = texture( textureX, tx ).mul( bf.x ); + const cy = texture( textureY, ty ).mul( bf.y ); + const cz = texture( textureZ, tz ).mul( bf.z ); + + return add( cx, cy, cz ); + + } + +} + +const triplanarTextures = /*@__PURE__*/ nodeProxy( TriplanarTexturesNode ); +const triplanarTexture = ( ...params ) => triplanarTextures( ...params ); + +const _reflectorPlane = new Plane(); +const _normal = new Vector3(); +const _reflectorWorldPosition = new Vector3(); +const _cameraWorldPosition = new Vector3(); +const _rotationMatrix = new Matrix4(); +const _lookAtPosition = new Vector3( 0, 0, - 1 ); +const clipPlane = new Vector4(); + +const _view = new Vector3(); +const _target = new Vector3(); +const _q = new Vector4(); + +const _size$9 = new Vector2(); + +const _defaultRT = new RenderTarget(); +const _defaultUV = screenUV.flipX(); + +let _inReflector = false; + +class ReflectorNode extends TextureNode { + + static get type() { + + return 'ReflectorNode'; + + } + + constructor( parameters = {} ) { + + super( _defaultRT.texture, _defaultUV ); + + const { + target = new Object3D(), + resolution = 1, + generateMipmaps = false, + bounces = true + } = parameters; + + // + + this.target = target; + this.resolution = resolution; + this.generateMipmaps = generateMipmaps; + this.bounces = bounces; + + this.updateBeforeType = bounces ? NodeUpdateType.RENDER : NodeUpdateType.FRAME; + + this.virtualCameras = new WeakMap(); + this.renderTargets = new WeakMap(); + + + } + + _updateResolution( renderTarget, renderer ) { + + const resolution = this.resolution; + + renderer.getDrawingBufferSize( _size$9 ); + + renderTarget.setSize( Math.round( _size$9.width * resolution ), Math.round( _size$9.height * resolution ) ); + + } + + setup( builder ) { + + this._updateResolution( _defaultRT, builder.renderer ); + + return super.setup( builder ); + + } + + getTextureNode() { + + return this.textureNode; + + } + + getVirtualCamera( camera ) { + + let virtualCamera = this.virtualCameras.get( camera ); + + if ( virtualCamera === undefined ) { + + virtualCamera = camera.clone(); + + this.virtualCameras.set( camera, virtualCamera ); + + } + + return virtualCamera; + + } + + getRenderTarget( camera ) { + + let renderTarget = this.renderTargets.get( camera ); + + if ( renderTarget === undefined ) { + + renderTarget = new RenderTarget( 0, 0, { type: HalfFloatType } ); + + if ( this.generateMipmaps === true ) { + + renderTarget.texture.minFilter = LinearMipMapLinearFilter; + renderTarget.texture.generateMipmaps = true; + + } + + this.renderTargets.set( camera, renderTarget ); + + } + + return renderTarget; + + } + + updateBefore( frame ) { + + if ( this.bounces === false && _inReflector ) return false; + + _inReflector = true; + + const { scene, camera, renderer, material } = frame; + const { target } = this; + + const virtualCamera = this.getVirtualCamera( camera ); + const renderTarget = this.getRenderTarget( virtualCamera ); + + renderer.getDrawingBufferSize( _size$9 ); + + this._updateResolution( renderTarget, renderer ); + + // + + _reflectorWorldPosition.setFromMatrixPosition( target.matrixWorld ); + _cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld ); + + _rotationMatrix.extractRotation( target.matrixWorld ); + + _normal.set( 0, 0, 1 ); + _normal.applyMatrix4( _rotationMatrix ); + + _view.subVectors( _reflectorWorldPosition, _cameraWorldPosition ); + + // Avoid rendering when reflector is facing away + + if ( _view.dot( _normal ) > 0 ) return; + + _view.reflect( _normal ).negate(); + _view.add( _reflectorWorldPosition ); + + _rotationMatrix.extractRotation( camera.matrixWorld ); + + _lookAtPosition.set( 0, 0, - 1 ); + _lookAtPosition.applyMatrix4( _rotationMatrix ); + _lookAtPosition.add( _cameraWorldPosition ); + + _target.subVectors( _reflectorWorldPosition, _lookAtPosition ); + _target.reflect( _normal ).negate(); + _target.add( _reflectorWorldPosition ); + + // + + virtualCamera.coordinateSystem = camera.coordinateSystem; + virtualCamera.position.copy( _view ); + virtualCamera.up.set( 0, 1, 0 ); + virtualCamera.up.applyMatrix4( _rotationMatrix ); + virtualCamera.up.reflect( _normal ); + virtualCamera.lookAt( _target ); + + virtualCamera.near = camera.near; + virtualCamera.far = camera.far; + + virtualCamera.updateMatrixWorld(); + virtualCamera.projectionMatrix.copy( camera.projectionMatrix ); + + // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html + // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf + _reflectorPlane.setFromNormalAndCoplanarPoint( _normal, _reflectorWorldPosition ); + _reflectorPlane.applyMatrix4( virtualCamera.matrixWorldInverse ); + + clipPlane.set( _reflectorPlane.normal.x, _reflectorPlane.normal.y, _reflectorPlane.normal.z, _reflectorPlane.constant ); + + const projectionMatrix = virtualCamera.projectionMatrix; + + _q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ]; + _q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ]; + _q.z = - 1.0; + _q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ]; + + // Calculate the scaled plane vector + clipPlane.multiplyScalar( 1.0 / clipPlane.dot( _q ) ); + + const clipBias = 0; + + // Replacing the third row of the projection matrix + projectionMatrix.elements[ 2 ] = clipPlane.x; + projectionMatrix.elements[ 6 ] = clipPlane.y; + projectionMatrix.elements[ 10 ] = clipPlane.z - clipBias; + projectionMatrix.elements[ 14 ] = clipPlane.w; + + // + + this.value = renderTarget.texture; + + material.visible = false; + + const currentRenderTarget = renderer.getRenderTarget(); + const currentMRT = renderer.getMRT(); + + renderer.setMRT( null ); + renderer.setRenderTarget( renderTarget ); + + renderer.render( scene, virtualCamera ); + + renderer.setMRT( currentMRT ); + renderer.setRenderTarget( currentRenderTarget ); + + material.visible = true; + + _inReflector = false; + + } + +} + +const reflector = ( parameters ) => nodeObject( new ReflectorNode( parameters ) ); + +// Helper for passes that need to fill the viewport with a single quad. + +const _camera = /*@__PURE__*/ new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); + +// https://github.com/mrdoob/three.js/pull/21358 + +class QuadGeometry extends BufferGeometry { + + constructor( flipY = false ) { + + super(); + + const uv = flipY === false ? [ 0, - 1, 0, 1, 2, 1 ] : [ 0, 2, 0, 0, 2, 0 ]; + + this.setAttribute( 'position', new Float32BufferAttribute( [ - 1, 3, 0, - 1, - 1, 0, 3, - 1, 0 ], 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uv, 2 ) ); + + } + +} + +const _geometry = /*@__PURE__*/ new QuadGeometry(); + +class QuadMesh extends Mesh { + + constructor( material = null ) { + + super( _geometry, material ); + + this.camera = _camera; + + this.isQuadMesh = true; + + } + + renderAsync( renderer ) { + + return renderer.renderAsync( this, _camera ); + + } + + render( renderer ) { + + renderer.render( this, _camera ); + + } + +} + +const _size$8 = /*@__PURE__*/ new Vector2(); + +class RTTNode extends TextureNode { + + static get type() { + + return 'RTTNode'; + + } + + constructor( node, width = null, height = null, options = { type: HalfFloatType } ) { + + const renderTarget = new RenderTarget( width, height, options ); + + super( renderTarget.texture, uv() ); + + this.node = node; + this.width = width; + this.height = height; + + this.renderTarget = renderTarget; + + this.textureNeedsUpdate = true; + this.autoUpdate = true; + + this.updateMap = new WeakMap(); + + this._rttNode = null; + this._quadMesh = new QuadMesh( new NodeMaterial() ); + + this.updateBeforeType = NodeUpdateType.RENDER; + + } + + get autoSize() { + + return this.width === null; + + } + + setup( builder ) { + + this._rttNode = this.node.context( builder.getSharedContext() ); + this._quadMesh.material.name = 'RTT'; + this._quadMesh.material.needsUpdate = true; + + return super.setup( builder ); + + } + + setSize( width, height ) { + + this.width = width; + this.height = height; + + const effectiveWidth = width * this.pixelRatio; + const effectiveHeight = height * this.pixelRatio; + + this.renderTarget.setSize( effectiveWidth, effectiveHeight ); + + this.textureNeedsUpdate = true; + + } + + setPixelRatio( pixelRatio ) { + + this.pixelRatio = pixelRatio; + + this.setSize( this.width, this.height ); + + } + + updateBefore( { renderer } ) { + + if ( this.textureNeedsUpdate === false && this.autoUpdate === false ) return; + + this.textureNeedsUpdate = false; + + // + + if ( this.autoSize === true ) { + + this.pixelRatio = renderer.getPixelRatio(); + + const size = renderer.getSize( _size$8 ); + + this.setSize( size.width, size.height ); + + } + + // + + this._quadMesh.material.fragmentNode = this._rttNode; + + // + + const currentRenderTarget = renderer.getRenderTarget(); + + renderer.setRenderTarget( this.renderTarget ); + + this._quadMesh.render( renderer ); + + renderer.setRenderTarget( currentRenderTarget ); + + } + + clone() { + + const newNode = new TextureNode( this.value, this.uvNode, this.levelNode ); + newNode.sampler = this.sampler; + newNode.referenceNode = this; + + return newNode; + + } + +} + +const rtt = ( node, ...params ) => nodeObject( new RTTNode( nodeObject( node ), ...params ) ); +const convertToTexture = ( node, ...params ) => node.isTextureNode ? node : rtt( node, ...params ); + +class VertexColorNode extends AttributeNode { + + static get type() { + + return 'VertexColorNode'; + + } + + constructor( index = 0 ) { + + super( null, 'vec4' ); + + this.isVertexColorNode = true; + + this.index = index; + + } + + getAttributeName( /*builder*/ ) { + + const index = this.index; + + return 'color' + ( index > 0 ? index : '' ); + + } + + generate( builder ) { + + const attributeName = this.getAttributeName( builder ); + const geometryAttribute = builder.hasGeometryAttribute( attributeName ); + + let result; + + if ( geometryAttribute === true ) { + + result = super.generate( builder ); + + } else { + + // Vertex color fallback should be white + result = builder.generateConst( this.nodeType, new Vector4( 1, 1, 1, 1 ) ); + + } + + return result; + + } + + serialize( data ) { + + super.serialize( data ); + + data.index = this.index; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.index = data.index; + + } + +} + +const vertexColor = ( ...params ) => nodeObject( new VertexColorNode( ...params ) ); + +class PointUVNode extends Node { + + static get type() { + + return 'PointUVNode'; + + } + + constructor() { + + super( 'vec2' ); + + this.isPointUVNode = true; + + } + + generate( /*builder*/ ) { + + return 'vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )'; + + } + +} + +const pointUV = /*@__PURE__*/ nodeImmutable( PointUVNode ); + +class SceneNode extends Node { + + static get type() { + + return 'SceneNode'; + + } + + constructor( scope = SceneNode.BACKGROUND_BLURRINESS, scene = null ) { + + super(); + + this.scope = scope; + this.scene = scene; + + } + + setup( builder ) { + + const scope = this.scope; + const scene = this.scene !== null ? this.scene : builder.scene; + + let output; + + if ( scope === SceneNode.BACKGROUND_BLURRINESS ) { + + output = reference( 'backgroundBlurriness', 'float', scene ); + + } else if ( scope === SceneNode.BACKGROUND_INTENSITY ) { + + output = reference( 'backgroundIntensity', 'float', scene ); + + } else { + + console.error( 'THREE.SceneNode: Unknown scope:', scope ); + + } + + return output; + + } + +} + +SceneNode.BACKGROUND_BLURRINESS = 'backgroundBlurriness'; +SceneNode.BACKGROUND_INTENSITY = 'backgroundIntensity'; + +const backgroundBlurriness = /*@__PURE__*/ nodeImmutable( SceneNode, SceneNode.BACKGROUND_BLURRINESS ); +const backgroundIntensity = /*@__PURE__*/ nodeImmutable( SceneNode, SceneNode.BACKGROUND_INTENSITY ); + +const GPUPrimitiveTopology = { + PointList: 'point-list', + LineList: 'line-list', + LineStrip: 'line-strip', + TriangleList: 'triangle-list', + TriangleStrip: 'triangle-strip', +}; + +const GPUCompareFunction = { + Never: 'never', + Less: 'less', + Equal: 'equal', + LessEqual: 'less-equal', + Greater: 'greater', + NotEqual: 'not-equal', + GreaterEqual: 'greater-equal', + Always: 'always' +}; + +const GPUStoreOp = { + Store: 'store', + Discard: 'discard' +}; + +const GPULoadOp = { + Load: 'load', + Clear: 'clear' +}; + +const GPUFrontFace = { + CCW: 'ccw', + CW: 'cw' +}; + +const GPUCullMode = { + None: 'none', + Front: 'front', + Back: 'back' +}; + +const GPUIndexFormat = { + Uint16: 'uint16', + Uint32: 'uint32' +}; + +const GPUTextureFormat = { + + // 8-bit formats + + R8Unorm: 'r8unorm', + R8Snorm: 'r8snorm', + R8Uint: 'r8uint', + R8Sint: 'r8sint', + + // 16-bit formats + + R16Uint: 'r16uint', + R16Sint: 'r16sint', + R16Float: 'r16float', + RG8Unorm: 'rg8unorm', + RG8Snorm: 'rg8snorm', + RG8Uint: 'rg8uint', + RG8Sint: 'rg8sint', + + // 32-bit formats + + R32Uint: 'r32uint', + R32Sint: 'r32sint', + R32Float: 'r32float', + RG16Uint: 'rg16uint', + RG16Sint: 'rg16sint', + RG16Float: 'rg16float', + RGBA8Unorm: 'rgba8unorm', + RGBA8UnormSRGB: 'rgba8unorm-srgb', + RGBA8Snorm: 'rgba8snorm', + RGBA8Uint: 'rgba8uint', + RGBA8Sint: 'rgba8sint', + BGRA8Unorm: 'bgra8unorm', + BGRA8UnormSRGB: 'bgra8unorm-srgb', + // Packed 32-bit formats + RGB9E5UFloat: 'rgb9e5ufloat', + RGB10A2Unorm: 'rgb10a2unorm', + RG11B10uFloat: 'rgb10a2unorm', + + // 64-bit formats + + RG32Uint: 'rg32uint', + RG32Sint: 'rg32sint', + RG32Float: 'rg32float', + RGBA16Uint: 'rgba16uint', + RGBA16Sint: 'rgba16sint', + RGBA16Float: 'rgba16float', + + // 128-bit formats + + RGBA32Uint: 'rgba32uint', + RGBA32Sint: 'rgba32sint', + RGBA32Float: 'rgba32float', + + // Depth and stencil formats + + Stencil8: 'stencil8', + Depth16Unorm: 'depth16unorm', + Depth24Plus: 'depth24plus', + Depth24PlusStencil8: 'depth24plus-stencil8', + Depth32Float: 'depth32float', + + // 'depth32float-stencil8' extension + + Depth32FloatStencil8: 'depth32float-stencil8', + + // BC compressed formats usable if 'texture-compression-bc' is both + // supported by the device/user agent and enabled in requestDevice. + + BC1RGBAUnorm: 'bc1-rgba-unorm', + BC1RGBAUnormSRGB: 'bc1-rgba-unorm-srgb', + BC2RGBAUnorm: 'bc2-rgba-unorm', + BC2RGBAUnormSRGB: 'bc2-rgba-unorm-srgb', + BC3RGBAUnorm: 'bc3-rgba-unorm', + BC3RGBAUnormSRGB: 'bc3-rgba-unorm-srgb', + BC4RUnorm: 'bc4-r-unorm', + BC4RSnorm: 'bc4-r-snorm', + BC5RGUnorm: 'bc5-rg-unorm', + BC5RGSnorm: 'bc5-rg-snorm', + BC6HRGBUFloat: 'bc6h-rgb-ufloat', + BC6HRGBFloat: 'bc6h-rgb-float', + BC7RGBAUnorm: 'bc7-rgba-unorm', + BC7RGBAUnormSRGB: 'bc7-rgba-srgb', + + // ETC2 compressed formats usable if 'texture-compression-etc2' is both + // supported by the device/user agent and enabled in requestDevice. + + ETC2RGB8Unorm: 'etc2-rgb8unorm', + ETC2RGB8UnormSRGB: 'etc2-rgb8unorm-srgb', + ETC2RGB8A1Unorm: 'etc2-rgb8a1unorm', + ETC2RGB8A1UnormSRGB: 'etc2-rgb8a1unorm-srgb', + ETC2RGBA8Unorm: 'etc2-rgba8unorm', + ETC2RGBA8UnormSRGB: 'etc2-rgba8unorm-srgb', + EACR11Unorm: 'eac-r11unorm', + EACR11Snorm: 'eac-r11snorm', + EACRG11Unorm: 'eac-rg11unorm', + EACRG11Snorm: 'eac-rg11snorm', + + // ASTC compressed formats usable if 'texture-compression-astc' is both + // supported by the device/user agent and enabled in requestDevice. + + ASTC4x4Unorm: 'astc-4x4-unorm', + ASTC4x4UnormSRGB: 'astc-4x4-unorm-srgb', + ASTC5x4Unorm: 'astc-5x4-unorm', + ASTC5x4UnormSRGB: 'astc-5x4-unorm-srgb', + ASTC5x5Unorm: 'astc-5x5-unorm', + ASTC5x5UnormSRGB: 'astc-5x5-unorm-srgb', + ASTC6x5Unorm: 'astc-6x5-unorm', + ASTC6x5UnormSRGB: 'astc-6x5-unorm-srgb', + ASTC6x6Unorm: 'astc-6x6-unorm', + ASTC6x6UnormSRGB: 'astc-6x6-unorm-srgb', + ASTC8x5Unorm: 'astc-8x5-unorm', + ASTC8x5UnormSRGB: 'astc-8x5-unorm-srgb', + ASTC8x6Unorm: 'astc-8x6-unorm', + ASTC8x6UnormSRGB: 'astc-8x6-unorm-srgb', + ASTC8x8Unorm: 'astc-8x8-unorm', + ASTC8x8UnormSRGB: 'astc-8x8-unorm-srgb', + ASTC10x5Unorm: 'astc-10x5-unorm', + ASTC10x5UnormSRGB: 'astc-10x5-unorm-srgb', + ASTC10x6Unorm: 'astc-10x6-unorm', + ASTC10x6UnormSRGB: 'astc-10x6-unorm-srgb', + ASTC10x8Unorm: 'astc-10x8-unorm', + ASTC10x8UnormSRGB: 'astc-10x8-unorm-srgb', + ASTC10x10Unorm: 'astc-10x10-unorm', + ASTC10x10UnormSRGB: 'astc-10x10-unorm-srgb', + ASTC12x10Unorm: 'astc-12x10-unorm', + ASTC12x10UnormSRGB: 'astc-12x10-unorm-srgb', + ASTC12x12Unorm: 'astc-12x12-unorm', + ASTC12x12UnormSRGB: 'astc-12x12-unorm-srgb', + +}; + +const GPUAddressMode = { + ClampToEdge: 'clamp-to-edge', + Repeat: 'repeat', + MirrorRepeat: 'mirror-repeat' +}; + +const GPUFilterMode = { + Linear: 'linear', + Nearest: 'nearest' +}; + +const GPUBlendFactor = { + Zero: 'zero', + One: 'one', + Src: 'src', + OneMinusSrc: 'one-minus-src', + SrcAlpha: 'src-alpha', + OneMinusSrcAlpha: 'one-minus-src-alpha', + Dst: 'dst', + OneMinusDstColor: 'one-minus-dst', + DstAlpha: 'dst-alpha', + OneMinusDstAlpha: 'one-minus-dst-alpha', + SrcAlphaSaturated: 'src-alpha-saturated', + Constant: 'constant', + OneMinusConstant: 'one-minus-constant' +}; + +const GPUBlendOperation = { + Add: 'add', + Subtract: 'subtract', + ReverseSubtract: 'reverse-subtract', + Min: 'min', + Max: 'max' +}; + +const GPUColorWriteFlags = { + None: 0, + Red: 0x1, + Green: 0x2, + Blue: 0x4, + Alpha: 0x8, + All: 0xF +}; + +const GPUStencilOperation = { + Keep: 'keep', + Zero: 'zero', + Replace: 'replace', + Invert: 'invert', + IncrementClamp: 'increment-clamp', + DecrementClamp: 'decrement-clamp', + IncrementWrap: 'increment-wrap', + DecrementWrap: 'decrement-wrap' +}; + +const GPUBufferBindingType = { + Uniform: 'uniform', + Storage: 'storage', + ReadOnlyStorage: 'read-only-storage' +}; + +const GPUStorageTextureAccess = { + WriteOnly: 'write-only', + ReadOnly: 'read-only', + ReadWrite: 'read-write', +}; + +const GPUTextureSampleType = { + Float: 'float', + UnfilterableFloat: 'unfilterable-float', + Depth: 'depth', + SInt: 'sint', + UInt: 'uint' +}; + +const GPUTextureDimension = { + OneD: '1d', + TwoD: '2d', + ThreeD: '3d' +}; + +const GPUTextureViewDimension = { + OneD: '1d', + TwoD: '2d', + TwoDArray: '2d-array', + Cube: 'cube', + CubeArray: 'cube-array', + ThreeD: '3d' +}; + +const GPUTextureAspect = { + All: 'all', + StencilOnly: 'stencil-only', + DepthOnly: 'depth-only' +}; + +const GPUInputStepMode = { + Vertex: 'vertex', + Instance: 'instance' +}; + +const GPUFeatureName = { + DepthClipControl: 'depth-clip-control', + Depth32FloatStencil8: 'depth32float-stencil8', + TextureCompressionBC: 'texture-compression-bc', + TextureCompressionETC2: 'texture-compression-etc2', + TextureCompressionASTC: 'texture-compression-astc', + TimestampQuery: 'timestamp-query', + IndirectFirstInstance: 'indirect-first-instance', + ShaderF16: 'shader-f16', + RG11B10UFloat: 'rg11b10ufloat-renderable', + BGRA8UNormStorage: 'bgra8unorm-storage', + Float32Filterable: 'float32-filterable', + ClipDistances: 'clip-distances', + DualSourceBlending: 'dual-source-blending', + Subgroups: 'subgroups' +}; + +class StorageBufferNode extends BufferNode { + + static get type() { + + return 'StorageBufferNode'; + + } + + constructor( value, bufferType, bufferCount = 0 ) { + + super( value, bufferType, bufferCount ); + + this.isStorageBufferNode = true; + + this.access = GPUBufferBindingType.Storage; + this.isAtomic = false; + + this.bufferObject = false; + this.bufferCount = bufferCount; + + this._attribute = null; + this._varying = null; + + this.global = true; + + if ( value.isStorageBufferAttribute !== true && value.isStorageInstancedBufferAttribute !== true ) { + + // TOOD: Improve it, possibly adding a new property to the BufferAttribute to identify it as a storage buffer read-only attribute in Renderer + + if ( value.isInstancedBufferAttribute ) value.isStorageInstancedBufferAttribute = true; + else value.isStorageBufferAttribute = true; + + } + + } + + getHash( builder ) { + + if ( this.bufferCount === 0 ) { + + let bufferData = builder.globalCache.getData( this.value ); + + if ( bufferData === undefined ) { + + bufferData = { + node: this + }; + + builder.globalCache.setData( this.value, bufferData ); + + } + + return bufferData.node.uuid; + + } + + return this.uuid; + + } + + getInputType( /*builder*/ ) { + + return 'storageBuffer'; + + } + + element( indexNode ) { + + return storageElement( this, indexNode ); + + } + + setBufferObject( value ) { + + this.bufferObject = value; + + return this; + + } + + setAccess( value ) { + + this.access = value; + + return this; + + } + + toReadOnly() { + + return this.setAccess( GPUBufferBindingType.ReadOnlyStorage ); + + } + + setAtomic( value ) { + + this.isAtomic = value; + + return this; + + } + + toAtomic() { + + return this.setAtomic( true ); + + } + + generate( builder ) { + + if ( builder.isAvailable( 'storageBuffer' ) ) { + + return super.generate( builder ); + + } + + const nodeType = this.getNodeType( builder ); + + if ( this._attribute === null ) { + + this._attribute = bufferAttribute( this.value ); + this._varying = varying( this._attribute ); + + } + + + const output = this._varying.build( builder, nodeType ); + + builder.registerTransform( output, this._attribute ); + + return output; + + } + +} + +// Read-Write Storage +const storage = ( value, type, count ) => nodeObject( new StorageBufferNode( value, type, count ) ); +const storageObject = ( value, type, count ) => nodeObject( new StorageBufferNode( value, type, count ).setBufferObject( true ) ); + +class StorageTextureNode extends TextureNode { + + static get type() { + + return 'StorageTextureNode'; + + } + + constructor( value, uvNode, storeNode = null ) { + + super( value, uvNode ); + + this.storeNode = storeNode; + + this.isStorageTextureNode = true; + + this.access = GPUStorageTextureAccess.WriteOnly; + + } + + getInputType( /*builder*/ ) { + + return 'storageTexture'; + + } + + setup( builder ) { + + super.setup( builder ); + + const properties = builder.getNodeProperties( this ); + properties.storeNode = this.storeNode; + + } + + setAccess( value ) { + + this.access = value; + return this; + + } + + generate( builder, output ) { + + let snippet; + + if ( this.storeNode !== null ) { + + snippet = this.generateStore( builder ); + + } else { + + snippet = super.generate( builder, output ); + + } + + return snippet; + + } + + toReadOnly() { + + return this.setAccess( GPUStorageTextureAccess.ReadOnly ); + + } + + toWriteOnly() { + + return this.setAccess( GPUStorageTextureAccess.WriteOnly ); + + } + + generateStore( builder ) { + + const properties = builder.getNodeProperties( this ); + + const { uvNode, storeNode } = properties; + + const textureProperty = super.generate( builder, 'property' ); + const uvSnippet = uvNode.build( builder, 'uvec2' ); + const storeSnippet = storeNode.build( builder, 'vec4' ); + + const snippet = builder.generateTextureStore( builder, textureProperty, uvSnippet, storeSnippet ); + + builder.addLineFlowCode( snippet, this ); + + } + +} + +const storageTexture = /*@__PURE__*/ nodeProxy( StorageTextureNode ); + +const textureStore = ( value, uvNode, storeNode ) => { + + const node = storageTexture( value, uvNode, storeNode ); + + if ( storeNode !== null ) node.append(); + + return node; + +}; + +class UserDataNode extends ReferenceNode { + + static get type() { + + return 'UserDataNode'; + + } + + constructor( property, inputType, userData = null ) { + + super( property, inputType, userData ); + + this.userData = userData; + + } + + updateReference( state ) { + + this.reference = this.userData !== null ? this.userData : state.object.userData; + + return this.reference; + + } + +} + +const userData = ( name, inputType, userData ) => nodeObject( new UserDataNode( name, inputType, userData ) ); + +class PosterizeNode extends TempNode { + + static get type() { + + return 'PosterizeNode'; + + } + + constructor( sourceNode, stepsNode ) { + + super(); + + this.sourceNode = sourceNode; + this.stepsNode = stepsNode; + + } + + setup() { + + const { sourceNode, stepsNode } = this; + + return sourceNode.mul( stepsNode ).floor().div( stepsNode ); + + } + +} + +const posterize = /*@__PURE__*/ nodeProxy( PosterizeNode ); + +let _sharedFramebuffer = null; + +class ViewportSharedTextureNode extends ViewportTextureNode { + + static get type() { + + return 'ViewportSharedTextureNode'; + + } + + constructor( uvNode = screenUV, levelNode = null ) { + + if ( _sharedFramebuffer === null ) { + + _sharedFramebuffer = new FramebufferTexture(); + + } + + super( uvNode, levelNode, _sharedFramebuffer ); + + } + + updateReference() { + + return this; + + } + +} + +const viewportSharedTexture = /*@__PURE__*/ nodeProxy( ViewportSharedTextureNode ); + +const _size$7 = /*@__PURE__*/ new Vector2(); + +class PassTextureNode extends TextureNode { + + static get type() { + + return 'PassTextureNode'; + + } + + constructor( passNode, texture ) { + + super( texture ); + + this.passNode = passNode; + + this.setUpdateMatrix( false ); + + } + + setup( builder ) { + + if ( builder.object.isQuadMesh ) this.passNode.build( builder ); + + return super.setup( builder ); + + } + + clone() { + + return new this.constructor( this.passNode, this.value ); + + } + +} + +class PassMultipleTextureNode extends PassTextureNode { + + static get type() { + + return 'PassMultipleTextureNode'; + + } + + constructor( passNode, textureName, previousTexture = false ) { + + super( passNode, null ); + + this.textureName = textureName; + this.previousTexture = previousTexture; + + } + + updateTexture() { + + this.value = this.previousTexture ? this.passNode.getPreviousTexture( this.textureName ) : this.passNode.getTexture( this.textureName ); + + } + + setup( builder ) { + + this.updateTexture(); + + return super.setup( builder ); + + } + + clone() { + + return new this.constructor( this.passNode, this.textureName, this.previousTexture ); + + } + +} + +class PassNode extends TempNode { + + static get type() { + + return 'PassNode'; + + } + + constructor( scope, scene, camera, options = {} ) { + + super( 'vec4' ); + + this.scope = scope; + this.scene = scene; + this.camera = camera; + this.options = options; + + this._pixelRatio = 1; + this._width = 1; + this._height = 1; + + const depthTexture = new DepthTexture(); + depthTexture.isRenderTargetTexture = true; + //depthTexture.type = FloatType; + depthTexture.name = 'depth'; + + const renderTarget = new RenderTarget( this._width * this._pixelRatio, this._height * this._pixelRatio, { type: HalfFloatType, ...options, } ); + renderTarget.texture.name = 'output'; + renderTarget.depthTexture = depthTexture; + + this.renderTarget = renderTarget; + + this.updateBeforeType = NodeUpdateType.FRAME; + + this._textures = { + output: renderTarget.texture, + depth: depthTexture + }; + + this._textureNodes = {}; + this._linearDepthNodes = {}; + this._viewZNodes = {}; + + this._previousTextures = {}; + this._previousTextureNodes = {}; + + this._cameraNear = uniform( 0 ); + this._cameraFar = uniform( 0 ); + + this._mrt = null; + + this.isPassNode = true; + + } + + setMRT( mrt ) { + + this._mrt = mrt; + + return this; + + } + + getMRT() { + + return this._mrt; + + } + + isGlobal() { + + return true; + + } + + getTexture( name ) { + + let texture = this._textures[ name ]; + + if ( texture === undefined ) { + + const refTexture = this.renderTarget.texture; + + texture = refTexture.clone(); + texture.isRenderTargetTexture = true; + texture.name = name; + + this._textures[ name ] = texture; + + this.renderTarget.textures.push( texture ); + + } + + return texture; + + } + + getPreviousTexture( name ) { + + let texture = this._previousTextures[ name ]; + + if ( texture === undefined ) { + + texture = this.getTexture( name ).clone(); + texture.isRenderTargetTexture = true; + + this._previousTextures[ name ] = texture; + + } + + return texture; + + } + + toggleTexture( name ) { + + const prevTexture = this._previousTextures[ name ]; + + if ( prevTexture !== undefined ) { + + const texture = this._textures[ name ]; + + const index = this.renderTarget.textures.indexOf( texture ); + this.renderTarget.textures[ index ] = prevTexture; + + this._textures[ name ] = prevTexture; + this._previousTextures[ name ] = texture; + + this._textureNodes[ name ].updateTexture(); + this._previousTextureNodes[ name ].updateTexture(); + + } + + } + + getTextureNode( name = 'output' ) { + + let textureNode = this._textureNodes[ name ]; + + if ( textureNode === undefined ) { + + this._textureNodes[ name ] = textureNode = nodeObject( new PassMultipleTextureNode( this, name ) ); + this._textureNodes[ name ].updateTexture(); + + } + + return textureNode; + + } + + getPreviousTextureNode( name = 'output' ) { + + let textureNode = this._previousTextureNodes[ name ]; + + if ( textureNode === undefined ) { + + if ( this._textureNodes[ name ] === undefined ) this.getTextureNode( name ); + + this._previousTextureNodes[ name ] = textureNode = nodeObject( new PassMultipleTextureNode( this, name, true ) ); + this._previousTextureNodes[ name ].updateTexture(); + + } + + return textureNode; + + } + + getViewZNode( name = 'depth' ) { + + let viewZNode = this._viewZNodes[ name ]; + + if ( viewZNode === undefined ) { + + const cameraNear = this._cameraNear; + const cameraFar = this._cameraFar; + + this._viewZNodes[ name ] = viewZNode = perspectiveDepthToViewZ( this.getTextureNode( name ), cameraNear, cameraFar ); + + } + + return viewZNode; + + } + + getLinearDepthNode( name = 'depth' ) { + + let linearDepthNode = this._linearDepthNodes[ name ]; + + if ( linearDepthNode === undefined ) { + + const cameraNear = this._cameraNear; + const cameraFar = this._cameraFar; + const viewZNode = this.getViewZNode( name ); + + // TODO: just if ( builder.camera.isPerspectiveCamera ) + + this._linearDepthNodes[ name ] = linearDepthNode = viewZToOrthographicDepth( viewZNode, cameraNear, cameraFar ); + + } + + return linearDepthNode; + + } + + setup( { renderer } ) { + + this.renderTarget.samples = this.options.samples === undefined ? renderer.samples : this.options.samples; + + // Disable MSAA for WebGL backend for now + if ( renderer.backend.isWebGLBackend === true ) { + + this.renderTarget.samples = 0; + + } + + this.renderTarget.depthTexture.isMultisampleRenderTargetTexture = this.renderTarget.samples > 1; + + return this.scope === PassNode.COLOR ? this.getTextureNode() : this.getLinearDepthNode(); + + } + + updateBefore( frame ) { + + const { renderer } = frame; + const { scene, camera } = this; + + this._pixelRatio = renderer.getPixelRatio(); + + const size = renderer.getSize( _size$7 ); + + this.setSize( size.width, size.height ); + + const currentRenderTarget = renderer.getRenderTarget(); + const currentMRT = renderer.getMRT(); + + this._cameraNear.value = camera.near; + this._cameraFar.value = camera.far; + + for ( const name in this._previousTextures ) { + + this.toggleTexture( name ); + + } + + renderer.setRenderTarget( this.renderTarget ); + renderer.setMRT( this._mrt ); + + renderer.render( scene, camera ); + + renderer.setRenderTarget( currentRenderTarget ); + renderer.setMRT( currentMRT ); + + } + + setSize( width, height ) { + + this._width = width; + this._height = height; + + const effectiveWidth = this._width * this._pixelRatio; + const effectiveHeight = this._height * this._pixelRatio; + + this.renderTarget.setSize( effectiveWidth, effectiveHeight ); + + } + + setPixelRatio( pixelRatio ) { + + this._pixelRatio = pixelRatio; + + this.setSize( this._width, this._height ); + + } + + dispose() { + + this.renderTarget.dispose(); + + } + + +} + +PassNode.COLOR = 'color'; +PassNode.DEPTH = 'depth'; + +const pass = ( scene, camera, options ) => nodeObject( new PassNode( PassNode.COLOR, scene, camera, options ) ); +const passTexture = ( pass, texture ) => nodeObject( new PassTextureNode( pass, texture ) ); +const depthPass = ( scene, camera ) => nodeObject( new PassNode( PassNode.DEPTH, scene, camera ) ); + +// WebGPU: The use of a single QuadMesh for both gaussian blur passes results in a single RenderObject with a SampledTexture binding that +// alternates between source textures and triggers creation of new BindGroups and BindGroupLayouts every frame. + +const _quadMesh1 = /*@__PURE__*/ new QuadMesh(); +const _quadMesh2 = /*@__PURE__*/ new QuadMesh(); + +class GaussianBlurNode extends TempNode { + + static get type() { + + return 'GaussianBlurNode'; + + } + + constructor( textureNode, directionNode = null, sigma = 2 ) { + + super( 'vec4' ); + + this.textureNode = textureNode; + this.directionNode = directionNode; + this.sigma = sigma; + + this._invSize = uniform( new Vector2() ); + this._passDirection = uniform( new Vector2() ); + + this._horizontalRT = new RenderTarget(); + this._horizontalRT.texture.name = 'GaussianBlurNode.horizontal'; + this._verticalRT = new RenderTarget(); + this._verticalRT.texture.name = 'GaussianBlurNode.vertical'; + + this._textureNode = passTexture( this, this._verticalRT.texture ); + + this.updateBeforeType = NodeUpdateType.RENDER; + + this.resolution = new Vector2( 1, 1 ); + + } + + setSize( width, height ) { + + width = Math.max( Math.round( width * this.resolution.x ), 1 ); + height = Math.max( Math.round( height * this.resolution.y ), 1 ); + + this._invSize.value.set( 1 / width, 1 / height ); + this._horizontalRT.setSize( width, height ); + this._verticalRT.setSize( width, height ); + + } + + updateBefore( frame ) { + + const { renderer } = frame; + + const textureNode = this.textureNode; + const map = textureNode.value; + + const currentRenderTarget = renderer.getRenderTarget(); + const currentMRT = renderer.getMRT(); + + const currentTexture = textureNode.value; + + _quadMesh1.material = this._material; + _quadMesh2.material = this._material; + + this.setSize( map.image.width, map.image.height ); + + const textureType = map.type; + + this._horizontalRT.texture.type = textureType; + this._verticalRT.texture.type = textureType; + + // clear + + renderer.setMRT( null ); + + // horizontal + + renderer.setRenderTarget( this._horizontalRT ); + + this._passDirection.value.set( 1, 0 ); + + _quadMesh1.render( renderer ); + + // vertical + + textureNode.value = this._horizontalRT.texture; + renderer.setRenderTarget( this._verticalRT ); + + this._passDirection.value.set( 0, 1 ); + + _quadMesh2.render( renderer ); + + // restore + + renderer.setRenderTarget( currentRenderTarget ); + renderer.setMRT( currentMRT ); + textureNode.value = currentTexture; + + } + + getTextureNode() { + + return this._textureNode; + + } + + setup( builder ) { + + const textureNode = this.textureNode; + + if ( textureNode.isTextureNode !== true ) { + + console.error( 'GaussianBlurNode requires a TextureNode.' ); + + return vec4(); + + } + + // + + const uvNode = textureNode.uvNode || uv(); + const directionNode = vec2( this.directionNode || 1 ); + + const sampleTexture = ( uv ) => textureNode.uv( uv ); + + const blur = Fn( () => { + + const kernelSize = 3 + ( 2 * this.sigma ); + const gaussianCoefficients = this._getCoefficients( kernelSize ); + + const invSize = this._invSize; + const direction = directionNode.mul( this._passDirection ); + + const weightSum = float( gaussianCoefficients[ 0 ] ).toVar(); + const diffuseSum = vec4( sampleTexture( uvNode ).mul( weightSum ) ).toVar(); + + for ( let i = 1; i < kernelSize; i ++ ) { + + const x = float( i ); + const w = float( gaussianCoefficients[ i ] ); + + const uvOffset = vec2( direction.mul( invSize.mul( x ) ) ).toVar(); + + const sample1 = vec4( sampleTexture( uvNode.add( uvOffset ) ) ); + const sample2 = vec4( sampleTexture( uvNode.sub( uvOffset ) ) ); + + diffuseSum.addAssign( sample1.add( sample2 ).mul( w ) ); + weightSum.addAssign( mul( 2.0, w ) ); + + } + + return diffuseSum.div( weightSum ); + + } ); + + // + + const material = this._material || ( this._material = new NodeMaterial() ); + material.fragmentNode = blur().context( builder.getSharedContext() ); + material.name = 'Gaussian_blur'; + material.needsUpdate = true; + + // + + const properties = builder.getNodeProperties( this ); + properties.textureNode = textureNode; + + // + + return this._textureNode; + + } + + dispose() { + + this._horizontalRT.dispose(); + this._verticalRT.dispose(); + + } + + _getCoefficients( kernelRadius ) { + + const coefficients = []; + + for ( let i = 0; i < kernelRadius; i ++ ) { + + coefficients.push( 0.39894 * Math.exp( - 0.5 * i * i / ( kernelRadius * kernelRadius ) ) / kernelRadius ); + + } + + return coefficients; + + } + +} + +const gaussianBlur = ( node, directionNode, sigma ) => nodeObject( new GaussianBlurNode( convertToTexture( node ), directionNode, sigma ) ); + +const _size$6 = /*@__PURE__*/ new Vector2(); + +const _quadMeshComp = /*@__PURE__*/ new QuadMesh(); + +class AfterImageNode extends TempNode { + + static get type() { + + return 'AfterImageNode'; + + } + + constructor( textureNode, damp = 0.96 ) { + + super( textureNode ); + + this.textureNode = textureNode; + this.textureNodeOld = texture(); + this.damp = uniform( damp ); + + this._compRT = new RenderTarget(); + this._compRT.texture.name = 'AfterImageNode.comp'; + + this._oldRT = new RenderTarget(); + this._oldRT.texture.name = 'AfterImageNode.old'; + + this._textureNode = passTexture( this, this._compRT.texture ); + + this.updateBeforeType = NodeUpdateType.RENDER; + + } + + getTextureNode() { + + return this._textureNode; + + } + + setSize( width, height ) { + + this._compRT.setSize( width, height ); + this._oldRT.setSize( width, height ); + + } + + updateBefore( frame ) { + + const { renderer } = frame; + + const textureNode = this.textureNode; + const map = textureNode.value; + + const textureType = map.type; + + this._compRT.texture.type = textureType; + this._oldRT.texture.type = textureType; + + renderer.getDrawingBufferSize( _size$6 ); + + this.setSize( _size$6.x, _size$6.y ); + + const currentRenderTarget = renderer.getRenderTarget(); + const currentTexture = textureNode.value; + + this.textureNodeOld.value = this._oldRT.texture; + + // comp + renderer.setRenderTarget( this._compRT ); + _quadMeshComp.render( renderer ); + + // Swap the textures + const temp = this._oldRT; + this._oldRT = this._compRT; + this._compRT = temp; + + renderer.setRenderTarget( currentRenderTarget ); + textureNode.value = currentTexture; + + } + + setup( builder ) { + + const textureNode = this.textureNode; + const textureNodeOld = this.textureNodeOld; + + // + + const uvNode = textureNode.uvNode || uv(); + + textureNodeOld.uvNode = uvNode; + + const sampleTexture = ( uv ) => textureNode.uv( uv ); + + const when_gt = Fn( ( [ x_immutable, y_immutable ] ) => { + + const y = float( y_immutable ).toVar(); + const x = vec4( x_immutable ).toVar(); + + return max$1( sign( x.sub( y ) ), 0.0 ); + + } ); + + const afterImg = Fn( () => { + + const texelOld = vec4( textureNodeOld ); + const texelNew = vec4( sampleTexture( uvNode ) ); + + texelOld.mulAssign( this.damp.mul( when_gt( texelOld, 0.1 ) ) ); + return max$1( texelNew, texelOld ); + + } ); + + // + + const materialComposed = this._materialComposed || ( this._materialComposed = new NodeMaterial() ); + materialComposed.name = 'AfterImage'; + materialComposed.fragmentNode = afterImg(); + + _quadMeshComp.material = materialComposed; + + // + + const properties = builder.getNodeProperties( this ); + properties.textureNode = textureNode; + + // + + return this._textureNode; + + } + + dispose() { + + this._compRT.dispose(); + this._oldRT.dispose(); + + } + +} + +const afterImage = ( node, damp ) => nodeObject( new AfterImageNode( convertToTexture( node ), damp ) ); + +const grayscale = /*@__PURE__*/ Fn( ( [ color ] ) => { + + return luminance( color.rgb ); + +} ); + +const saturation = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { + + return adjustment.mix( luminance( color.rgb ), color.rgb ); + +} ); + +const vibrance = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { + + const average = add( color.r, color.g, color.b ).div( 3.0 ); + + const mx = color.r.max( color.g.max( color.b ) ); + const amt = mx.sub( average ).mul( adjustment ).mul( - 3.0 ); + + return mix( color.rgb, mx, amt ); + +} ); + +const hue = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { + + const k = vec3( 0.57735, 0.57735, 0.57735 ); + + const cosAngle = adjustment.cos(); + + return vec3( color.rgb.mul( cosAngle ).add( k.cross( color.rgb ).mul( adjustment.sin() ).add( k.mul( dot( k, color.rgb ).mul( cosAngle.oneMinus() ) ) ) ) ); + +} ); + +const _luminanceCoefficients = /*@__PURE__*/ new Vector3(); +const luminance = ( + color, + luminanceCoefficients = vec3( ... ColorManagement.getLuminanceCoefficients( _luminanceCoefficients ) ) +) => dot( color, luminanceCoefficients ); + +const threshold = ( color, threshold ) => mix( vec3( 0.0 ), color, luminance( color ).sub( threshold ).max( 0 ) ); + +const _quadMesh$5 = /*@__PURE__*/ new QuadMesh(); + +class AnamorphicNode extends TempNode { + + static get type() { + + return 'AnamorphicNode'; + + } + + constructor( textureNode, tresholdNode, scaleNode, samples ) { + + super( 'vec4' ); + + this.textureNode = textureNode; + this.tresholdNode = tresholdNode; + this.scaleNode = scaleNode; + this.colorNode = vec3( 0.1, 0.0, 1.0 ); + this.samples = samples; + this.resolution = new Vector2( 1, 1 ); + + this._renderTarget = new RenderTarget(); + this._renderTarget.texture.name = 'anamorphic'; + + this._invSize = uniform( new Vector2() ); + + this._textureNode = passTexture( this, this._renderTarget.texture ); + + this.updateBeforeType = NodeUpdateType.RENDER; + + } + + getTextureNode() { + + return this._textureNode; + + } + + setSize( width, height ) { + + this._invSize.value.set( 1 / width, 1 / height ); + + width = Math.max( Math.round( width * this.resolution.x ), 1 ); + height = Math.max( Math.round( height * this.resolution.y ), 1 ); + + this._renderTarget.setSize( width, height ); + + } + + updateBefore( frame ) { + + const { renderer } = frame; + + const textureNode = this.textureNode; + const map = textureNode.value; + + this._renderTarget.texture.type = map.type; + + const currentRenderTarget = renderer.getRenderTarget(); + const currentTexture = textureNode.value; + + _quadMesh$5.material = this._material; + + this.setSize( map.image.width, map.image.height ); + + // render + + renderer.setRenderTarget( this._renderTarget ); + + _quadMesh$5.render( renderer ); + + // restore + + renderer.setRenderTarget( currentRenderTarget ); + textureNode.value = currentTexture; + + } + + setup( builder ) { + + const textureNode = this.textureNode; + const uvNode = textureNode.uvNode || uv(); + + const sampleTexture = ( uv ) => textureNode.uv( uv ); + + const anamorph = Fn( () => { + + const samples = this.samples; + const halfSamples = Math.floor( samples / 2 ); + + const total = vec3( 0 ).toVar(); + + Loop( { start: - halfSamples, end: halfSamples }, ( { i } ) => { + + const softness = float( i ).abs().div( halfSamples ).oneMinus(); + + const uv = vec2( uvNode.x.add( this._invSize.x.mul( i ).mul( this.scaleNode ) ), uvNode.y ); + const color = sampleTexture( uv ); + const pass = threshold( color, this.tresholdNode ).mul( softness ); + + total.addAssign( pass ); + + } ); + + return total.mul( this.colorNode ); + + } ); + + // + + const material = this._material || ( this._material = new NodeMaterial() ); + material.name = 'Anamorphic'; + material.fragmentNode = anamorph(); + + // + + const properties = builder.getNodeProperties( this ); + properties.textureNode = textureNode; + + // + + return this._textureNode; + + } + + dispose() { + + this._renderTarget.dispose(); + + } + +} + +const anamorphic = ( node, threshold = .9, scale = 3, samples = 32 ) => nodeObject( new AnamorphicNode( convertToTexture( node ), nodeObject( threshold ), nodeObject( scale ), samples ) ); + +class SobelOperatorNode extends TempNode { + + static get type() { + + return 'SobelOperatorNode'; + + } + + constructor( textureNode ) { + + super(); + + this.textureNode = textureNode; + + this.updateBeforeType = NodeUpdateType.RENDER; + + this._invSize = uniform( new Vector2() ); + + } + + updateBefore() { + + const map = this.textureNode.value; + + this._invSize.value.set( 1 / map.image.width, 1 / map.image.height ); + + } + + setup() { + + const { textureNode } = this; + + const uvNode = textureNode.uvNode || uv(); + + const sampleTexture = ( uv ) => textureNode.uv( uv ); + + const sobel = Fn( () => { + + // Sobel Edge Detection (see https://youtu.be/uihBwtPIBxM) + + const texel = this._invSize; + + // kernel definition (in glsl matrices are filled in column-major order) + + const Gx = mat3( - 1, - 2, - 1, 0, 0, 0, 1, 2, 1 ); // x direction kernel + const Gy = mat3( - 1, 0, 1, - 2, 0, 2, - 1, 0, 1 ); // y direction kernel + + // fetch the 3x3 neighbourhood of a fragment + + // first column + + const tx0y0 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( - 1, - 1 ) ) ) ).xyz ); + const tx0y1 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( - 1, 0 ) ) ) ).xyz ); + const tx0y2 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( - 1, 1 ) ) ) ).xyz ); + + // second column + + const tx1y0 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 0, - 1 ) ) ) ).xyz ); + const tx1y1 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 0, 0 ) ) ) ).xyz ); + const tx1y2 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 0, 1 ) ) ) ).xyz ); + + // third column + + const tx2y0 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 1, - 1 ) ) ) ).xyz ); + const tx2y1 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 1, 0 ) ) ) ).xyz ); + const tx2y2 = luminance( sampleTexture( uvNode.add( texel.mul( vec2( 1, 1 ) ) ) ).xyz ); + + // gradient value in x direction + + const valueGx = add( + Gx[ 0 ][ 0 ].mul( tx0y0 ), + Gx[ 1 ][ 0 ].mul( tx1y0 ), + Gx[ 2 ][ 0 ].mul( tx2y0 ), + Gx[ 0 ][ 1 ].mul( tx0y1 ), + Gx[ 1 ][ 1 ].mul( tx1y1 ), + Gx[ 2 ][ 1 ].mul( tx2y1 ), + Gx[ 0 ][ 2 ].mul( tx0y2 ), + Gx[ 1 ][ 2 ].mul( tx1y2 ), + Gx[ 2 ][ 2 ].mul( tx2y2 ) + ); + + + // gradient value in y direction + + const valueGy = add( + Gy[ 0 ][ 0 ].mul( tx0y0 ), + Gy[ 1 ][ 0 ].mul( tx1y0 ), + Gy[ 2 ][ 0 ].mul( tx2y0 ), + Gy[ 0 ][ 1 ].mul( tx0y1 ), + Gy[ 1 ][ 1 ].mul( tx1y1 ), + Gy[ 2 ][ 1 ].mul( tx2y1 ), + Gy[ 0 ][ 2 ].mul( tx0y2 ), + Gy[ 1 ][ 2 ].mul( tx1y2 ), + Gy[ 2 ][ 2 ].mul( tx2y2 ) + ); + + // magnitute of the total gradient + + const G = valueGx.mul( valueGx ).add( valueGy.mul( valueGy ) ).sqrt(); + + return vec4( vec3( G ), 1 ); + + } ); + + const outputNode = sobel(); + + return outputNode; + + } + +} + +const sobel = ( node ) => nodeObject( new SobelOperatorNode( convertToTexture( node ) ) ); + +class DepthOfFieldNode extends TempNode { + + static get type() { + + return 'DepthOfFieldNode'; + + } + + constructor( textureNode, viewZNode, focusNode, apertureNode, maxblurNode ) { + + super(); + + this.textureNode = textureNode; + this.viewZNode = viewZNode; + + this.focusNode = focusNode; + this.apertureNode = apertureNode; + this.maxblurNode = maxblurNode; + + this._aspect = uniform( 0 ); + + this.updateBeforeType = NodeUpdateType.RENDER; + + } + + updateBefore() { + + const map = this.textureNode.value; + + this._aspect.value = map.image.width / map.image.height; + + } + + setup() { + + const textureNode = this.textureNode; + const uvNode = textureNode.uvNode || uv(); + + const sampleTexture = ( uv ) => textureNode.uv( uv ); + + const dof = Fn( () => { + + const aspectcorrect = vec2( 1.0, this._aspect ); + + const factor = this.focusNode.add( this.viewZNode ); + + const dofblur = vec2( clamp( factor.mul( this.apertureNode ), this.maxblurNode.negate(), this.maxblurNode ) ); + + const dofblur9 = dofblur.mul( 0.9 ); + const dofblur7 = dofblur.mul( 0.7 ); + const dofblur4 = dofblur.mul( 0.4 ); + + let col = vec4( 0.0 ); + + col = col.add( sampleTexture( uvNode ) ); + + col = col.add( sampleTexture( uvNode.add( vec2( 0.0, 0.4 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.40, 0.0 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.0, - 0.4 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.40, 0.0 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.0, - 0.4 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.0, 0.4 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.0, - 0.4 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + col = col.add( sampleTexture( uvNode.add( vec2( 0.0, 0.4 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) ); + + col = col.div( 41 ); + col.a = 1; + + return vec4( col ); + + + } ); + + const outputNode = dof(); + + return outputNode; + + } + +} + +const dof = ( node, viewZNode, focus = 1, aperture = 0.025, maxblur = 1 ) => nodeObject( new DepthOfFieldNode( convertToTexture( node ), nodeObject( viewZNode ), nodeObject( focus ), nodeObject( aperture ), nodeObject( maxblur ) ) ); + +class DotScreenNode extends TempNode { + + static get type() { + + return 'DotScreenNode'; + + } + + constructor( inputNode, center = new Vector2( 0.5, 0.5 ), angle = 1.57, scale = 1 ) { + + super( 'vec4' ); + + this.inputNode = inputNode; + this.center = uniform( center ); + this.angle = uniform( angle ); + this.scale = uniform( scale ); + + } + + setup() { + + const inputNode = this.inputNode; + + const pattern = Fn( () => { + + const s = sin( this.angle ); + const c = cos( this.angle ); + + const tex = uv().mul( screenSize ).sub( this.center ); + const point = vec2( c.mul( tex.x ).sub( s.mul( tex.y ) ), s.mul( tex.x ).add( c.mul( tex.y ) ) ).mul( this.scale ); + + return sin( point.x ).mul( sin( point.y ) ).mul( 4 ); + + } ); + + const dotScreen = Fn( () => { + + const color = inputNode; + + const average = add( color.r, color.g, color.b ).div( 3 ); + + return vec4( vec3( average.mul( 10 ).sub( 5 ).add( pattern() ) ), color.a ); + + } ); + + const outputNode = dotScreen(); + + return outputNode; + + } + +} + +const dotScreen = ( node, center, angle, scale ) => nodeObject( new DotScreenNode( nodeObject( node ), center, angle, scale ) ); + +class RGBShiftNode extends TempNode { + + static get type() { + + return 'RGBShiftNode'; + + } + + constructor( textureNode, amount = 0.005, angle = 0 ) { + + super( 'vec4' ); + + this.textureNode = textureNode; + this.amount = uniform( amount ); + this.angle = uniform( angle ); + + } + + setup() { + + const { textureNode } = this; + + const uvNode = textureNode.uvNode || uv(); + + const sampleTexture = ( uv ) => textureNode.uv( uv ); + + const rgbShift = Fn( () => { + + const offset = vec2( cos( this.angle ), sin( this.angle ) ).mul( this.amount ); + const cr = sampleTexture( uvNode.add( offset ) ); + const cga = sampleTexture( uvNode ); + const cb = sampleTexture( uvNode.sub( offset ) ); + + return vec4( cr.r, cga.g, cb.b, cga.a ); + + } ); + + return rgbShift(); + + } + +} + +const rgbShift = ( node, amount, angle ) => nodeObject( new RGBShiftNode( convertToTexture( node ), amount, angle ) ); + +class FilmNode extends TempNode { + + static get type() { + + return 'FilmNode'; + + } + + constructor( inputNode, intensityNode = null, uvNode = null ) { + + super(); + + this.inputNode = inputNode; + this.intensityNode = intensityNode; + this.uvNode = uvNode; + + } + + setup() { + + const uvNode = this.uvNode || uv(); + + const film = Fn( () => { + + const base = this.inputNode.rgb; + const noise = rand( fract( uvNode.add( timerLocal() ) ) ); + + let color = base.add( base.mul( clamp( noise.add( 0.1 ), 0, 1 ) ) ); + + if ( this.intensityNode !== null ) { + + color = mix( base, color, this.intensityNode ); + + } + + return vec4( color, this.inputNode.a ); + + } ); + + const outputNode = film(); + + return outputNode; + + } + +} + +const film = /*@__PURE__*/ nodeProxy( FilmNode ); + +class Lut3DNode extends TempNode { + + static get type() { + + return 'Lut3DNode'; + + } + + constructor( inputNode, lutNode, size, intensityNode ) { + + super(); + + this.inputNode = inputNode; + this.lutNode = lutNode; + this.size = uniform( size ); + this.intensityNode = intensityNode; + + } + + setup() { + + const { inputNode, lutNode } = this; + + const sampleLut = ( uv ) => lutNode.uv( uv ); + + const lut3D = Fn( () => { + + const base = inputNode; + + // pull the sample in by half a pixel so the sample begins at the center of the edge pixels. + + const pixelWidth = float( 1.0 ).div( this.size ); + const halfPixelWidth = float( 0.5 ).div( this.size ); + const uvw = vec3( halfPixelWidth ).add( base.rgb.mul( float( 1.0 ).sub( pixelWidth ) ) ); + + const lutValue = vec4( sampleLut( uvw ).rgb, base.a ); + + return vec4( mix( base, lutValue, this.intensityNode ) ); + + } ); + + const outputNode = lut3D(); + + return outputNode; + + } + +} + +const lut3D = ( node, lut, size, intensity ) => nodeObject( new Lut3DNode( nodeObject( node ), nodeObject( lut ), size, nodeObject( intensity ) ) ); + +const _quadMesh$4 = /*@__PURE__*/ new QuadMesh(); +const _currentClearColor$1 = /*@__PURE__*/ new Color(); +const _size$5 = /*@__PURE__*/ new Vector2(); + +class GTAONode extends TempNode { + + static get type() { + + return 'GTAONode'; + + } + + constructor( depthNode, normalNode, camera ) { + + super(); + + this.depthNode = depthNode; + this.normalNode = normalNode; + + this.radius = uniform( 0.25 ); + this.resolution = uniform( new Vector2() ); + this.thickness = uniform( 1 ); + this.distanceExponent = uniform( 1 ); + this.distanceFallOff = uniform( 1 ); + this.scale = uniform( 1 ); + this.noiseNode = texture( generateMagicSquareNoise() ); + + this.cameraProjectionMatrix = uniform( camera.projectionMatrix ); + this.cameraProjectionMatrixInverse = uniform( camera.projectionMatrixInverse ); + + this.SAMPLES = uniform( 16 ); + + this._aoRenderTarget = new RenderTarget(); + this._aoRenderTarget.texture.name = 'GTAONode.AO'; + + this._material = null; + this._textureNode = passTexture( this, this._aoRenderTarget.texture ); + + this.updateBeforeType = NodeUpdateType.FRAME; + + } + + getTextureNode() { + + return this._textureNode; + + } + + setSize( width, height ) { + + this.resolution.value.set( width, height ); + this._aoRenderTarget.setSize( width, height ); + + } + + updateBefore( frame ) { + + const { renderer } = frame; + + const size = renderer.getDrawingBufferSize( _size$5 ); + + const currentRenderTarget = renderer.getRenderTarget(); + const currentMRT = renderer.getMRT(); + renderer.getClearColor( _currentClearColor$1 ); + const currentClearAlpha = renderer.getClearAlpha(); + + _quadMesh$4.material = this._material; + + this.setSize( size.width, size.height ); + + // clear + + renderer.setMRT( null ); + renderer.setClearColor( 0xffffff, 1 ); + + // ao + + renderer.setRenderTarget( this._aoRenderTarget ); + _quadMesh$4.render( renderer ); + + // restore + + renderer.setRenderTarget( currentRenderTarget ); + renderer.setMRT( currentMRT ); + renderer.setClearColor( _currentClearColor$1, currentClearAlpha ); + + } + + setup( builder ) { + + const uvNode = uv(); + + const sampleDepth = ( uv ) => this.depthNode.uv( uv ).x; + const sampleNoise = ( uv ) => this.noiseNode.uv( uv ); + + const getSceneUvAndDepth = Fn( ( [ sampleViewPos ] )=> { + + const sampleClipPos = this.cameraProjectionMatrix.mul( vec4( sampleViewPos, 1.0 ) ); + let sampleUv = sampleClipPos.xy.div( sampleClipPos.w ).mul( 0.5 ).add( 0.5 ).toVar(); + sampleUv = vec2( sampleUv.x, sampleUv.y.oneMinus() ); + const sampleSceneDepth = sampleDepth( sampleUv ); + return vec3( sampleUv, sampleSceneDepth ); + + } ); + + const getViewPosition = Fn( ( [ screenPosition, depth ] ) => { + + screenPosition = vec2( screenPosition.x, screenPosition.y.oneMinus() ).mul( 2.0 ).sub( 1.0 ); + + const clipSpacePosition = vec4( vec3( screenPosition, depth ), 1.0 ); + const viewSpacePosition = vec4( this.cameraProjectionMatrixInverse.mul( clipSpacePosition ) ); + + return viewSpacePosition.xyz.div( viewSpacePosition.w ); + + } ); + + const ao = Fn( () => { + + const depth = sampleDepth( uvNode ); + + depth.greaterThanEqual( 1.0 ).discard(); + + const viewPosition = getViewPosition( uvNode, depth ); + const viewNormal = this.normalNode.rgb.normalize(); + + const radiusToUse = this.radius; + + const noiseResolution = textureSize( this.noiseNode, 0 ); + let noiseUv = vec2( uvNode.x, uvNode.y.oneMinus() ); + noiseUv = noiseUv.mul( this.resolution.div( noiseResolution ) ); + const noiseTexel = sampleNoise( noiseUv ); + const randomVec = noiseTexel.xyz.mul( 2.0 ).sub( 1.0 ); + const tangent = vec3( randomVec.xy, 0.0 ).normalize(); + const bitangent = vec3( tangent.y.mul( - 1.0 ), tangent.x, 0.0 ); + const kernelMatrix = mat3( tangent, bitangent, vec3( 0.0, 0.0, 1.0 ) ); + + const DIRECTIONS = this.SAMPLES.lessThan( 30 ).select( 3, 5 ); + const STEPS = add( this.SAMPLES, DIRECTIONS.sub( 1 ) ).div( DIRECTIONS ); + + const ao = float( 0 ).toVar(); + + Loop( { start: int( 0 ), end: DIRECTIONS, type: 'int', condition: '<' }, ( { i } ) => { + + const angle = float( i ).div( float( DIRECTIONS ) ).mul( PI ); + const sampleDir = vec4( cos( angle ), sin( angle ), 0., add( 0.5, mul( 0.5, noiseTexel.w ) ) ); + sampleDir.xyz = normalize( kernelMatrix.mul( sampleDir.xyz ) ); + + const viewDir = normalize( viewPosition.xyz.negate() ); + const sliceBitangent = normalize( cross( sampleDir.xyz, viewDir ) ); + const sliceTangent = cross( sliceBitangent, viewDir ); + const normalInSlice = normalize( viewNormal.sub( sliceBitangent.mul( dot( viewNormal, sliceBitangent ) ) ) ); + + const tangentToNormalInSlice = cross( normalInSlice, sliceBitangent ); + const cosHorizons = vec2( dot( viewDir, tangentToNormalInSlice ), dot( viewDir, tangentToNormalInSlice.negate() ) ).toVar(); + + Loop( { end: STEPS, type: 'int', name: 'j', condition: '<' }, ( { j } ) => { + + const sampleViewOffset = sampleDir.xyz.mul( radiusToUse ).mul( sampleDir.w ).mul( pow( div( float( j ).add( 1.0 ), float( STEPS ) ), this.distanceExponent ) ); + + // x + + const sampleSceneUvDepthX = getSceneUvAndDepth( viewPosition.add( sampleViewOffset ) ); + const sampleSceneViewPositionX = getViewPosition( sampleSceneUvDepthX.xy, sampleSceneUvDepthX.z ); + const viewDeltaX = sampleSceneViewPositionX.sub( viewPosition ); + + If( abs( viewDeltaX.z ).lessThan( this.thickness ), () => { + + const sampleCosHorizon = dot( viewDir, normalize( viewDeltaX ) ); + cosHorizons.x.addAssign( max$1( 0, mul( sampleCosHorizon.sub( cosHorizons.x ), mix( 1.0, float( 2.0 ).div( float( j ).add( 2 ) ), this.distanceFallOff ) ) ) ); + + } ); + + // y + + const sampleSceneUvDepthY = getSceneUvAndDepth( viewPosition.sub( sampleViewOffset ) ); + const sampleSceneViewPositionY = getViewPosition( sampleSceneUvDepthY.xy, sampleSceneUvDepthY.z ); + const viewDeltaY = sampleSceneViewPositionY.sub( viewPosition ); + + If( abs( viewDeltaY.z ).lessThan( this.thickness ), () => { + + const sampleCosHorizon = dot( viewDir, normalize( viewDeltaY ) ); + cosHorizons.y.addAssign( max$1( 0, mul( sampleCosHorizon.sub( cosHorizons.y ), mix( 1.0, float( 2.0 ).div( float( j ).add( 2 ) ), this.distanceFallOff ) ) ) ); + + } ); + + } ); + + const sinHorizons = sqrt( sub( 1.0, cosHorizons.mul( cosHorizons ) ) ); + const nx = dot( normalInSlice, sliceTangent ); + const ny = dot( normalInSlice, viewDir ); + const nxb = mul( 0.5, acos( cosHorizons.y ).sub( acos( cosHorizons.x ) ).add( sinHorizons.x.mul( cosHorizons.x ).sub( sinHorizons.y.mul( cosHorizons.y ) ) ) ); + const nyb = mul( 0.5, sub( 2.0, cosHorizons.x.mul( cosHorizons.x ) ).sub( cosHorizons.y.mul( cosHorizons.y ) ) ); + const occlusion = nx.mul( nxb ).add( ny.mul( nyb ) ); + ao.addAssign( occlusion ); + + } ); + + ao.assign( clamp( ao.div( DIRECTIONS ), 0, 1 ) ); + ao.assign( pow( ao, this.scale ) ); + + return vec4( vec3( ao ), 1.0 ); + + } ); + + const material = this._material || ( this._material = new NodeMaterial() ); + material.fragmentNode = ao().context( builder.getSharedContext() ); + material.name = 'GTAO'; + material.needsUpdate = true; + + // + + return this._textureNode; + + } + + dispose() { + + this._aoRenderTarget.dispose(); + + } + +} + +function generateMagicSquareNoise( size = 5 ) { + + const noiseSize = Math.floor( size ) % 2 === 0 ? Math.floor( size ) + 1 : Math.floor( size ); + const magicSquare = generateMagicSquare( noiseSize ); + const noiseSquareSize = magicSquare.length; + const data = new Uint8Array( noiseSquareSize * 4 ); + + for ( let inx = 0; inx < noiseSquareSize; ++ inx ) { + + const iAng = magicSquare[ inx ]; + const angle = ( 2 * Math.PI * iAng ) / noiseSquareSize; + const randomVec = new Vector3( + Math.cos( angle ), + Math.sin( angle ), + 0 + ).normalize(); + data[ inx * 4 ] = ( randomVec.x * 0.5 + 0.5 ) * 255; + data[ inx * 4 + 1 ] = ( randomVec.y * 0.5 + 0.5 ) * 255; + data[ inx * 4 + 2 ] = 127; + data[ inx * 4 + 3 ] = 255; + + } + + const noiseTexture = new DataTexture( data, noiseSize, noiseSize ); + noiseTexture.wrapS = RepeatWrapping; + noiseTexture.wrapT = RepeatWrapping; + noiseTexture.needsUpdate = true; + + return noiseTexture; + +} + +function generateMagicSquare( size ) { + + const noiseSize = Math.floor( size ) % 2 === 0 ? Math.floor( size ) + 1 : Math.floor( size ); + const noiseSquareSize = noiseSize * noiseSize; + const magicSquare = Array( noiseSquareSize ).fill( 0 ); + let i = Math.floor( noiseSize / 2 ); + let j = noiseSize - 1; + + for ( let num = 1; num <= noiseSquareSize; ) { + + if ( i === - 1 && j === noiseSize ) { + + j = noiseSize - 2; + i = 0; + + } else { + + if ( j === noiseSize ) { + + j = 0; + + } + + if ( i < 0 ) { + + i = noiseSize - 1; + + } + + } + + if ( magicSquare[ i * noiseSize + j ] !== 0 ) { + + j -= 2; + i ++; + continue; + + } else { + + magicSquare[ i * noiseSize + j ] = num ++; + + } + + j ++; + i --; + + } + + return magicSquare; + +} + +const ao = ( depthNode, normalNode, camera ) => nodeObject( new GTAONode( nodeObject( depthNode ), nodeObject( normalNode ), camera ) ); + +class DenoiseNode extends TempNode { + + static get type() { + + return 'DenoiseNode'; + + } + + constructor( textureNode, depthNode, normalNode, noiseNode, camera ) { + + super(); + + this.textureNode = textureNode; + this.depthNode = depthNode; + this.normalNode = normalNode; + this.noiseNode = noiseNode; + + this.cameraProjectionMatrixInverse = uniform( camera.projectionMatrixInverse ); + this.lumaPhi = uniform( 5 ); + this.depthPhi = uniform( 5 ); + this.normalPhi = uniform( 5 ); + this.radius = uniform( 5 ); + this.index = uniform( 0 ); + + this._resolution = uniform( new Vector2() ); + this._sampleVectors = uniformArray( generatePdSamplePointInitializer( 16, 2, 1 ) ); + + this.updateBeforeType = NodeUpdateType.RENDER; + + } + + updateBefore() { + + const map = this.textureNode.value; + + this._resolution.value.set( map.image.width, map.image.height ); + + } + + setup() { + + const uvNode = uv(); + + const sampleTexture = ( uv ) => this.textureNode.uv( uv ); + const sampleDepth = ( uv ) => this.depthNode.uv( uv ).x; + const sampleNormal = ( uv ) => this.normalNode.uv( uv ); + const sampleNoise = ( uv ) => this.noiseNode.uv( uv ); + + const getViewPosition = Fn( ( [ screenPosition, depth ] ) => { + + screenPosition = vec2( screenPosition.x, screenPosition.y.oneMinus() ).mul( 2.0 ).sub( 1.0 ); + + const clipSpacePosition = vec4( vec3( screenPosition, depth ), 1.0 ); + const viewSpacePosition = vec4( this.cameraProjectionMatrixInverse.mul( clipSpacePosition ) ); + + return viewSpacePosition.xyz.div( viewSpacePosition.w ); + + } ); + + const denoiseSample = Fn( ( [ center, viewNormal, viewPosition, sampleUv ] ) => { + + const texel = sampleTexture( sampleUv ); + const depth = sampleDepth( sampleUv ); + const normal = sampleNormal( sampleUv ).rgb.normalize(); + const neighborColor = texel.rgb; + const viewPos = getViewPosition( sampleUv, depth ); + + const normalDiff = dot( viewNormal, normal ).toVar(); + const normalSimilarity = pow( max$1( normalDiff, 0 ), this.normalPhi ).toVar(); + const lumaDiff = abs( luminance( neighborColor ).sub( luminance( center ) ) ).toVar(); + const lumaSimilarity = max$1( float( 1.0 ).sub( lumaDiff.div( this.lumaPhi ) ), 0 ).toVar(); + const depthDiff = abs( dot( viewPosition.sub( viewPos ), viewNormal ) ).toVar(); + const depthSimilarity = max$1( float( 1.0 ).sub( depthDiff.div( this.depthPhi ) ), 0 ); + const w = lumaSimilarity.mul( depthSimilarity ).mul( normalSimilarity ); + + return vec4( neighborColor.mul( w ), w ); + + } ); + + const denoise = Fn( ( [ uvNode ] ) => { + + const depth = sampleDepth( uvNode ); + const viewNormal = sampleNormal( uvNode ).rgb.normalize(); + + const texel = sampleTexture( uvNode ); + + If( depth.greaterThanEqual( 1.0 ).or( dot( viewNormal, viewNormal ).equal( 0.0 ) ), () => { + + return texel; + + } ); + + const center = vec3( texel.rgb ); + + const viewPosition = getViewPosition( uvNode, depth ); + + const noiseResolution = textureSize( this.noiseNode, 0 ); + let noiseUv = vec2( uvNode.x, uvNode.y.oneMinus() ); + noiseUv = noiseUv.mul( this._resolution.div( noiseResolution ) ); + const noiseTexel = sampleNoise( noiseUv ); + + const x = sin( noiseTexel.element( this.index.mod( 4 ).mul( 2 ).mul( PI ) ) ); + const y = cos( noiseTexel.element( this.index.mod( 4 ).mul( 2 ).mul( PI ) ) ); + + const noiseVec = vec2( x, y ); + const rotationMatrix = mat2( noiseVec.x, noiseVec.y.negate(), noiseVec.x, noiseVec.y ); + + const totalWeight = float( 1.0 ).toVar(); + const denoised = vec3( texel.rgb ).toVar(); + + Loop( { start: int( 0 ), end: int( 16 ), type: 'int', condition: '<' }, ( { i } ) => { + + const sampleDir = this._sampleVectors.element( i ).toVar(); + const offset = rotationMatrix.mul( sampleDir.xy.mul( float( 1.0 ).add( sampleDir.z.mul( this.radius.sub( 1 ) ) ) ) ).div( this._resolution ).toVar(); + const sampleUv = uvNode.add( offset ).toVar(); + + const result = denoiseSample( center, viewNormal, viewPosition, sampleUv ); + + denoised.addAssign( result.xyz ); + totalWeight.addAssign( result.w ); + + } ); + + If( totalWeight.greaterThan( float( 0 ) ), () => { + + denoised.divAssign( totalWeight ); + + } ); + + return vec4( denoised, texel.a ); + + } ).setLayout( { + name: 'denoise', + type: 'vec4', + inputs: [ + { name: 'uv', type: 'vec2' } + ] + } ); + + const output = Fn( () => { + + return denoise( uvNode ); + + } ); + + const outputNode = output(); + + return outputNode; + + } + +} + +function generatePdSamplePointInitializer( samples, rings, radiusExponent ) { + + const poissonDisk = generateDenoiseSamples( samples, rings, radiusExponent ); + + const array = []; + + for ( let i = 0; i < samples; i ++ ) { + + const sample = poissonDisk[ i ]; + array.push( sample ); + + } + + return array; + +} + +function generateDenoiseSamples( numSamples, numRings, radiusExponent ) { + + const samples = []; + + for ( let i = 0; i < numSamples; i ++ ) { + + const angle = 2 * Math.PI * numRings * i / numSamples; + const radius = Math.pow( i / ( numSamples - 1 ), radiusExponent ); + samples.push( new Vector3( Math.cos( angle ), Math.sin( angle ), radius ) ); + + } + + return samples; + +} + +const denoise = ( node, depthNode, normalNode, noiseNode, camera ) => nodeObject( new DenoiseNode( convertToTexture( node ), nodeObject( depthNode ), nodeObject( normalNode ), nodeObject( noiseNode ), camera ) ); + +class FXAANode extends TempNode { + + static get type() { + + return 'FXAANode'; + + } + + constructor( textureNode ) { + + super(); + + this.textureNode = textureNode; + + this.updateBeforeType = NodeUpdateType.RENDER; + + this._invSize = uniform( new Vector2() ); + + } + + updateBefore() { + + const map = this.textureNode.value; + + this._invSize.value.set( 1 / map.image.width, 1 / map.image.height ); + + } + + setup() { + + const textureNode = this.textureNode.bias( - 100 ); + const uvNode = textureNode.uvNode || uv(); + + // FXAA 3.11 implementation by NVIDIA, ported to WebGL by Agost Biro (biro@archilogic.com) + + //---------------------------------------------------------------------------------- + // File: es3-kepler\FXAA\assets\shaders/FXAA_DefaultES.frag + // SDK Version: v3.00 + // Email: gameworks@nvidia.com + // Site: http://developer.nvidia.com/ + // + // Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. + // + // Redistribution and use in source and binary forms, with or without + // modification, are permitted provided that the following conditions + // are met: + // * Redistributions of source code must retain the above copyright + // notice, this list of conditions and the following disclaimer. + // * Redistributions in binary form must reproduce the above copyright + // notice, this list of conditions and the following disclaimer in the + // documentation and/or other materials provided with the distribution. + // * Neither the name of NVIDIA CORPORATION nor the names of its + // contributors may be used to endorse or promote products derived + // from this software without specific prior written permission. + // + // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + // + //---------------------------------------------------------------------------------- + + const FxaaTexTop = ( p ) => textureNode.uv( p ); + const FxaaTexOff = ( p, o, r ) => textureNode.uv( p.add( o.mul( r ) ) ); + + const NUM_SAMPLES = int( 5 ); + + const contrast = Fn( ( [ a_immutable, b_immutable ] ) => { + + // assumes colors have premultipliedAlpha, so that the calculated color contrast is scaled by alpha + + const b = vec4( b_immutable ).toVar(); + const a = vec4( a_immutable ).toVar(); + const diff = vec4( abs( a.sub( b ) ) ).toVar(); + + return max$1( max$1( max$1( diff.r, diff.g ), diff.b ), diff.a ); + + } ); + + // FXAA3 QUALITY - PC + + const FxaaPixelShader = Fn( ( [ uv, fxaaQualityRcpFrame, fxaaQualityEdgeThreshold, fxaaQualityinvEdgeThreshold ] ) => { + + const rgbaM = FxaaTexTop( uv ).toVar(); + const rgbaS = FxaaTexOff( uv, vec2( 0.0, - 1.0 ), fxaaQualityRcpFrame.xy ).toVar(); + const rgbaE = FxaaTexOff( uv, vec2( 1.0, 0.0 ), fxaaQualityRcpFrame.xy ).toVar(); + const rgbaN = FxaaTexOff( uv, vec2( 0.0, 1.0 ), fxaaQualityRcpFrame.xy ).toVar(); + const rgbaW = FxaaTexOff( uv, vec2( - 1.0, 0.0 ), fxaaQualityRcpFrame.xy ).toVar(); + // . S . + // W M E + // . N . + + const contrastN = contrast( rgbaM, rgbaN ).toVar(); + const contrastS = contrast( rgbaM, rgbaS ).toVar(); + const contrastE = contrast( rgbaM, rgbaE ).toVar(); + const contrastW = contrast( rgbaM, rgbaW ).toVar(); + + const maxValue = max$1( contrastN, max$1( contrastS, max$1( contrastE, contrastW ) ) ).toVar(); + + // . 0 . + // 0 0 0 + // . 0 . + + If( maxValue.lessThan( fxaaQualityEdgeThreshold ), () => { + + return rgbaM; // assuming define FXAA_DISCARD is always 0 + + } ); + + // + + const relativeVContrast = sub( contrastN.add( contrastS ), ( contrastE.add( contrastW ) ) ).toVar(); + relativeVContrast.mulAssign( fxaaQualityinvEdgeThreshold ); + + // 45 deg edge detection and corners of objects, aka V/H contrast is too similar + + If( abs( relativeVContrast ).lessThan( 0.3 ), () => { + + // locate the edge + + const x = contrastE.greaterThan( contrastW ).select( 1, - 1 ).toVar(); + const y = contrastS.greaterThan( contrastN ).select( 1, - 1 ).toVar(); + + const dirToEdge = vec2( x, y ).toVar(); + // . 2 . . 1 . + // 1 0 2 ~= 0 0 1 + // . 1 . . 0 . + + // tap 2 pixels and see which ones are "outside" the edge, to + // determine if the edge is vertical or horizontal + + const rgbaAlongH = FxaaTexOff( uv, vec2( dirToEdge.x, dirToEdge.y ), fxaaQualityRcpFrame.xy ); + const matchAlongH = contrast( rgbaM, rgbaAlongH ).toVar(); + // . 1 . + // 0 0 1 + // . 0 H + + const rgbaAlongV = FxaaTexOff( uv, vec2( dirToEdge.x.negate(), dirToEdge.y.negate() ), fxaaQualityRcpFrame.xy ); + const matchAlongV = contrast( rgbaM, rgbaAlongV ).toVar(); + // V 1 . + // 0 0 1 + // . 0 . + + relativeVContrast.assign( matchAlongV.sub( matchAlongH ) ); + relativeVContrast.mulAssign( fxaaQualityinvEdgeThreshold ); + + If( abs( relativeVContrast ).lessThan( 0.3 ), () => { // 45 deg edge + + // 1 1 . + // 0 0 1 + // . 0 1 + + // do a simple blur + const sum = rgbaN.add( rgbaS ).add( rgbaE ).add( rgbaW ); + return mix( rgbaM, sum.mul( 0.25 ), 0.4 ); + + } ); + + } ); + + const offNP = vec2().toVar(); + + If( relativeVContrast.lessThanEqual( 0 ), () => { + + rgbaN.assign( rgbaW ); + rgbaS.assign( rgbaE ); + + // . 0 . 1 + // 1 0 1 -> 0 + // . 0 . 1 + + offNP.x.assign( 0 ); + offNP.y.assign( fxaaQualityRcpFrame.y ); + + } ).Else( () => { + + offNP.x.assign( fxaaQualityRcpFrame.x ); + offNP.y.assign( 0 ); + + } ); + + const mn = contrast( rgbaM, rgbaN ).toVar(); + const ms = contrast( rgbaM, rgbaS ).toVar(); + + If( mn.lessThanEqual( ms ), () => { + + rgbaN.assign( rgbaS ); + + } ); + + const doneN = int( 0 ).toVar(); + const doneP = int( 0 ).toVar(); + + const nDist = float( 0 ).toVar(); + const pDist = float( 0 ).toVar(); + + const posN = vec2( uv ).toVar(); + const posP = vec2( uv ).toVar(); + + const iterationsUsedN = int( 0 ).toVar(); + const iterationsUsedP = int( 0 ).toVar(); + + Loop( NUM_SAMPLES, ( { i } ) => { + + const increment = i.add( 1 ).toVar(); + + If( doneN.equal( 0 ), () => { + + nDist.addAssign( increment ); + posN.assign( uv.add( offNP.mul( nDist ) ) ); + const rgbaEndN = FxaaTexTop( posN.xy ); + + const nm = contrast( rgbaEndN, rgbaM ).toVar(); + const nn = contrast( rgbaEndN, rgbaN ).toVar(); + + If( nm.greaterThan( nn ), () => { + + doneN.assign( 1 ); + + } ); + + iterationsUsedN.assign( i ); + + } ); + + If( doneP.equal( 0 ), () => { + + pDist.addAssign( increment ); + posP.assign( uv.sub( offNP.mul( pDist ) ) ); + const rgbaEndP = FxaaTexTop( posP.xy ); + + const pm = contrast( rgbaEndP, rgbaM ).toVar(); + const pn = contrast( rgbaEndP, rgbaN ).toVar(); + + If( pm.greaterThan( pn ), () => { + + doneP.assign( 1 ); + + } ); + + iterationsUsedP.assign( i ); + + } ); + + If( doneN.equal( 1 ).or( doneP.equal( 1 ) ), () => { + + Break(); + + } ); + + } ); + + If( doneN.equal( 0 ).and( doneP.equal( 0 ) ), () => { + + return rgbaM; // failed to find end of edge + + } ); + + const distN = float( 1 ).toVar(); + const distP = float( 1 ).toVar(); + + If( doneN.equal( 1 ), () => { + + distN.assign( float( iterationsUsedN ).div( float( NUM_SAMPLES.sub( 1 ) ) ) ); + + } ); + + If( doneP.equal( 1 ), () => { + + distP.assign( float( iterationsUsedP ).div( float( NUM_SAMPLES.sub( 1 ) ) ) ); + + } ); + + const dist = min$1( distN, distP ); + + // hacky way of reduces blurriness of mostly diagonal edges + // but reduces AA quality + dist.assign( pow( dist, 0.5 ) ); + dist.assign( float( 1 ).sub( dist ) ); + + return mix( rgbaM, rgbaN, dist.mul( 0.5 ) ); + + } ).setLayout( { + name: 'FxaaPixelShader', + type: 'vec4', + inputs: [ + { name: 'uv', type: 'vec2' }, + { name: 'fxaaQualityRcpFrame', type: 'vec2' }, + { name: 'fxaaQualityEdgeThreshold', type: 'float' }, + { name: 'fxaaQualityinvEdgeThreshold', type: 'float' }, + ] + } ); + + const fxaa = Fn( () => { + + const edgeDetectionQuality = float( 0.2 ); + const invEdgeDetectionQuality = float( 1 ).div( edgeDetectionQuality ); + + return FxaaPixelShader( uvNode, this._invSize, edgeDetectionQuality, invEdgeDetectionQuality ); + + } ); + + const outputNode = fxaa(); + + return outputNode; + + } + +} + +const fxaa = ( node ) => nodeObject( new FXAANode( convertToTexture( node ) ) ); + +const _quadMesh$3 = /*@__PURE__*/ new QuadMesh(); + +const _clearColor$1 = /*@__PURE__*/ new Color( 0, 0, 0 ); +const _currentClearColor = /*@__PURE__*/ new Color(); +const _size$4 = /*@__PURE__*/ new Vector2(); + +const _BlurDirectionX = /*@__PURE__*/ new Vector2( 1.0, 0.0 ); +const _BlurDirectionY = /*@__PURE__*/ new Vector2( 0.0, 1.0 ); + +class BloomNode extends TempNode { + + static get type() { + + return 'BloomNode'; + + } + + constructor( inputNode, strength = 1, radius = 0, threshold = 0 ) { + + super(); + + this.inputNode = inputNode; + this.strength = uniform( strength ); + this.radius = uniform( radius ); + this.threshold = uniform( threshold ); + + this.smoothWidth = uniform( 0.01 ); + + // + + this._renderTargetsHorizontal = []; + this._renderTargetsVertical = []; + this._nMips = 5; + + // render targets + + this._renderTargetBright = new RenderTarget( 1, 1, { type: HalfFloatType } ); + this._renderTargetBright.texture.name = 'UnrealBloomPass.bright'; + this._renderTargetBright.texture.generateMipmaps = false; + + for ( let i = 0; i < this._nMips; i ++ ) { + + const renderTargetHorizontal = new RenderTarget( 1, 1, { type: HalfFloatType } ); + + renderTargetHorizontal.texture.name = 'UnrealBloomPass.h' + i; + renderTargetHorizontal.texture.generateMipmaps = false; + + this._renderTargetsHorizontal.push( renderTargetHorizontal ); + + const renderTargetVertical = new RenderTarget( 1, 1, { type: HalfFloatType } ); + + renderTargetVertical.texture.name = 'UnrealBloomPass.v' + i; + renderTargetVertical.texture.generateMipmaps = false; + + this._renderTargetsVertical.push( renderTargetVertical ); + + } + + // materials + + this._compositeMaterial = null; + this._highPassFilterMaterial = null; + this._separableBlurMaterials = []; + + // pass and texture nodes + + this._textureNodeBright = texture( this._renderTargetBright.texture ); + this._textureNodeBlur0 = texture( this._renderTargetsVertical[ 0 ].texture ); + this._textureNodeBlur1 = texture( this._renderTargetsVertical[ 1 ].texture ); + this._textureNodeBlur2 = texture( this._renderTargetsVertical[ 2 ].texture ); + this._textureNodeBlur3 = texture( this._renderTargetsVertical[ 3 ].texture ); + this._textureNodeBlur4 = texture( this._renderTargetsVertical[ 4 ].texture ); + + this._textureOutput = passTexture( this, this._renderTargetsHorizontal[ 0 ].texture ); + + this.updateBeforeType = NodeUpdateType.FRAME; + + } + + getTextureNode() { + + return this._textureOutput; + + } + + setSize( width, height ) { + + let resx = Math.round( width / 2 ); + let resy = Math.round( height / 2 ); + + this._renderTargetBright.setSize( resx, resy ); + + for ( let i = 0; i < this._nMips; i ++ ) { + + this._renderTargetsHorizontal[ i ].setSize( resx, resy ); + this._renderTargetsVertical[ i ].setSize( resx, resy ); + + this._separableBlurMaterials[ i ].invSize.value.set( 1 / resx, 1 / resy ); + + resx = Math.round( resx / 2 ); + resy = Math.round( resy / 2 ); + + } + + } + + updateBefore( frame ) { + + const { renderer } = frame; + + const size = renderer.getDrawingBufferSize( _size$4 ); + this.setSize( size.width, size.height ); + + const currentRenderTarget = renderer.getRenderTarget(); + const currentMRT = renderer.getMRT(); + renderer.getClearColor( _currentClearColor ); + const currentClearAlpha = renderer.getClearAlpha(); + + this.setSize( size.width, size.height ); + + renderer.setMRT( null ); + renderer.setClearColor( _clearColor$1, 0 ); + + // 1. Extract Bright Areas + + renderer.setRenderTarget( this._renderTargetBright ); + _quadMesh$3.material = this._highPassFilterMaterial; + _quadMesh$3.render( renderer ); + + // 2. Blur All the mips progressively + + let inputRenderTarget = this._renderTargetBright; + + for ( let i = 0; i < this._nMips; i ++ ) { + + _quadMesh$3.material = this._separableBlurMaterials[ i ]; + + this._separableBlurMaterials[ i ].colorTexture.value = inputRenderTarget.texture; + this._separableBlurMaterials[ i ].direction.value = _BlurDirectionX; + renderer.setRenderTarget( this._renderTargetsHorizontal[ i ] ); + renderer.clear(); + _quadMesh$3.render( renderer ); + + this._separableBlurMaterials[ i ].colorTexture.value = this._renderTargetsHorizontal[ i ].texture; + this._separableBlurMaterials[ i ].direction.value = _BlurDirectionY; + renderer.setRenderTarget( this._renderTargetsVertical[ i ] ); + renderer.clear(); + _quadMesh$3.render( renderer ); + + inputRenderTarget = this._renderTargetsVertical[ i ]; + + } + + // 3. Composite All the mips + + renderer.setRenderTarget( this._renderTargetsHorizontal[ 0 ] ); + renderer.clear(); + _quadMesh$3.material = this._compositeMaterial; + _quadMesh$3.render( renderer ); + + // restore + + renderer.setRenderTarget( currentRenderTarget ); + renderer.setMRT( currentMRT ); + renderer.setClearColor( _currentClearColor, currentClearAlpha ); + + } + + setup( builder ) { + + // luminosity high pass material + + const luminosityHighPass = Fn( () => { + + const texel = this.inputNode; + const v = luminance( texel.rgb ); + + const alpha = smoothstep( this.threshold, this.threshold.add( this.smoothWidth ), v ); + + return mix( vec4( 0 ), texel, alpha ); + + } ); + + this._highPassFilterMaterial = this._highPassFilterMaterial || new NodeMaterial(); + this._highPassFilterMaterial.fragmentNode = luminosityHighPass().context( builder.getSharedContext() ); + this._highPassFilterMaterial.name = 'Bloom_highPass'; + this._highPassFilterMaterial.needsUpdate = true; + + // gaussian blur materials + + const kernelSizeArray = [ 3, 5, 7, 9, 11 ]; + + for ( let i = 0; i < this._nMips; i ++ ) { + + this._separableBlurMaterials.push( this._getSeperableBlurMaterial( builder, kernelSizeArray[ i ] ) ); + + } + + // composite material + + const bloomFactors = uniformArray( [ 1.0, 0.8, 0.6, 0.4, 0.2 ] ); + const bloomTintColors = uniformArray( [ new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ) ] ); + + const lerpBloomFactor = Fn( ( [ factor, radius ] ) => { + + const mirrorFactor = float( 1.2 ).sub( factor ); + return mix( factor, mirrorFactor, radius ); + + } ).setLayout( { + name: 'lerpBloomFactor', + type: 'float', + inputs: [ + { name: 'factor', type: 'float' }, + { name: 'radius', type: 'float' }, + ] + } ); + + + const compositePass = Fn( () => { + + const color0 = lerpBloomFactor( bloomFactors.element( 0 ), this.radius ).mul( vec4( bloomTintColors.element( 0 ), 1.0 ) ).mul( this._textureNodeBlur0 ); + const color1 = lerpBloomFactor( bloomFactors.element( 1 ), this.radius ).mul( vec4( bloomTintColors.element( 1 ), 1.0 ) ).mul( this._textureNodeBlur1 ); + const color2 = lerpBloomFactor( bloomFactors.element( 2 ), this.radius ).mul( vec4( bloomTintColors.element( 2 ), 1.0 ) ).mul( this._textureNodeBlur2 ); + const color3 = lerpBloomFactor( bloomFactors.element( 3 ), this.radius ).mul( vec4( bloomTintColors.element( 3 ), 1.0 ) ).mul( this._textureNodeBlur3 ); + const color4 = lerpBloomFactor( bloomFactors.element( 4 ), this.radius ).mul( vec4( bloomTintColors.element( 4 ), 1.0 ) ).mul( this._textureNodeBlur4 ); + + const sum = color0.add( color1 ).add( color2 ).add( color3 ).add( color4 ); + + return sum.mul( this.strength ); + + } ); + + this._compositeMaterial = this._compositeMaterial || new NodeMaterial(); + this._compositeMaterial.fragmentNode = compositePass().context( builder.getSharedContext() ); + this._compositeMaterial.name = 'Bloom_comp'; + this._compositeMaterial.needsUpdate = true; + + // + + return this._textureOutput; + + } + + dispose() { + + for ( let i = 0; i < this._renderTargetsHorizontal.length; i ++ ) { + + this._renderTargetsHorizontal[ i ].dispose(); + + } + + for ( let i = 0; i < this._renderTargetsVertical.length; i ++ ) { + + this._renderTargetsVertical[ i ].dispose(); + + } + + this._renderTargetBright.dispose(); + + } + + _getSeperableBlurMaterial( builder, kernelRadius ) { + + const coefficients = []; + + for ( let i = 0; i < kernelRadius; i ++ ) { + + coefficients.push( 0.39894 * Math.exp( - 0.5 * i * i / ( kernelRadius * kernelRadius ) ) / kernelRadius ); + + } + + // + + const colorTexture = texture(); + const gaussianCoefficients = uniformArray( coefficients ); + const invSize = uniform( new Vector2() ); + const direction = uniform( new Vector2( 0.5, 0.5 ) ); + + const uvNode = uv(); + const sampleTexel = ( uv ) => colorTexture.uv( uv ); + + const seperableBlurPass = Fn( () => { + + const weightSum = gaussianCoefficients.element( 0 ).toVar(); + const diffuseSum = sampleTexel( uvNode ).rgb.mul( weightSum ).toVar(); + + Loop( { start: int( 1 ), end: int( kernelRadius ), type: 'int', condition: '<' }, ( { i } ) => { + + const x = float( i ); + const w = gaussianCoefficients.element( i ); + const uvOffset = direction.mul( invSize ).mul( x ); + const sample1 = sampleTexel( uvNode.add( uvOffset ) ).rgb; + const sample2 = sampleTexel( uvNode.sub( uvOffset ) ).rgb; + diffuseSum.addAssign( add( sample1, sample2 ).mul( w ) ); + weightSum.addAssign( float( 2.0 ).mul( w ) ); + + } ); + + return vec4( diffuseSum.div( weightSum ), 1.0 ); + + } ); + + const seperableBlurMaterial = new NodeMaterial(); + seperableBlurMaterial.fragmentNode = seperableBlurPass().context( builder.getSharedContext() ); + seperableBlurMaterial.name = 'Bloom_seperable'; + seperableBlurMaterial.needsUpdate = true; + + // uniforms + seperableBlurMaterial.colorTexture = colorTexture; + seperableBlurMaterial.direction = direction; + seperableBlurMaterial.invSize = invSize; + + return seperableBlurMaterial; + + } + +} + +const bloom = ( node, strength, radius, threshold ) => nodeObject( new BloomNode( nodeObject( node ), strength, radius, threshold ) ); + +class TransitionNode extends TempNode { + + static get type() { + + return 'TransitionNode'; + + } + + constructor( textureNodeA, textureNodeB, mixTextureNode, mixRatioNode, thresholdNode, useTextureNode ) { + + super(); + + // Input textures + + this.textureNodeA = textureNodeA; + this.textureNodeB = textureNodeB; + this.mixTextureNode = mixTextureNode; + + // Uniforms + + this.mixRatioNode = mixRatioNode; + this.thresholdNode = thresholdNode; + this.useTextureNode = useTextureNode; + + } + + setup() { + + const { textureNodeA, textureNodeB, mixTextureNode, mixRatioNode, thresholdNode, useTextureNode } = this; + + const sampleTexture = ( textureNode ) => { + + const uvNodeTexture = textureNode.uvNode || uv(); + return textureNode.uv( uvNodeTexture ); + + }; + + const transition = Fn( () => { + + const texelOne = sampleTexture( textureNodeA ); + const texelTwo = sampleTexture( textureNodeB ); + + const color = vec4().toVar(); + + If( useTextureNode.equal( int( 1 ) ), () => { + + const transitionTexel = sampleTexture( mixTextureNode ); + const r = mixRatioNode.mul( thresholdNode.mul( 2.0 ).add( 1.0 ) ).sub( thresholdNode ); + const mixf = clamp( sub( transitionTexel.r, r ).mul( float( 1.0 ).div( thresholdNode ) ), 0.0, 1.0 ); + + color.assign( mix( texelOne, texelTwo, mixf ) ); + + } ).Else( () => { + + color.assign( mix( texelTwo, texelOne, mixRatioNode ) ); + + } ); + + return color; + + } ); + + const outputNode = transition(); + + return outputNode; + + } + +} + +const transition = ( nodeA, nodeB, mixTexture, mixRatio = 0.0, threshold = 0.1, useTexture = 0 ) => nodeObject( new TransitionNode( convertToTexture( nodeA ), convertToTexture( nodeB ), convertToTexture( mixTexture ), nodeObject( mixRatio ), nodeObject( threshold ), nodeObject( useTexture ) ) ); + +class PixelationNode extends TempNode { + + static get type() { + + return 'PixelationNode'; + + } + + constructor( textureNode, depthNode, normalNode, pixelSize, normalEdgeStrength, depthEdgeStrength ) { + + super(); + + // Input textures + + this.textureNode = textureNode; + this.depthNode = depthNode; + this.normalNode = normalNode; + + // Input uniforms + + this.pixelSize = pixelSize; + this.normalEdgeStrength = normalEdgeStrength; + this.depthEdgeStrength = depthEdgeStrength; + + // Private uniforms + + this._resolution = uniform( new Vector4() ); + + this.updateBeforeType = NodeUpdateType.RENDER; + + } + + updateBefore() { + + const map = this.textureNode.value; + + const width = map.image.width; + const height = map.image.height; + + this._resolution.value.set( width, height, 1 / width, 1 / height ); + + } + + setup() { + + const { textureNode, depthNode, normalNode } = this; + + const uvNodeTexture = textureNode.uvNode || uv(); + const uvNodeDepth = depthNode.uvNode || uv(); + const uvNodeNormal = normalNode.uvNode || uv(); + + const sampleTexture = () => textureNode.uv( uvNodeTexture ); + + const sampleDepth = ( x, y ) => depthNode.uv( uvNodeDepth.add( vec2( x, y ).mul( this._resolution.zw ) ) ).r; + + const sampleNormal = ( x, y ) => normalNode.uv( uvNodeNormal.add( vec2( x, y ).mul( this._resolution.zw ) ) ).rgb.normalize(); + + const depthEdgeIndicator = ( depth ) => { + + const diff = property( 'float', 'diff' ); + diff.addAssign( clamp( sampleDepth( 1, 0 ).sub( depth ) ) ); + diff.addAssign( clamp( sampleDepth( - 1, 0 ).sub( depth ) ) ); + diff.addAssign( clamp( sampleDepth( 0, 1 ).sub( depth ) ) ); + diff.addAssign( clamp( sampleDepth( 0, - 1 ).sub( depth ) ) ); + + return floor( smoothstep( 0.01, 0.02, diff ).mul( 2 ) ).div( 2 ); + + }; + + const neighborNormalEdgeIndicator = ( x, y, depth, normal ) => { + + const depthDiff = sampleDepth( x, y ).sub( depth ); + const neighborNormal = sampleNormal( x, y ); + + // Edge pixels should yield to faces who's normals are closer to the bias normal. + + const normalEdgeBias = vec3( 1, 1, 1 ); // This should probably be a parameter. + const normalDiff = dot( normal.sub( neighborNormal ), normalEdgeBias ); + const normalIndicator = clamp( smoothstep( - 0.01, 0.01, normalDiff ), 0.0, 1.0 ); + + // Only the shallower pixel should detect the normal edge. + + const depthIndicator = clamp( sign( depthDiff.mul( .25 ).add( .0025 ) ), 0.0, 1.0 ); + + return float( 1.0 ).sub( dot( normal, neighborNormal ) ).mul( depthIndicator ).mul( normalIndicator ); + + }; + + const normalEdgeIndicator = ( depth, normal ) => { + + const indicator = property( 'float', 'indicator' ); + + indicator.addAssign( neighborNormalEdgeIndicator( 0, - 1, depth, normal ) ); + indicator.addAssign( neighborNormalEdgeIndicator( 0, 1, depth, normal ) ); + indicator.addAssign( neighborNormalEdgeIndicator( - 1, 0, depth, normal ) ); + indicator.addAssign( neighborNormalEdgeIndicator( 1, 0, depth, normal ) ); + + return step( 0.1, indicator ); + + }; + + const pixelation = Fn( () => { + + const texel = sampleTexture(); + + const depth = property( 'float', 'depth' ); + const normal = property( 'vec3', 'normal' ); + + If( this.depthEdgeStrength.greaterThan( 0.0 ).or( this.normalEdgeStrength.greaterThan( 0.0 ) ), () => { + + depth.assign( sampleDepth( 0, 0 ) ); + normal.assign( sampleNormal( 0, 0 ) ); + + } ); + + const dei = property( 'float', 'dei' ); + + If( this.depthEdgeStrength.greaterThan( 0.0 ), () => { + + dei.assign( depthEdgeIndicator( depth ) ); + + } ); + + const nei = property( 'float', 'nei' ); + + If( this.normalEdgeStrength.greaterThan( 0.0 ), () => { + + nei.assign( normalEdgeIndicator( depth, normal ) ); + + } ); + + const strength = dei.greaterThan( 0 ).select( float( 1.0 ).sub( dei.mul( this.depthEdgeStrength ) ), nei.mul( this.normalEdgeStrength ).add( 1 ) ); + + return texel.mul( strength ); + + } ); + + const outputNode = pixelation(); + + return outputNode; + + } + +} + +const pixelation = ( node, depthNode, normalNode, pixelSize = 6, normalEdgeStrength = 0.3, depthEdgeStrength = 0.4 ) => nodeObject( new PixelationNode( convertToTexture( node ), convertToTexture( depthNode ), convertToTexture( normalNode ), nodeObject( pixelSize ), nodeObject( normalEdgeStrength ), nodeObject( depthEdgeStrength ) ) ); + +class PixelationPassNode extends PassNode { + + static get type() { + + return 'PixelationPassNode'; + + } + + constructor( scene, camera, pixelSize = 6, normalEdgeStrength = 0.3, depthEdgeStrength = 0.4 ) { + + super( 'color', scene, camera, { minFilter: NearestFilter, magFilter: NearestFilter } ); + + this.pixelSize = pixelSize; + this.normalEdgeStrength = normalEdgeStrength; + this.depthEdgeStrength = depthEdgeStrength; + + this.isPixelationPassNode = true; + + this._mrt = mrt( { + output: output, + normal: normalView + } ); + + } + + setSize( width, height ) { + + const pixelSize = this.pixelSize.value ? this.pixelSize.value : this.pixelSize; + + const adjustedWidth = Math.floor( width / pixelSize ); + const adjustedHeight = Math.floor( height / pixelSize ); + + super.setSize( adjustedWidth, adjustedHeight ); + + } + + setup() { + + const color = super.getTextureNode( 'output' ); + const depth = super.getTextureNode( 'depth' ); + const normal = super.getTextureNode( 'normal' ); + + return pixelation( color, depth, normal, this.pixelSize, this.normalEdgeStrength, this.depthEdgeStrength ); + + } + +} + +const pixelationPass = ( scene, camera, pixelSize, normalEdgeStrength, depthEdgeStrength ) => nodeObject( new PixelationPassNode( scene, camera, pixelSize, normalEdgeStrength, depthEdgeStrength ) ); + +const _size$3 = /*@__PURE__*/ new Vector2(); + +/** +* +* Supersample Anti-Aliasing Render Pass +* +* This manual approach to SSAA re-renders the scene ones for each sample with camera jitter and accumulates the results. +* +* References: https://en.wikipedia.org/wiki/Supersampling +* +*/ + +class SSAAPassNode extends PassNode { + + static get type() { + + return 'SSAAPassNode'; + + } + + constructor( scene, camera ) { + + super( PassNode.COLOR, scene, camera ); + + this.isSSAAPassNode = true; + + this.sampleLevel = 4; // specified as n, where the number of samples is 2^n, so sampleLevel = 4, is 2^4 samples, 16. + this.unbiased = true; + this.clearColor = new Color( 0x000000 ); + this.clearAlpha = 0; + + this._currentClearColor = new Color(); + + this.sampleWeight = uniform( 1 ); + + this.sampleRenderTarget = null; + + this._quadMesh = new QuadMesh(); + + } + + updateBefore( frame ) { + + const { renderer } = frame; + const { scene, camera } = this; + + this._pixelRatio = renderer.getPixelRatio(); + + const size = renderer.getSize( _size$3 ); + + this.setSize( size.width, size.height ); + this.sampleRenderTarget.setSize( this.renderTarget.width, this.renderTarget.height ); + + // save current renderer settings + + renderer.getClearColor( this._currentClearColor ); + const currentClearAlpha = renderer.getClearAlpha(); + const currentRenderTarget = renderer.getRenderTarget(); + const currentMRT = renderer.getMRT(); + const currentAutoClear = renderer.autoClear; + + // + + this._cameraNear.value = camera.near; + this._cameraFar.value = camera.far; + + renderer.setMRT( this.getMRT() ); + renderer.autoClear = false; + + const jitterOffsets = _JitterVectors[ Math.max( 0, Math.min( this.sampleLevel, 5 ) ) ]; + + const baseSampleWeight = 1.0 / jitterOffsets.length; + const roundingRange = 1 / 32; + + const viewOffset = { + + fullWidth: this.renderTarget.width, + fullHeight: this.renderTarget.height, + offsetX: 0, + offsetY: 0, + width: this.renderTarget.width, + height: this.renderTarget.height + + }; + + const originalViewOffset = Object.assign( {}, camera.view ); + + if ( originalViewOffset.enabled ) Object.assign( viewOffset, originalViewOffset ); + + // render the scene multiple times, each slightly jitter offset from the last and accumulate the results. + + for ( let i = 0; i < jitterOffsets.length; i ++ ) { + + const jitterOffset = jitterOffsets[ i ]; + + if ( camera.setViewOffset ) { + + camera.setViewOffset( + + viewOffset.fullWidth, viewOffset.fullHeight, + + viewOffset.offsetX + jitterOffset[ 0 ] * 0.0625, viewOffset.offsetY + jitterOffset[ 1 ] * 0.0625, // 0.0625 = 1 / 16 + + viewOffset.width, viewOffset.height + + ); + + } + + this.sampleWeight.value = baseSampleWeight; + + if ( this.unbiased ) { + + // the theory is that equal weights for each sample lead to an accumulation of rounding errors. + // The following equation varies the sampleWeight per sample so that it is uniformly distributed + // across a range of values whose rounding errors cancel each other out. + + const uniformCenteredDistribution = ( - 0.5 + ( i + 0.5 ) / jitterOffsets.length ); + this.sampleWeight.value += roundingRange * uniformCenteredDistribution; + + } + + renderer.setClearColor( this.clearColor, this.clearAlpha ); + renderer.setRenderTarget( this.sampleRenderTarget ); + renderer.clear(); + renderer.render( scene, camera ); + + // accumulation + + renderer.setRenderTarget( this.renderTarget ); + + if ( i === 0 ) { + + renderer.setClearColor( 0x000000, 0.0 ); + renderer.clear(); + + } + + this._quadMesh.render( renderer ); + + } + + renderer.copyTextureToTexture( this.sampleRenderTarget.depthTexture, this.renderTarget.depthTexture ); + + // restore + + if ( camera.setViewOffset && originalViewOffset.enabled ) { + + camera.setViewOffset( + + originalViewOffset.fullWidth, originalViewOffset.fullHeight, + + originalViewOffset.offsetX, originalViewOffset.offsetY, + + originalViewOffset.width, originalViewOffset.height + + ); + + } else if ( camera.clearViewOffset ) { + + camera.clearViewOffset(); + + } + + renderer.setRenderTarget( currentRenderTarget ); + renderer.setMRT( currentMRT ); + + renderer.autoClear = currentAutoClear; + renderer.setClearColor( this._currentClearColor, currentClearAlpha ); + + } + + setup( builder ) { + + if ( this.sampleRenderTarget === null ) { + + this.sampleRenderTarget = this.renderTarget.clone(); + + } + + let sampleTexture; + + const passMRT = this.getMRT(); + + if ( passMRT !== null ) { + + const outputs = {}; + + for ( const name in passMRT.outputNodes ) { + + const index = getTextureIndex( this.sampleRenderTarget.textures, name ); + + if ( index >= 0 ) { + + outputs[ name ] = texture( this.sampleRenderTarget.textures[ index ] ).mul( this.sampleWeight ); + + } + + } + + sampleTexture = mrt( outputs ); + + } else { + + sampleTexture = texture( this.sampleRenderTarget.texture ).mul( this.sampleWeight ); + + } + + this._quadMesh.material = new NodeMaterial(); + this._quadMesh.material.fragmentNode = sampleTexture; + this._quadMesh.material.transparent = true; + this._quadMesh.material.depthTest = false; + this._quadMesh.material.depthWrite = false; + this._quadMesh.material.premultipliedAlpha = true; + this._quadMesh.material.blending = AdditiveBlending; + this._quadMesh.material.normals = false; + this._quadMesh.material.name = 'SSAA'; + + return super.setup( builder ); + + } + + dispose() { + + super.dispose(); + + if ( this.sampleRenderTarget !== null ) { + + this.sampleRenderTarget.dispose(); + + } + + } + +} + +// These jitter vectors are specified in integers because it is easier. +// I am assuming a [-8,8) integer grid, but it needs to be mapped onto [-0.5,0.5) +// before being used, thus these integers need to be scaled by 1/16. +// +// Sample patterns reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476218%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 +const _JitterVectors = [ + [ + [ 0, 0 ] + ], + [ + [ 4, 4 ], [ - 4, - 4 ] + ], + [ + [ - 2, - 6 ], [ 6, - 2 ], [ - 6, 2 ], [ 2, 6 ] + ], + [ + [ 1, - 3 ], [ - 1, 3 ], [ 5, 1 ], [ - 3, - 5 ], + [ - 5, 5 ], [ - 7, - 1 ], [ 3, 7 ], [ 7, - 7 ] + ], + [ + [ 1, 1 ], [ - 1, - 3 ], [ - 3, 2 ], [ 4, - 1 ], + [ - 5, - 2 ], [ 2, 5 ], [ 5, 3 ], [ 3, - 5 ], + [ - 2, 6 ], [ 0, - 7 ], [ - 4, - 6 ], [ - 6, 4 ], + [ - 8, 0 ], [ 7, - 4 ], [ 6, 7 ], [ - 7, - 8 ] + ], + [ + [ - 4, - 7 ], [ - 7, - 5 ], [ - 3, - 5 ], [ - 5, - 4 ], + [ - 1, - 4 ], [ - 2, - 2 ], [ - 6, - 1 ], [ - 4, 0 ], + [ - 7, 1 ], [ - 1, 2 ], [ - 6, 3 ], [ - 3, 3 ], + [ - 7, 6 ], [ - 3, 6 ], [ - 5, 7 ], [ - 1, 7 ], + [ 5, - 7 ], [ 1, - 6 ], [ 6, - 5 ], [ 4, - 4 ], + [ 2, - 3 ], [ 7, - 2 ], [ 1, - 1 ], [ 4, - 1 ], + [ 2, 1 ], [ 6, 2 ], [ 0, 4 ], [ 4, 4 ], + [ 2, 5 ], [ 7, 5 ], [ 5, 6 ], [ 3, 7 ] + ] +]; + +const ssaaPass = ( scene, camera ) => nodeObject( new SSAAPassNode( scene, camera ) ); + +const _size$2 = /*@__PURE__*/ new Vector2(); + +class StereoPassNode extends PassNode { + + static get type() { + + return 'StereoPassNode'; + + } + + constructor( scene, camera ) { + + super( PassNode.COLOR, scene, camera ); + + this.isStereoPassNode = true; + + this.stereo = new StereoCamera(); + this.stereo.aspect = 0.5; + + } + + updateBefore( frame ) { + + const { renderer } = frame; + const { scene, camera, stereo, renderTarget } = this; + + this._pixelRatio = renderer.getPixelRatio(); + + stereo.cameraL.coordinateSystem = renderer.coordinateSystem; + stereo.cameraR.coordinateSystem = renderer.coordinateSystem; + stereo.update( camera ); + + const size = renderer.getSize( _size$2 ); + this.setSize( size.width, size.height ); + + const currentAutoClear = renderer.autoClear; + renderer.autoClear = false; + + const currentRenderTarget = renderer.getRenderTarget(); + const currentMRT = renderer.getMRT(); + + this._cameraNear.value = camera.near; + this._cameraFar.value = camera.far; + + for ( const name in this._previousTextures ) { + + this.toggleTexture( name ); + + } + + renderer.setRenderTarget( renderTarget ); + renderer.setMRT( this._mrt ); + renderer.clear(); + + renderTarget.scissorTest = true; + + renderTarget.scissor.set( 0, 0, renderTarget.width / 2, renderTarget.height ); + renderTarget.viewport.set( 0, 0, renderTarget.width / 2, renderTarget.height ); + renderer.render( scene, stereo.cameraL ); + + renderTarget.scissor.set( renderTarget.width / 2, 0, renderTarget.width / 2, renderTarget.height ); + renderTarget.viewport.set( renderTarget.width / 2, 0, renderTarget.width / 2, renderTarget.height ); + renderer.render( scene, stereo.cameraR ); + + renderTarget.scissorTest = false; + + renderer.setRenderTarget( currentRenderTarget ); + renderer.setMRT( currentMRT ); + + renderer.autoClear = currentAutoClear; + + } + +} + +const stereoPass = ( scene, camera ) => nodeObject( new StereoPassNode( scene, camera ) ); + +const _size$1 = /*@__PURE__*/ new Vector2(); +const _quadMesh$2 = /*@__PURE__*/ new QuadMesh(); + +class StereoCompositePassNode extends PassNode { + + static get type() { + + return 'StereoCompositePassNode'; + + } + + constructor( scene, camera ) { + + super( PassNode.COLOR, scene, camera ); + + this.isStereoCompositePassNode = true; + + this.stereo = new StereoCamera(); + const _params = { minFilter: LinearFilter, magFilter: NearestFilter, type: HalfFloatType }; + + this._renderTargetL = new RenderTarget( 1, 1, _params ); + this._renderTargetR = new RenderTarget( 1, 1, _params ); + + this._mapLeft = texture( this._renderTargetL.texture ); + this._mapRight = texture( this._renderTargetR.texture ); + + this._material = null; + + } + + updateStereoCamera( coordinateSystem ) { + + this.stereo.cameraL.coordinateSystem = coordinateSystem; + this.stereo.cameraR.coordinateSystem = coordinateSystem; + this.stereo.update( this.camera ); + + } + + setSize( width, height ) { + + super.setSize( width, height ); + + this._renderTargetL.setSize( this.renderTarget.width, this.renderTarget.height ); + this._renderTargetR.setSize( this.renderTarget.width, this.renderTarget.height ); + + } + + updateBefore( frame ) { + + const { renderer } = frame; + const { scene, stereo, renderTarget } = this; + + this._pixelRatio = renderer.getPixelRatio(); + + this.updateStereoCamera( renderer.coordinateSystem ); + + const size = renderer.getSize( _size$1 ); + this.setSize( size.width, size.height ); + + const currentRenderTarget = renderer.getRenderTarget(); + + // left + + renderer.setRenderTarget( this._renderTargetL ); + renderer.render( scene, stereo.cameraL ); + + // right + + renderer.setRenderTarget( this._renderTargetR ); + renderer.render( scene, stereo.cameraR ); + + // composite + + renderer.setRenderTarget( renderTarget ); + _quadMesh$2.material = this._material; + _quadMesh$2.render( renderer ); + + // restore + + renderer.setRenderTarget( currentRenderTarget ); + + } + + dispose() { + + super.dispose(); + + this._renderTargetL.dispose(); + this._renderTargetR.dispose(); + + if ( this._material !== null ) { + + this._material.dispose(); + + } + + } + +} + +class AnaglyphPassNode extends StereoCompositePassNode { + + static get type() { + + return 'AnaglyphPassNode'; + + } + + constructor( scene, camera ) { + + super( scene, camera ); + + this.isAnaglyphPassNode = true; + + // Dubois matrices from https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.7.6968&rep=rep1&type=pdf#page=4 + + this._colorMatrixLeft = uniform( new Matrix3().fromArray( [ + 0.456100, - 0.0400822, - 0.0152161, + 0.500484, - 0.0378246, - 0.0205971, + 0.176381, - 0.0157589, - 0.00546856 + ] ) ); + + this._colorMatrixRight = uniform( new Matrix3().fromArray( [ + - 0.0434706, 0.378476, - 0.0721527, + - 0.0879388, 0.73364, - 0.112961, + - 0.00155529, - 0.0184503, 1.2264 + ] ) ); + + } + + setup( builder ) { + + const uvNode = uv(); + + const anaglyph = Fn( () => { + + const colorL = this._mapLeft.uv( uvNode ); + const colorR = this._mapRight.uv( uvNode ); + + const color = clamp( this._colorMatrixLeft.mul( colorL.rgb ).add( this._colorMatrixRight.mul( colorR.rgb ) ) ); + + return vec4( color.rgb, max$1( colorL.a, colorR.a ) ); + + } ); + + const material = this._material || ( this._material = new NodeMaterial() ); + material.fragmentNode = anaglyph().context( builder.getSharedContext() ); + material.name = 'Anaglyph'; + material.needsUpdate = true; + + return super.setup( builder ); + + } + +} + +const anaglyphPass = ( scene, camera ) => nodeObject( new AnaglyphPassNode( scene, camera ) ); + +class ParallaxBarrierPassNode extends StereoCompositePassNode { + + static get type() { + + return 'ParallaxBarrierPassNode'; + + } + + constructor( scene, camera ) { + + super( scene, camera ); + + this.isParallaxBarrierPassNode = true; + + } + + setup( builder ) { + + const uvNode = uv(); + + const parallaxBarrier = Fn( () => { + + const color = vec4().toVar(); + + If( mod( screenCoordinate.y, 2 ).greaterThan( 1 ), () => { + + color.assign( this._mapLeft.uv( uvNode ) ); + + } ).Else( () => { + + color.assign( this._mapRight.uv( uvNode ) ); + + } ); + + return color; + + } ); + + const material = this._material || ( this._material = new NodeMaterial() ); + material.fragmentNode = parallaxBarrier().context( builder.getSharedContext() ); + material.needsUpdate = true; + + return super.setup( builder ); + + } + +} + +const parallaxBarrierPass = ( scene, camera ) => nodeObject( new ParallaxBarrierPassNode( scene, camera ) ); + +class ToonOutlinePassNode extends PassNode { + + static get type() { + + return 'ToonOutlinePassNode'; + + } + + constructor( scene, camera, colorNode, thicknessNode, alphaNode ) { + + super( PassNode.COLOR, scene, camera ); + + this.colorNode = colorNode; + this.thicknessNode = thicknessNode; + this.alphaNode = alphaNode; + + this._materialCache = new WeakMap(); + + } + + updateBefore( frame ) { + + const { renderer } = frame; + + const currentRenderObjectFunction = renderer.getRenderObjectFunction(); + + renderer.setRenderObjectFunction( ( object, scene, camera, geometry, material, group, lightsNode ) => { + + // only render outline for supported materials + + if ( material.isMeshToonMaterial || material.isMeshToonNodeMaterial ) { + + if ( material.wireframe === false ) { + + const outlineMaterial = this._getOutlineMaterial( material ); + renderer.renderObject( object, scene, camera, geometry, outlineMaterial, group, lightsNode ); + + } + + } + + // default + + renderer.renderObject( object, scene, camera, geometry, material, group, lightsNode ); + + } ); + + super.updateBefore( frame ); + + renderer.setRenderObjectFunction( currentRenderObjectFunction ); + + } + + _createMaterial() { + + const material = new NodeMaterial(); + material.isMeshToonOutlineMaterial = true; + material.name = 'Toon_Outline'; + material.side = BackSide; + + // vertex node + + const outlineNormal = normalLocal.negate(); + const mvp = cameraProjectionMatrix.mul( modelViewMatrix ); + + const ratio = float( 1.0 ); // TODO: support outline thickness ratio for each vertex + const pos = mvp.mul( vec4( positionLocal, 1.0 ) ); + const pos2 = mvp.mul( vec4( positionLocal.add( outlineNormal ), 1.0 ) ); + const norm = normalize( pos.sub( pos2 ) ); // NOTE: subtract pos2 from pos because BackSide objectNormal is negative + + material.vertexNode = pos.add( norm.mul( this.thicknessNode ).mul( pos.w ).mul( ratio ) ); + + // color node + + material.colorNode = vec4( this.colorNode, this.alphaNode ); + + return material; + + } + + _getOutlineMaterial( originalMaterial ) { + + let outlineMaterial = this._materialCache.get( originalMaterial ); + + if ( outlineMaterial === undefined ) { + + outlineMaterial = this._createMaterial(); + + this._materialCache.set( originalMaterial, outlineMaterial ); + + } + + return outlineMaterial; + + } + +} + +const toonOutlinePass = ( scene, camera, color = new Color( 0, 0, 0 ), thickness = 0.003, alpha = 1 ) => nodeObject( new ToonOutlinePassNode( scene, camera, nodeObject( color ), nodeObject( thickness ), nodeObject( alpha ) ) ); + +class ScriptableValueNode extends Node { + + static get type() { + + return 'ScriptableValueNode'; + + } + + constructor( value = null ) { + + super(); + + this._value = value; + this._cache = null; + + this.inputType = null; + this.outpuType = null; + + this.events = new EventDispatcher(); + + this.isScriptableValueNode = true; + + } + + get isScriptableOutputNode() { + + return this.outputType !== null; + + } + + set value( val ) { + + if ( this._value === val ) return; + + if ( this._cache && this.inputType === 'URL' && this.value.value instanceof ArrayBuffer ) { + + URL.revokeObjectURL( this._cache ); + + this._cache = null; + + } + + this._value = val; + + this.events.dispatchEvent( { type: 'change' } ); + + this.refresh(); + + } + + get value() { + + return this._value; + + } + + refresh() { + + this.events.dispatchEvent( { type: 'refresh' } ); + + } + + getValue() { + + const value = this.value; + + if ( value && this._cache === null && this.inputType === 'URL' && value.value instanceof ArrayBuffer ) { + + this._cache = URL.createObjectURL( new Blob( [ value.value ] ) ); + + } else if ( value && value.value !== null && value.value !== undefined && ( + ( ( this.inputType === 'URL' || this.inputType === 'String' ) && typeof value.value === 'string' ) || + ( this.inputType === 'Number' && typeof value.value === 'number' ) || + ( this.inputType === 'Vector2' && value.value.isVector2 ) || + ( this.inputType === 'Vector3' && value.value.isVector3 ) || + ( this.inputType === 'Vector4' && value.value.isVector4 ) || + ( this.inputType === 'Color' && value.value.isColor ) || + ( this.inputType === 'Matrix3' && value.value.isMatrix3 ) || + ( this.inputType === 'Matrix4' && value.value.isMatrix4 ) + ) ) { + + return value.value; + + } + + return this._cache || value; + + } + + getNodeType( builder ) { + + return this.value && this.value.isNode ? this.value.getNodeType( builder ) : 'float'; + + } + + setup() { + + return this.value && this.value.isNode ? this.value : float(); + + } + + serialize( data ) { + + super.serialize( data ); + + if ( this.value !== null ) { + + if ( this.inputType === 'ArrayBuffer' ) { + + data.value = arrayBufferToBase64( this.value ); + + } else { + + data.value = this.value ? this.value.toJSON( data.meta ).uuid : null; + + } + + } else { + + data.value = null; + + } + + data.inputType = this.inputType; + data.outputType = this.outputType; + + } + + deserialize( data ) { + + super.deserialize( data ); + + let value = null; + + if ( data.value !== null ) { + + if ( data.inputType === 'ArrayBuffer' ) { + + value = base64ToArrayBuffer( data.value ); + + } else if ( data.inputType === 'Texture' ) { + + value = data.meta.textures[ data.value ]; + + } else { + + value = data.meta.nodes[ data.value ] || null; + + } + + } + + this.value = value; + + this.inputType = data.inputType; + this.outputType = data.outputType; + + } + +} + +const scriptableValue = /*@__PURE__*/ nodeProxy( ScriptableValueNode ); + +class Resources extends Map { + + get( key, callback = null, ...params ) { + + if ( this.has( key ) ) return super.get( key ); + + if ( callback !== null ) { + + const value = callback( ...params ); + this.set( key, value ); + return value; + + } + + } + +} + +class Parameters { + + constructor( scriptableNode ) { + + this.scriptableNode = scriptableNode; + + } + + get parameters() { + + return this.scriptableNode.parameters; + + } + + get layout() { + + return this.scriptableNode.getLayout(); + + } + + getInputLayout( id ) { + + return this.scriptableNode.getInputLayout( id ); + + } + + get( name ) { + + const param = this.parameters[ name ]; + const value = param ? param.getValue() : null; + + return value; + + } + +} + +const global = new Resources(); + +class ScriptableNode extends Node { + + static get type() { + + return 'ScriptableNode'; + + } + + constructor( codeNode = null, parameters = {} ) { + + super(); + + this.codeNode = codeNode; + this.parameters = parameters; + + this._local = new Resources(); + this._output = scriptableValue(); + this._outputs = {}; + this._source = this.source; + this._method = null; + this._object = null; + this._value = null; + this._needsOutputUpdate = true; + + this.onRefresh = this.onRefresh.bind( this ); + + this.isScriptableNode = true; + + } + + get source() { + + return this.codeNode ? this.codeNode.code : ''; + + } + + setLocal( name, value ) { + + return this._local.set( name, value ); + + } + + getLocal( name ) { + + return this._local.get( name ); + + } + + onRefresh() { + + this._refresh(); + + } + + getInputLayout( id ) { + + for ( const element of this.getLayout() ) { + + if ( element.inputType && ( element.id === id || element.name === id ) ) { + + return element; + + } + + } + + } + + getOutputLayout( id ) { + + for ( const element of this.getLayout() ) { + + if ( element.outputType && ( element.id === id || element.name === id ) ) { + + return element; + + } + + } + + } + + setOutput( name, value ) { + + const outputs = this._outputs; + + if ( outputs[ name ] === undefined ) { + + outputs[ name ] = scriptableValue( value ); + + } else { + + outputs[ name ].value = value; + + } + + return this; + + } + + getOutput( name ) { + + return this._outputs[ name ]; + + } + + getParameter( name ) { + + return this.parameters[ name ]; + + } + + setParameter( name, value ) { + + const parameters = this.parameters; + + if ( value && value.isScriptableNode ) { + + this.deleteParameter( name ); + + parameters[ name ] = value; + parameters[ name ].getDefaultOutput().events.addEventListener( 'refresh', this.onRefresh ); + + } else if ( value && value.isScriptableValueNode ) { + + this.deleteParameter( name ); + + parameters[ name ] = value; + parameters[ name ].events.addEventListener( 'refresh', this.onRefresh ); + + } else if ( parameters[ name ] === undefined ) { + + parameters[ name ] = scriptableValue( value ); + parameters[ name ].events.addEventListener( 'refresh', this.onRefresh ); + + } else { + + parameters[ name ].value = value; + + } + + return this; + + } + + getValue() { + + return this.getDefaultOutput().getValue(); + + } + + deleteParameter( name ) { + + let valueNode = this.parameters[ name ]; + + if ( valueNode ) { + + if ( valueNode.isScriptableNode ) valueNode = valueNode.getDefaultOutput(); + + valueNode.events.removeEventListener( 'refresh', this.onRefresh ); + + } + + return this; + + } + + clearParameters() { + + for ( const name of Object.keys( this.parameters ) ) { + + this.deleteParameter( name ); + + } + + this.needsUpdate = true; + + return this; + + } + + call( name, ...params ) { + + const object = this.getObject(); + const method = object[ name ]; + + if ( typeof method === 'function' ) { + + return method( ...params ); + + } + + } + + async callAsync( name, ...params ) { + + const object = this.getObject(); + const method = object[ name ]; + + if ( typeof method === 'function' ) { + + return method.constructor.name === 'AsyncFunction' ? await method( ...params ) : method( ...params ); + + } + + } + + getNodeType( builder ) { + + return this.getDefaultOutputNode().getNodeType( builder ); + + } + + refresh( output = null ) { + + if ( output !== null ) { + + this.getOutput( output ).refresh(); + + } else { + + this._refresh(); + + } + + } + + getObject() { + + if ( this.needsUpdate ) this.dispose(); + if ( this._object !== null ) return this._object; + + // + + const refresh = () => this.refresh(); + const setOutput = ( id, value ) => this.setOutput( id, value ); + + const parameters = new Parameters( this ); + + const THREE = global.get( 'THREE' ); + const TSL = global.get( 'TSL' ); + + const method = this.getMethod( this.codeNode ); + const params = [ parameters, this._local, global, refresh, setOutput, THREE, TSL ]; + + this._object = method( ...params ); + + const layout = this._object.layout; + + if ( layout ) { + + if ( layout.cache === false ) { + + this._local.clear(); + + } + + // default output + this._output.outputType = layout.outputType || null; + + if ( Array.isArray( layout.elements ) ) { + + for ( const element of layout.elements ) { + + const id = element.id || element.name; + + if ( element.inputType ) { + + if ( this.getParameter( id ) === undefined ) this.setParameter( id, null ); + + this.getParameter( id ).inputType = element.inputType; + + } + + if ( element.outputType ) { + + if ( this.getOutput( id ) === undefined ) this.setOutput( id, null ); + + this.getOutput( id ).outputType = element.outputType; + + } + + } + + } + + } + + return this._object; + + } + + deserialize( data ) { + + super.deserialize( data ); + + for ( const name in this.parameters ) { + + let valueNode = this.parameters[ name ]; + + if ( valueNode.isScriptableNode ) valueNode = valueNode.getDefaultOutput(); + + valueNode.events.addEventListener( 'refresh', this.onRefresh ); + + } + + } + + getLayout() { + + return this.getObject().layout; + + } + + getDefaultOutputNode() { + + const output = this.getDefaultOutput().value; + + if ( output && output.isNode ) { + + return output; + + } + + return float(); + + } + + getDefaultOutput() { + + return this._exec()._output; + + } + + getMethod() { + + if ( this.needsUpdate ) this.dispose(); + if ( this._method !== null ) return this._method; + + // + + const parametersProps = [ 'parameters', 'local', 'global', 'refresh', 'setOutput', 'THREE', 'TSL' ]; + const interfaceProps = [ 'layout', 'init', 'main', 'dispose' ]; + + const properties = interfaceProps.join( ', ' ); + const declarations = 'var ' + properties + '; var output = {};\n'; + const returns = '\nreturn { ...output, ' + properties + ' };'; + + const code = declarations + this.codeNode.code + returns; + + // + + this._method = new Function( ...parametersProps, code ); + + return this._method; + + } + + dispose() { + + if ( this._method === null ) return; + + if ( this._object && typeof this._object.dispose === 'function' ) { + + this._object.dispose(); + + } + + this._method = null; + this._object = null; + this._source = null; + this._value = null; + this._needsOutputUpdate = true; + this._output.value = null; + this._outputs = {}; + + } + + setup() { + + return this.getDefaultOutputNode(); + + } + + getCacheKey( force ) { + + const values = [ hashString( this.source ), this.getDefaultOutputNode().getCacheKey( force ) ]; + + for ( const param in this.parameters ) { + + values.push( this.parameters[ param ].getCacheKey( force ) ); + + } + + return hashArray( values ); + + } + + set needsUpdate( value ) { + + if ( value === true ) this.dispose(); + + } + + get needsUpdate() { + + return this.source !== this._source; + + } + + _exec() { + + if ( this.codeNode === null ) return this; + + if ( this._needsOutputUpdate === true ) { + + this._value = this.call( 'main' ); + + this._needsOutputUpdate = false; + + } + + this._output.value = this._value; + + return this; + + } + + _refresh() { + + this.needsUpdate = true; + + this._exec(); + + this._output.refresh(); + + } + +} + +const scriptable = /*@__PURE__*/ nodeProxy( ScriptableNode ); + +class FogNode extends Node { + + static get type() { + + return 'FogNode'; + + } + + constructor( colorNode, factorNode ) { + + super( 'float' ); + + this.isFogNode = true; + + this.colorNode = colorNode; + this.factorNode = factorNode; + + } + + getViewZNode( builder ) { + + let viewZ; + + const getViewZ = builder.context.getViewZ; + + if ( getViewZ !== undefined ) { + + viewZ = getViewZ( this ); + + } + + return ( viewZ || positionView.z ).negate(); + + } + + setup() { + + return this.factorNode; + + } + +} + +const fog = /*@__PURE__*/ nodeProxy( FogNode ); + +class FogRangeNode extends FogNode { + + static get type() { + + return 'FogRangeNode'; + + } + + constructor( colorNode, nearNode, farNode ) { + + super( colorNode ); + + this.isFogRangeNode = true; + + this.nearNode = nearNode; + this.farNode = farNode; + + } + + setup( builder ) { + + const viewZ = this.getViewZNode( builder ); + + return smoothstep( this.nearNode, this.farNode, viewZ ); + + } + +} + +const rangeFog = /*@__PURE__*/ nodeProxy( FogRangeNode ); + +class FogExp2Node extends FogNode { + + static get type() { + + return 'FogExp2Node'; + + } + + constructor( colorNode, densityNode ) { + + super( colorNode ); + + this.isFogExp2Node = true; + + this.densityNode = densityNode; + + } + + setup( builder ) { + + const viewZ = this.getViewZNode( builder ); + const density = this.densityNode; + + return density.mul( density, viewZ, viewZ ).negate().exp().oneMinus(); + + } + +} + +const densityFog = /*@__PURE__*/ nodeProxy( FogExp2Node ); + +let min = null; +let max = null; + +class RangeNode extends Node { + + static get type() { + + return 'RangeNode'; + + } + + constructor( minNode = float(), maxNode = float() ) { + + super(); + + this.minNode = minNode; + this.maxNode = maxNode; + + } + + getVectorLength( builder ) { + + const minLength = builder.getTypeLength( getValueType( this.minNode.value ) ); + const maxLength = builder.getTypeLength( getValueType( this.maxNode.value ) ); + + return minLength > maxLength ? minLength : maxLength; + + } + + getNodeType( builder ) { + + return builder.object.count > 1 ? builder.getTypeFromLength( this.getVectorLength( builder ) ) : 'float'; + + } + + setup( builder ) { + + const object = builder.object; + + let output = null; + + if ( object.count > 1 ) { + + const minValue = this.minNode.value; + const maxValue = this.maxNode.value; + + const minLength = builder.getTypeLength( getValueType( minValue ) ); + const maxLength = builder.getTypeLength( getValueType( maxValue ) ); + + min = min || new Vector4(); + max = max || new Vector4(); + + min.setScalar( 0 ); + max.setScalar( 0 ); + + if ( minLength === 1 ) min.setScalar( minValue ); + else if ( minValue.isColor ) min.set( minValue.r, minValue.g, minValue.b ); + else min.set( minValue.x, minValue.y, minValue.z || 0, minValue.w || 0 ); + + if ( maxLength === 1 ) max.setScalar( maxValue ); + else if ( maxValue.isColor ) max.set( maxValue.r, maxValue.g, maxValue.b ); + else max.set( maxValue.x, maxValue.y, maxValue.z || 0, maxValue.w || 0 ); + + const stride = 4; + + const length = stride * object.count; + const array = new Float32Array( length ); + + for ( let i = 0; i < length; i ++ ) { + + const index = i % stride; + + const minElementValue = min.getComponent( index ); + const maxElementValue = max.getComponent( index ); + + array[ i ] = MathUtils.lerp( minElementValue, maxElementValue, Math.random() ); + + } + + const nodeType = this.getNodeType( builder ); + + if ( object.count <= 4096 ) { + + output = buffer( array, 'vec4', object.count ).element( instanceIndex ).convert( nodeType ); + + } else { + + // TODO: Improve anonymous buffer attribute creation removing this part + const bufferAttribute = new InstancedBufferAttribute( array, 4 ); + builder.geometry.setAttribute( '__range' + this.id, bufferAttribute ); + + output = instancedBufferAttribute( bufferAttribute ).convert( nodeType ); + + } + + } else { + + output = float( 0 ); + + } + + return output; + + } + +} + +const range = /*@__PURE__*/ nodeProxy( RangeNode ); + +const BasicShadowMap = Fn( ( { depthTexture, shadowCoord } ) => { + + return texture( depthTexture, shadowCoord.xy ).compare( shadowCoord.z ); + +} ); + +const PCFShadowMap = Fn( ( { depthTexture, shadowCoord, shadow } ) => { + + const depthCompare = ( uv, compare ) => texture( depthTexture, uv ).compare( compare ); + + const mapSize = reference( 'mapSize', 'vec2', shadow ).setGroup( renderGroup ); + const radius = reference( 'radius', 'float', shadow ).setGroup( renderGroup ); + + const texelSize = vec2( 1 ).div( mapSize ); + const dx0 = texelSize.x.negate().mul( radius ); + const dy0 = texelSize.y.negate().mul( radius ); + const dx1 = texelSize.x.mul( radius ); + const dy1 = texelSize.y.mul( radius ); + const dx2 = dx0.div( 2 ); + const dy2 = dy0.div( 2 ); + const dx3 = dx1.div( 2 ); + const dy3 = dy1.div( 2 ); + + return add( + depthCompare( shadowCoord.xy.add( vec2( dx0, dy0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( 0, dy0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx1, dy0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx2, dy2 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( 0, dy2 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx3, dy2 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx0, 0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx2, 0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy, shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx3, 0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx1, 0 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx2, dy3 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( 0, dy3 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx3, dy3 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx0, dy1 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( 0, dy1 ) ), shadowCoord.z ), + depthCompare( shadowCoord.xy.add( vec2( dx1, dy1 ) ), shadowCoord.z ) + ).mul( 1 / 17 ); + +} ); + +const PCFSoftShadowMap = Fn( ( { depthTexture, shadowCoord, shadow } ) => { + + const depthCompare = ( uv, compare ) => texture( depthTexture, uv ).compare( compare ); + + const mapSize = reference( 'mapSize', 'vec2', shadow ).setGroup( renderGroup ); + + const texelSize = vec2( 1 ).div( mapSize ); + const dx = texelSize.x; + const dy = texelSize.y; + + const uv = shadowCoord.xy; + const f = fract( uv.mul( mapSize ).add( 0.5 ) ); + uv.subAssign( f.mul( texelSize ) ); + + return add( + depthCompare( uv, shadowCoord.z ), + depthCompare( uv.add( vec2( dx, 0 ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( 0, dy ) ), shadowCoord.z ), + depthCompare( uv.add( texelSize ), shadowCoord.z ), + mix( + depthCompare( uv.add( vec2( dx.negate(), 0 ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( dx.mul( 2 ), 0 ) ), shadowCoord.z ), + f.x + ), + mix( + depthCompare( uv.add( vec2( dx.negate(), dy ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( dx.mul( 2 ), dy ) ), shadowCoord.z ), + f.x + ), + mix( + depthCompare( uv.add( vec2( 0, dy.negate() ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( 0, dy.mul( 2 ) ) ), shadowCoord.z ), + f.y + ), + mix( + depthCompare( uv.add( vec2( dx, dy.negate() ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( dx, dy.mul( 2 ) ) ), shadowCoord.z ), + f.y + ), + mix( + mix( + depthCompare( uv.add( vec2( dx.negate(), dy.negate() ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( dx.mul( 2 ), dy.negate() ) ), shadowCoord.z ), + f.x + ), + mix( + depthCompare( uv.add( vec2( dx.negate(), dy.mul( 2 ) ) ), shadowCoord.z ), + depthCompare( uv.add( vec2( dx.mul( 2 ), dy.mul( 2 ) ) ), shadowCoord.z ), + f.x + ), + f.y + ) + ).mul( 1 / 9 ); + +} ); + +// VSM + +const VSMShadowMapNode = Fn( ( { depthTexture, shadowCoord } ) => { + + const occlusion = float( 1 ).toVar(); + + const distribution = texture( depthTexture ).uv( shadowCoord.xy ).rg; + + const hardShadow = step( shadowCoord.z, distribution.x ); + + If( hardShadow.notEqual( float( 1.0 ) ), () => { + + const distance = shadowCoord.z.sub( distribution.x ); + const variance = max$1( 0, distribution.y.mul( distribution.y ) ); + let softnessProbability = variance.div( variance.add( distance.mul( distance ) ) ); // Chebeyshevs inequality + softnessProbability = clamp( sub( softnessProbability, 0.3 ).div( 0.95 - 0.3 ) ); + occlusion.assign( clamp( max$1( hardShadow, softnessProbability ) ) ); + + } ); + + return occlusion; + +} ); + +const VSMPassVertical = Fn( ( { samples, radius, size, shadowPass } ) => { + + const mean = float( 0 ).toVar(); + const squaredMean = float( 0 ).toVar(); + + const uvStride = samples.lessThanEqual( float( 1 ) ).select( float( 0 ), float( 2 ).div( samples.sub( 1 ) ) ); + const uvStart = samples.lessThanEqual( float( 1 ) ).select( float( 0 ), float( - 1 ) ); + + Loop( { start: int( 0 ), end: int( samples ), type: 'int', condition: '<' }, ( { i } ) => { + + const uvOffset = uvStart.add( float( i ).mul( uvStride ) ); + + const depth = shadowPass.uv( add( screenCoordinate.xy, vec2( 0, uvOffset ).mul( radius ) ).div( size ) ).x; + mean.addAssign( depth ); + squaredMean.addAssign( depth.mul( depth ) ); + + } ); + + mean.divAssign( samples ); + squaredMean.divAssign( samples ); + + const std_dev = sqrt( squaredMean.sub( mean.mul( mean ) ) ); + return vec2( mean, std_dev ); + +} ); + +const VSMPassHorizontal = Fn( ( { samples, radius, size, shadowPass } ) => { + + const mean = float( 0 ).toVar(); + const squaredMean = float( 0 ).toVar(); + + const uvStride = samples.lessThanEqual( float( 1 ) ).select( float( 0 ), float( 2 ).div( samples.sub( 1 ) ) ); + const uvStart = samples.lessThanEqual( float( 1 ) ).select( float( 0 ), float( - 1 ) ); + + Loop( { start: int( 0 ), end: int( samples ), type: 'int', condition: '<' }, ( { i } ) => { + + const uvOffset = uvStart.add( float( i ).mul( uvStride ) ); + + const distribution = shadowPass.uv( add( screenCoordinate.xy, vec2( uvOffset, 0 ).mul( radius ) ).div( size ) ); + mean.addAssign( distribution.x ); + squaredMean.addAssign( add( distribution.y.mul( distribution.y ), distribution.x.mul( distribution.x ) ) ); + + } ); + + mean.divAssign( samples ); + squaredMean.divAssign( samples ); + + const std_dev = sqrt( squaredMean.sub( mean.mul( mean ) ) ); + return vec2( mean, std_dev ); + +} ); + +const _shadowFilterLib = [ BasicShadowMap, PCFShadowMap, PCFSoftShadowMap, VSMShadowMapNode ]; + +// + +let _overrideMaterial = null; +const _quadMesh$1 = /*@__PURE__*/ new QuadMesh(); + +class AnalyticLightNode extends LightingNode { + + static get type() { + + return 'AnalyticLightNode'; + + } + + constructor( light = null ) { + + super(); + + this.updateType = NodeUpdateType.FRAME; + + this.light = light; + + this.color = new Color(); + this.colorNode = uniform( this.color ).setGroup( renderGroup ); + + this.baseColorNode = null; + + this.shadowMap = null; + this.shadowNode = null; + this.shadowColorNode = null; + + this.vsmShadowMapVertical = null; + this.vsmShadowMapHorizontal = null; + + this.vsmMaterialVertical = null; + this.vsmMaterialHorizontal = null; + + this.isAnalyticLightNode = true; + + } + + getCacheKey() { + + return hash$1( super.getCacheKey(), this.light.id, this.light.castShadow ? 1 : 0 ); + + } + + getHash() { + + return this.light.uuid; + + } + + setupShadow( builder ) { + + const { object, renderer } = builder; + + if ( renderer.shadowMap.enabled === false ) return; + + let shadowColorNode = this.shadowColorNode; + + if ( shadowColorNode === null ) { + + if ( _overrideMaterial === null ) { + + _overrideMaterial = new NodeMaterial(); + _overrideMaterial.fragmentNode = vec4( 0, 0, 0, 1 ); + _overrideMaterial.isShadowNodeMaterial = true; // Use to avoid other overrideMaterial override material.fragmentNode unintentionally when using material.shadowNode + _overrideMaterial.name = 'ShadowMaterial'; + + } + + const shadowMapType = renderer.shadowMap.type; + const shadow = this.light.shadow; + + const depthTexture = new DepthTexture(); + depthTexture.compareFunction = LessCompare; + + const shadowMap = builder.createRenderTarget( shadow.mapSize.width, shadow.mapSize.height ); + shadowMap.depthTexture = depthTexture; + + shadow.camera.updateProjectionMatrix(); + + // VSM + + if ( shadowMapType === VSMShadowMap ) { + + depthTexture.compareFunction = null; // VSM does not use textureSampleCompare()/texture2DCompare() + + this.vsmShadowMapVertical = builder.createRenderTarget( shadow.mapSize.width, shadow.mapSize.height, { format: RGFormat, type: HalfFloatType } ); + this.vsmShadowMapHorizontal = builder.createRenderTarget( shadow.mapSize.width, shadow.mapSize.height, { format: RGFormat, type: HalfFloatType } ); + + const shadowPassVertical = texture( depthTexture ); + const shadowPassHorizontal = texture( this.vsmShadowMapVertical.texture ); + + const samples = reference( 'blurSamples', 'float', shadow ).setGroup( renderGroup ); + const radius = reference( 'radius', 'float', shadow ).setGroup( renderGroup ); + const size = reference( 'mapSize', 'vec2', shadow ).setGroup( renderGroup ); + + let material = this.vsmMaterialVertical || ( this.vsmMaterialVertical = new NodeMaterial() ); + material.fragmentNode = VSMPassVertical( { samples, radius, size, shadowPass: shadowPassVertical } ).context( builder.getSharedContext() ); + material.name = 'VSMVertical'; + + material = this.vsmMaterialHorizontal || ( this.vsmMaterialHorizontal = new NodeMaterial() ); + material.fragmentNode = VSMPassHorizontal( { samples, radius, size, shadowPass: shadowPassHorizontal } ).context( builder.getSharedContext() ); + material.name = 'VSMHorizontal'; + + } + + // + + const shadowIntensity = reference( 'intensity', 'float', shadow ).setGroup( renderGroup ); + const bias = reference( 'bias', 'float', shadow ).setGroup( renderGroup ); + const normalBias = reference( 'normalBias', 'float', shadow ).setGroup( renderGroup ); + + const position = object.material.shadowPositionNode || positionWorld; + + let shadowCoord = uniform( shadow.matrix ).setGroup( renderGroup ).mul( position.add( normalWorld.mul( normalBias ) ) ); + shadowCoord = shadowCoord.xyz.div( shadowCoord.w ); + + let coordZ = shadowCoord.z.add( bias ); + + if ( renderer.coordinateSystem === WebGPUCoordinateSystem ) { + + coordZ = coordZ.mul( 2 ).sub( 1 ); // WebGPU: Convertion [ 0, 1 ] to [ - 1, 1 ] + + } + + shadowCoord = vec3( + shadowCoord.x, + shadowCoord.y.oneMinus(), // follow webgpu standards + coordZ + ); + + const frustumTest = shadowCoord.x.greaterThanEqual( 0 ) + .and( shadowCoord.x.lessThanEqual( 1 ) ) + .and( shadowCoord.y.greaterThanEqual( 0 ) ) + .and( shadowCoord.y.lessThanEqual( 1 ) ) + .and( shadowCoord.z.lessThanEqual( 1 ) ); + + // + + const filterFn = shadow.filterNode || _shadowFilterLib[ renderer.shadowMap.type ] || null; + + if ( filterFn === null ) { + + throw new Error( 'THREE.WebGPURenderer: Shadow map type not supported yet.' ); + + } + + const shadowColor = texture( shadowMap.texture, shadowCoord ); + const shadowNode = frustumTest.select( filterFn( { depthTexture: ( shadowMapType === VSMShadowMap ) ? this.vsmShadowMapHorizontal.texture : depthTexture, shadowCoord, shadow } ), float( 1 ) ); + + this.shadowMap = shadowMap; + this.light.shadow.map = shadowMap; + + this.shadowNode = shadowNode; + this.shadowColorNode = shadowColorNode = this.colorNode.mul( mix( 1, shadowNode.rgb.mix( shadowColor, 1 ), shadowIntensity.mul( shadowColor.a ) ) ); + + this.baseColorNode = this.colorNode; + + } + + // + + this.colorNode = shadowColorNode; + + this.updateBeforeType = NodeUpdateType.RENDER; + + } + + setup( builder ) { + + this.colorNode = this.baseColorNode || this.colorNode; + + if ( this.light.castShadow ) { + + if ( builder.object.receiveShadow ) { + + this.setupShadow( builder ); + + } + + } else if ( this.shadowNode !== null ) { + + this.disposeShadow(); + + } + + } + + updateShadow( frame ) { + + const { shadowMap, light } = this; + const { renderer, scene, camera } = frame; + + const shadowType = renderer.shadowMap.type; + + const depthVersion = shadowMap.depthTexture.version; + this._depthVersionCached = depthVersion; + + const currentOverrideMaterial = scene.overrideMaterial; + + scene.overrideMaterial = _overrideMaterial; + + shadowMap.setSize( light.shadow.mapSize.width, light.shadow.mapSize.height ); + + light.shadow.updateMatrices( light ); + light.shadow.camera.layers.mask = camera.layers.mask; + + const currentRenderTarget = renderer.getRenderTarget(); + const currentRenderObjectFunction = renderer.getRenderObjectFunction(); + + renderer.setRenderObjectFunction( ( object, ...params ) => { + + if ( object.castShadow === true || ( object.receiveShadow && shadowType === VSMShadowMap ) ) { + + renderer.renderObject( object, ...params ); + + } + + } ); + + renderer.setRenderTarget( shadowMap ); + renderer.render( scene, light.shadow.camera ); + + renderer.setRenderObjectFunction( currentRenderObjectFunction ); + + // vsm blur pass + + if ( light.isPointLight !== true && shadowType === VSMShadowMap ) { + + this.vsmPass( frame, light ); + + } + + renderer.setRenderTarget( currentRenderTarget ); + + scene.overrideMaterial = currentOverrideMaterial; + + } + + vsmPass( frame, light ) { + + const { renderer } = frame; + + this.vsmShadowMapVertical.setSize( light.shadow.mapSize.width, light.shadow.mapSize.height ); + this.vsmShadowMapHorizontal.setSize( light.shadow.mapSize.width, light.shadow.mapSize.height ); + + renderer.setRenderTarget( this.vsmShadowMapVertical ); + _quadMesh$1.material = this.vsmMaterialVertical; + _quadMesh$1.render( renderer ); + + renderer.setRenderTarget( this.vsmShadowMapHorizontal ); + _quadMesh$1.material = this.vsmMaterialHorizontal; + _quadMesh$1.render( renderer ); + + } + + disposeShadow() { + + this.shadowMap.dispose(); + this.shadowMap = null; + + if ( this.vsmShadowMapVertical !== null ) { + + this.vsmShadowMapVertical.dispose(); + this.vsmShadowMapVertical = null; + + this.vsmMaterialVertical.dispose(); + this.vsmMaterialVertical = null; + + } + + if ( this.vsmShadowMapHorizontal !== null ) { + + this.vsmShadowMapHorizontal.dispose(); + this.vsmShadowMapHorizontal = null; + + this.vsmMaterialHorizontal.dispose(); + this.vsmMaterialHorizontal = null; + + } + + this.shadowNode = null; + this.shadowColorNode = null; + + this.baseColorNode = null; + + this.updateBeforeType = NodeUpdateType.NONE; + + } + + updateBefore( frame ) { + + const shadow = this.light.shadow; + + const needsUpdate = shadow.needsUpdate || shadow.autoUpdate; + + if ( needsUpdate ) { + + this.updateShadow( frame ); + + if ( this.shadowMap.depthTexture.version === this._depthVersionCached ) { + + shadow.needsUpdate = false; + + } + + } + + } + + update( /*frame*/ ) { + + const { light } = this; + + this.color.copy( light.color ).multiplyScalar( light.intensity ); + + } + +} + +const getDistanceAttenuation = /*@__PURE__*/ Fn( ( inputs ) => { + + const { lightDistance, cutoffDistance, decayExponent } = inputs; + + // based upon Frostbite 3 Moving to Physically-based Rendering + // page 32, equation 26: E[window1] + // https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf + const distanceFalloff = lightDistance.pow( decayExponent ).max( 0.01 ).reciprocal(); + + return cutoffDistance.greaterThan( 0 ).select( + distanceFalloff.mul( lightDistance.div( cutoffDistance ).pow4().oneMinus().clamp().pow2() ), + distanceFalloff + ); + +} ); // validated + +let uniformsLib; + +function getLightData( light ) { + + uniformsLib = uniformsLib || new WeakMap(); + + let uniforms = uniformsLib.get( light ); + + if ( uniforms === undefined ) uniformsLib.set( light, uniforms = {} ); + + return uniforms; + +} + +function lightPosition( light ) { + + const data = getLightData( light ); + + return data.position || ( data.position = uniform( new Vector3() ).setGroup( renderGroup ).onRenderUpdate( ( _, self ) => self.value.setFromMatrixPosition( light.matrixWorld ) ) ); + +} + +function lightTargetPosition( light ) { + + const data = getLightData( light ); + + return data.targetPosition || ( data.targetPosition = uniform( new Vector3() ).setGroup( renderGroup ).onRenderUpdate( ( _, self ) => self.value.setFromMatrixPosition( light.target.matrixWorld ) ) ); + +} + +function lightViewPosition( light ) { + + const data = getLightData( light ); + + return data.viewPosition || ( data.viewPosition = uniform( new Vector3() ).setGroup( renderGroup ).onRenderUpdate( ( { camera }, self ) => { + + self.value = self.value || new Vector3(); + self.value.setFromMatrixPosition( light.matrixWorld ); + + self.value.applyMatrix4( camera.matrixWorldInverse ); + + } ) ); + +} + +const lightTargetDirection = ( light ) => cameraViewMatrix.transformDirection( lightPosition( light ).sub( lightTargetPosition( light ) ) ); + +const hash = /*@__PURE__*/ Fn( ( [ seed ] ) => { + + // Taken from https://www.shadertoy.com/view/XlGcRh, originally from pcg-random.org + + const state = seed.toUint().mul( 747796405 ).add( 2891336453 ); + const word = state.shiftRight( state.shiftRight( 28 ).add( 4 ) ).bitXor( state ).mul( 277803737 ); + const result = word.shiftRight( 22 ).bitXor( word ); + + return result.toFloat().mul( 1 / 2 ** 32 ); // Convert to range [0, 1) + +} ); + +// remapping functions https://iquilezles.org/articles/functions/ +const parabola = ( x, k ) => pow( mul( 4.0, x.mul( sub( 1.0, x ) ) ), k ); +const gain = ( x, k ) => x.lessThan( 0.5 ) ? parabola( x.mul( 2.0 ), k ).div( 2.0 ) : sub( 1.0, parabola( mul( sub( 1.0, x ), 2.0 ), k ).div( 2.0 ) ); +const pcurve = ( x, a, b ) => pow( div( pow( x, a ), add( pow( x, a ), pow( sub( 1.0, x ), b ) ) ), 1.0 / a ); +const sinc = ( x, k ) => sin( PI.mul( k.mul( x ).sub( 1.0 ) ) ).div( PI.mul( k.mul( x ).sub( 1.0 ) ) ); + +// https://github.com/cabbibo/glsl-tri-noise-3d + + +const tri = /*@__PURE__*/ Fn( ( [ x ] ) => { + + return x.fract().sub( .5 ).abs(); + +} ).setLayout( { + name: 'tri', + type: 'float', + inputs: [ + { name: 'x', type: 'float' } + ] +} ); + +const tri3 = /*@__PURE__*/ Fn( ( [ p ] ) => { + + return vec3( tri( p.z.add( tri( p.y.mul( 1. ) ) ) ), tri( p.z.add( tri( p.x.mul( 1. ) ) ) ), tri( p.y.add( tri( p.x.mul( 1. ) ) ) ) ); + +} ).setLayout( { + name: 'tri3', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec3' } + ] +} ); + +const triNoise3D = /*@__PURE__*/ Fn( ( [ p_immutable, spd, time ] ) => { + + const p = vec3( p_immutable ).toVar(); + const z = float( 1.4 ).toVar(); + const rz = float( 0.0 ).toVar(); + const bp = vec3( p ).toVar(); + + Loop( { start: float( 0.0 ), end: float( 3.0 ), type: 'float', condition: '<=' }, () => { + + const dg = vec3( tri3( bp.mul( 2.0 ) ) ).toVar(); + p.addAssign( dg.add( time.mul( float( 0.1 ).mul( spd ) ) ) ); + bp.mulAssign( 1.8 ); + z.mulAssign( 1.5 ); + p.mulAssign( 1.2 ); + + const t = float( tri( p.z.add( tri( p.x.add( tri( p.y ) ) ) ) ) ).toVar(); + rz.addAssign( t.div( z ) ); + bp.addAssign( 0.14 ); + + } ); + + return rz; + +} ).setLayout( { + name: 'triNoise3D', + type: 'float', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'spd', type: 'float' }, + { name: 'time', type: 'float' } + ] +} ); + +const rotateUV = /*@__PURE__*/ Fn( ( [ uv, rotation, center = vec2( 0.5 ) ] ) => { + + return rotate( uv.sub( center ), rotation ).add( center ); + +} ); + +const spherizeUV = /*@__PURE__*/ Fn( ( [ uv, strength, center = vec2( 0.5 ) ] ) => { + + const delta = uv.sub( center ); + const delta2 = delta.dot( delta ); + const delta4 = delta2.mul( delta2 ); + const deltaOffset = delta4.mul( strength ); + + return uv.add( delta.mul( deltaOffset ) ); + +} ); + +const billboarding = /*@__PURE__*/ Fn( ( { position = null, horizontal = true, vertical = false } ) => { + + let worldMatrix; + + if ( position !== null ) { + + worldMatrix = modelWorldMatrix.toVar(); + worldMatrix[ 3 ][ 0 ] = position.x; + worldMatrix[ 3 ][ 1 ] = position.y; + worldMatrix[ 3 ][ 2 ] = position.z; + + } else { + + worldMatrix = modelWorldMatrix; + + } + + const modelViewMatrix = cameraViewMatrix.mul( worldMatrix ); + + if ( defined( horizontal ) ) { + + modelViewMatrix[ 0 ][ 0 ] = modelWorldMatrix[ 0 ].length(); + modelViewMatrix[ 0 ][ 1 ] = 0; + modelViewMatrix[ 0 ][ 2 ] = 0; + + } + + if ( defined( vertical ) ) { + + modelViewMatrix[ 1 ][ 0 ] = 0; + modelViewMatrix[ 1 ][ 1 ] = modelWorldMatrix[ 1 ].length(); + modelViewMatrix[ 1 ][ 2 ] = 0; + + } + + modelViewMatrix[ 2 ][ 0 ] = 0; + modelViewMatrix[ 2 ][ 1 ] = 0; + modelViewMatrix[ 2 ][ 2 ] = 1; + + return cameraProjectionMatrix.mul( modelViewMatrix ).mul( positionLocal ); + +} ); + +const viewportSafeUV = /*@__PURE__*/ Fn( ( [ uv = null ] ) => { + + const depth = linearDepth(); + const depthDiff = linearDepth( viewportDepthTexture( uv ) ).sub( depth ); + const finalUV = depthDiff.lessThan( 0 ).select( screenUV, uv ); + + return finalUV; + +} ); + +const _objectData = new WeakMap(); + +class VelocityNode extends TempNode { + + static get type() { + + return 'VelocityNode'; + + } + + constructor() { + + super( 'vec2' ); + + this.updateType = NodeUpdateType.OBJECT; + this.updateAfterType = NodeUpdateType.OBJECT; + + this.previousModelWorldMatrix = uniform( new Matrix4() ); + this.previousProjectionMatrix = uniform( new Matrix4() ).setGroup( renderGroup ); + this.previousCameraViewMatrix = uniform( new Matrix4() ); + + } + + update( { frameId, camera, object } ) { + + const previousModelMatrix = getPreviousMatrix( object ); + + this.previousModelWorldMatrix.value.copy( previousModelMatrix ); + + // + + const cameraData = getData( camera ); + + if ( cameraData.frameId !== frameId ) { + + cameraData.frameId = frameId; + + if ( cameraData.previousProjectionMatrix === undefined ) { + + cameraData.previousProjectionMatrix = new Matrix4(); + cameraData.previousCameraViewMatrix = new Matrix4(); + + cameraData.currentProjectionMatrix = new Matrix4(); + cameraData.currentCameraViewMatrix = new Matrix4(); + + cameraData.previousProjectionMatrix.copy( camera.projectionMatrix ); + cameraData.previousCameraViewMatrix.copy( camera.matrixWorldInverse ); + + } else { + + cameraData.previousProjectionMatrix.copy( cameraData.currentProjectionMatrix ); + cameraData.previousCameraViewMatrix.copy( cameraData.currentCameraViewMatrix ); + + } + + cameraData.currentProjectionMatrix.copy( camera.projectionMatrix ); + cameraData.currentCameraViewMatrix.copy( camera.matrixWorldInverse ); + + this.previousProjectionMatrix.value.copy( cameraData.previousProjectionMatrix ); + this.previousCameraViewMatrix.value.copy( cameraData.previousCameraViewMatrix ); + + } + + } + + updateAfter( { object } ) { + + getPreviousMatrix( object ).copy( object.matrixWorld ); + + } + + setup( /*builder*/ ) { + + const previousModelViewMatrix = this.previousCameraViewMatrix.mul( this.previousModelWorldMatrix ); + + const clipPositionCurrent = cameraProjectionMatrix.mul( modelViewMatrix ).mul( positionLocal ); + const clipPositionPrevious = this.previousProjectionMatrix.mul( previousModelViewMatrix ).mul( positionPrevious ); + + const ndcPositionCurrent = clipPositionCurrent.xy.div( clipPositionCurrent.w ); + const ndcPositionPrevious = clipPositionPrevious.xy.div( clipPositionPrevious.w ); + + const velocity = sub( ndcPositionCurrent, ndcPositionPrevious ); + + return velocity; + + } + +} + +function getData( object ) { + + let objectData = _objectData.get( object ); + + if ( objectData === undefined ) { + + objectData = {}; + _objectData.set( object, objectData ); + + } + + return objectData; + +} + +function getPreviousMatrix( object, index = 0 ) { + + const objectData = getData( object ); + + let matrix = objectData[ index ]; + + if ( matrix === undefined ) { + + objectData[ index ] = matrix = new Matrix4(); + + } + + return matrix; + +} + +const velocity = /*@__PURE__*/ nodeImmutable( VelocityNode ); + +const burn = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { + + return min$1( 1.0, base.oneMinus().div( blend ) ).oneMinus(); + +} ).setLayout( { + name: 'burnBlend', + type: 'vec3', + inputs: [ + { name: 'base', type: 'vec3' }, + { name: 'blend', type: 'vec3' } + ] +} ); + +const dodge = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { + + return min$1( base.div( blend.oneMinus() ), 1.0 ); + +} ).setLayout( { + name: 'dodgeBlend', + type: 'vec3', + inputs: [ + { name: 'base', type: 'vec3' }, + { name: 'blend', type: 'vec3' } + ] +} ); + +const screen = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { + + return base.oneMinus().mul( blend.oneMinus() ).oneMinus(); + +} ).setLayout( { + name: 'screenBlend', + type: 'vec3', + inputs: [ + { name: 'base', type: 'vec3' }, + { name: 'blend', type: 'vec3' } + ] +} ); + +const overlay = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { + + return mix( base.mul( 2.0 ).mul( blend ), base.oneMinus().mul( 2.0 ).mul( blend.oneMinus() ).oneMinus(), step( 0.5, base ) ); + +} ).setLayout( { + name: 'overlayBlend', + type: 'vec3', + inputs: [ + { name: 'base', type: 'vec3' }, + { name: 'blend', type: 'vec3' } + ] +} ); + +const motionBlur = /*@__PURE__*/ Fn( ( [ inputNode, velocity, numSamples = int( 16 ) ] ) => { + + const sampleColor = ( uv ) => inputNode.uv( uv ); + + const uvs = uv(); + + const colorResult = sampleColor( uvs ).toVar(); + const fSamples = float( numSamples ); + + Loop( { start: int( 1 ), end: numSamples, type: 'int', condition: '<=' }, ( { i } ) => { + + const offset = velocity.mul( float( i ).div( fSamples.sub( 1 ) ).sub( 0.5 ) ); + colorResult.addAssign( sampleColor( uvs.add( offset ) ) ); + + } ); + + colorResult.divAssign( fSamples ); + + return colorResult; + +} ); + +const bleach = /*@__PURE__*/ Fn( ( [ color, opacity = 1 ] ) => { + + const base = color; + const lum = luminance( base.rgb ); + const blend = vec3( lum ); + + const L = min$1( 1.0, max$1( 0.0, float( 10.0 ).mul( lum.sub( 0.45 ) ) ) ); + + const result1 = blend.mul( base.rgb ).mul( 2.0 ); + const result2 = float( 2.0 ).mul( blend.oneMinus() ).mul( base.rgb.oneMinus() ).oneMinus(); + + const newColor = mix( result1, result2, L ); + + const A2 = base.a.mul( opacity ); + + const mixRGB = A2.mul( newColor.rgb ); + + mixRGB.addAssign( base.rgb.mul( A2.oneMinus() ) ); + + return vec4( mixRGB, base.a ); + +} ); + +const sepia = /*@__PURE__*/ Fn( ( [ color ] ) => { + + const c = vec3( color ); + + // https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/sepia.js + + return vec4( + dot( c, vec3( 0.393, 0.769, 0.189 ) ), + dot( c, vec3( 0.349, 0.686, 0.168 ) ), + dot( c, vec3( 0.272, 0.534, 0.131 ) ), + color.a + ); + +} ); + +const sRGBToLinearSRGB = /*@__PURE__*/ Fn( ( [ color ] ) => { + + const a = color.mul( 0.9478672986 ).add( 0.0521327014 ).pow( 2.4 ); + const b = color.mul( 0.0773993808 ); + const factor = color.lessThanEqual( 0.04045 ); + + const rgbResult = mix( a, b, factor ); + + return rgbResult; + +} ).setLayout( { + name: 'sRGBToLinearSRGB', + type: 'vec3', + inputs: [ + { name: 'color', type: 'vec3' } + ] +} ); + +const linearSRGBTosRGB = /*@__PURE__*/ Fn( ( [ color ] ) => { + + const a = color.pow( 0.41666 ).mul( 1.055 ).sub( 0.055 ); + const b = color.mul( 12.92 ); + const factor = color.lessThanEqual( 0.0031308 ); + + const rgbResult = mix( a, b, factor ); + + return rgbResult; + +} ).setLayout( { + name: 'linearSRGBTosRGB', + type: 'vec3', + inputs: [ + { name: 'color', type: 'vec3' } + ] +} ); + +// exposure only + +const linearToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { + + return color.mul( exposure ).clamp(); + +} ).setLayout( { + name: 'linearToneMapping', + type: 'vec3', + inputs: [ + { name: 'color', type: 'vec3' }, + { name: 'exposure', type: 'float' } + ] +} ); + +// source: https://www.cs.utah.edu/docs/techreports/2002/pdf/UUCS-02-001.pdf + +const reinhardToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { + + color = color.mul( exposure ); + + return color.div( color.add( 1.0 ) ).clamp(); + +} ).setLayout( { + name: 'reinhardToneMapping', + type: 'vec3', + inputs: [ + { name: 'color', type: 'vec3' }, + { name: 'exposure', type: 'float' } + ] +} ); + +// source: http://filmicworlds.com/blog/filmic-tonemapping-operators/ + +const cineonToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { + + // filmic operator by Jim Hejl and Richard Burgess-Dawson + color = color.mul( exposure ); + color = color.sub( 0.004 ).max( 0.0 ); + + const a = color.mul( color.mul( 6.2 ).add( 0.5 ) ); + const b = color.mul( color.mul( 6.2 ).add( 1.7 ) ).add( 0.06 ); + + return a.div( b ).pow( 2.2 ); + +} ).setLayout( { + name: 'cineonToneMapping', + type: 'vec3', + inputs: [ + { name: 'color', type: 'vec3' }, + { name: 'exposure', type: 'float' } + ] +} ); + +// source: https://github.com/selfshadow/ltc_code/blob/master/webgl/shaders/ltc/ltc_blit.fs + +const RRTAndODTFit = /*@__PURE__*/ Fn( ( [ color ] ) => { + + const a = color.mul( color.add( 0.0245786 ) ).sub( 0.000090537 ); + const b = color.mul( color.add( 0.4329510 ).mul( 0.983729 ) ).add( 0.238081 ); + + return a.div( b ); + +} ); + +// source: https://github.com/selfshadow/ltc_code/blob/master/webgl/shaders/ltc/ltc_blit.fs + +const acesFilmicToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { + + // sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT + const ACESInputMat = mat3( + 0.59719, 0.35458, 0.04823, + 0.07600, 0.90834, 0.01566, + 0.02840, 0.13383, 0.83777 + ); + + // ODT_SAT => XYZ => D60_2_D65 => sRGB + const ACESOutputMat = mat3( + 1.60475, - 0.53108, - 0.07367, + - 0.10208, 1.10813, - 0.00605, + - 0.00327, - 0.07276, 1.07602 + ); + + color = color.mul( exposure ).div( 0.6 ); + + color = ACESInputMat.mul( color ); + + // Apply RRT and ODT + color = RRTAndODTFit( color ); + + color = ACESOutputMat.mul( color ); + + // Clamp to [0, 1] + return color.clamp(); + +} ).setLayout( { + name: 'acesFilmicToneMapping', + type: 'vec3', + inputs: [ + { name: 'color', type: 'vec3' }, + { name: 'exposure', type: 'float' } + ] +} ); + +const LINEAR_REC2020_TO_LINEAR_SRGB = /*@__PURE__*/ mat3( vec3( 1.6605, - 0.1246, - 0.0182 ), vec3( - 0.5876, 1.1329, - 0.1006 ), vec3( - 0.0728, - 0.0083, 1.1187 ) ); +const LINEAR_SRGB_TO_LINEAR_REC2020 = /*@__PURE__*/ mat3( vec3( 0.6274, 0.0691, 0.0164 ), vec3( 0.3293, 0.9195, 0.0880 ), vec3( 0.0433, 0.0113, 0.8956 ) ); + +const agxDefaultContrastApprox = /*@__PURE__*/ Fn( ( [ x_immutable ] ) => { + + const x = vec3( x_immutable ).toVar(); + const x2 = vec3( x.mul( x ) ).toVar(); + const x4 = vec3( x2.mul( x2 ) ).toVar(); + + return float( 15.5 ).mul( x4.mul( x2 ) ).sub( mul( 40.14, x4.mul( x ) ) ).add( mul( 31.96, x4 ).sub( mul( 6.868, x2.mul( x ) ) ).add( mul( 0.4298, x2 ).add( mul( 0.1191, x ).sub( 0.00232 ) ) ) ); + +} ); + +const agxToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { + + const colortone = vec3( color ).toVar(); + const AgXInsetMatrix = mat3( vec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ), vec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ), vec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 ) ); + const AgXOutsetMatrix = mat3( vec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ), vec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ), vec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 ) ); + const AgxMinEv = float( - 12.47393 ); + const AgxMaxEv = float( 4.026069 ); + colortone.mulAssign( exposure ); + colortone.assign( LINEAR_SRGB_TO_LINEAR_REC2020.mul( colortone ) ); + colortone.assign( AgXInsetMatrix.mul( colortone ) ); + colortone.assign( max$1( colortone, 1e-10 ) ); + colortone.assign( log2( colortone ) ); + colortone.assign( colortone.sub( AgxMinEv ).div( AgxMaxEv.sub( AgxMinEv ) ) ); + colortone.assign( clamp( colortone, 0.0, 1.0 ) ); + colortone.assign( agxDefaultContrastApprox( colortone ) ); + colortone.assign( AgXOutsetMatrix.mul( colortone ) ); + colortone.assign( pow( max$1( vec3( 0.0 ), colortone ), vec3( 2.2 ) ) ); + colortone.assign( LINEAR_REC2020_TO_LINEAR_SRGB.mul( colortone ) ); + colortone.assign( clamp( colortone, 0.0, 1.0 ) ); + + return colortone; + +} ).setLayout( { + name: 'agxToneMapping', + type: 'vec3', + inputs: [ + { name: 'color', type: 'vec3' }, + { name: 'exposure', type: 'float' } + ] +} ); + +// https://modelviewer.dev/examples/tone-mapping + +const neutralToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { + + const StartCompression = float( 0.8 - 0.04 ); + const Desaturation = float( 0.15 ); + + color = color.mul( exposure ); + + const x = min$1( color.r, min$1( color.g, color.b ) ); + const offset = select( x.lessThan( 0.08 ), x.sub( mul( 6.25, x.mul( x ) ) ), 0.04 ); + + color.subAssign( offset ); + + const peak = max$1( color.r, max$1( color.g, color.b ) ); + + If( peak.lessThan( StartCompression ), () => { + + return color; + + } ); + + const d = sub( 1, StartCompression ); + const newPeak = sub( 1, d.mul( d ).div( peak.add( d.sub( StartCompression ) ) ) ); + color.mulAssign( newPeak.div( peak ) ); + const g = sub( 1, div( 1, Desaturation.mul( peak.sub( newPeak ) ).add( 1 ) ) ); + + return mix( color, vec3( newPeak ), g ); + +} ).setLayout( { + name: 'neutralToneMapping', + type: 'vec3', + inputs: [ + { name: 'color', type: 'vec3' }, + { name: 'exposure', type: 'float' } + ] +} ); + +class ComputeBuiltinNode extends Node { + + static get type() { + + return 'ComputeBuiltinNode'; + + } + + constructor( builtinName, nodeType ) { + + super( nodeType ); + + this._builtinName = builtinName; + + } + + getHash( builder ) { + + return this.getBuiltinName( builder ); + + } + + getNodeType( /*builder*/ ) { + + return this.nodeType; + + } + + setBuiltinName( builtinName ) { + + this._builtinName = builtinName; + + return this; + + } + + getBuiltinName( /*builder*/ ) { + + return this._builtinName; + + } + + hasBuiltin( builder ) { + + builder.hasBuiltin( this._builtinName ); + + } + + generate( builder, output ) { + + const builtinName = this.getBuiltinName( builder ); + const nodeType = this.getNodeType( builder ); + + if ( builder.shaderStage === 'compute' ) { + + return builder.format( builtinName, nodeType, output ); + + } else { + + console.warn( `ComputeBuiltinNode: Compute built-in value ${builtinName} can not be accessed in the ${builder.shaderStage} stage` ); + return builder.generateConst( nodeType ); + + } + + } + + serialize( data ) { + + super.serialize( data ); + + data.global = this.global; + data._builtinName = this._builtinName; + + } + + deserialize( data ) { + + super.deserialize( data ); + + this.global = data.global; + this._builtinName = data._builtinName; + + } + +} + +const computeBuiltin = ( name, nodeType ) => nodeObject( new ComputeBuiltinNode( name, nodeType ) ); + +const numWorkgroups = /*@__PURE__*/ computeBuiltin( 'numWorkgroups', 'uvec3' ); +const workgroupId = /*@__PURE__*/ computeBuiltin( 'workgroupId', 'uvec3' ); +const localId = /*@__PURE__*/ computeBuiltin( 'localId', 'uvec3' ); +const subgroupSize = /*@__PURE__*/ computeBuiltin( 'subgroupSize', 'uint' ); + +class BarrierNode extends Node { + + constructor( scope ) { + + super(); + + this.scope = scope; + + } + + generate( builder ) { + + const { scope } = this; + const { renderer } = builder; + + if ( renderer.backend.isWebGLBackend === true ) { + + builder.addFlowCode( `\t// ${scope}Barrier \n` ); + + } else { + + builder.addLineFlowCode( `${scope}Barrier()`, this ); + + } + + } + +} + +const barrier = nodeProxy( BarrierNode ); + +const workgroupBarrier = () => barrier( 'workgroup' ).append(); +const storageBarrier = () => barrier( 'storage' ).append(); +const textureBarrier = () => barrier( 'texture' ).append(); + +class WorkgroupInfoElementNode extends ArrayElementNode { + + constructor( workgroupInfoNode, indexNode ) { + + super( workgroupInfoNode, indexNode ); + + this.isWorkgroupInfoElementNode = true; + + } + + generate( builder, output ) { + + let snippet; + + const isAssignContext = builder.context.assign; + snippet = super.generate( builder ); + + if ( isAssignContext !== true ) { + + const type = this.getNodeType( builder ); + + snippet = builder.format( snippet, type, output ); + + } + + // TODO: Possibly activate clip distance index on index access rather than from clipping context + + return snippet; + + } + +} + + +class WorkgroupInfoNode extends Node { + + constructor( scope, bufferType, bufferCount = 0 ) { + + super( bufferType ); + + this.bufferType = bufferType; + this.bufferCount = bufferCount; + + this.isWorkgroupInfoNode = true; + + this.scope = scope; + + } + + label( name ) { + + this.name = name; + + return this; + + } + + getHash() { + + return this.uuid; + + } + + setScope( scope ) { + + this.scope = scope; + + return this; + + } + + getInputType( /*builder*/ ) { + + return `${this.scope}Array`; + + } + + element( indexNode ) { + + return nodeObject( new WorkgroupInfoElementNode( this, indexNode ) ); + + } + + generate( builder ) { + + return builder.getScopedArray( this.name || `${this.scope}Array_${this.id}`, this.scope.toLowerCase(), this.bufferType, this.bufferCount ); + + } + +} + +const workgroupArray = ( type, count ) => nodeObject( new WorkgroupInfoNode( 'Workgroup', type, count ) ); + +class AtomicFunctionNode extends TempNode { + + static get type() { + + return 'AtomicFunctionNode'; + + } + + constructor( method, pointerNode, valueNode, storeNode = null ) { + + super( 'uint' ); + + this.method = method; + + this.pointerNode = pointerNode; + this.valueNode = valueNode; + this.storeNode = storeNode; + + } + + getInputType( builder ) { + + return this.pointerNode.getNodeType( builder ); + + } + + getNodeType( builder ) { + + return this.getInputType( builder ); + + } + + generate( builder ) { + + const method = this.method; + + const type = this.getNodeType( builder ); + const inputType = this.getInputType( builder ); + + const a = this.pointerNode; + const b = this.valueNode; + + const params = []; + + params.push( `&${ a.build( builder, inputType ) }` ); + params.push( b.build( builder, inputType ) ); + + const methodSnippet = `${ builder.getMethod( method, type ) }( ${params.join( ', ' )} )`; + + if ( this.storeNode !== null ) { + + const varSnippet = this.storeNode.build( builder, inputType ); + + builder.addLineFlowCode( `${varSnippet} = ${methodSnippet}`, this ); + + } else { + + builder.addLineFlowCode( methodSnippet, this ); + + } + + } + +} + +AtomicFunctionNode.ATOMIC_LOAD = 'atomicLoad'; +AtomicFunctionNode.ATOMIC_STORE = 'atomicStore'; +AtomicFunctionNode.ATOMIC_ADD = 'atomicAdd'; +AtomicFunctionNode.ATOMIC_SUB = 'atomicSub'; +AtomicFunctionNode.ATOMIC_MAX = 'atomicMax'; +AtomicFunctionNode.ATOMIC_MIN = 'atomicMin'; +AtomicFunctionNode.ATOMIC_AND = 'atomicAnd'; +AtomicFunctionNode.ATOMIC_OR = 'atomicOr'; +AtomicFunctionNode.ATOMIC_XOR = 'atomicXor'; + +const atomicNode = nodeProxy( AtomicFunctionNode ); + +const atomicFunc = ( method, pointerNode, valueNode, storeNode ) => { + + const node = atomicNode( method, pointerNode, valueNode, storeNode ); + node.append(); + + return node; + +}; + +const atomicStore = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_STORE, pointerNode, valueNode, storeNode ); +const atomicAdd = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_ADD, pointerNode, valueNode, storeNode ); +const atomicSub = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_SUB, pointerNode, valueNode, storeNode ); +const atomicMax = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_MAX, pointerNode, valueNode, storeNode ); +const atomicMin = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_MIN, pointerNode, valueNode, storeNode ); +const atomicAnd = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_AND, pointerNode, valueNode, storeNode ); +const atomicOr = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_OR, pointerNode, valueNode, storeNode ); +const atomicXor = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_XOR, pointerNode, valueNode, storeNode ); + +const checker = /*@__PURE__*/ Fn( ( [ coord = uv() ] ) => { + + const uv = coord.mul( 2.0 ); + + const cx = uv.x.floor(); + const cy = uv.y.floor(); + const result = cx.add( cy ).mod( 2.0 ); + + return result.sign(); + +} ); + +// Three.js Transpiler +// https://raw.githubusercontent.com/AcademySoftwareFoundation/MaterialX/main/libraries/stdlib/genglsl/lib/mx_noise.glsl + + + +const mx_select = /*@__PURE__*/ Fn( ( [ b_immutable, t_immutable, f_immutable ] ) => { + + const f = float( f_immutable ).toVar(); + const t = float( t_immutable ).toVar(); + const b = bool( b_immutable ).toVar(); + + return select( b, t, f ); + +} ).setLayout( { + name: 'mx_select', + type: 'float', + inputs: [ + { name: 'b', type: 'bool' }, + { name: 't', type: 'float' }, + { name: 'f', type: 'float' } + ] +} ); + +const mx_negate_if = /*@__PURE__*/ Fn( ( [ val_immutable, b_immutable ] ) => { + + const b = bool( b_immutable ).toVar(); + const val = float( val_immutable ).toVar(); + + return select( b, val.negate(), val ); + +} ).setLayout( { + name: 'mx_negate_if', + type: 'float', + inputs: [ + { name: 'val', type: 'float' }, + { name: 'b', type: 'bool' } + ] +} ); + +const mx_floor = /*@__PURE__*/ Fn( ( [ x_immutable ] ) => { + + const x = float( x_immutable ).toVar(); + + return int( floor( x ) ); + +} ).setLayout( { + name: 'mx_floor', + type: 'int', + inputs: [ + { name: 'x', type: 'float' } + ] +} ); + +const mx_floorfrac = /*@__PURE__*/ Fn( ( [ x_immutable, i ] ) => { + + const x = float( x_immutable ).toVar(); + i.assign( mx_floor( x ) ); + + return x.sub( float( i ) ); + +} ); + +const mx_bilerp_0 = /*@__PURE__*/ Fn( ( [ v0_immutable, v1_immutable, v2_immutable, v3_immutable, s_immutable, t_immutable ] ) => { + + const t = float( t_immutable ).toVar(); + const s = float( s_immutable ).toVar(); + const v3 = float( v3_immutable ).toVar(); + const v2 = float( v2_immutable ).toVar(); + const v1 = float( v1_immutable ).toVar(); + const v0 = float( v0_immutable ).toVar(); + const s1 = float( sub( 1.0, s ) ).toVar(); + + return sub( 1.0, t ).mul( v0.mul( s1 ).add( v1.mul( s ) ) ).add( t.mul( v2.mul( s1 ).add( v3.mul( s ) ) ) ); + +} ).setLayout( { + name: 'mx_bilerp_0', + type: 'float', + inputs: [ + { name: 'v0', type: 'float' }, + { name: 'v1', type: 'float' }, + { name: 'v2', type: 'float' }, + { name: 'v3', type: 'float' }, + { name: 's', type: 'float' }, + { name: 't', type: 'float' } + ] +} ); + +const mx_bilerp_1 = /*@__PURE__*/ Fn( ( [ v0_immutable, v1_immutable, v2_immutable, v3_immutable, s_immutable, t_immutable ] ) => { + + const t = float( t_immutable ).toVar(); + const s = float( s_immutable ).toVar(); + const v3 = vec3( v3_immutable ).toVar(); + const v2 = vec3( v2_immutable ).toVar(); + const v1 = vec3( v1_immutable ).toVar(); + const v0 = vec3( v0_immutable ).toVar(); + const s1 = float( sub( 1.0, s ) ).toVar(); + + return sub( 1.0, t ).mul( v0.mul( s1 ).add( v1.mul( s ) ) ).add( t.mul( v2.mul( s1 ).add( v3.mul( s ) ) ) ); + +} ).setLayout( { + name: 'mx_bilerp_1', + type: 'vec3', + inputs: [ + { name: 'v0', type: 'vec3' }, + { name: 'v1', type: 'vec3' }, + { name: 'v2', type: 'vec3' }, + { name: 'v3', type: 'vec3' }, + { name: 's', type: 'float' }, + { name: 't', type: 'float' } + ] +} ); + +const mx_bilerp = /*@__PURE__*/ overloadingFn( [ mx_bilerp_0, mx_bilerp_1 ] ); + +const mx_trilerp_0 = /*@__PURE__*/ Fn( ( [ v0_immutable, v1_immutable, v2_immutable, v3_immutable, v4_immutable, v5_immutable, v6_immutable, v7_immutable, s_immutable, t_immutable, r_immutable ] ) => { + + const r = float( r_immutable ).toVar(); + const t = float( t_immutable ).toVar(); + const s = float( s_immutable ).toVar(); + const v7 = float( v7_immutable ).toVar(); + const v6 = float( v6_immutable ).toVar(); + const v5 = float( v5_immutable ).toVar(); + const v4 = float( v4_immutable ).toVar(); + const v3 = float( v3_immutable ).toVar(); + const v2 = float( v2_immutable ).toVar(); + const v1 = float( v1_immutable ).toVar(); + const v0 = float( v0_immutable ).toVar(); + const s1 = float( sub( 1.0, s ) ).toVar(); + const t1 = float( sub( 1.0, t ) ).toVar(); + const r1 = float( sub( 1.0, r ) ).toVar(); + + return r1.mul( t1.mul( v0.mul( s1 ).add( v1.mul( s ) ) ).add( t.mul( v2.mul( s1 ).add( v3.mul( s ) ) ) ) ).add( r.mul( t1.mul( v4.mul( s1 ).add( v5.mul( s ) ) ).add( t.mul( v6.mul( s1 ).add( v7.mul( s ) ) ) ) ) ); + +} ).setLayout( { + name: 'mx_trilerp_0', + type: 'float', + inputs: [ + { name: 'v0', type: 'float' }, + { name: 'v1', type: 'float' }, + { name: 'v2', type: 'float' }, + { name: 'v3', type: 'float' }, + { name: 'v4', type: 'float' }, + { name: 'v5', type: 'float' }, + { name: 'v6', type: 'float' }, + { name: 'v7', type: 'float' }, + { name: 's', type: 'float' }, + { name: 't', type: 'float' }, + { name: 'r', type: 'float' } + ] +} ); + +const mx_trilerp_1 = /*@__PURE__*/ Fn( ( [ v0_immutable, v1_immutable, v2_immutable, v3_immutable, v4_immutable, v5_immutable, v6_immutable, v7_immutable, s_immutable, t_immutable, r_immutable ] ) => { + + const r = float( r_immutable ).toVar(); + const t = float( t_immutable ).toVar(); + const s = float( s_immutable ).toVar(); + const v7 = vec3( v7_immutable ).toVar(); + const v6 = vec3( v6_immutable ).toVar(); + const v5 = vec3( v5_immutable ).toVar(); + const v4 = vec3( v4_immutable ).toVar(); + const v3 = vec3( v3_immutable ).toVar(); + const v2 = vec3( v2_immutable ).toVar(); + const v1 = vec3( v1_immutable ).toVar(); + const v0 = vec3( v0_immutable ).toVar(); + const s1 = float( sub( 1.0, s ) ).toVar(); + const t1 = float( sub( 1.0, t ) ).toVar(); + const r1 = float( sub( 1.0, r ) ).toVar(); + + return r1.mul( t1.mul( v0.mul( s1 ).add( v1.mul( s ) ) ).add( t.mul( v2.mul( s1 ).add( v3.mul( s ) ) ) ) ).add( r.mul( t1.mul( v4.mul( s1 ).add( v5.mul( s ) ) ).add( t.mul( v6.mul( s1 ).add( v7.mul( s ) ) ) ) ) ); + +} ).setLayout( { + name: 'mx_trilerp_1', + type: 'vec3', + inputs: [ + { name: 'v0', type: 'vec3' }, + { name: 'v1', type: 'vec3' }, + { name: 'v2', type: 'vec3' }, + { name: 'v3', type: 'vec3' }, + { name: 'v4', type: 'vec3' }, + { name: 'v5', type: 'vec3' }, + { name: 'v6', type: 'vec3' }, + { name: 'v7', type: 'vec3' }, + { name: 's', type: 'float' }, + { name: 't', type: 'float' }, + { name: 'r', type: 'float' } + ] +} ); + +const mx_trilerp = /*@__PURE__*/ overloadingFn( [ mx_trilerp_0, mx_trilerp_1 ] ); + +const mx_gradient_float_0 = /*@__PURE__*/ Fn( ( [ hash_immutable, x_immutable, y_immutable ] ) => { + + const y = float( y_immutable ).toVar(); + const x = float( x_immutable ).toVar(); + const hash = uint( hash_immutable ).toVar(); + const h = uint( hash.bitAnd( uint( 7 ) ) ).toVar(); + const u = float( mx_select( h.lessThan( uint( 4 ) ), x, y ) ).toVar(); + const v = float( mul( 2.0, mx_select( h.lessThan( uint( 4 ) ), y, x ) ) ).toVar(); + + return mx_negate_if( u, bool( h.bitAnd( uint( 1 ) ) ) ).add( mx_negate_if( v, bool( h.bitAnd( uint( 2 ) ) ) ) ); + +} ).setLayout( { + name: 'mx_gradient_float_0', + type: 'float', + inputs: [ + { name: 'hash', type: 'uint' }, + { name: 'x', type: 'float' }, + { name: 'y', type: 'float' } + ] +} ); + +const mx_gradient_float_1 = /*@__PURE__*/ Fn( ( [ hash_immutable, x_immutable, y_immutable, z_immutable ] ) => { + + const z = float( z_immutable ).toVar(); + const y = float( y_immutable ).toVar(); + const x = float( x_immutable ).toVar(); + const hash = uint( hash_immutable ).toVar(); + const h = uint( hash.bitAnd( uint( 15 ) ) ).toVar(); + const u = float( mx_select( h.lessThan( uint( 8 ) ), x, y ) ).toVar(); + const v = float( mx_select( h.lessThan( uint( 4 ) ), y, mx_select( h.equal( uint( 12 ) ).or( h.equal( uint( 14 ) ) ), x, z ) ) ).toVar(); + + return mx_negate_if( u, bool( h.bitAnd( uint( 1 ) ) ) ).add( mx_negate_if( v, bool( h.bitAnd( uint( 2 ) ) ) ) ); + +} ).setLayout( { + name: 'mx_gradient_float_1', + type: 'float', + inputs: [ + { name: 'hash', type: 'uint' }, + { name: 'x', type: 'float' }, + { name: 'y', type: 'float' }, + { name: 'z', type: 'float' } + ] +} ); + +const mx_gradient_float = /*@__PURE__*/ overloadingFn( [ mx_gradient_float_0, mx_gradient_float_1 ] ); + +const mx_gradient_vec3_0 = /*@__PURE__*/ Fn( ( [ hash_immutable, x_immutable, y_immutable ] ) => { + + const y = float( y_immutable ).toVar(); + const x = float( x_immutable ).toVar(); + const hash = uvec3( hash_immutable ).toVar(); + + return vec3( mx_gradient_float( hash.x, x, y ), mx_gradient_float( hash.y, x, y ), mx_gradient_float( hash.z, x, y ) ); + +} ).setLayout( { + name: 'mx_gradient_vec3_0', + type: 'vec3', + inputs: [ + { name: 'hash', type: 'uvec3' }, + { name: 'x', type: 'float' }, + { name: 'y', type: 'float' } + ] +} ); + +const mx_gradient_vec3_1 = /*@__PURE__*/ Fn( ( [ hash_immutable, x_immutable, y_immutable, z_immutable ] ) => { + + const z = float( z_immutable ).toVar(); + const y = float( y_immutable ).toVar(); + const x = float( x_immutable ).toVar(); + const hash = uvec3( hash_immutable ).toVar(); + + return vec3( mx_gradient_float( hash.x, x, y, z ), mx_gradient_float( hash.y, x, y, z ), mx_gradient_float( hash.z, x, y, z ) ); + +} ).setLayout( { + name: 'mx_gradient_vec3_1', + type: 'vec3', + inputs: [ + { name: 'hash', type: 'uvec3' }, + { name: 'x', type: 'float' }, + { name: 'y', type: 'float' }, + { name: 'z', type: 'float' } + ] +} ); + +const mx_gradient_vec3 = /*@__PURE__*/ overloadingFn( [ mx_gradient_vec3_0, mx_gradient_vec3_1 ] ); + +const mx_gradient_scale2d_0 = /*@__PURE__*/ Fn( ( [ v_immutable ] ) => { + + const v = float( v_immutable ).toVar(); + + return mul( 0.6616, v ); + +} ).setLayout( { + name: 'mx_gradient_scale2d_0', + type: 'float', + inputs: [ + { name: 'v', type: 'float' } + ] +} ); + +const mx_gradient_scale3d_0 = /*@__PURE__*/ Fn( ( [ v_immutable ] ) => { + + const v = float( v_immutable ).toVar(); + + return mul( 0.9820, v ); + +} ).setLayout( { + name: 'mx_gradient_scale3d_0', + type: 'float', + inputs: [ + { name: 'v', type: 'float' } + ] +} ); + +const mx_gradient_scale2d_1 = /*@__PURE__*/ Fn( ( [ v_immutable ] ) => { + + const v = vec3( v_immutable ).toVar(); + + return mul( 0.6616, v ); + +} ).setLayout( { + name: 'mx_gradient_scale2d_1', + type: 'vec3', + inputs: [ + { name: 'v', type: 'vec3' } + ] +} ); + +const mx_gradient_scale2d = /*@__PURE__*/ overloadingFn( [ mx_gradient_scale2d_0, mx_gradient_scale2d_1 ] ); + +const mx_gradient_scale3d_1 = /*@__PURE__*/ Fn( ( [ v_immutable ] ) => { + + const v = vec3( v_immutable ).toVar(); + + return mul( 0.9820, v ); + +} ).setLayout( { + name: 'mx_gradient_scale3d_1', + type: 'vec3', + inputs: [ + { name: 'v', type: 'vec3' } + ] +} ); + +const mx_gradient_scale3d = /*@__PURE__*/ overloadingFn( [ mx_gradient_scale3d_0, mx_gradient_scale3d_1 ] ); + +const mx_rotl32 = /*@__PURE__*/ Fn( ( [ x_immutable, k_immutable ] ) => { + + const k = int( k_immutable ).toVar(); + const x = uint( x_immutable ).toVar(); + + return x.shiftLeft( k ).bitOr( x.shiftRight( int( 32 ).sub( k ) ) ); + +} ).setLayout( { + name: 'mx_rotl32', + type: 'uint', + inputs: [ + { name: 'x', type: 'uint' }, + { name: 'k', type: 'int' } + ] +} ); + +const mx_bjmix = /*@__PURE__*/ Fn( ( [ a, b, c ] ) => { + + a.subAssign( c ); + a.bitXorAssign( mx_rotl32( c, int( 4 ) ) ); + c.addAssign( b ); + b.subAssign( a ); + b.bitXorAssign( mx_rotl32( a, int( 6 ) ) ); + a.addAssign( c ); + c.subAssign( b ); + c.bitXorAssign( mx_rotl32( b, int( 8 ) ) ); + b.addAssign( a ); + a.subAssign( c ); + a.bitXorAssign( mx_rotl32( c, int( 16 ) ) ); + c.addAssign( b ); + b.subAssign( a ); + b.bitXorAssign( mx_rotl32( a, int( 19 ) ) ); + a.addAssign( c ); + c.subAssign( b ); + c.bitXorAssign( mx_rotl32( b, int( 4 ) ) ); + b.addAssign( a ); + +} ); + +const mx_bjfinal = /*@__PURE__*/ Fn( ( [ a_immutable, b_immutable, c_immutable ] ) => { + + const c = uint( c_immutable ).toVar(); + const b = uint( b_immutable ).toVar(); + const a = uint( a_immutable ).toVar(); + c.bitXorAssign( b ); + c.subAssign( mx_rotl32( b, int( 14 ) ) ); + a.bitXorAssign( c ); + a.subAssign( mx_rotl32( c, int( 11 ) ) ); + b.bitXorAssign( a ); + b.subAssign( mx_rotl32( a, int( 25 ) ) ); + c.bitXorAssign( b ); + c.subAssign( mx_rotl32( b, int( 16 ) ) ); + a.bitXorAssign( c ); + a.subAssign( mx_rotl32( c, int( 4 ) ) ); + b.bitXorAssign( a ); + b.subAssign( mx_rotl32( a, int( 14 ) ) ); + c.bitXorAssign( b ); + c.subAssign( mx_rotl32( b, int( 24 ) ) ); + + return c; + +} ).setLayout( { + name: 'mx_bjfinal', + type: 'uint', + inputs: [ + { name: 'a', type: 'uint' }, + { name: 'b', type: 'uint' }, + { name: 'c', type: 'uint' } + ] +} ); + +const mx_bits_to_01 = /*@__PURE__*/ Fn( ( [ bits_immutable ] ) => { + + const bits = uint( bits_immutable ).toVar(); + + return float( bits ).div( float( uint( int( 0xffffffff ) ) ) ); + +} ).setLayout( { + name: 'mx_bits_to_01', + type: 'float', + inputs: [ + { name: 'bits', type: 'uint' } + ] +} ); + +const mx_fade = /*@__PURE__*/ Fn( ( [ t_immutable ] ) => { + + const t = float( t_immutable ).toVar(); + + return t.mul( t ).mul( t ).mul( t.mul( t.mul( 6.0 ).sub( 15.0 ) ).add( 10.0 ) ); + +} ).setLayout( { + name: 'mx_fade', + type: 'float', + inputs: [ + { name: 't', type: 'float' } + ] +} ); + +const mx_hash_int_0 = /*@__PURE__*/ Fn( ( [ x_immutable ] ) => { + + const x = int( x_immutable ).toVar(); + const len = uint( uint( 1 ) ).toVar(); + const seed = uint( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ).toVar(); + + return mx_bjfinal( seed.add( uint( x ) ), seed, seed ); + +} ).setLayout( { + name: 'mx_hash_int_0', + type: 'uint', + inputs: [ + { name: 'x', type: 'int' } + ] +} ); + +const mx_hash_int_1 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable ] ) => { + + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const len = uint( uint( 2 ) ).toVar(); + const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); + a.assign( b.assign( c.assign( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ) ) ); + a.addAssign( uint( x ) ); + b.addAssign( uint( y ) ); + + return mx_bjfinal( a, b, c ); + +} ).setLayout( { + name: 'mx_hash_int_1', + type: 'uint', + inputs: [ + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' } + ] +} ); + +const mx_hash_int_2 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable, z_immutable ] ) => { + + const z = int( z_immutable ).toVar(); + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const len = uint( uint( 3 ) ).toVar(); + const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); + a.assign( b.assign( c.assign( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ) ) ); + a.addAssign( uint( x ) ); + b.addAssign( uint( y ) ); + c.addAssign( uint( z ) ); + + return mx_bjfinal( a, b, c ); + +} ).setLayout( { + name: 'mx_hash_int_2', + type: 'uint', + inputs: [ + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' }, + { name: 'z', type: 'int' } + ] +} ); + +const mx_hash_int_3 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable, z_immutable, xx_immutable ] ) => { + + const xx = int( xx_immutable ).toVar(); + const z = int( z_immutable ).toVar(); + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const len = uint( uint( 4 ) ).toVar(); + const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); + a.assign( b.assign( c.assign( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ) ) ); + a.addAssign( uint( x ) ); + b.addAssign( uint( y ) ); + c.addAssign( uint( z ) ); + mx_bjmix( a, b, c ); + a.addAssign( uint( xx ) ); + + return mx_bjfinal( a, b, c ); + +} ).setLayout( { + name: 'mx_hash_int_3', + type: 'uint', + inputs: [ + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' }, + { name: 'z', type: 'int' }, + { name: 'xx', type: 'int' } + ] +} ); + +const mx_hash_int_4 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable, z_immutable, xx_immutable, yy_immutable ] ) => { + + const yy = int( yy_immutable ).toVar(); + const xx = int( xx_immutable ).toVar(); + const z = int( z_immutable ).toVar(); + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const len = uint( uint( 5 ) ).toVar(); + const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); + a.assign( b.assign( c.assign( uint( int( 0xdeadbeef ) ).add( len.shiftLeft( uint( 2 ) ) ).add( uint( 13 ) ) ) ) ); + a.addAssign( uint( x ) ); + b.addAssign( uint( y ) ); + c.addAssign( uint( z ) ); + mx_bjmix( a, b, c ); + a.addAssign( uint( xx ) ); + b.addAssign( uint( yy ) ); + + return mx_bjfinal( a, b, c ); + +} ).setLayout( { + name: 'mx_hash_int_4', + type: 'uint', + inputs: [ + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' }, + { name: 'z', type: 'int' }, + { name: 'xx', type: 'int' }, + { name: 'yy', type: 'int' } + ] +} ); + +const mx_hash_int = /*@__PURE__*/ overloadingFn( [ mx_hash_int_0, mx_hash_int_1, mx_hash_int_2, mx_hash_int_3, mx_hash_int_4 ] ); + +const mx_hash_vec3_0 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable ] ) => { + + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const h = uint( mx_hash_int( x, y ) ).toVar(); + const result = uvec3().toVar(); + result.x.assign( h.bitAnd( int( 0xFF ) ) ); + result.y.assign( h.shiftRight( int( 8 ) ).bitAnd( int( 0xFF ) ) ); + result.z.assign( h.shiftRight( int( 16 ) ).bitAnd( int( 0xFF ) ) ); + + return result; + +} ).setLayout( { + name: 'mx_hash_vec3_0', + type: 'uvec3', + inputs: [ + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' } + ] +} ); + +const mx_hash_vec3_1 = /*@__PURE__*/ Fn( ( [ x_immutable, y_immutable, z_immutable ] ) => { + + const z = int( z_immutable ).toVar(); + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const h = uint( mx_hash_int( x, y, z ) ).toVar(); + const result = uvec3().toVar(); + result.x.assign( h.bitAnd( int( 0xFF ) ) ); + result.y.assign( h.shiftRight( int( 8 ) ).bitAnd( int( 0xFF ) ) ); + result.z.assign( h.shiftRight( int( 16 ) ).bitAnd( int( 0xFF ) ) ); + + return result; + +} ).setLayout( { + name: 'mx_hash_vec3_1', + type: 'uvec3', + inputs: [ + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' }, + { name: 'z', type: 'int' } + ] +} ); + +const mx_hash_vec3 = /*@__PURE__*/ overloadingFn( [ mx_hash_vec3_0, mx_hash_vec3_1 ] ); + +const mx_perlin_noise_float_0 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec2( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(); + const fx = float( mx_floorfrac( p.x, X ) ).toVar(); + const fy = float( mx_floorfrac( p.y, Y ) ).toVar(); + const u = float( mx_fade( fx ) ).toVar(); + const v = float( mx_fade( fy ) ).toVar(); + const result = float( mx_bilerp( mx_gradient_float( mx_hash_int( X, Y ), fx, fy ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y ), fx.sub( 1.0 ), fy ), mx_gradient_float( mx_hash_int( X, Y.add( int( 1 ) ) ), fx, fy.sub( 1.0 ) ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y.add( int( 1 ) ) ), fx.sub( 1.0 ), fy.sub( 1.0 ) ), u, v ) ).toVar(); + + return mx_gradient_scale2d( result ); + +} ).setLayout( { + name: 'mx_perlin_noise_float_0', + type: 'float', + inputs: [ + { name: 'p', type: 'vec2' } + ] +} ); + +const mx_perlin_noise_float_1 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec3( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); + const fx = float( mx_floorfrac( p.x, X ) ).toVar(); + const fy = float( mx_floorfrac( p.y, Y ) ).toVar(); + const fz = float( mx_floorfrac( p.z, Z ) ).toVar(); + const u = float( mx_fade( fx ) ).toVar(); + const v = float( mx_fade( fy ) ).toVar(); + const w = float( mx_fade( fz ) ).toVar(); + const result = float( mx_trilerp( mx_gradient_float( mx_hash_int( X, Y, Z ), fx, fy, fz ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y, Z ), fx.sub( 1.0 ), fy, fz ), mx_gradient_float( mx_hash_int( X, Y.add( int( 1 ) ), Z ), fx, fy.sub( 1.0 ), fz ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y.add( int( 1 ) ), Z ), fx.sub( 1.0 ), fy.sub( 1.0 ), fz ), mx_gradient_float( mx_hash_int( X, Y, Z.add( int( 1 ) ) ), fx, fy, fz.sub( 1.0 ) ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y, Z.add( int( 1 ) ) ), fx.sub( 1.0 ), fy, fz.sub( 1.0 ) ), mx_gradient_float( mx_hash_int( X, Y.add( int( 1 ) ), Z.add( int( 1 ) ) ), fx, fy.sub( 1.0 ), fz.sub( 1.0 ) ), mx_gradient_float( mx_hash_int( X.add( int( 1 ) ), Y.add( int( 1 ) ), Z.add( int( 1 ) ) ), fx.sub( 1.0 ), fy.sub( 1.0 ), fz.sub( 1.0 ) ), u, v, w ) ).toVar(); + + return mx_gradient_scale3d( result ); + +} ).setLayout( { + name: 'mx_perlin_noise_float_1', + type: 'float', + inputs: [ + { name: 'p', type: 'vec3' } + ] +} ); + +const mx_perlin_noise_float = /*@__PURE__*/ overloadingFn( [ mx_perlin_noise_float_0, mx_perlin_noise_float_1 ] ); + +const mx_perlin_noise_vec3_0 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec2( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(); + const fx = float( mx_floorfrac( p.x, X ) ).toVar(); + const fy = float( mx_floorfrac( p.y, Y ) ).toVar(); + const u = float( mx_fade( fx ) ).toVar(); + const v = float( mx_fade( fy ) ).toVar(); + const result = vec3( mx_bilerp( mx_gradient_vec3( mx_hash_vec3( X, Y ), fx, fy ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y ), fx.sub( 1.0 ), fy ), mx_gradient_vec3( mx_hash_vec3( X, Y.add( int( 1 ) ) ), fx, fy.sub( 1.0 ) ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y.add( int( 1 ) ) ), fx.sub( 1.0 ), fy.sub( 1.0 ) ), u, v ) ).toVar(); + + return mx_gradient_scale2d( result ); + +} ).setLayout( { + name: 'mx_perlin_noise_vec3_0', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec2' } + ] +} ); + +const mx_perlin_noise_vec3_1 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec3( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); + const fx = float( mx_floorfrac( p.x, X ) ).toVar(); + const fy = float( mx_floorfrac( p.y, Y ) ).toVar(); + const fz = float( mx_floorfrac( p.z, Z ) ).toVar(); + const u = float( mx_fade( fx ) ).toVar(); + const v = float( mx_fade( fy ) ).toVar(); + const w = float( mx_fade( fz ) ).toVar(); + const result = vec3( mx_trilerp( mx_gradient_vec3( mx_hash_vec3( X, Y, Z ), fx, fy, fz ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y, Z ), fx.sub( 1.0 ), fy, fz ), mx_gradient_vec3( mx_hash_vec3( X, Y.add( int( 1 ) ), Z ), fx, fy.sub( 1.0 ), fz ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y.add( int( 1 ) ), Z ), fx.sub( 1.0 ), fy.sub( 1.0 ), fz ), mx_gradient_vec3( mx_hash_vec3( X, Y, Z.add( int( 1 ) ) ), fx, fy, fz.sub( 1.0 ) ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y, Z.add( int( 1 ) ) ), fx.sub( 1.0 ), fy, fz.sub( 1.0 ) ), mx_gradient_vec3( mx_hash_vec3( X, Y.add( int( 1 ) ), Z.add( int( 1 ) ) ), fx, fy.sub( 1.0 ), fz.sub( 1.0 ) ), mx_gradient_vec3( mx_hash_vec3( X.add( int( 1 ) ), Y.add( int( 1 ) ), Z.add( int( 1 ) ) ), fx.sub( 1.0 ), fy.sub( 1.0 ), fz.sub( 1.0 ) ), u, v, w ) ).toVar(); + + return mx_gradient_scale3d( result ); + +} ).setLayout( { + name: 'mx_perlin_noise_vec3_1', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec3' } + ] +} ); + +const mx_perlin_noise_vec3 = /*@__PURE__*/ overloadingFn( [ mx_perlin_noise_vec3_0, mx_perlin_noise_vec3_1 ] ); + +const mx_cell_noise_float_0 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = float( p_immutable ).toVar(); + const ix = int( mx_floor( p ) ).toVar(); + + return mx_bits_to_01( mx_hash_int( ix ) ); + +} ).setLayout( { + name: 'mx_cell_noise_float_0', + type: 'float', + inputs: [ + { name: 'p', type: 'float' } + ] +} ); + +const mx_cell_noise_float_1 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec2( p_immutable ).toVar(); + const ix = int( mx_floor( p.x ) ).toVar(); + const iy = int( mx_floor( p.y ) ).toVar(); + + return mx_bits_to_01( mx_hash_int( ix, iy ) ); + +} ).setLayout( { + name: 'mx_cell_noise_float_1', + type: 'float', + inputs: [ + { name: 'p', type: 'vec2' } + ] +} ); + +const mx_cell_noise_float_2 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec3( p_immutable ).toVar(); + const ix = int( mx_floor( p.x ) ).toVar(); + const iy = int( mx_floor( p.y ) ).toVar(); + const iz = int( mx_floor( p.z ) ).toVar(); + + return mx_bits_to_01( mx_hash_int( ix, iy, iz ) ); + +} ).setLayout( { + name: 'mx_cell_noise_float_2', + type: 'float', + inputs: [ + { name: 'p', type: 'vec3' } + ] +} ); + +const mx_cell_noise_float_3 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec4( p_immutable ).toVar(); + const ix = int( mx_floor( p.x ) ).toVar(); + const iy = int( mx_floor( p.y ) ).toVar(); + const iz = int( mx_floor( p.z ) ).toVar(); + const iw = int( mx_floor( p.w ) ).toVar(); + + return mx_bits_to_01( mx_hash_int( ix, iy, iz, iw ) ); + +} ).setLayout( { + name: 'mx_cell_noise_float_3', + type: 'float', + inputs: [ + { name: 'p', type: 'vec4' } + ] +} ); + +const mx_cell_noise_float$1 = /*@__PURE__*/ overloadingFn( [ mx_cell_noise_float_0, mx_cell_noise_float_1, mx_cell_noise_float_2, mx_cell_noise_float_3 ] ); + +const mx_cell_noise_vec3_0 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = float( p_immutable ).toVar(); + const ix = int( mx_floor( p ) ).toVar(); + + return vec3( mx_bits_to_01( mx_hash_int( ix, int( 0 ) ) ), mx_bits_to_01( mx_hash_int( ix, int( 1 ) ) ), mx_bits_to_01( mx_hash_int( ix, int( 2 ) ) ) ); + +} ).setLayout( { + name: 'mx_cell_noise_vec3_0', + type: 'vec3', + inputs: [ + { name: 'p', type: 'float' } + ] +} ); + +const mx_cell_noise_vec3_1 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec2( p_immutable ).toVar(); + const ix = int( mx_floor( p.x ) ).toVar(); + const iy = int( mx_floor( p.y ) ).toVar(); + + return vec3( mx_bits_to_01( mx_hash_int( ix, iy, int( 0 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, int( 1 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, int( 2 ) ) ) ); + +} ).setLayout( { + name: 'mx_cell_noise_vec3_1', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec2' } + ] +} ); + +const mx_cell_noise_vec3_2 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec3( p_immutable ).toVar(); + const ix = int( mx_floor( p.x ) ).toVar(); + const iy = int( mx_floor( p.y ) ).toVar(); + const iz = int( mx_floor( p.z ) ).toVar(); + + return vec3( mx_bits_to_01( mx_hash_int( ix, iy, iz, int( 0 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, iz, int( 1 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, iz, int( 2 ) ) ) ); + +} ).setLayout( { + name: 'mx_cell_noise_vec3_2', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec3' } + ] +} ); + +const mx_cell_noise_vec3_3 = /*@__PURE__*/ Fn( ( [ p_immutable ] ) => { + + const p = vec4( p_immutable ).toVar(); + const ix = int( mx_floor( p.x ) ).toVar(); + const iy = int( mx_floor( p.y ) ).toVar(); + const iz = int( mx_floor( p.z ) ).toVar(); + const iw = int( mx_floor( p.w ) ).toVar(); + + return vec3( mx_bits_to_01( mx_hash_int( ix, iy, iz, iw, int( 0 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, iz, iw, int( 1 ) ) ), mx_bits_to_01( mx_hash_int( ix, iy, iz, iw, int( 2 ) ) ) ); + +} ).setLayout( { + name: 'mx_cell_noise_vec3_3', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec4' } + ] +} ); + +const mx_cell_noise_vec3 = /*@__PURE__*/ overloadingFn( [ mx_cell_noise_vec3_0, mx_cell_noise_vec3_1, mx_cell_noise_vec3_2, mx_cell_noise_vec3_3 ] ); + +const mx_fractal_noise_float$1 = /*@__PURE__*/ Fn( ( [ p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable ] ) => { + + const diminish = float( diminish_immutable ).toVar(); + const lacunarity = float( lacunarity_immutable ).toVar(); + const octaves = int( octaves_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const result = float( 0.0 ).toVar(); + const amplitude = float( 1.0 ).toVar(); + + Loop( octaves, () => { + + result.addAssign( amplitude.mul( mx_perlin_noise_float( p ) ) ); + amplitude.mulAssign( diminish ); + p.mulAssign( lacunarity ); + + } ); + + return result; + +} ).setLayout( { + name: 'mx_fractal_noise_float', + type: 'float', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'octaves', type: 'int' }, + { name: 'lacunarity', type: 'float' }, + { name: 'diminish', type: 'float' } + ] +} ); + +const mx_fractal_noise_vec3$1 = /*@__PURE__*/ Fn( ( [ p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable ] ) => { + + const diminish = float( diminish_immutable ).toVar(); + const lacunarity = float( lacunarity_immutable ).toVar(); + const octaves = int( octaves_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const result = vec3( 0.0 ).toVar(); + const amplitude = float( 1.0 ).toVar(); + + Loop( octaves, () => { + + result.addAssign( amplitude.mul( mx_perlin_noise_vec3( p ) ) ); + amplitude.mulAssign( diminish ); + p.mulAssign( lacunarity ); + + } ); + + return result; + +} ).setLayout( { + name: 'mx_fractal_noise_vec3', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'octaves', type: 'int' }, + { name: 'lacunarity', type: 'float' }, + { name: 'diminish', type: 'float' } + ] +} ); + +const mx_fractal_noise_vec2$1 = /*@__PURE__*/ Fn( ( [ p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable ] ) => { + + const diminish = float( diminish_immutable ).toVar(); + const lacunarity = float( lacunarity_immutable ).toVar(); + const octaves = int( octaves_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + + return vec2( mx_fractal_noise_float$1( p, octaves, lacunarity, diminish ), mx_fractal_noise_float$1( p.add( vec3( int( 19 ), int( 193 ), int( 17 ) ) ), octaves, lacunarity, diminish ) ); + +} ).setLayout( { + name: 'mx_fractal_noise_vec2', + type: 'vec2', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'octaves', type: 'int' }, + { name: 'lacunarity', type: 'float' }, + { name: 'diminish', type: 'float' } + ] +} ); + +const mx_fractal_noise_vec4$1 = /*@__PURE__*/ Fn( ( [ p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable ] ) => { + + const diminish = float( diminish_immutable ).toVar(); + const lacunarity = float( lacunarity_immutable ).toVar(); + const octaves = int( octaves_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const c = vec3( mx_fractal_noise_vec3$1( p, octaves, lacunarity, diminish ) ).toVar(); + const f = float( mx_fractal_noise_float$1( p.add( vec3( int( 19 ), int( 193 ), int( 17 ) ) ), octaves, lacunarity, diminish ) ).toVar(); + + return vec4( c, f ); + +} ).setLayout( { + name: 'mx_fractal_noise_vec4', + type: 'vec4', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'octaves', type: 'int' }, + { name: 'lacunarity', type: 'float' }, + { name: 'diminish', type: 'float' } + ] +} ); + +const mx_worley_distance_0 = /*@__PURE__*/ Fn( ( [ p_immutable, x_immutable, y_immutable, xoff_immutable, yoff_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const yoff = int( yoff_immutable ).toVar(); + const xoff = int( xoff_immutable ).toVar(); + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const p = vec2( p_immutable ).toVar(); + const tmp = vec3( mx_cell_noise_vec3( vec2( x.add( xoff ), y.add( yoff ) ) ) ).toVar(); + const off = vec2( tmp.x, tmp.y ).toVar(); + off.subAssign( 0.5 ); + off.mulAssign( jitter ); + off.addAssign( 0.5 ); + const cellpos = vec2( vec2( float( x ), float( y ) ).add( off ) ).toVar(); + const diff = vec2( cellpos.sub( p ) ).toVar(); + + If( metric.equal( int( 2 ) ), () => { + + return abs( diff.x ).add( abs( diff.y ) ); + + } ); + + If( metric.equal( int( 3 ) ), () => { + + return max$1( abs( diff.x ), abs( diff.y ) ); + + } ); + + return dot( diff, diff ); + +} ).setLayout( { + name: 'mx_worley_distance_0', + type: 'float', + inputs: [ + { name: 'p', type: 'vec2' }, + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' }, + { name: 'xoff', type: 'int' }, + { name: 'yoff', type: 'int' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_distance_1 = /*@__PURE__*/ Fn( ( [ p_immutable, x_immutable, y_immutable, z_immutable, xoff_immutable, yoff_immutable, zoff_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const zoff = int( zoff_immutable ).toVar(); + const yoff = int( yoff_immutable ).toVar(); + const xoff = int( xoff_immutable ).toVar(); + const z = int( z_immutable ).toVar(); + const y = int( y_immutable ).toVar(); + const x = int( x_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const off = vec3( mx_cell_noise_vec3( vec3( x.add( xoff ), y.add( yoff ), z.add( zoff ) ) ) ).toVar(); + off.subAssign( 0.5 ); + off.mulAssign( jitter ); + off.addAssign( 0.5 ); + const cellpos = vec3( vec3( float( x ), float( y ), float( z ) ).add( off ) ).toVar(); + const diff = vec3( cellpos.sub( p ) ).toVar(); + + If( metric.equal( int( 2 ) ), () => { + + return abs( diff.x ).add( abs( diff.y ) ).add( abs( diff.z ) ); + + } ); + + If( metric.equal( int( 3 ) ), () => { + + return max$1( max$1( abs( diff.x ), abs( diff.y ) ), abs( diff.z ) ); + + } ); + + return dot( diff, diff ); + +} ).setLayout( { + name: 'mx_worley_distance_1', + type: 'float', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'x', type: 'int' }, + { name: 'y', type: 'int' }, + { name: 'z', type: 'int' }, + { name: 'xoff', type: 'int' }, + { name: 'yoff', type: 'int' }, + { name: 'zoff', type: 'int' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_distance = /*@__PURE__*/ overloadingFn( [ mx_worley_distance_0, mx_worley_distance_1 ] ); + +const mx_worley_noise_float_0 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const p = vec2( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(); + const localpos = vec2( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ) ).toVar(); + const sqdist = float( 1e6 ).toVar(); + + Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + + const dist = float( mx_worley_distance( localpos, x, y, X, Y, jitter, metric ) ).toVar(); + sqdist.assign( min$1( sqdist, dist ) ); + + } ); + + } ); + + If( metric.equal( int( 0 ) ), () => { + + sqdist.assign( sqrt( sqdist ) ); + + } ); + + return sqdist; + +} ).setLayout( { + name: 'mx_worley_noise_float_0', + type: 'float', + inputs: [ + { name: 'p', type: 'vec2' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_noise_vec2_0 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const p = vec2( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(); + const localpos = vec2( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ) ).toVar(); + const sqdist = vec2( 1e6, 1e6 ).toVar(); + + Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + + const dist = float( mx_worley_distance( localpos, x, y, X, Y, jitter, metric ) ).toVar(); + + If( dist.lessThan( sqdist.x ), () => { + + sqdist.y.assign( sqdist.x ); + sqdist.x.assign( dist ); + + } ).ElseIf( dist.lessThan( sqdist.y ), () => { + + sqdist.y.assign( dist ); + + } ); + + } ); + + } ); + + If( metric.equal( int( 0 ) ), () => { + + sqdist.assign( sqrt( sqdist ) ); + + } ); + + return sqdist; + +} ).setLayout( { + name: 'mx_worley_noise_vec2_0', + type: 'vec2', + inputs: [ + { name: 'p', type: 'vec2' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_noise_vec3_0 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const p = vec2( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(); + const localpos = vec2( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ) ).toVar(); + const sqdist = vec3( 1e6, 1e6, 1e6 ).toVar(); + + Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + + const dist = float( mx_worley_distance( localpos, x, y, X, Y, jitter, metric ) ).toVar(); + + If( dist.lessThan( sqdist.x ), () => { + + sqdist.z.assign( sqdist.y ); + sqdist.y.assign( sqdist.x ); + sqdist.x.assign( dist ); + + } ).ElseIf( dist.lessThan( sqdist.y ), () => { + + sqdist.z.assign( sqdist.y ); + sqdist.y.assign( dist ); + + } ).ElseIf( dist.lessThan( sqdist.z ), () => { + + sqdist.z.assign( dist ); + + } ); + + } ); + + } ); + + If( metric.equal( int( 0 ) ), () => { + + sqdist.assign( sqrt( sqdist ) ); + + } ); + + return sqdist; + +} ).setLayout( { + name: 'mx_worley_noise_vec3_0', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec2' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_noise_float_1 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); + const localpos = vec3( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ), mx_floorfrac( p.z, Z ) ).toVar(); + const sqdist = float( 1e6 ).toVar(); + + Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'z', condition: '<=' }, ( { z } ) => { + + const dist = float( mx_worley_distance( localpos, x, y, z, X, Y, Z, jitter, metric ) ).toVar(); + sqdist.assign( min$1( sqdist, dist ) ); + + } ); + + } ); + + } ); + + If( metric.equal( int( 0 ) ), () => { + + sqdist.assign( sqrt( sqdist ) ); + + } ); + + return sqdist; + +} ).setLayout( { + name: 'mx_worley_noise_float_1', + type: 'float', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_noise_float$1 = /*@__PURE__*/ overloadingFn( [ mx_worley_noise_float_0, mx_worley_noise_float_1 ] ); + +const mx_worley_noise_vec2_1 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); + const localpos = vec3( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ), mx_floorfrac( p.z, Z ) ).toVar(); + const sqdist = vec2( 1e6, 1e6 ).toVar(); + + Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'z', condition: '<=' }, ( { z } ) => { + + const dist = float( mx_worley_distance( localpos, x, y, z, X, Y, Z, jitter, metric ) ).toVar(); + + If( dist.lessThan( sqdist.x ), () => { + + sqdist.y.assign( sqdist.x ); + sqdist.x.assign( dist ); + + } ).ElseIf( dist.lessThan( sqdist.y ), () => { + + sqdist.y.assign( dist ); + + } ); + + } ); + + } ); + + } ); + + If( metric.equal( int( 0 ) ), () => { + + sqdist.assign( sqrt( sqdist ) ); + + } ); + + return sqdist; + +} ).setLayout( { + name: 'mx_worley_noise_vec2_1', + type: 'vec2', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_noise_vec2$1 = /*@__PURE__*/ overloadingFn( [ mx_worley_noise_vec2_0, mx_worley_noise_vec2_1 ] ); + +const mx_worley_noise_vec3_1 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_immutable, metric_immutable ] ) => { + + const metric = int( metric_immutable ).toVar(); + const jitter = float( jitter_immutable ).toVar(); + const p = vec3( p_immutable ).toVar(); + const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); + const localpos = vec3( mx_floorfrac( p.x, X ), mx_floorfrac( p.y, Y ), mx_floorfrac( p.z, Z ) ).toVar(); + const sqdist = vec3( 1e6, 1e6, 1e6 ).toVar(); + + Loop( { start: - 1, end: int( 1 ), name: 'x', condition: '<=' }, ( { x } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'y', condition: '<=' }, ( { y } ) => { + + Loop( { start: - 1, end: int( 1 ), name: 'z', condition: '<=' }, ( { z } ) => { + + const dist = float( mx_worley_distance( localpos, x, y, z, X, Y, Z, jitter, metric ) ).toVar(); + + If( dist.lessThan( sqdist.x ), () => { + + sqdist.z.assign( sqdist.y ); + sqdist.y.assign( sqdist.x ); + sqdist.x.assign( dist ); + + } ).ElseIf( dist.lessThan( sqdist.y ), () => { + + sqdist.z.assign( sqdist.y ); + sqdist.y.assign( dist ); + + } ).ElseIf( dist.lessThan( sqdist.z ), () => { + + sqdist.z.assign( dist ); + + } ); + + } ); + + } ); + + } ); + + If( metric.equal( int( 0 ) ), () => { + + sqdist.assign( sqrt( sqdist ) ); + + } ); + + return sqdist; + +} ).setLayout( { + name: 'mx_worley_noise_vec3_1', + type: 'vec3', + inputs: [ + { name: 'p', type: 'vec3' }, + { name: 'jitter', type: 'float' }, + { name: 'metric', type: 'int' } + ] +} ); + +const mx_worley_noise_vec3$1 = /*@__PURE__*/ overloadingFn( [ mx_worley_noise_vec3_0, mx_worley_noise_vec3_1 ] ); + +// Three.js Transpiler +// https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/stdlib/genglsl/lib/mx_hsv.glsl + + +const mx_hsvtorgb = /*@__PURE__*/ Fn( ( [ hsv ] ) => { + + const s = hsv.y; + const v = hsv.z; + + const result = vec3().toVar(); + + If( s.lessThan( 0.0001 ), () => { + + result.assign( vec3( v, v, v ) ); + + } ).Else( () => { + + let h = hsv.x; + h = h.sub( floor( h ) ).mul( 6.0 ).toVar(); // TODO: check what .toVar() is needed in node system cache + const hi = int( trunc( h ) ); + const f = h.sub( float( hi ) ); + const p = v.mul( s.oneMinus() ); + const q = v.mul( s.mul( f ).oneMinus() ); + const t = v.mul( s.mul( f.oneMinus() ).oneMinus() ); + + If( hi.equal( int( 0 ) ), () => { + + result.assign( vec3( v, t, p ) ); + + } ).ElseIf( hi.equal( int( 1 ) ), () => { + + result.assign( vec3( q, v, p ) ); + + } ).ElseIf( hi.equal( int( 2 ) ), () => { + + result.assign( vec3( p, v, t ) ); + + } ).ElseIf( hi.equal( int( 3 ) ), () => { + + result.assign( vec3( p, q, v ) ); + + } ).ElseIf( hi.equal( int( 4 ) ), () => { + + result.assign( vec3( t, p, v ) ); + + } ).Else( () => { + + result.assign( vec3( v, p, q ) ); + + } ); + + } ); + + return result; + +} ).setLayout( { + name: 'mx_hsvtorgb', + type: 'vec3', + inputs: [ + { name: 'hsv', type: 'vec3' } + ] +} ); + +const mx_rgbtohsv = /*@__PURE__*/ Fn( ( [ c_immutable ] ) => { + + const c = vec3( c_immutable ).toVar(); + const r = float( c.x ).toVar(); + const g = float( c.y ).toVar(); + const b = float( c.z ).toVar(); + const mincomp = float( min$1( r, min$1( g, b ) ) ).toVar(); + const maxcomp = float( max$1( r, max$1( g, b ) ) ).toVar(); + const delta = float( maxcomp.sub( mincomp ) ).toVar(); + const h = float().toVar(), s = float().toVar(), v = float().toVar(); + v.assign( maxcomp ); + + If( maxcomp.greaterThan( 0.0 ), () => { + + s.assign( delta.div( maxcomp ) ); + + } ).Else( () => { + + s.assign( 0.0 ); + + } ); + + If( s.lessThanEqual( 0.0 ), () => { + + h.assign( 0.0 ); + + } ).Else( () => { + + If( r.greaterThanEqual( maxcomp ), () => { + + h.assign( g.sub( b ).div( delta ) ); + + } ).ElseIf( g.greaterThanEqual( maxcomp ), () => { + + h.assign( add( 2.0, b.sub( r ).div( delta ) ) ); + + } ).Else( () => { + + h.assign( add( 4.0, r.sub( g ).div( delta ) ) ); + + } ); + + h.mulAssign( 1.0 / 6.0 ); + + If( h.lessThan( 0.0 ), () => { + + h.addAssign( 1.0 ); + + } ); + + } ); + + return vec3( h, s, v ); + +} ).setLayout( { + name: 'mx_rgbtohsv', + type: 'vec3', + inputs: [ + { name: 'c', type: 'vec3' } + ] +} ); + +// Three.js Transpiler +// https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/stdlib/genglsl/lib/mx_transform_color.glsl + + +const mx_srgb_texture_to_lin_rec709 = /*@__PURE__*/ Fn( ( [ color_immutable ] ) => { + + const color = vec3( color_immutable ).toVar(); + const isAbove = bvec3( greaterThan( color, vec3( 0.04045 ) ) ).toVar(); + const linSeg = vec3( color.div( 12.92 ) ).toVar(); + const powSeg = vec3( pow( max$1( color.add( vec3( 0.055 ) ), vec3( 0.0 ) ).div( 1.055 ), vec3( 2.4 ) ) ).toVar(); + + return mix( linSeg, powSeg, isAbove ); + +} ).setLayout( { + name: 'mx_srgb_texture_to_lin_rec709', + type: 'vec3', + inputs: [ + { name: 'color', type: 'vec3' } + ] +} ); + +const mx_aastep = ( threshold, value ) => { + + threshold = float( threshold ); + value = float( value ); + + const afwidth = vec2( value.dFdx(), value.dFdy() ).length().mul( 0.70710678118654757 ); + + return smoothstep( threshold.sub( afwidth ), threshold.add( afwidth ), value ); + +}; + +const _ramp = ( a, b, uv, p ) => mix( a, b, uv[ p ].clamp() ); +const mx_ramplr = ( valuel, valuer, texcoord = uv() ) => _ramp( valuel, valuer, texcoord, 'x' ); +const mx_ramptb = ( valuet, valueb, texcoord = uv() ) => _ramp( valuet, valueb, texcoord, 'y' ); + +const _split = ( a, b, center, uv, p ) => mix( a, b, mx_aastep( center, uv[ p ] ) ); +const mx_splitlr = ( valuel, valuer, center, texcoord = uv() ) => _split( valuel, valuer, center, texcoord, 'x' ); +const mx_splittb = ( valuet, valueb, center, texcoord = uv() ) => _split( valuet, valueb, center, texcoord, 'y' ); + +const mx_transform_uv = ( uv_scale = 1, uv_offset = 0, uv_geo = uv() ) => uv_geo.mul( uv_scale ).add( uv_offset ); + +const mx_safepower = ( in1, in2 = 1 ) => { + + in1 = float( in1 ); + + return in1.abs().pow( in2 ).mul( in1.sign() ); + +}; + +const mx_contrast = ( input, amount = 1, pivot = .5 ) => float( input ).sub( pivot ).mul( amount ).add( pivot ); + +const mx_noise_float = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_float( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot ); +//export const mx_noise_vec2 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_vec3( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot ); +const mx_noise_vec3 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_vec3( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot ); +const mx_noise_vec4 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => { + + texcoord = texcoord.convert( 'vec2|vec3' ); // overloading type + + const noise_vec4 = vec4( mx_perlin_noise_vec3( texcoord ), mx_perlin_noise_float( texcoord.add( vec2( 19, 73 ) ) ) ); + + return noise_vec4.mul( amplitude ).add( pivot ); + +}; + +const mx_worley_noise_float = ( texcoord = uv(), jitter = 1 ) => mx_worley_noise_float$1( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) ); +const mx_worley_noise_vec2 = ( texcoord = uv(), jitter = 1 ) => mx_worley_noise_vec2$1( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) ); +const mx_worley_noise_vec3 = ( texcoord = uv(), jitter = 1 ) => mx_worley_noise_vec3$1( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) ); + +const mx_cell_noise_float = ( texcoord = uv() ) => mx_cell_noise_float$1( texcoord.convert( 'vec2|vec3' ) ); + +const mx_fractal_noise_float = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mx_fractal_noise_float$1( position, int( octaves ), lacunarity, diminish ).mul( amplitude ); +const mx_fractal_noise_vec2 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mx_fractal_noise_vec2$1( position, int( octaves ), lacunarity, diminish ).mul( amplitude ); +const mx_fractal_noise_vec3 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mx_fractal_noise_vec3$1( position, int( octaves ), lacunarity, diminish ).mul( amplitude ); +const mx_fractal_noise_vec4 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mx_fractal_noise_vec4$1( position, int( octaves ), lacunarity, diminish ).mul( amplitude ); + +const getShIrradianceAt = /*@__PURE__*/ Fn( ( [ normal, shCoefficients ] ) => { + + // normal is assumed to have unit length + + const x = normal.x, y = normal.y, z = normal.z; + + // band 0 + let result = shCoefficients.element( 0 ).mul( 0.886227 ); + + // band 1 + result = result.add( shCoefficients.element( 1 ).mul( 2.0 * 0.511664 ).mul( y ) ); + result = result.add( shCoefficients.element( 2 ).mul( 2.0 * 0.511664 ).mul( z ) ); + result = result.add( shCoefficients.element( 3 ).mul( 2.0 * 0.511664 ).mul( x ) ); + + // band 2 + result = result.add( shCoefficients.element( 4 ).mul( 2.0 * 0.429043 ).mul( x ).mul( y ) ); + result = result.add( shCoefficients.element( 5 ).mul( 2.0 * 0.429043 ).mul( y ).mul( z ) ); + result = result.add( shCoefficients.element( 6 ).mul( z.mul( z ).mul( 0.743125 ).sub( 0.247708 ) ) ); + result = result.add( shCoefficients.element( 7 ).mul( 2.0 * 0.429043 ).mul( x ).mul( z ) ); + result = result.add( shCoefficients.element( 8 ).mul( 0.429043 ).mul( mul( x, x ).sub( mul( y, y ) ) ) ); + + return result; + +} ); + +class PointLightNode extends AnalyticLightNode { + + static get type() { + + return 'PointLightNode'; + + } + + constructor( light = null ) { + + super( light ); + + this.cutoffDistanceNode = uniform( 0 ).setGroup( renderGroup ); + this.decayExponentNode = uniform( 0 ).setGroup( renderGroup ); + + } + + update( frame ) { + + const { light } = this; + + super.update( frame ); + + this.cutoffDistanceNode.value = light.distance; + this.decayExponentNode.value = light.decay; + + } + + setup( builder ) { + + const { colorNode, cutoffDistanceNode, decayExponentNode, light } = this; + + const lightingModel = builder.context.lightingModel; + + const lVector = lightViewPosition( light ).sub( positionView ); // @TODO: Add it into LightNode + + const lightDirection = lVector.normalize(); + const lightDistance = lVector.length(); + + const lightAttenuation = getDistanceAttenuation( { + lightDistance, + cutoffDistance: cutoffDistanceNode, + decayExponent: decayExponentNode + } ); + + const lightColor = colorNode.mul( lightAttenuation ); + + const reflectedLight = builder.context.reflectedLight; + + lightingModel.direct( { + lightDirection, + lightColor, + reflectedLight + }, builder.stack, builder ); + + } + +} + +class DirectionalLightNode extends AnalyticLightNode { + + static get type() { + + return 'DirectionalLightNode'; + + } + + constructor( light = null ) { + + super( light ); + + } + + setup( builder ) { + + super.setup( builder ); + + const lightingModel = builder.context.lightingModel; + + const lightColor = this.colorNode; + const lightDirection = lightTargetDirection( this.light ); + const reflectedLight = builder.context.reflectedLight; + + lightingModel.direct( { + lightDirection, + lightColor, + reflectedLight + }, builder.stack, builder ); + + } + +} + +const _matrix41 = /*@__PURE__*/ new Matrix4(); +const _matrix42 = /*@__PURE__*/ new Matrix4(); + +let ltcLib = null; + +class RectAreaLightNode extends AnalyticLightNode { + + static get type() { + + return 'RectAreaLightNode'; + + } + + constructor( light = null ) { + + super( light ); + + this.halfHeight = uniform( new Vector3() ).setGroup( renderGroup ); + this.halfWidth = uniform( new Vector3() ).setGroup( renderGroup ); + + } + + update( frame ) { + + super.update( frame ); + + const { light } = this; + + const viewMatrix = frame.camera.matrixWorldInverse; + + _matrix42.identity(); + _matrix41.copy( light.matrixWorld ); + _matrix41.premultiply( viewMatrix ); + _matrix42.extractRotation( _matrix41 ); + + this.halfWidth.value.set( light.width * 0.5, 0.0, 0.0 ); + this.halfHeight.value.set( 0.0, light.height * 0.5, 0.0 ); + + this.halfWidth.value.applyMatrix4( _matrix42 ); + this.halfHeight.value.applyMatrix4( _matrix42 ); + + } + + setup( builder ) { + + super.setup( builder ); + + let ltc_1, ltc_2; + + if ( builder.isAvailable( 'float32Filterable' ) ) { + + ltc_1 = texture( ltcLib.LTC_FLOAT_1 ); + ltc_2 = texture( ltcLib.LTC_FLOAT_2 ); + + } else { + + ltc_1 = texture( ltcLib.LTC_HALF_1 ); + ltc_2 = texture( ltcLib.LTC_HALF_2 ); + + } + + const { colorNode, light } = this; + const lightingModel = builder.context.lightingModel; + + const lightPosition = lightViewPosition( light ); + const reflectedLight = builder.context.reflectedLight; + + lightingModel.directRectArea( { + lightColor: colorNode, + lightPosition, + halfWidth: this.halfWidth, + halfHeight: this.halfHeight, + reflectedLight, + ltc_1, + ltc_2 + }, builder.stack, builder ); + + } + + static setLTC( ltc ) { + + ltcLib = ltc; + + } + +} + +class SpotLightNode extends AnalyticLightNode { + + static get type() { + + return 'SpotLightNode'; + + } + + constructor( light = null ) { + + super( light ); + + this.coneCosNode = uniform( 0 ).setGroup( renderGroup ); + this.penumbraCosNode = uniform( 0 ).setGroup( renderGroup ); + + this.cutoffDistanceNode = uniform( 0 ).setGroup( renderGroup ); + this.decayExponentNode = uniform( 0 ).setGroup( renderGroup ); + + } + + update( frame ) { + + super.update( frame ); + + const { light } = this; + + this.coneCosNode.value = Math.cos( light.angle ); + this.penumbraCosNode.value = Math.cos( light.angle * ( 1 - light.penumbra ) ); + + this.cutoffDistanceNode.value = light.distance; + this.decayExponentNode.value = light.decay; + + } + + getSpotAttenuation( angleCosine ) { + + const { coneCosNode, penumbraCosNode } = this; + + return smoothstep( coneCosNode, penumbraCosNode, angleCosine ); + + } + + setup( builder ) { + + super.setup( builder ); + + const lightingModel = builder.context.lightingModel; + + const { colorNode, cutoffDistanceNode, decayExponentNode, light } = this; + + const lVector = lightViewPosition( light ).sub( positionView ); // @TODO: Add it into LightNode + + const lightDirection = lVector.normalize(); + const angleCos = lightDirection.dot( lightTargetDirection( light ) ); + const spotAttenuation = this.getSpotAttenuation( angleCos ); + + const lightDistance = lVector.length(); + + const lightAttenuation = getDistanceAttenuation( { + lightDistance, + cutoffDistance: cutoffDistanceNode, + decayExponent: decayExponentNode + } ); + + const lightColor = colorNode.mul( spotAttenuation ).mul( lightAttenuation ); + + const reflectedLight = builder.context.reflectedLight; + + lightingModel.direct( { + lightDirection, + lightColor, + reflectedLight + }, builder.stack, builder ); + + } + +} + +class IESSpotLightNode extends SpotLightNode { + + static get type() { + + return 'IESSpotLightNode'; + + } + + getSpotAttenuation( angleCosine ) { + + const iesMap = this.light.iesMap; + + let spotAttenuation = null; + + if ( iesMap && iesMap.isTexture === true ) { + + const angle = angleCosine.acos().mul( 1.0 / Math.PI ); + + spotAttenuation = texture( iesMap, vec2( angle, 0 ), 0 ).r; + + } else { + + spotAttenuation = super.getSpotAttenuation( angleCosine ); + + } + + return spotAttenuation; + + } + +} + +class AmbientLightNode extends AnalyticLightNode { + + static get type() { + + return 'AmbientLightNode'; + + } + + constructor( light = null ) { + + super( light ); + + } + + setup( { context } ) { + + context.irradiance.addAssign( this.colorNode ); + + } + +} + +class HemisphereLightNode extends AnalyticLightNode { + + static get type() { + + return 'HemisphereLightNode'; + + } + + constructor( light = null ) { + + super( light ); + + this.lightPositionNode = lightPosition( light ); + this.lightDirectionNode = this.lightPositionNode.normalize(); + + this.groundColorNode = uniform( new Color() ).setGroup( renderGroup ); + + } + + update( frame ) { + + const { light } = this; + + super.update( frame ); + + this.lightPositionNode.object3d = light; + + this.groundColorNode.value.copy( light.groundColor ).multiplyScalar( light.intensity ); + + } + + setup( builder ) { + + const { colorNode, groundColorNode, lightDirectionNode } = this; + + const dotNL = normalView.dot( lightDirectionNode ); + const hemiDiffuseWeight = dotNL.mul( 0.5 ).add( 0.5 ); + + const irradiance = mix( groundColorNode, colorNode, hemiDiffuseWeight ); + + builder.context.irradiance.addAssign( irradiance ); + + } + +} + +class LightProbeNode extends AnalyticLightNode { + + static get type() { + + return 'LightProbeNode'; + + } + + constructor( light = null ) { + + super( light ); + + const array = []; + + for ( let i = 0; i < 9; i ++ ) array.push( new Vector3() ); + + this.lightProbe = uniformArray( array ); + + } + + update( frame ) { + + const { light } = this; + + super.update( frame ); + + // + + for ( let i = 0; i < 9; i ++ ) { + + this.lightProbe.array[ i ].copy( light.sh.coefficients[ i ] ).multiplyScalar( light.intensity ); + + } + + } + + setup( builder ) { + + const irradiance = getShIrradianceAt( normalWorld, this.lightProbe ); + + builder.context.irradiance.addAssign( irradiance ); + + } + +} + +class NodeParser { + + parseFunction( /*source*/ ) { + + console.warn( 'Abstract function.' ); + + } + +} + +class NodeFunction { + + constructor( type, inputs, name = '', precision = '' ) { + + this.type = type; + this.inputs = inputs; + this.name = name; + this.precision = precision; + + } + + getCode( /*name = this.name*/ ) { + + console.warn( 'Abstract function.' ); + + } + +} + +NodeFunction.isNodeFunction = true; + +const declarationRegexp$1 = /^\s*(highp|mediump|lowp)?\s*([a-z_0-9]+)\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)/i; +const propertiesRegexp$1 = /[a-z_0-9]+/ig; + +const pragmaMain = '#pragma main'; + +const parse$1 = ( source ) => { + + source = source.trim(); + + const pragmaMainIndex = source.indexOf( pragmaMain ); + + const mainCode = pragmaMainIndex !== - 1 ? source.slice( pragmaMainIndex + pragmaMain.length ) : source; + + const declaration = mainCode.match( declarationRegexp$1 ); + + if ( declaration !== null && declaration.length === 5 ) { + + // tokenizer + + const inputsCode = declaration[ 4 ]; + const propsMatches = []; + + let nameMatch = null; + + while ( ( nameMatch = propertiesRegexp$1.exec( inputsCode ) ) !== null ) { + + propsMatches.push( nameMatch ); + + } + + // parser + + const inputs = []; + + let i = 0; + + while ( i < propsMatches.length ) { + + const isConst = propsMatches[ i ][ 0 ] === 'const'; + + if ( isConst === true ) { + + i ++; + + } + + let qualifier = propsMatches[ i ][ 0 ]; + + if ( qualifier === 'in' || qualifier === 'out' || qualifier === 'inout' ) { + + i ++; + + } else { + + qualifier = ''; + + } + + const type = propsMatches[ i ++ ][ 0 ]; + + let count = Number.parseInt( propsMatches[ i ][ 0 ] ); + + if ( Number.isNaN( count ) === false ) i ++; + else count = null; + + const name = propsMatches[ i ++ ][ 0 ]; + + inputs.push( new NodeFunctionInput( type, name, count, qualifier, isConst ) ); + + } + + // + + const blockCode = mainCode.substring( declaration[ 0 ].length ); + + const name = declaration[ 3 ] !== undefined ? declaration[ 3 ] : ''; + const type = declaration[ 2 ]; + + const precision = declaration[ 1 ] !== undefined ? declaration[ 1 ] : ''; + + const headerCode = pragmaMainIndex !== - 1 ? source.slice( 0, pragmaMainIndex ) : ''; + + return { + type, + inputs, + name, + precision, + inputsCode, + blockCode, + headerCode + }; + + } else { + + throw new Error( 'FunctionNode: Function is not a GLSL code.' ); + + } + +}; + +class GLSLNodeFunction extends NodeFunction { + + constructor( source ) { + + const { type, inputs, name, precision, inputsCode, blockCode, headerCode } = parse$1( source ); + + super( type, inputs, name, precision ); + + this.inputsCode = inputsCode; + this.blockCode = blockCode; + this.headerCode = headerCode; + + } + + getCode( name = this.name ) { + + let code; + + const blockCode = this.blockCode; + + if ( blockCode !== '' ) { + + const { type, inputsCode, headerCode, precision } = this; + + let declarationCode = `${ type } ${ name } ( ${ inputsCode.trim() } )`; + + if ( precision !== '' ) { + + declarationCode = `${ precision } ${ declarationCode }`; + + } + + code = headerCode + declarationCode + blockCode; + + } else { + + // interface function + + code = ''; + + } + + return code; + + } + +} + +class GLSLNodeParser extends NodeParser { + + parseFunction( source ) { + + return new GLSLNodeFunction( source ); + + } + +} + +function painterSortStable( a, b ) { + + if ( a.groupOrder !== b.groupOrder ) { + + return a.groupOrder - b.groupOrder; + + } else if ( a.renderOrder !== b.renderOrder ) { + + return a.renderOrder - b.renderOrder; + + } else if ( a.material.id !== b.material.id ) { + + return a.material.id - b.material.id; + + } else if ( a.z !== b.z ) { + + return a.z - b.z; + + } else { + + return a.id - b.id; + + } + +} + +function reversePainterSortStable( a, b ) { + + if ( a.groupOrder !== b.groupOrder ) { + + return a.groupOrder - b.groupOrder; + + } else if ( a.renderOrder !== b.renderOrder ) { + + return a.renderOrder - b.renderOrder; + + } else if ( a.z !== b.z ) { + + return b.z - a.z; + + } else { + + return a.id - b.id; + + } + +} + +class RenderList { + + constructor() { + + this.renderItems = []; + this.renderItemsIndex = 0; + + this.opaque = []; + this.transparent = []; + this.bundles = []; + + this.lightsNode = new LightsNode( [] ); + this.lightsArray = []; + + this.occlusionQueryCount = 0; + + } + + begin() { + + this.renderItemsIndex = 0; + + this.opaque.length = 0; + this.transparent.length = 0; + this.bundles.length = 0; + + this.lightsArray.length = 0; + + this.occlusionQueryCount = 0; + + return this; + + } + + getNextRenderItem( object, geometry, material, groupOrder, z, group ) { + + let renderItem = this.renderItems[ this.renderItemsIndex ]; + + if ( renderItem === undefined ) { + + renderItem = { + id: object.id, + object: object, + geometry: geometry, + material: material, + groupOrder: groupOrder, + renderOrder: object.renderOrder, + z: z, + group: group + }; + + this.renderItems[ this.renderItemsIndex ] = renderItem; + + } else { + + renderItem.id = object.id; + renderItem.object = object; + renderItem.geometry = geometry; + renderItem.material = material; + renderItem.groupOrder = groupOrder; + renderItem.renderOrder = object.renderOrder; + renderItem.z = z; + renderItem.group = group; + + } + + this.renderItemsIndex ++; + + return renderItem; + + } + + push( object, geometry, material, groupOrder, z, group ) { + + const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group ); + + if ( object.occlusionTest === true ) this.occlusionQueryCount ++; + + ( material.transparent === true || material.transmission > 0 ? this.transparent : this.opaque ).push( renderItem ); + + } + + unshift( object, geometry, material, groupOrder, z, group ) { + + const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group ); + + ( material.transparent === true ? this.transparent : this.opaque ).unshift( renderItem ); + + } + + pushBundle( group ) { + + this.bundles.push( group ); + + } + + pushLight( light ) { + + this.lightsArray.push( light ); + + } + + getLightsNode() { + + return this.lightsNode.fromLights( this.lightsArray ); + + } + + sort( customOpaqueSort, customTransparentSort ) { + + if ( this.opaque.length > 1 ) this.opaque.sort( customOpaqueSort || painterSortStable ); + if ( this.transparent.length > 1 ) this.transparent.sort( customTransparentSort || reversePainterSortStable ); + + } + + finish() { + + // update lights + + this.lightsNode.setLights( this.lightsArray ); + + // Clear references from inactive renderItems in the list + + for ( let i = this.renderItemsIndex, il = this.renderItems.length; i < il; i ++ ) { + + const renderItem = this.renderItems[ i ]; + + if ( renderItem.id === null ) break; + + renderItem.id = null; + renderItem.object = null; + renderItem.geometry = null; + renderItem.material = null; + renderItem.groupOrder = null; + renderItem.renderOrder = null; + renderItem.z = null; + renderItem.group = null; + + } + + } + +} + +class RenderLists { + + constructor() { + + this.lists = new ChainMap(); + + } + + get( scene, camera ) { + + const lists = this.lists; + const keys = [ scene, camera ]; + + let list = lists.get( keys ); + + if ( list === undefined ) { + + list = new RenderList(); + lists.set( keys, list ); + + } + + return list; + + } + + dispose() { + + this.lists = new ChainMap(); + + } + +} + +let id = 0; + +class RenderContext { + + constructor() { + + this.id = id ++; + + this.color = true; + this.clearColor = true; + this.clearColorValue = { r: 0, g: 0, b: 0, a: 1 }; + + this.depth = true; + this.clearDepth = true; + this.clearDepthValue = 1; + + this.stencil = false; + this.clearStencil = true; + this.clearStencilValue = 1; + + this.viewport = false; + this.viewportValue = new Vector4(); + + this.scissor = false; + this.scissorValue = new Vector4(); + + this.textures = null; + this.depthTexture = null; + this.activeCubeFace = 0; + this.sampleCount = 1; + + this.width = 0; + this.height = 0; + + this.isRenderContext = true; + + } + + getCacheKey() { + + return getCacheKey( this ); + + } + +} + +function getCacheKey( renderContext ) { + + const { textures, activeCubeFace } = renderContext; + + const values = [ activeCubeFace ]; + + for ( const texture of textures ) { + + values.push( texture.id ); + + } + + return hashArray( values ); + +} + +class RenderContexts { + + constructor() { + + this.chainMaps = {}; + + } + + get( scene, camera, renderTarget = null ) { + + const chainKey = [ scene, camera ]; + + let attachmentState; + + if ( renderTarget === null ) { + + attachmentState = 'default'; + + } else { + + const format = renderTarget.texture.format; + const count = renderTarget.textures.length; + + attachmentState = `${ count }:${ format }:${ renderTarget.samples }:${ renderTarget.depthBuffer }:${ renderTarget.stencilBuffer }`; + + } + + const chainMap = this.getChainMap( attachmentState ); + + let renderState = chainMap.get( chainKey ); + + if ( renderState === undefined ) { + + renderState = new RenderContext(); + + chainMap.set( chainKey, renderState ); + + } + + if ( renderTarget !== null ) renderState.sampleCount = renderTarget.samples === 0 ? 1 : renderTarget.samples; + + return renderState; + + } + + getChainMap( attachmentState ) { + + return this.chainMaps[ attachmentState ] || ( this.chainMaps[ attachmentState ] = new ChainMap() ); + + } + + dispose() { + + this.chainMaps = {}; + + } + +} + +const _size = /*@__PURE__*/ new Vector3(); + +class Textures extends DataMap { + + constructor( renderer, backend, info ) { + + super(); + + this.renderer = renderer; + this.backend = backend; + this.info = info; + + } + + updateRenderTarget( renderTarget, activeMipmapLevel = 0 ) { + + const renderTargetData = this.get( renderTarget ); + + const sampleCount = renderTarget.samples === 0 ? 1 : renderTarget.samples; + const depthTextureMips = renderTargetData.depthTextureMips || ( renderTargetData.depthTextureMips = {} ); + + const textures = renderTarget.textures; + + const size = this.getSize( textures[ 0 ] ); + + const mipWidth = size.width >> activeMipmapLevel; + const mipHeight = size.height >> activeMipmapLevel; + + let depthTexture = renderTarget.depthTexture || depthTextureMips[ activeMipmapLevel ]; + let textureNeedsUpdate = false; + + if ( depthTexture === undefined ) { + + depthTexture = new DepthTexture(); + depthTexture.format = renderTarget.stencilBuffer ? DepthStencilFormat : DepthFormat; + depthTexture.type = renderTarget.stencilBuffer ? UnsignedInt248Type : UnsignedIntType; // FloatType + depthTexture.image.width = mipWidth; + depthTexture.image.height = mipHeight; + + depthTextureMips[ activeMipmapLevel ] = depthTexture; + + } + + if ( renderTargetData.width !== size.width || size.height !== renderTargetData.height ) { + + textureNeedsUpdate = true; + depthTexture.needsUpdate = true; + + depthTexture.image.width = mipWidth; + depthTexture.image.height = mipHeight; + + } + + renderTargetData.width = size.width; + renderTargetData.height = size.height; + renderTargetData.textures = textures; + renderTargetData.depthTexture = depthTexture; + renderTargetData.depth = renderTarget.depthBuffer; + renderTargetData.stencil = renderTarget.stencilBuffer; + renderTargetData.renderTarget = renderTarget; + + if ( renderTargetData.sampleCount !== sampleCount ) { + + textureNeedsUpdate = true; + depthTexture.needsUpdate = true; + + renderTargetData.sampleCount = sampleCount; + + } + + // + + const options = { sampleCount }; + + for ( let i = 0; i < textures.length; i ++ ) { + + const texture = textures[ i ]; + + if ( textureNeedsUpdate ) texture.needsUpdate = true; + + this.updateTexture( texture, options ); + + } + + this.updateTexture( depthTexture, options ); + + // dispose handler + + if ( renderTargetData.initialized !== true ) { + + renderTargetData.initialized = true; + + // dispose + + const onDispose = () => { + + renderTarget.removeEventListener( 'dispose', onDispose ); + + for ( let i = 0; i < textures.length; i ++ ) { + + this._destroyTexture( textures[ i ] ); + + } + + this._destroyTexture( depthTexture ); + + this.delete( renderTarget ); + + }; + + renderTarget.addEventListener( 'dispose', onDispose ); + + } + + } + + updateTexture( texture, options = {} ) { + + const textureData = this.get( texture ); + if ( textureData.initialized === true && textureData.version === texture.version ) return; + + const isRenderTarget = texture.isRenderTargetTexture || texture.isDepthTexture || texture.isFramebufferTexture; + const backend = this.backend; + + if ( isRenderTarget && textureData.initialized === true ) { + + // it's an update + + backend.destroySampler( texture ); + backend.destroyTexture( texture ); + + } + + // + + if ( texture.isFramebufferTexture ) { + + const renderer = this.renderer; + const renderTarget = renderer.getRenderTarget(); + + if ( renderTarget ) { + + texture.type = renderTarget.texture.type; + + } else { + + texture.type = UnsignedByteType; + + } + + } + + // + + const { width, height, depth } = this.getSize( texture ); + + options.width = width; + options.height = height; + options.depth = depth; + options.needsMipmaps = this.needsMipmaps( texture ); + options.levels = options.needsMipmaps ? this.getMipLevels( texture, width, height ) : 1; + + // + + if ( isRenderTarget || texture.isStorageTexture === true ) { + + backend.createSampler( texture ); + backend.createTexture( texture, options ); + + textureData.generation = texture.version; + + } else { + + const needsCreate = textureData.initialized !== true; + + if ( needsCreate ) backend.createSampler( texture ); + + if ( texture.version > 0 ) { + + const image = texture.image; + + if ( image === undefined ) { + + console.warn( 'THREE.Renderer: Texture marked for update but image is undefined.' ); + + } else if ( image.complete === false ) { + + console.warn( 'THREE.Renderer: Texture marked for update but image is incomplete.' ); + + } else { + + if ( texture.images ) { + + const images = []; + + for ( const image of texture.images ) { + + images.push( image ); + + } + + options.images = images; + + } else { + + options.image = image; + + } + + if ( textureData.isDefaultTexture === undefined || textureData.isDefaultTexture === true ) { + + backend.createTexture( texture, options ); + + textureData.isDefaultTexture = false; + textureData.generation = texture.version; + + } + + if ( texture.source.dataReady === true ) backend.updateTexture( texture, options ); + + if ( options.needsMipmaps && texture.mipmaps.length === 0 ) backend.generateMipmaps( texture ); + + } + + } else { + + // async update + + backend.createDefaultTexture( texture ); + + textureData.isDefaultTexture = true; + textureData.generation = texture.version; + + } + + } + + // dispose handler + + if ( textureData.initialized !== true ) { + + textureData.initialized = true; + textureData.generation = texture.version; + + // + + this.info.memory.textures ++; + + // dispose + + const onDispose = () => { + + texture.removeEventListener( 'dispose', onDispose ); + + this._destroyTexture( texture ); + + this.info.memory.textures --; + + }; + + texture.addEventListener( 'dispose', onDispose ); + + } + + // + + textureData.version = texture.version; + + } + + getSize( texture, target = _size ) { + + let image = texture.images ? texture.images[ 0 ] : texture.image; + + if ( image ) { + + if ( image.image !== undefined ) image = image.image; + + target.width = image.width; + target.height = image.height; + target.depth = texture.isCubeTexture ? 6 : ( image.depth || 1 ); + + } else { + + target.width = target.height = target.depth = 1; + + } + + return target; + + } + + getMipLevels( texture, width, height ) { + + let mipLevelCount; + + if ( texture.isCompressedTexture ) { + + mipLevelCount = texture.mipmaps.length; + + } else { + + mipLevelCount = Math.floor( Math.log2( Math.max( width, height ) ) ) + 1; + + } + + return mipLevelCount; + + } + + needsMipmaps( texture ) { + + if ( this.isEnvironmentTexture( texture ) ) return true; + + return ( texture.isCompressedTexture === true ) || ( ( texture.minFilter !== NearestFilter ) && ( texture.minFilter !== LinearFilter ) ); + + } + + isEnvironmentTexture( texture ) { + + const mapping = texture.mapping; + + return ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) || ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping ); + + } + + _destroyTexture( texture ) { + + this.backend.destroySampler( texture ); + this.backend.destroyTexture( texture ); + + this.delete( texture ); + + } + +} + +class Color4 extends Color { + + constructor( r, g, b, a = 1 ) { + + super( r, g, b ); + + this.a = a; + + } + + set( r, g, b, a = 1 ) { + + this.a = a; + + return super.set( r, g, b ); + + } + + copy( color ) { + + if ( color.a !== undefined ) this.a = color.a; + + return super.copy( color ); + + } + + clone() { + + return new this.constructor( this.r, this.g, this.b, this.a ); + + } + +} + +const _clearColor = /*@__PURE__*/ new Color4(); + +class Background extends DataMap { + + constructor( renderer, nodes ) { + + super(); + + this.renderer = renderer; + this.nodes = nodes; + + } + + update( scene, renderList, renderContext ) { + + const renderer = this.renderer; + const background = this.nodes.getBackgroundNode( scene ) || scene.background; + + let forceClear = false; + + if ( background === null ) { + + // no background settings, use clear color configuration from the renderer + + renderer._clearColor.getRGB( _clearColor, LinearSRGBColorSpace ); + _clearColor.a = renderer._clearColor.a; + + } else if ( background.isColor === true ) { + + // background is an opaque color + + background.getRGB( _clearColor, LinearSRGBColorSpace ); + _clearColor.a = 1; + + forceClear = true; + + } else if ( background.isNode === true ) { + + const sceneData = this.get( scene ); + const backgroundNode = background; + + _clearColor.copy( renderer._clearColor ); + + let backgroundMesh = sceneData.backgroundMesh; + + if ( backgroundMesh === undefined ) { + + const backgroundMeshNode = context( vec4( backgroundNode ).mul( backgroundIntensity ), { + // @TODO: Add Texture2D support using node context + getUV: () => normalWorld, + getTextureLevel: () => backgroundBlurriness + } ); + + let viewProj = modelViewProjection(); + viewProj = viewProj.setZ( viewProj.w ); + + const nodeMaterial = new NodeMaterial(); + nodeMaterial.name = 'Background.material'; + nodeMaterial.side = BackSide; + nodeMaterial.depthTest = false; + nodeMaterial.depthWrite = false; + nodeMaterial.fog = false; + nodeMaterial.lights = false; + nodeMaterial.vertexNode = viewProj; + nodeMaterial.colorNode = backgroundMeshNode; + + sceneData.backgroundMeshNode = backgroundMeshNode; + sceneData.backgroundMesh = backgroundMesh = new Mesh( new SphereGeometry( 1, 32, 32 ), nodeMaterial ); + backgroundMesh.frustumCulled = false; + backgroundMesh.name = 'Background.mesh'; + + backgroundMesh.onBeforeRender = function ( renderer, scene, camera ) { + + this.matrixWorld.copyPosition( camera.matrixWorld ); + + }; + + } + + const backgroundCacheKey = backgroundNode.getCacheKey(); + + if ( sceneData.backgroundCacheKey !== backgroundCacheKey ) { + + sceneData.backgroundMeshNode.node = vec4( backgroundNode ).mul( backgroundIntensity ); + sceneData.backgroundMeshNode.needsUpdate = true; + + backgroundMesh.material.needsUpdate = true; + + sceneData.backgroundCacheKey = backgroundCacheKey; + + } + + renderList.unshift( backgroundMesh, backgroundMesh.geometry, backgroundMesh.material, 0, 0, null ); + + } else { + + console.error( 'THREE.Renderer: Unsupported background configuration.', background ); + + } + + // + + if ( renderer.autoClear === true || forceClear === true ) { + + _clearColor.multiplyScalar( _clearColor.a ); + + const clearColorValue = renderContext.clearColorValue; + + clearColorValue.r = _clearColor.r; + clearColorValue.g = _clearColor.g; + clearColorValue.b = _clearColor.b; + clearColorValue.a = _clearColor.a; + + renderContext.depthClearValue = renderer._clearDepth; + renderContext.stencilClearValue = renderer._clearStencil; + + renderContext.clearColor = renderer.autoClearColor === true; + renderContext.clearDepth = renderer.autoClearDepth === true; + renderContext.clearStencil = renderer.autoClearStencil === true; + + } else { + + renderContext.clearColor = false; + renderContext.clearDepth = false; + renderContext.clearStencil = false; + + } + + } + +} + +class NodeBuilderState { + + constructor( vertexShader, fragmentShader, computeShader, nodeAttributes, bindings, updateNodes, updateBeforeNodes, updateAfterNodes, monitor, transforms = [] ) { + + this.vertexShader = vertexShader; + this.fragmentShader = fragmentShader; + this.computeShader = computeShader; + this.transforms = transforms; + + this.nodeAttributes = nodeAttributes; + this.bindings = bindings; + + this.updateNodes = updateNodes; + this.updateBeforeNodes = updateBeforeNodes; + this.updateAfterNodes = updateAfterNodes; + + this.monitor = monitor; + + this.usedTimes = 0; + + } + + createBindings() { + + const bindings = []; + + for ( const instanceGroup of this.bindings ) { + + const shared = instanceGroup.bindings[ 0 ].groupNode.shared; + + if ( shared !== true ) { + + const bindingsGroup = new BindGroup( instanceGroup.name, [], instanceGroup.index, instanceGroup ); + bindings.push( bindingsGroup ); + + for ( const instanceBinding of instanceGroup.bindings ) { + + bindingsGroup.bindings.push( instanceBinding.clone() ); + + } + + } else { + + bindings.push( instanceGroup ); + + } + + } + + return bindings; + + } + +} + +const outputNodeMap = new WeakMap(); + +class Nodes extends DataMap { + + constructor( renderer, backend ) { + + super(); + + this.renderer = renderer; + this.backend = backend; + this.nodeFrame = new NodeFrame(); + this.nodeBuilderCache = new Map(); + this.callHashCache = new ChainMap(); + this.groupsData = new ChainMap(); + + } + + updateGroup( nodeUniformsGroup ) { + + const groupNode = nodeUniformsGroup.groupNode; + const name = groupNode.name; + + // objectGroup is every updated + + if ( name === objectGroup.name ) return true; + + // renderGroup is updated once per render/compute call + + if ( name === renderGroup.name ) { + + const uniformsGroupData = this.get( nodeUniformsGroup ); + const renderId = this.nodeFrame.renderId; + + if ( uniformsGroupData.renderId !== renderId ) { + + uniformsGroupData.renderId = renderId; + + return true; + + } + + return false; + + } + + // frameGroup is updated once per frame + + if ( name === frameGroup.name ) { + + const uniformsGroupData = this.get( nodeUniformsGroup ); + const frameId = this.nodeFrame.frameId; + + if ( uniformsGroupData.frameId !== frameId ) { + + uniformsGroupData.frameId = frameId; + + return true; + + } + + return false; + + } + + // other groups are updated just when groupNode.needsUpdate is true + + const groupChain = [ groupNode, nodeUniformsGroup ]; + + let groupData = this.groupsData.get( groupChain ); + if ( groupData === undefined ) this.groupsData.set( groupChain, groupData = {} ); + + if ( groupData.version !== groupNode.version ) { + + groupData.version = groupNode.version; + + return true; + + } + + return false; + + } + + getForRenderCacheKey( renderObject ) { + + return renderObject.initialCacheKey; + + } + + getForRender( renderObject ) { + + const renderObjectData = this.get( renderObject ); + + let nodeBuilderState = renderObjectData.nodeBuilderState; + + if ( nodeBuilderState === undefined ) { + + const { nodeBuilderCache } = this; + + const cacheKey = this.getForRenderCacheKey( renderObject ); + + nodeBuilderState = nodeBuilderCache.get( cacheKey ); + + if ( nodeBuilderState === undefined ) { + + const nodeBuilder = this.backend.createNodeBuilder( renderObject.object, this.renderer ); + nodeBuilder.scene = renderObject.scene; + nodeBuilder.material = renderObject.material; + nodeBuilder.camera = renderObject.camera; + nodeBuilder.context.material = renderObject.material; + nodeBuilder.lightsNode = renderObject.lightsNode; + nodeBuilder.environmentNode = this.getEnvironmentNode( renderObject.scene ); + nodeBuilder.fogNode = this.getFogNode( renderObject.scene ); + nodeBuilder.clippingContext = renderObject.clippingContext; + nodeBuilder.build(); + + nodeBuilderState = this._createNodeBuilderState( nodeBuilder ); + + nodeBuilderCache.set( cacheKey, nodeBuilderState ); + + } + + nodeBuilderState.usedTimes ++; + + renderObjectData.nodeBuilderState = nodeBuilderState; + + } + + return nodeBuilderState; + + } + + delete( object ) { + + if ( object.isRenderObject ) { + + const nodeBuilderState = this.get( object ).nodeBuilderState; + nodeBuilderState.usedTimes --; + + if ( nodeBuilderState.usedTimes === 0 ) { + + this.nodeBuilderCache.delete( this.getForRenderCacheKey( object ) ); + + } + + } + + return super.delete( object ); + + } + + getForCompute( computeNode ) { + + const computeData = this.get( computeNode ); + + let nodeBuilderState = computeData.nodeBuilderState; + + if ( nodeBuilderState === undefined ) { + + const nodeBuilder = this.backend.createNodeBuilder( computeNode, this.renderer ); + nodeBuilder.build(); + + nodeBuilderState = this._createNodeBuilderState( nodeBuilder ); + + computeData.nodeBuilderState = nodeBuilderState; + + } + + return nodeBuilderState; + + } + + _createNodeBuilderState( nodeBuilder ) { + + return new NodeBuilderState( + nodeBuilder.vertexShader, + nodeBuilder.fragmentShader, + nodeBuilder.computeShader, + nodeBuilder.getAttributesArray(), + nodeBuilder.getBindings(), + nodeBuilder.updateNodes, + nodeBuilder.updateBeforeNodes, + nodeBuilder.updateAfterNodes, + nodeBuilder.monitor, + nodeBuilder.transforms + ); + + } + + getEnvironmentNode( scene ) { + + return scene.environmentNode || this.get( scene ).environmentNode || null; + + } + + getBackgroundNode( scene ) { + + return scene.backgroundNode || this.get( scene ).backgroundNode || null; + + } + + getFogNode( scene ) { + + return scene.fogNode || this.get( scene ).fogNode || null; + + } + + getCacheKey( scene, lightsNode ) { + + const chain = [ scene, lightsNode ]; + const callId = this.renderer.info.calls; + + let cacheKeyData = this.callHashCache.get( chain ); + + if ( cacheKeyData === undefined || cacheKeyData.callId !== callId ) { + + const environmentNode = this.getEnvironmentNode( scene ); + const fogNode = this.getFogNode( scene ); + + const values = []; + + if ( lightsNode ) values.push( lightsNode.getCacheKey( true ) ); + if ( environmentNode ) values.push( environmentNode.getCacheKey() ); + if ( fogNode ) values.push( fogNode.getCacheKey() ); + + values.push( this.renderer.shadowMap.enabled ? 1 : 0 ); + + cacheKeyData = { + callId, + cacheKey: hashArray( values ) + }; + + this.callHashCache.set( chain, cacheKeyData ); + + } + + return cacheKeyData.cacheKey; + + } + + updateScene( scene ) { + + this.updateEnvironment( scene ); + this.updateFog( scene ); + this.updateBackground( scene ); + + } + + get isToneMappingState() { + + return this.renderer.getRenderTarget() ? false : true; + + } + + updateBackground( scene ) { + + const sceneData = this.get( scene ); + const background = scene.background; + + if ( background ) { + + const forceUpdate = ( scene.backgroundBlurriness === 0 && sceneData.backgroundBlurriness > 0 ) || ( scene.backgroundBlurriness > 0 && sceneData.backgroundBlurriness === 0 ); + + if ( sceneData.background !== background || forceUpdate ) { + + let backgroundNode = null; + + if ( background.isCubeTexture === true || ( background.mapping === EquirectangularReflectionMapping || background.mapping === EquirectangularRefractionMapping || background.mapping === CubeUVReflectionMapping ) ) { + + if ( scene.backgroundBlurriness > 0 || background.mapping === CubeUVReflectionMapping ) { + + backgroundNode = pmremTexture( background, normalWorld ); + + } else { + + let envMap; + + if ( background.isCubeTexture === true ) { + + envMap = cubeTexture( background ); + + } else { + + envMap = texture( background ); + + } + + backgroundNode = cubeMapNode( envMap ); + + } + + } else if ( background.isTexture === true ) { + + backgroundNode = texture( background, screenUV.flipY() ).setUpdateMatrix( true ); + + } else if ( background.isColor !== true ) { + + console.error( 'WebGPUNodes: Unsupported background configuration.', background ); + + } + + sceneData.backgroundNode = backgroundNode; + sceneData.background = background; + sceneData.backgroundBlurriness = scene.backgroundBlurriness; + + } + + } else if ( sceneData.backgroundNode ) { + + delete sceneData.backgroundNode; + delete sceneData.background; + + } + + } + + updateFog( scene ) { + + const sceneData = this.get( scene ); + const fog = scene.fog; + + if ( fog ) { + + if ( sceneData.fog !== fog ) { + + let fogNode = null; + + if ( fog.isFogExp2 ) { + + const color = reference( 'color', 'color', fog ).setGroup( renderGroup ); + const density = reference( 'density', 'float', fog ).setGroup( renderGroup ); + + fogNode = densityFog( color, density ); + + } else if ( fog.isFog ) { + + const color = reference( 'color', 'color', fog ).setGroup( renderGroup ); + const near = reference( 'near', 'float', fog ).setGroup( renderGroup ); + const far = reference( 'far', 'float', fog ).setGroup( renderGroup ); + + fogNode = rangeFog( color, near, far ); + + } else { + + console.error( 'WebGPUNodes: Unsupported fog configuration.', fog ); + + } + + sceneData.fogNode = fogNode; + sceneData.fog = fog; + + } + + } else { + + delete sceneData.fogNode; + delete sceneData.fog; + + } + + } + + updateEnvironment( scene ) { + + const sceneData = this.get( scene ); + const environment = scene.environment; + + if ( environment ) { + + if ( sceneData.environment !== environment ) { + + let environmentNode = null; + + if ( environment.isCubeTexture === true ) { + + environmentNode = cubeTexture( environment ); + + } else if ( environment.isTexture === true ) { + + environmentNode = texture( environment ); + + } else { + + console.error( 'Nodes: Unsupported environment configuration.', environment ); + + } + + sceneData.environmentNode = environmentNode; + sceneData.environment = environment; + + } + + } else if ( sceneData.environmentNode ) { + + delete sceneData.environmentNode; + delete sceneData.environment; + + } + + } + + getNodeFrame( renderer = this.renderer, scene = null, object = null, camera = null, material = null ) { + + const nodeFrame = this.nodeFrame; + nodeFrame.renderer = renderer; + nodeFrame.scene = scene; + nodeFrame.object = object; + nodeFrame.camera = camera; + nodeFrame.material = material; + + return nodeFrame; + + } + + getNodeFrameForRender( renderObject ) { + + return this.getNodeFrame( renderObject.renderer, renderObject.scene, renderObject.object, renderObject.camera, renderObject.material ); + + } + + getOutputCacheKey() { + + const renderer = this.renderer; + + return renderer.toneMapping + ',' + renderer.currentColorSpace; + + } + + hasOutputChange( outputTarget ) { + + const cacheKey = outputNodeMap.get( outputTarget ); + + return cacheKey !== this.getOutputCacheKey(); + + } + + getOutputNode( outputTexture ) { + + const renderer = this.renderer; + const cacheKey = this.getOutputCacheKey(); + + const output = texture( outputTexture, screenUV ).renderOutput( renderer.toneMapping, renderer.currentColorSpace ); + + outputNodeMap.set( outputTexture, cacheKey ); + + return output; + + } + + updateBefore( renderObject ) { + + const nodeBuilder = renderObject.getNodeBuilderState(); + + for ( const node of nodeBuilder.updateBeforeNodes ) { + + // update frame state for each node + + this.getNodeFrameForRender( renderObject ).updateBeforeNode( node ); + + } + + } + + updateAfter( renderObject ) { + + const nodeBuilder = renderObject.getNodeBuilderState(); + + for ( const node of nodeBuilder.updateAfterNodes ) { + + // update frame state for each node + + this.getNodeFrameForRender( renderObject ).updateAfterNode( node ); + + } + + } + + updateForCompute( computeNode ) { + + const nodeFrame = this.getNodeFrame(); + const nodeBuilder = this.getForCompute( computeNode ); + + for ( const node of nodeBuilder.updateNodes ) { + + nodeFrame.updateNode( node ); + + } + + } + + updateForRender( renderObject ) { + + const nodeFrame = this.getNodeFrameForRender( renderObject ); + const nodeBuilder = renderObject.getNodeBuilderState(); + + for ( const node of nodeBuilder.updateNodes ) { + + nodeFrame.updateNode( node ); + + } + + } + + needsRefresh( renderObject ) { + + const nodeFrame = this.getNodeFrameForRender( renderObject ); + const monitor = renderObject.getMonitor(); + + return monitor.needsRefresh( renderObject, nodeFrame ); + + } + + dispose() { + + super.dispose(); + + this.nodeFrame = new NodeFrame(); + this.nodeBuilderCache = new Map(); + + } + +} + +class RenderBundle { + + constructor( scene, camera ) { + + this.scene = scene; + this.camera = camera; + + } + + clone() { + + return Object.assign( new this.constructor(), this ); + + } + +} + +class RenderBundles { + + constructor() { + + this.lists = new ChainMap(); + + } + + get( scene, camera ) { + + const lists = this.lists; + const keys = [ scene, camera ]; + + let list = lists.get( keys ); + + if ( list === undefined ) { + + list = new RenderBundle( scene, camera ); + lists.set( keys, list ); + + } + + return list; + + } + + dispose() { + + this.lists = new ChainMap(); + + } + +} + +class NodeLibrary { + + constructor() { + + this.lightNodes = new WeakMap(); + this.materialNodes = new Map(); + this.toneMappingNodes = new Map(); + this.colorSpaceNodes = new Map(); + + } + + fromMaterial( material ) { + + if ( material.isNodeMaterial ) return material; + + let nodeMaterial = null; + + const nodeMaterialClass = this.getMaterialNodeClass( material.type ); + + if ( nodeMaterialClass !== null ) { + + nodeMaterial = new nodeMaterialClass(); + + for ( const key in material ) { + + nodeMaterial[ key ] = material[ key ]; + + } + + } + + return nodeMaterial; + + } + + addColorSpace( colorSpaceNode, colorSpace ) { + + this.addType( colorSpaceNode, colorSpace, this.colorSpaceNodes ); + + } + + getColorSpaceFunction( colorSpace ) { + + return this.colorSpaceNodes.get( colorSpace ) || null; + + } + + addToneMapping( toneMappingNode, toneMapping ) { + + this.addType( toneMappingNode, toneMapping, this.toneMappingNodes ); + + } + + getToneMappingFunction( toneMapping ) { + + return this.toneMappingNodes.get( toneMapping ) || null; + + } + + getMaterialNodeClass( materialType ) { + + return this.materialNodes.get( materialType ) || null; + + } + + addMaterial( materialNodeClass, materialClass ) { + + this.addType( materialNodeClass, materialClass.name, this.materialNodes ); + + } + + getLightNodeClass( light ) { + + return this.lightNodes.get( light ) || null; + + } + + addLight( lightNodeClass, lightClass ) { + + this.addClass( lightNodeClass, lightClass, this.lightNodes ); + + } + + addType( nodeClass, type, library ) { + + if ( library.has( type ) ) { + + console.warn( `Redefinition of node ${ type }` ); + return; + + } + + if ( typeof nodeClass !== 'function' ) throw new Error( `Node class ${ nodeClass.name } is not a class.` ); + if ( typeof type === 'function' || typeof type === 'object' ) throw new Error( `Base class ${ type } is not a class.` ); + + library.set( type, nodeClass ); + + } + + addClass( nodeClass, baseClass, library ) { + + if ( library.has( baseClass ) ) { + + console.warn( `Redefinition of node ${ baseClass.name }` ); + return; + + } + + if ( typeof nodeClass !== 'function' ) throw new Error( `Node class ${ nodeClass.name } is not a class.` ); + if ( typeof baseClass !== 'function' ) throw new Error( `Base class ${ baseClass.name } is not a class.` ); + + library.set( baseClass, nodeClass ); + + } + +} + +const _scene = /*@__PURE__*/ new Scene(); +const _drawingBufferSize = /*@__PURE__*/ new Vector2(); +const _screen = /*@__PURE__*/ new Vector4(); +const _frustum = /*@__PURE__*/ new Frustum(); +const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); +const _vector4 = /*@__PURE__*/ new Vector4(); + +class Renderer { + + constructor( backend, parameters = {} ) { + + this.isRenderer = true; + + // + + const { + logarithmicDepthBuffer = false, + alpha = true, + depth = true, + stencil = false, + antialias = false, + samples = 0, + getFallback = null + } = parameters; + + // public + this.domElement = backend.getDomElement(); + + this.backend = backend; + + this.samples = samples || ( antialias === true ) ? 4 : 0; + + this.autoClear = true; + this.autoClearColor = true; + this.autoClearDepth = true; + this.autoClearStencil = true; + + this.alpha = alpha; + + this.logarithmicDepthBuffer = logarithmicDepthBuffer; + + this.outputColorSpace = SRGBColorSpace; + + this.toneMapping = NoToneMapping; + this.toneMappingExposure = 1.0; + + this.sortObjects = true; + + this.depth = depth; + this.stencil = stencil; + + this.clippingPlanes = []; + + this.info = new Info(); + + this.nodes = { + library: new NodeLibrary(), + modelViewMatrix: null, + modelNormalViewMatrix: null + }; + + // internals + + this._getFallback = getFallback; + + this._pixelRatio = 1; + this._width = this.domElement.width; + this._height = this.domElement.height; + + this._viewport = new Vector4( 0, 0, this._width, this._height ); + this._scissor = new Vector4( 0, 0, this._width, this._height ); + this._scissorTest = false; + + this._attributes = null; + this._geometries = null; + this._nodes = null; + this._animation = null; + this._bindings = null; + this._objects = null; + this._pipelines = null; + this._bundles = null; + this._renderLists = null; + this._renderContexts = null; + this._textures = null; + this._background = null; + + this._quad = new QuadMesh( new NodeMaterial() ); + this._quad.material.type = 'Renderer_output'; + + this._currentRenderContext = null; + + this._opaqueSort = null; + this._transparentSort = null; + + this._frameBufferTarget = null; + + const alphaClear = this.alpha === true ? 0 : 1; + + this._clearColor = new Color4( 0, 0, 0, alphaClear ); + this._clearDepth = 1; + this._clearStencil = 0; + + this._renderTarget = null; + this._activeCubeFace = 0; + this._activeMipmapLevel = 0; + + this._mrt = null; + + this._renderObjectFunction = null; + this._currentRenderObjectFunction = null; + this._currentRenderBundle = null; + + this._handleObjectFunction = this._renderObjectDirect; + + this._initialized = false; + this._initPromise = null; + + this._compilationPromises = null; + + this.transparent = true; + this.opaque = true; + + this.shadowMap = { + enabled: false, + type: PCFShadowMap$1 + }; + + this.xr = { + enabled: false + }; + + this.debug = { + checkShaderErrors: true, + onShaderError: null, + getShaderAsync: async ( scene, camera, object ) => { + + await this.compileAsync( scene, camera ); + + const renderList = this._renderLists.get( scene, camera ); + const renderContext = this._renderContexts.get( scene, camera, this._renderTarget ); + + const material = scene.overrideMaterial || object.material; + + const renderObject = this._objects.get( object, material, scene, camera, renderList.lightsNode, renderContext ); + + const { fragmentShader, vertexShader } = renderObject.getNodeBuilderState(); + + return { fragmentShader, vertexShader }; + + } + }; + + } + + async init() { + + if ( this._initialized ) { + + throw new Error( 'Renderer: Backend has already been initialized.' ); + + } + + if ( this._initPromise !== null ) { + + return this._initPromise; + + } + + this._initPromise = new Promise( async ( resolve, reject ) => { + + let backend = this.backend; + + try { + + await backend.init( this ); + + } catch ( error ) { + + if ( this._getFallback !== null ) { + + // try the fallback + + try { + + this.backend = backend = this._getFallback( error ); + await backend.init( this ); + + } catch ( error ) { + + reject( error ); + return; + + } + + } else { + + reject( error ); + return; + + } + + } + + this._nodes = new Nodes( this, backend ); + this._animation = new Animation( this._nodes, this.info ); + this._attributes = new Attributes( backend ); + this._background = new Background( this, this._nodes ); + this._geometries = new Geometries( this._attributes, this.info ); + this._textures = new Textures( this, backend, this.info ); + this._pipelines = new Pipelines( backend, this._nodes ); + this._bindings = new Bindings( backend, this._nodes, this._textures, this._attributes, this._pipelines, this.info ); + this._objects = new RenderObjects( this, this._nodes, this._geometries, this._pipelines, this._bindings, this.info ); + this._renderLists = new RenderLists(); + this._bundles = new RenderBundles(); + this._renderContexts = new RenderContexts(); + + // + + this._initialized = true; + + resolve(); + + } ); + + return this._initPromise; + + } + + get coordinateSystem() { + + return this.backend.coordinateSystem; + + } + + async compileAsync( scene, camera, targetScene = null ) { + + if ( this._initialized === false ) await this.init(); + + // preserve render tree + + const nodeFrame = this._nodes.nodeFrame; + + const previousRenderId = nodeFrame.renderId; + const previousRenderContext = this._currentRenderContext; + const previousRenderObjectFunction = this._currentRenderObjectFunction; + const previousCompilationPromises = this._compilationPromises; + + // + + const sceneRef = ( scene.isScene === true ) ? scene : _scene; + + if ( targetScene === null ) targetScene = scene; + + const renderTarget = this._renderTarget; + const renderContext = this._renderContexts.get( targetScene, camera, renderTarget ); + const activeMipmapLevel = this._activeMipmapLevel; + + const compilationPromises = []; + + this._currentRenderContext = renderContext; + this._currentRenderObjectFunction = this.renderObject; + + this._handleObjectFunction = this._createObjectPipeline; + + this._compilationPromises = compilationPromises; + + nodeFrame.renderId ++; + + // + + nodeFrame.update(); + + // + + renderContext.depth = this.depth; + renderContext.stencil = this.stencil; + + if ( ! renderContext.clippingContext ) renderContext.clippingContext = new ClippingContext(); + renderContext.clippingContext.updateGlobal( this, camera ); + + // + + sceneRef.onBeforeRender( this, scene, camera, renderTarget ); + + // + + const renderList = this._renderLists.get( scene, camera ); + renderList.begin(); + + this._projectObject( scene, camera, 0, renderList ); + + // include lights from target scene + if ( targetScene !== scene ) { + + targetScene.traverseVisible( function ( object ) { + + if ( object.isLight && object.layers.test( camera.layers ) ) { + + renderList.pushLight( object ); + + } + + } ); + + } + + renderList.finish(); + + // + + if ( renderTarget !== null ) { + + this._textures.updateRenderTarget( renderTarget, activeMipmapLevel ); + + const renderTargetData = this._textures.get( renderTarget ); + + renderContext.textures = renderTargetData.textures; + renderContext.depthTexture = renderTargetData.depthTexture; + + } else { + + renderContext.textures = null; + renderContext.depthTexture = null; + + } + + // + + this._nodes.updateScene( sceneRef ); + + // + + this._background.update( sceneRef, renderList, renderContext ); + + // process render lists + + const opaqueObjects = renderList.opaque; + const transparentObjects = renderList.transparent; + const lightsNode = renderList.lightsNode; + + if ( this.opaque === true && opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode ); + if ( this.transparent === true && transparentObjects.length > 0 ) this._renderObjects( transparentObjects, camera, sceneRef, lightsNode ); + + // restore render tree + + nodeFrame.renderId = previousRenderId; + + this._currentRenderContext = previousRenderContext; + this._currentRenderObjectFunction = previousRenderObjectFunction; + this._compilationPromises = previousCompilationPromises; + + this._handleObjectFunction = this._renderObjectDirect; + + // wait for all promises setup by backends awaiting compilation/linking/pipeline creation to complete + + await Promise.all( compilationPromises ); + + } + + async renderAsync( scene, camera ) { + + if ( this._initialized === false ) await this.init(); + + const renderContext = this._renderScene( scene, camera ); + + await this.backend.resolveTimestampAsync( renderContext, 'render' ); + + } + + setMRT( mrt ) { + + this._mrt = mrt; + + return this; + + } + + getMRT() { + + return this._mrt; + + } + + _renderBundle( bundle, sceneRef, lightsNode ) { + + const { bundleGroup, camera, renderList } = bundle; + + const renderContext = this._currentRenderContext; + + // + + const renderBundle = this._bundles.get( bundleGroup, camera ); + const renderBundleData = this.backend.get( renderBundle ); + + if ( renderBundleData.renderContexts === undefined ) renderBundleData.renderContexts = new Set(); + + // + + const needsUpdate = bundleGroup.version !== renderBundleData.version; + const renderBundleNeedsUpdate = renderBundleData.renderContexts.has( renderContext ) === false || needsUpdate; + + renderBundleData.renderContexts.add( renderContext ); + + if ( renderBundleNeedsUpdate ) { + + this.backend.beginBundle( renderContext ); + + if ( renderBundleData.renderObjects === undefined || needsUpdate ) { + + renderBundleData.renderObjects = []; + + } + + this._currentRenderBundle = renderBundle; + + const opaqueObjects = renderList.opaque; + + if ( opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode ); + + this._currentRenderBundle = null; + + // + + this.backend.finishBundle( renderContext, renderBundle ); + + renderBundleData.version = bundleGroup.version; + + } else { + + const { renderObjects } = renderBundleData; + + for ( let i = 0, l = renderObjects.length; i < l; i ++ ) { + + const renderObject = renderObjects[ i ]; + + if ( this._nodes.needsRefresh( renderObject ) ) { + + this._nodes.updateBefore( renderObject ); + + this._nodes.updateForRender( renderObject ); + this._bindings.updateForRender( renderObject ); + + this._nodes.updateAfter( renderObject ); + + } + + } + + } + + this.backend.addBundle( renderContext, renderBundle ); + + } + + render( scene, camera ) { + + if ( this._initialized === false ) { + + console.warn( 'THREE.Renderer: .render() called before the backend is initialized. Try using .renderAsync() instead.' ); + + return this.renderAsync( scene, camera ); + + } + + this._renderScene( scene, camera ); + + } + + _getFrameBufferTarget() { + + const { currentToneMapping, currentColorSpace } = this; + + const useToneMapping = currentToneMapping !== NoToneMapping; + const useColorSpace = currentColorSpace !== LinearSRGBColorSpace; + + if ( useToneMapping === false && useColorSpace === false ) return null; + + const { width, height } = this.getDrawingBufferSize( _drawingBufferSize ); + const { depth, stencil } = this; + + let frameBufferTarget = this._frameBufferTarget; + + if ( frameBufferTarget === null ) { + + frameBufferTarget = new RenderTarget( width, height, { + depthBuffer: depth, + stencilBuffer: stencil, + type: HalfFloatType, // FloatType + format: RGBAFormat, + colorSpace: LinearSRGBColorSpace, + generateMipmaps: false, + minFilter: LinearFilter, + magFilter: LinearFilter, + samples: this.samples + } ); + + frameBufferTarget.isPostProcessingRenderTarget = true; + + this._frameBufferTarget = frameBufferTarget; + + } + + frameBufferTarget.depthBuffer = depth; + frameBufferTarget.stencilBuffer = stencil; + frameBufferTarget.setSize( width, height ); + frameBufferTarget.viewport.copy( this._viewport ); + frameBufferTarget.scissor.copy( this._scissor ); + frameBufferTarget.viewport.multiplyScalar( this._pixelRatio ); + frameBufferTarget.scissor.multiplyScalar( this._pixelRatio ); + frameBufferTarget.scissorTest = this._scissorTest; + + return frameBufferTarget; + + } + + _renderScene( scene, camera, useFrameBufferTarget = true ) { + + const frameBufferTarget = useFrameBufferTarget ? this._getFrameBufferTarget() : null; + + // preserve render tree + + const nodeFrame = this._nodes.nodeFrame; + + const previousRenderId = nodeFrame.renderId; + const previousRenderContext = this._currentRenderContext; + const previousRenderObjectFunction = this._currentRenderObjectFunction; + + // + + const sceneRef = ( scene.isScene === true ) ? scene : _scene; + + const outputRenderTarget = this._renderTarget; + + const activeCubeFace = this._activeCubeFace; + const activeMipmapLevel = this._activeMipmapLevel; + + // + + let renderTarget; + + if ( frameBufferTarget !== null ) { + + renderTarget = frameBufferTarget; + + this.setRenderTarget( renderTarget ); + + } else { + + renderTarget = outputRenderTarget; + + } + + // + + const renderContext = this._renderContexts.get( scene, camera, renderTarget ); + + this._currentRenderContext = renderContext; + this._currentRenderObjectFunction = this._renderObjectFunction || this.renderObject; + + // + + this.info.calls ++; + this.info.render.calls ++; + this.info.render.frameCalls ++; + + nodeFrame.renderId = this.info.calls; + + // + + const coordinateSystem = this.coordinateSystem; + + if ( camera.coordinateSystem !== coordinateSystem ) { + + camera.coordinateSystem = coordinateSystem; + + camera.updateProjectionMatrix(); + + } + + // + + if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); + + if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); + + // + + let viewport = this._viewport; + let scissor = this._scissor; + let pixelRatio = this._pixelRatio; + + if ( renderTarget !== null ) { + + viewport = renderTarget.viewport; + scissor = renderTarget.scissor; + pixelRatio = 1; + + } + + this.getDrawingBufferSize( _drawingBufferSize ); + + _screen.set( 0, 0, _drawingBufferSize.width, _drawingBufferSize.height ); + + const minDepth = ( viewport.minDepth === undefined ) ? 0 : viewport.minDepth; + const maxDepth = ( viewport.maxDepth === undefined ) ? 1 : viewport.maxDepth; + + renderContext.viewportValue.copy( viewport ).multiplyScalar( pixelRatio ).floor(); + renderContext.viewportValue.width >>= activeMipmapLevel; + renderContext.viewportValue.height >>= activeMipmapLevel; + renderContext.viewportValue.minDepth = minDepth; + renderContext.viewportValue.maxDepth = maxDepth; + renderContext.viewport = renderContext.viewportValue.equals( _screen ) === false; + + renderContext.scissorValue.copy( scissor ).multiplyScalar( pixelRatio ).floor(); + renderContext.scissor = this._scissorTest && renderContext.scissorValue.equals( _screen ) === false; + renderContext.scissorValue.width >>= activeMipmapLevel; + renderContext.scissorValue.height >>= activeMipmapLevel; + + if ( ! renderContext.clippingContext ) renderContext.clippingContext = new ClippingContext(); + renderContext.clippingContext.updateGlobal( this, camera ); + + // + + sceneRef.onBeforeRender( this, scene, camera, renderTarget ); + + // + + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromProjectionMatrix( _projScreenMatrix, coordinateSystem ); + + const renderList = this._renderLists.get( scene, camera ); + renderList.begin(); + + this._projectObject( scene, camera, 0, renderList ); + + renderList.finish(); + + if ( this.sortObjects === true ) { + + renderList.sort( this._opaqueSort, this._transparentSort ); + + } + + // + + if ( renderTarget !== null ) { + + this._textures.updateRenderTarget( renderTarget, activeMipmapLevel ); + + const renderTargetData = this._textures.get( renderTarget ); + + renderContext.textures = renderTargetData.textures; + renderContext.depthTexture = renderTargetData.depthTexture; + renderContext.width = renderTargetData.width; + renderContext.height = renderTargetData.height; + renderContext.renderTarget = renderTarget; + renderContext.depth = renderTarget.depthBuffer; + renderContext.stencil = renderTarget.stencilBuffer; + + } else { + + renderContext.textures = null; + renderContext.depthTexture = null; + renderContext.width = this.domElement.width; + renderContext.height = this.domElement.height; + renderContext.depth = this.depth; + renderContext.stencil = this.stencil; + + } + + renderContext.width >>= activeMipmapLevel; + renderContext.height >>= activeMipmapLevel; + renderContext.activeCubeFace = activeCubeFace; + renderContext.activeMipmapLevel = activeMipmapLevel; + renderContext.occlusionQueryCount = renderList.occlusionQueryCount; + + // + + this._nodes.updateScene( sceneRef ); + + // + + this._background.update( sceneRef, renderList, renderContext ); + + // + + this.backend.beginRender( renderContext ); + + // process render lists + + const { + bundles, + lightsNode, + transparent: transparentObjects, + opaque: opaqueObjects + } = renderList; + + if ( bundles.length > 0 ) this._renderBundles( bundles, sceneRef, lightsNode ); + if ( this.opaque === true && opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode ); + if ( this.transparent === true && transparentObjects.length > 0 ) this._renderObjects( transparentObjects, camera, sceneRef, lightsNode ); + + // finish render pass + + this.backend.finishRender( renderContext ); + + // restore render tree + + nodeFrame.renderId = previousRenderId; + + this._currentRenderContext = previousRenderContext; + this._currentRenderObjectFunction = previousRenderObjectFunction; + + // + + if ( frameBufferTarget !== null ) { + + this.setRenderTarget( outputRenderTarget, activeCubeFace, activeMipmapLevel ); + + const quad = this._quad; + + if ( this._nodes.hasOutputChange( renderTarget.texture ) ) { + + quad.material.fragmentNode = this._nodes.getOutputNode( renderTarget.texture ); + quad.material.needsUpdate = true; + + } + + this._renderScene( quad, quad.camera, false ); + + } + + // + + sceneRef.onAfterRender( this, scene, camera, renderTarget ); + + // + + return renderContext; + + } + + getMaxAnisotropy() { + + return this.backend.getMaxAnisotropy(); + + } + + getActiveCubeFace() { + + return this._activeCubeFace; + + } + + getActiveMipmapLevel() { + + return this._activeMipmapLevel; + + } + + async setAnimationLoop( callback ) { + + if ( this._initialized === false ) await this.init(); + + this._animation.setAnimationLoop( callback ); + + } + + async getArrayBufferAsync( attribute ) { + + return await this.backend.getArrayBufferAsync( attribute ); + + } + + getContext() { + + return this.backend.getContext(); + + } + + getPixelRatio() { + + return this._pixelRatio; + + } + + getDrawingBufferSize( target ) { + + return target.set( this._width * this._pixelRatio, this._height * this._pixelRatio ).floor(); + + } + + getSize( target ) { + + return target.set( this._width, this._height ); + + } + + setPixelRatio( value = 1 ) { + + this._pixelRatio = value; + + this.setSize( this._width, this._height, false ); + + } + + setDrawingBufferSize( width, height, pixelRatio ) { + + this._width = width; + this._height = height; + + this._pixelRatio = pixelRatio; + + this.domElement.width = Math.floor( width * pixelRatio ); + this.domElement.height = Math.floor( height * pixelRatio ); + + this.setViewport( 0, 0, width, height ); + + if ( this._initialized ) this.backend.updateSize(); + + } + + setSize( width, height, updateStyle = true ) { + + this._width = width; + this._height = height; + + this.domElement.width = Math.floor( width * this._pixelRatio ); + this.domElement.height = Math.floor( height * this._pixelRatio ); + + if ( updateStyle === true ) { + + this.domElement.style.width = width + 'px'; + this.domElement.style.height = height + 'px'; + + } + + this.setViewport( 0, 0, width, height ); + + if ( this._initialized ) this.backend.updateSize(); + + } + + setOpaqueSort( method ) { + + this._opaqueSort = method; + + } + + setTransparentSort( method ) { + + this._transparentSort = method; + + } + + getScissor( target ) { + + const scissor = this._scissor; + + target.x = scissor.x; + target.y = scissor.y; + target.width = scissor.width; + target.height = scissor.height; + + return target; + + } + + setScissor( x, y, width, height ) { + + const scissor = this._scissor; + + if ( x.isVector4 ) { + + scissor.copy( x ); + + } else { + + scissor.set( x, y, width, height ); + + } + + } + + getScissorTest() { + + return this._scissorTest; + + } + + setScissorTest( boolean ) { + + this._scissorTest = boolean; + + this.backend.setScissorTest( boolean ); + + } + + getViewport( target ) { + + return target.copy( this._viewport ); + + } + + setViewport( x, y, width, height, minDepth = 0, maxDepth = 1 ) { + + const viewport = this._viewport; + + if ( x.isVector4 ) { + + viewport.copy( x ); + + } else { + + viewport.set( x, y, width, height ); + + } + + viewport.minDepth = minDepth; + viewport.maxDepth = maxDepth; + + } + + getClearColor( target ) { + + return target.copy( this._clearColor ); + + } + + setClearColor( color, alpha = 1 ) { + + this._clearColor.set( color ); + this._clearColor.a = alpha; + + } + + getClearAlpha() { + + return this._clearColor.a; + + } + + setClearAlpha( alpha ) { + + this._clearColor.a = alpha; + + } + + getClearDepth() { + + return this._clearDepth; + + } + + setClearDepth( depth ) { + + this._clearDepth = depth; + + } + + getClearStencil() { + + return this._clearStencil; + + } + + setClearStencil( stencil ) { + + this._clearStencil = stencil; + + } + + isOccluded( object ) { + + const renderContext = this._currentRenderContext; + + return renderContext && this.backend.isOccluded( renderContext, object ); + + } + + clear( color = true, depth = true, stencil = true ) { + + if ( this._initialized === false ) { + + console.warn( 'THREE.Renderer: .clear() called before the backend is initialized. Try using .clearAsync() instead.' ); + + return this.clearAsync( color, depth, stencil ); + + } + + const renderTarget = this._renderTarget || this._getFrameBufferTarget(); + + let renderTargetData = null; + + if ( renderTarget !== null ) { + + this._textures.updateRenderTarget( renderTarget ); + + renderTargetData = this._textures.get( renderTarget ); + + } + + this.backend.clear( color, depth, stencil, renderTargetData ); + + if ( renderTarget !== null && this._renderTarget === null ) { + + // If a color space transform or tone mapping is required, + // the clear operation clears the intermediate renderTarget texture, but does not update the screen canvas. + + const quad = this._quad; + + if ( this._nodes.hasOutputChange( renderTarget.texture ) ) { + + quad.material.fragmentNode = this._nodes.getOutputNode( renderTarget.texture ); + quad.material.needsUpdate = true; + + } + + this._renderScene( quad, quad.camera, false ); + + } + + } + + clearColor() { + + return this.clear( true, false, false ); + + } + + clearDepth() { + + return this.clear( false, true, false ); + + } + + clearStencil() { + + return this.clear( false, false, true ); + + } + + async clearAsync( color = true, depth = true, stencil = true ) { + + if ( this._initialized === false ) await this.init(); + + this.clear( color, depth, stencil ); + + } + + clearColorAsync() { + + return this.clearAsync( true, false, false ); + + } + + clearDepthAsync() { + + return this.clearAsync( false, true, false ); + + } + + clearStencilAsync() { + + return this.clearAsync( false, false, true ); + + } + + get currentToneMapping() { + + return this._renderTarget !== null ? NoToneMapping : this.toneMapping; + + } + + get currentColorSpace() { + + return this._renderTarget !== null ? LinearSRGBColorSpace : this.outputColorSpace; + + } + + dispose() { + + this.info.dispose(); + + this._animation.dispose(); + this._objects.dispose(); + this._pipelines.dispose(); + this._nodes.dispose(); + this._bindings.dispose(); + this._renderLists.dispose(); + this._renderContexts.dispose(); + this._textures.dispose(); + + this.setRenderTarget( null ); + this.setAnimationLoop( null ); + + } + + setRenderTarget( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { + + this._renderTarget = renderTarget; + this._activeCubeFace = activeCubeFace; + this._activeMipmapLevel = activeMipmapLevel; + + } + + getRenderTarget() { + + return this._renderTarget; + + } + + setRenderObjectFunction( renderObjectFunction ) { + + this._renderObjectFunction = renderObjectFunction; + + } + + getRenderObjectFunction() { + + return this._renderObjectFunction; + + } + + async computeAsync( computeNodes ) { + + if ( this._initialized === false ) await this.init(); + + const nodeFrame = this._nodes.nodeFrame; + + const previousRenderId = nodeFrame.renderId; + + // + + this.info.calls ++; + this.info.compute.calls ++; + this.info.compute.frameCalls ++; + + nodeFrame.renderId = this.info.calls; + + // + + const backend = this.backend; + const pipelines = this._pipelines; + const bindings = this._bindings; + const nodes = this._nodes; + + const computeList = Array.isArray( computeNodes ) ? computeNodes : [ computeNodes ]; + + if ( computeList[ 0 ] === undefined || computeList[ 0 ].isComputeNode !== true ) { + + throw new Error( 'THREE.Renderer: .compute() expects a ComputeNode.' ); + + } + + backend.beginCompute( computeNodes ); + + for ( const computeNode of computeList ) { + + // onInit + + if ( pipelines.has( computeNode ) === false ) { + + const dispose = () => { + + computeNode.removeEventListener( 'dispose', dispose ); + + pipelines.delete( computeNode ); + bindings.delete( computeNode ); + nodes.delete( computeNode ); + + }; + + computeNode.addEventListener( 'dispose', dispose ); + + // + + computeNode.onInit( { renderer: this } ); + + } + + nodes.updateForCompute( computeNode ); + bindings.updateForCompute( computeNode ); + + const computeBindings = bindings.getForCompute( computeNode ); + const computePipeline = pipelines.getForCompute( computeNode, computeBindings ); + + backend.compute( computeNodes, computeNode, computeBindings, computePipeline ); + + } + + backend.finishCompute( computeNodes ); + + await this.backend.resolveTimestampAsync( computeNodes, 'compute' ); + + // + + nodeFrame.renderId = previousRenderId; + + } + + async hasFeatureAsync( name ) { + + if ( this._initialized === false ) await this.init(); + + return this.backend.hasFeature( name ); + + } + + hasFeature( name ) { + + if ( this._initialized === false ) { + + console.warn( 'THREE.Renderer: .hasFeature() called before the backend is initialized. Try using .hasFeatureAsync() instead.' ); + + return false; + + } + + return this.backend.hasFeature( name ); + + } + + copyFramebufferToTexture( framebufferTexture, rectangle = null ) { + + const renderContext = this._currentRenderContext; + + this._textures.updateTexture( framebufferTexture ); + + rectangle = rectangle === null ? _vector4.set( 0, 0, framebufferTexture.image.width, framebufferTexture.image.height ) : rectangle; + + this.backend.copyFramebufferToTexture( framebufferTexture, renderContext, rectangle ); + + } + + copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { + + this._textures.updateTexture( srcTexture ); + this._textures.updateTexture( dstTexture ); + + this.backend.copyTextureToTexture( srcTexture, dstTexture, srcRegion, dstPosition, level ); + + } + + + readRenderTargetPixelsAsync( renderTarget, x, y, width, height, index = 0, faceIndex = 0 ) { + + return this.backend.copyTextureToBuffer( renderTarget.textures[ index ], x, y, width, height, faceIndex ); + + } + + _projectObject( object, camera, groupOrder, renderList ) { + + if ( object.visible === false ) return; + + const visible = object.layers.test( camera.layers ); + + if ( visible ) { + + if ( object.isGroup ) { + + groupOrder = object.renderOrder; + + } else if ( object.isLOD ) { + + if ( object.autoUpdate === true ) object.update( camera ); + + } else if ( object.isLight ) { + + renderList.pushLight( object ); + + } else if ( object.isSprite ) { + + if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { + + if ( this.sortObjects === true ) { + + _vector4.setFromMatrixPosition( object.matrixWorld ).applyMatrix4( _projScreenMatrix ); + + } + + const { geometry, material } = object; + + if ( material.visible ) { + + renderList.push( object, geometry, material, groupOrder, _vector4.z, null ); + + } + + } + + } else if ( object.isLineLoop ) { + + console.error( 'THREE.Renderer: Objects of type THREE.LineLoop are not supported. Please use THREE.Line or THREE.LineSegments.' ); + + } else if ( object.isMesh || object.isLine || object.isPoints ) { + + if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { + + const { geometry, material } = object; + + if ( this.sortObjects === true ) { + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + _vector4 + .copy( geometry.boundingSphere.center ) + .applyMatrix4( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); + + } + + if ( Array.isArray( material ) ) { + + const groups = geometry.groups; + + for ( let i = 0, l = groups.length; i < l; i ++ ) { + + const group = groups[ i ]; + const groupMaterial = material[ group.materialIndex ]; + + if ( groupMaterial && groupMaterial.visible ) { + + renderList.push( object, geometry, groupMaterial, groupOrder, _vector4.z, group ); + + } + + } + + } else if ( material.visible ) { + + renderList.push( object, geometry, material, groupOrder, _vector4.z, null ); + + } + + } + + } + + } + + if ( object.isBundleGroup === true && this.backend.beginBundle !== undefined ) { + + const baseRenderList = renderList; + + // replace render list + renderList = this._renderLists.get( object, camera ); + + renderList.begin(); + + baseRenderList.pushBundle( { + bundleGroup: object, + camera, + renderList, + } ); + + renderList.finish(); + + } + + const children = object.children; + + for ( let i = 0, l = children.length; i < l; i ++ ) { + + this._projectObject( children[ i ], camera, groupOrder, renderList ); + + } + + } + + _renderBundles( bundles, sceneRef, lightsNode ) { + + for ( const bundle of bundles ) { + + this._renderBundle( bundle, sceneRef, lightsNode ); + + } + + } + + _renderObjects( renderList, camera, scene, lightsNode ) { + + // process renderable objects + + for ( let i = 0, il = renderList.length; i < il; i ++ ) { + + const renderItem = renderList[ i ]; + + // @TODO: Add support for multiple materials per object. This will require to extract + // the material from the renderItem object and pass it with its group data to renderObject(). + + const { object, geometry, material, group } = renderItem; + + if ( camera.isArrayCamera ) { + + const cameras = camera.cameras; + + for ( let j = 0, jl = cameras.length; j < jl; j ++ ) { + + const camera2 = cameras[ j ]; + + if ( object.layers.test( camera2.layers ) ) { + + const vp = camera2.viewport; + const minDepth = ( vp.minDepth === undefined ) ? 0 : vp.minDepth; + const maxDepth = ( vp.maxDepth === undefined ) ? 1 : vp.maxDepth; + + const viewportValue = this._currentRenderContext.viewportValue; + viewportValue.copy( vp ).multiplyScalar( this._pixelRatio ).floor(); + viewportValue.minDepth = minDepth; + viewportValue.maxDepth = maxDepth; + + this.backend.updateViewport( this._currentRenderContext ); + + this._currentRenderObjectFunction( object, scene, camera2, geometry, material, group, lightsNode ); + + } + + } + + } else { + + this._currentRenderObjectFunction( object, scene, camera, geometry, material, group, lightsNode ); + + } + + } + + } + + renderObject( object, scene, camera, geometry, material, group, lightsNode ) { + + let overridePositionNode; + let overrideFragmentNode; + let overrideDepthNode; + + // + + object.onBeforeRender( this, scene, camera, geometry, material, group ); + + // + + if ( scene.overrideMaterial !== null ) { + + const overrideMaterial = scene.overrideMaterial; + + if ( material.positionNode && material.positionNode.isNode ) { + + overridePositionNode = overrideMaterial.positionNode; + overrideMaterial.positionNode = material.positionNode; + + } + + if ( overrideMaterial.isShadowNodeMaterial ) { + + overrideMaterial.side = material.shadowSide === null ? material.side : material.shadowSide; + + if ( material.depthNode && material.depthNode.isNode ) { + + overrideDepthNode = overrideMaterial.depthNode; + overrideMaterial.depthNode = material.depthNode; + + } + + + if ( material.shadowNode && material.shadowNode.isNode ) { + + overrideFragmentNode = overrideMaterial.fragmentNode; + overrideMaterial.fragmentNode = material.shadowNode; + + } + + if ( this.localClippingEnabled ) { + + if ( material.clipShadows ) { + + if ( overrideMaterial.clippingPlanes !== material.clippingPlanes ) { + + overrideMaterial.clippingPlanes = material.clippingPlanes; + overrideMaterial.needsUpdate = true; + + } + + if ( overrideMaterial.clipIntersection !== material.clipIntersection ) { + + overrideMaterial.clipIntersection = material.clipIntersection; + + } + + } else if ( Array.isArray( overrideMaterial.clippingPlanes ) ) { + + overrideMaterial.clippingPlanes = null; + overrideMaterial.needsUpdate = true; + + } + + } + + } + + material = overrideMaterial; + + } + + // + + if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { + + material.side = BackSide; + this._handleObjectFunction( object, material, scene, camera, lightsNode, group, 'backSide' ); // create backSide pass id + + material.side = FrontSide; + this._handleObjectFunction( object, material, scene, camera, lightsNode, group ); // use default pass id + + material.side = DoubleSide; + + } else { + + this._handleObjectFunction( object, material, scene, camera, lightsNode, group ); + + } + + // + + if ( overridePositionNode !== undefined ) { + + scene.overrideMaterial.positionNode = overridePositionNode; + + } + + if ( overrideDepthNode !== undefined ) { + + scene.overrideMaterial.depthNode = overrideDepthNode; + + } + + if ( overrideFragmentNode !== undefined ) { + + scene.overrideMaterial.fragmentNode = overrideFragmentNode; + + } + + // + + object.onAfterRender( this, scene, camera, geometry, material, group ); + + } + + _renderObjectDirect( object, material, scene, camera, lightsNode, group, passId ) { + + const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, passId ); + renderObject.drawRange = object.geometry.drawRange; + renderObject.group = group; + + // + + const needsRefresh = this._nodes.needsRefresh( renderObject ); + + if ( needsRefresh ) { + + this._nodes.updateBefore( renderObject ); + + this._geometries.updateForRender( renderObject ); + + this._nodes.updateForRender( renderObject ); + this._bindings.updateForRender( renderObject ); + + } + + this._pipelines.updateForRender( renderObject ); + + // + + if ( this._currentRenderBundle !== null ) { + + const renderBundleData = this.backend.get( this._currentRenderBundle ); + + renderBundleData.renderObjects.push( renderObject ); + + renderObject.bundle = this._currentRenderBundle.scene; + + } + + this.backend.draw( renderObject, this.info ); + + if ( needsRefresh ) this._nodes.updateAfter( renderObject ); + + } + + _createObjectPipeline( object, material, scene, camera, lightsNode, passId ) { + + const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, passId ); + + // + + this._nodes.updateBefore( renderObject ); + + this._geometries.updateForRender( renderObject ); + + this._nodes.updateForRender( renderObject ); + this._bindings.updateForRender( renderObject ); + + this._pipelines.getForRender( renderObject, this._compilationPromises ); + + this._nodes.updateAfter( renderObject ); + + } + + get compute() { + + return this.computeAsync; + + } + + get compile() { + + return this.compileAsync; + + } + +} + +class Binding { + + constructor( name = '' ) { + + this.name = name; + + this.visibility = 0; + + } + + setVisibility( visibility ) { + + this.visibility |= visibility; + + } + + clone() { + + return Object.assign( new this.constructor(), this ); + + } + +} + +function getFloatLength( floatLength ) { + + // ensure chunk size alignment (STD140 layout) + + return floatLength + ( ( GPU_CHUNK_BYTES - ( floatLength % GPU_CHUNK_BYTES ) ) % GPU_CHUNK_BYTES ); + +} + +class Buffer extends Binding { + + constructor( name, buffer = null ) { + + super( name ); + + this.isBuffer = true; + + this.bytesPerElement = Float32Array.BYTES_PER_ELEMENT; + + this._buffer = buffer; + + } + + get byteLength() { + + return getFloatLength( this._buffer.byteLength ); + + } + + get buffer() { + + return this._buffer; + + } + + update() { + + return true; + + } + +} + +class UniformBuffer extends Buffer { + + constructor( name, buffer = null ) { + + super( name, buffer ); + + this.isUniformBuffer = true; + + } + +} + +let _id$4 = 0; + +class NodeUniformBuffer extends UniformBuffer { + + constructor( nodeUniform, groupNode ) { + + super( 'UniformBuffer_' + _id$4 ++, nodeUniform ? nodeUniform.value : null ); + + this.nodeUniform = nodeUniform; + this.groupNode = groupNode; + + } + + get buffer() { + + return this.nodeUniform.value; + + } + +} + +class UniformsGroup extends UniformBuffer { + + constructor( name ) { + + super( name ); + + this.isUniformsGroup = true; + + this._values = null; + + // the order of uniforms in this array must match the order of uniforms in the shader + + this.uniforms = []; + + } + + addUniform( uniform ) { + + this.uniforms.push( uniform ); + + return this; + + } + + removeUniform( uniform ) { + + const index = this.uniforms.indexOf( uniform ); + + if ( index !== - 1 ) { + + this.uniforms.splice( index, 1 ); + + } + + return this; + + } + + get values() { + + if ( this._values === null ) { + + this._values = Array.from( this.buffer ); + + } + + return this._values; + + } + + get buffer() { + + let buffer = this._buffer; + + if ( buffer === null ) { + + const byteLength = this.byteLength; + + buffer = new Float32Array( new ArrayBuffer( byteLength ) ); + + this._buffer = buffer; + + } + + return buffer; + + } + + get byteLength() { + + let offset = 0; // global buffer offset in bytes + + for ( let i = 0, l = this.uniforms.length; i < l; i ++ ) { + + const uniform = this.uniforms[ i ]; + + const { boundary, itemSize } = uniform; + + // offset within a single chunk in bytes + + const chunkOffset = offset % GPU_CHUNK_BYTES; + const remainingSizeInChunk = GPU_CHUNK_BYTES - chunkOffset; + + // conformance tests + + if ( chunkOffset !== 0 && ( remainingSizeInChunk - boundary ) < 0 ) { + + // check for chunk overflow + + offset += ( GPU_CHUNK_BYTES - chunkOffset ); + + } else if ( chunkOffset % boundary !== 0 ) { + + // check for correct alignment + + offset += ( chunkOffset % boundary ); + + } + + uniform.offset = ( offset / this.bytesPerElement ); + + offset += ( itemSize * this.bytesPerElement ); + + } + + return Math.ceil( offset / GPU_CHUNK_BYTES ) * GPU_CHUNK_BYTES; + + } + + update() { + + let updated = false; + + for ( const uniform of this.uniforms ) { + + if ( this.updateByType( uniform ) === true ) { + + updated = true; + + } + + } + + return updated; + + } + + updateByType( uniform ) { + + if ( uniform.isNumberUniform ) return this.updateNumber( uniform ); + if ( uniform.isVector2Uniform ) return this.updateVector2( uniform ); + if ( uniform.isVector3Uniform ) return this.updateVector3( uniform ); + if ( uniform.isVector4Uniform ) return this.updateVector4( uniform ); + if ( uniform.isColorUniform ) return this.updateColor( uniform ); + if ( uniform.isMatrix3Uniform ) return this.updateMatrix3( uniform ); + if ( uniform.isMatrix4Uniform ) return this.updateMatrix4( uniform ); + + console.error( 'THREE.WebGPUUniformsGroup: Unsupported uniform type.', uniform ); + + } + + updateNumber( uniform ) { + + let updated = false; + + const a = this.values; + const v = uniform.getValue(); + const offset = uniform.offset; + + if ( a[ offset ] !== v ) { + + const b = this.buffer; + + b[ offset ] = a[ offset ] = v; + updated = true; + + } + + return updated; + + } + + updateVector2( uniform ) { + + let updated = false; + + const a = this.values; + const v = uniform.getValue(); + const offset = uniform.offset; + + if ( a[ offset + 0 ] !== v.x || a[ offset + 1 ] !== v.y ) { + + const b = this.buffer; + + b[ offset + 0 ] = a[ offset + 0 ] = v.x; + b[ offset + 1 ] = a[ offset + 1 ] = v.y; + + updated = true; + + } + + return updated; + + } + + updateVector3( uniform ) { + + let updated = false; + + const a = this.values; + const v = uniform.getValue(); + const offset = uniform.offset; + + if ( a[ offset + 0 ] !== v.x || a[ offset + 1 ] !== v.y || a[ offset + 2 ] !== v.z ) { + + const b = this.buffer; + + b[ offset + 0 ] = a[ offset + 0 ] = v.x; + b[ offset + 1 ] = a[ offset + 1 ] = v.y; + b[ offset + 2 ] = a[ offset + 2 ] = v.z; + + updated = true; + + } + + return updated; + + } + + updateVector4( uniform ) { + + let updated = false; + + const a = this.values; + const v = uniform.getValue(); + const offset = uniform.offset; + + if ( a[ offset + 0 ] !== v.x || a[ offset + 1 ] !== v.y || a[ offset + 2 ] !== v.z || a[ offset + 4 ] !== v.w ) { + + const b = this.buffer; + + b[ offset + 0 ] = a[ offset + 0 ] = v.x; + b[ offset + 1 ] = a[ offset + 1 ] = v.y; + b[ offset + 2 ] = a[ offset + 2 ] = v.z; + b[ offset + 3 ] = a[ offset + 3 ] = v.w; + + updated = true; + + } + + return updated; + + } + + updateColor( uniform ) { + + let updated = false; + + const a = this.values; + const c = uniform.getValue(); + const offset = uniform.offset; + + if ( a[ offset + 0 ] !== c.r || a[ offset + 1 ] !== c.g || a[ offset + 2 ] !== c.b ) { + + const b = this.buffer; + + b[ offset + 0 ] = a[ offset + 0 ] = c.r; + b[ offset + 1 ] = a[ offset + 1 ] = c.g; + b[ offset + 2 ] = a[ offset + 2 ] = c.b; + + updated = true; + + } + + return updated; + + } + + updateMatrix3( uniform ) { + + let updated = false; + + const a = this.values; + const e = uniform.getValue().elements; + const offset = uniform.offset; + + if ( a[ offset + 0 ] !== e[ 0 ] || a[ offset + 1 ] !== e[ 1 ] || a[ offset + 2 ] !== e[ 2 ] || + a[ offset + 4 ] !== e[ 3 ] || a[ offset + 5 ] !== e[ 4 ] || a[ offset + 6 ] !== e[ 5 ] || + a[ offset + 8 ] !== e[ 6 ] || a[ offset + 9 ] !== e[ 7 ] || a[ offset + 10 ] !== e[ 8 ] ) { + + const b = this.buffer; + + b[ offset + 0 ] = a[ offset + 0 ] = e[ 0 ]; + b[ offset + 1 ] = a[ offset + 1 ] = e[ 1 ]; + b[ offset + 2 ] = a[ offset + 2 ] = e[ 2 ]; + b[ offset + 4 ] = a[ offset + 4 ] = e[ 3 ]; + b[ offset + 5 ] = a[ offset + 5 ] = e[ 4 ]; + b[ offset + 6 ] = a[ offset + 6 ] = e[ 5 ]; + b[ offset + 8 ] = a[ offset + 8 ] = e[ 6 ]; + b[ offset + 9 ] = a[ offset + 9 ] = e[ 7 ]; + b[ offset + 10 ] = a[ offset + 10 ] = e[ 8 ]; + + updated = true; + + } + + return updated; + + } + + updateMatrix4( uniform ) { + + let updated = false; + + const a = this.values; + const e = uniform.getValue().elements; + const offset = uniform.offset; + + if ( arraysEqual( a, e, offset ) === false ) { + + const b = this.buffer; + b.set( e, offset ); + setArray( a, e, offset ); + updated = true; + + } + + return updated; + + } + +} + +function setArray( a, b, offset ) { + + for ( let i = 0, l = b.length; i < l; i ++ ) { + + a[ offset + i ] = b[ i ]; + + } + +} + +function arraysEqual( a, b, offset ) { + + for ( let i = 0, l = b.length; i < l; i ++ ) { + + if ( a[ offset + i ] !== b[ i ] ) return false; + + } + + return true; + +} + +let _id$3 = 0; + +class NodeUniformsGroup extends UniformsGroup { + + constructor( name, groupNode ) { + + super( name ); + + this.id = _id$3 ++; + this.groupNode = groupNode; + + this.isNodeUniformsGroup = true; + + } + + getNodes() { + + const nodes = []; + + for ( const uniform of this.uniforms ) { + + const node = uniform.nodeUniform.node; + + if ( ! node ) throw new Error( 'NodeUniformsGroup: Uniform has no node.' ); + + nodes.push( node ); + + } + + return nodes; + + } + +} + +let _id$2 = 0; + +class SampledTexture extends Binding { + + constructor( name, texture ) { + + super( name ); + + this.id = _id$2 ++; + + this.texture = texture; + this.version = texture ? texture.version : 0; + this.store = false; + this.generation = null; + + this.isSampledTexture = true; + + } + + needsBindingsUpdate( generation ) { + + const { texture } = this; + + if ( generation !== this.generation ) { + + this.generation = generation; + + return true; + + } + + return texture.isVideoTexture; + + } + + update() { + + const { texture, version } = this; + + if ( version !== texture.version ) { + + this.version = texture.version; + + return true; + + } + + return false; + + } + +} + +class NodeSampledTexture extends SampledTexture { + + constructor( name, textureNode, groupNode, access = null ) { + + super( name, textureNode ? textureNode.value : null ); + + this.textureNode = textureNode; + this.groupNode = groupNode; + + this.access = access; + + } + + needsBindingsUpdate( generation ) { + + return this.textureNode.value !== this.texture || super.needsBindingsUpdate( generation ); + + } + + update() { + + const { textureNode } = this; + + if ( this.texture !== textureNode.value ) { + + this.texture = textureNode.value; + + return true; + + } + + return super.update(); + + } + +} + +class NodeSampledCubeTexture extends NodeSampledTexture { + + constructor( name, textureNode, groupNode, access ) { + + super( name, textureNode, groupNode, access ); + + this.isSampledCubeTexture = true; + + } + +} + +class NodeSampledTexture3D extends NodeSampledTexture { + + constructor( name, textureNode, groupNode, access ) { + + super( name, textureNode, groupNode, access ); + + this.isSampledTexture3D = true; + + } + +} + +const glslMethods = { + atan2: 'atan', + textureDimensions: 'textureSize', + equals: 'equal' +}; + +const precisionLib = { + low: 'lowp', + medium: 'mediump', + high: 'highp' +}; + +const supports$1 = { + swizzleAssign: true, + storageBuffer: false +}; + +const defaultPrecisions = ` +precision highp float; +precision highp int; +precision highp sampler2D; +precision highp sampler3D; +precision highp samplerCube; +precision highp sampler2DArray; + +precision highp usampler2D; +precision highp usampler3D; +precision highp usamplerCube; +precision highp usampler2DArray; + +precision highp isampler2D; +precision highp isampler3D; +precision highp isamplerCube; +precision highp isampler2DArray; + +precision lowp sampler2DShadow; +`; + +class GLSLNodeBuilder extends NodeBuilder { + + constructor( object, renderer ) { + + super( object, renderer, new GLSLNodeParser() ); + + this.uniformGroups = {}; + this.transforms = []; + this.extensions = {}; + + this.useComparisonMethod = true; + + } + + needsColorSpaceToLinearSRGB( texture ) { + + return texture.isVideoTexture === true && texture.colorSpace !== NoColorSpace; + + } + + getMethod( method ) { + + return glslMethods[ method ] || method; + + } + + getOutputStructName() { + + return ''; + + } + + buildFunctionCode( shaderNode ) { + + const layout = shaderNode.layout; + const flowData = this.flowShaderNode( shaderNode ); + + const parameters = []; + + for ( const input of layout.inputs ) { + + parameters.push( this.getType( input.type ) + ' ' + input.name ); + + } + + // + + const code = `${ this.getType( layout.type ) } ${ layout.name }( ${ parameters.join( ', ' ) } ) { + + ${ flowData.vars } + +${ flowData.code } + return ${ flowData.result }; + +}`; + + // + + return code; + + } + + setupPBO( storageBufferNode ) { + + const attribute = storageBufferNode.value; + + if ( attribute.pbo === undefined ) { + + const originalArray = attribute.array; + const numElements = attribute.count * attribute.itemSize; + + const { itemSize } = attribute; + + const isInteger = attribute.array.constructor.name.toLowerCase().includes( 'int' ); + + let format = isInteger ? RedIntegerFormat : RedFormat; + + + if ( itemSize === 2 ) { + + format = isInteger ? RGIntegerFormat : RGFormat; + + } else if ( itemSize === 3 ) { + + format = isInteger ? RGBIntegerFormat : RGBFormat; + + } else if ( itemSize === 4 ) { + + format = isInteger ? RGBAIntegerFormat : RGBAFormat; + + } + + const typeMap = { + Float32Array: FloatType, + Uint8Array: UnsignedByteType, + Uint16Array: UnsignedShortType, + Uint32Array: UnsignedIntType, + Int8Array: ByteType, + Int16Array: ShortType, + Int32Array: IntType, + Uint8ClampedArray: UnsignedByteType, + }; + + const width = Math.pow( 2, Math.ceil( Math.log2( Math.sqrt( numElements / itemSize ) ) ) ); + let height = Math.ceil( ( numElements / itemSize ) / width ); + if ( width * height * itemSize < numElements ) height ++; // Ensure enough space + + const newSize = width * height * itemSize; + + const newArray = new originalArray.constructor( newSize ); + + newArray.set( originalArray, 0 ); + + attribute.array = newArray; + + const pboTexture = new DataTexture( attribute.array, width, height, format, typeMap[ attribute.array.constructor.name ] || FloatType ); + pboTexture.needsUpdate = true; + pboTexture.isPBOTexture = true; + + const pbo = new TextureNode( pboTexture, null, null ); + pbo.setPrecision( 'high' ); + + attribute.pboNode = pbo; + attribute.pbo = pbo.value; + + this.getUniformFromNode( attribute.pboNode, 'texture', this.shaderStage, this.context.label ); + + } + + } + + getPropertyName( node, shaderStage = this.shaderStage ) { + + if ( node.isNodeUniform && node.node.isTextureNode !== true && node.node.isBufferNode !== true ) { + + return shaderStage.charAt( 0 ) + '_' + node.name; + + } + + return super.getPropertyName( node, shaderStage ); + + } + + generatePBO( storageArrayElementNode ) { + + const { node, indexNode } = storageArrayElementNode; + const attribute = node.value; + + if ( this.renderer.backend.has( attribute ) ) { + + const attributeData = this.renderer.backend.get( attribute ); + attributeData.pbo = attribute.pbo; + + } + + + const nodeUniform = this.getUniformFromNode( attribute.pboNode, 'texture', this.shaderStage, this.context.label ); + const textureName = this.getPropertyName( nodeUniform ); + + this.increaseUsage( indexNode ); // force cache generate to be used as index in x,y + const indexSnippet = indexNode.build( this, 'uint' ); + + const elementNodeData = this.getDataFromNode( storageArrayElementNode ); + + let propertyName = elementNodeData.propertyName; + + if ( propertyName === undefined ) { + + // property element + + const nodeVar = this.getVarFromNode( storageArrayElementNode ); + + propertyName = this.getPropertyName( nodeVar ); + + // property size + + const bufferNodeData = this.getDataFromNode( node ); + + let propertySizeName = bufferNodeData.propertySizeName; + + if ( propertySizeName === undefined ) { + + propertySizeName = propertyName + 'Size'; + + this.getVarFromNode( node, propertySizeName, 'uint' ); + + this.addLineFlowCode( `${ propertySizeName } = uint( textureSize( ${ textureName }, 0 ).x )`, storageArrayElementNode ); + + bufferNodeData.propertySizeName = propertySizeName; + + } + + // + + const { itemSize } = attribute; + + const channel = '.' + vectorComponents.join( '' ).slice( 0, itemSize ); + const uvSnippet = `ivec2(${indexSnippet} % ${ propertySizeName }, ${indexSnippet} / ${ propertySizeName })`; + + const snippet = this.generateTextureLoad( null, textureName, uvSnippet, null, '0' ); + + // + + + let prefix = 'vec4'; + + if ( attribute.pbo.type === UnsignedIntType ) { + + prefix = 'uvec4'; + + } else if ( attribute.pbo.type === IntType ) { + + prefix = 'ivec4'; + + } + + this.addLineFlowCode( `${ propertyName } = ${prefix}(${ snippet })${channel}`, storageArrayElementNode ); + + elementNodeData.propertyName = propertyName; + + } + + return propertyName; + + } + + generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0' ) { + + if ( depthSnippet ) { + + return `texelFetch( ${ textureProperty }, ivec3( ${ uvIndexSnippet }, ${ depthSnippet } ), ${ levelSnippet } )`; + + } else { + + return `texelFetch( ${ textureProperty }, ${ uvIndexSnippet }, ${ levelSnippet } )`; + + } + + } + + generateTexture( texture, textureProperty, uvSnippet, depthSnippet ) { + + if ( texture.isDepthTexture ) { + + return `texture( ${ textureProperty }, ${ uvSnippet } ).x`; + + } else { + + if ( depthSnippet ) uvSnippet = `vec3( ${ uvSnippet }, ${ depthSnippet } )`; + + return `texture( ${ textureProperty }, ${ uvSnippet } )`; + + } + + } + + generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet ) { + + return `textureLod( ${ textureProperty }, ${ uvSnippet }, ${ levelSnippet } )`; + + } + + generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet ) { + + return `texture( ${ textureProperty }, ${ uvSnippet }, ${ biasSnippet } )`; + + } + + generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet ) { + + return `textureGrad( ${ textureProperty }, ${ uvSnippet }, ${ gradSnippet[ 0 ] }, ${ gradSnippet[ 1 ] } )`; + + } + + generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, shaderStage = this.shaderStage ) { + + if ( shaderStage === 'fragment' ) { + + return `texture( ${ textureProperty }, vec3( ${ uvSnippet }, ${ compareSnippet } ) )`; + + } else { + + console.error( `WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${ shaderStage } shader.` ); + + } + + } + + getVars( shaderStage ) { + + const snippets = []; + + const vars = this.vars[ shaderStage ]; + + if ( vars !== undefined ) { + + for ( const variable of vars ) { + + snippets.push( `${ this.getVar( variable.type, variable.name ) };` ); + + } + + } + + return snippets.join( '\n\t' ); + + } + + getUniforms( shaderStage ) { + + const uniforms = this.uniforms[ shaderStage ]; + + const bindingSnippets = []; + const uniformGroups = {}; + + for ( const uniform of uniforms ) { + + let snippet = null; + let group = false; + + if ( uniform.type === 'texture' ) { + + const texture = uniform.node.value; + + let typePrefix = ''; + + if ( texture.isDataTexture === true ) { + + + if ( texture.type === UnsignedIntType ) { + + typePrefix = 'u'; + + } else if ( texture.type === IntType ) { + + typePrefix = 'i'; + + } + + } + + if ( texture.compareFunction ) { + + snippet = `sampler2DShadow ${ uniform.name };`; + + } else if ( texture.isDataArrayTexture === true || texture.isCompressedArrayTexture === true ) { + + snippet = `${typePrefix}sampler2DArray ${ uniform.name };`; + + } else { + + snippet = `${typePrefix}sampler2D ${ uniform.name };`; + + } + + } else if ( uniform.type === 'cubeTexture' ) { + + snippet = `samplerCube ${ uniform.name };`; + + } else if ( uniform.type === 'texture3D' ) { + + snippet = `sampler3D ${ uniform.name };`; + + } else if ( uniform.type === 'buffer' ) { + + const bufferNode = uniform.node; + const bufferType = this.getType( bufferNode.bufferType ); + const bufferCount = bufferNode.bufferCount; + + const bufferCountSnippet = bufferCount > 0 ? bufferCount : ''; + snippet = `${bufferNode.name} {\n\t${ bufferType } ${ uniform.name }[${ bufferCountSnippet }];\n};\n`; + + } else { + + const vectorType = this.getVectorType( uniform.type ); + + snippet = `${ vectorType } ${ this.getPropertyName( uniform, shaderStage ) };`; + + group = true; + + } + + const precision = uniform.node.precision; + + if ( precision !== null ) { + + snippet = precisionLib[ precision ] + ' ' + snippet; + + } + + if ( group ) { + + snippet = '\t' + snippet; + + const groupName = uniform.groupNode.name; + const groupSnippets = uniformGroups[ groupName ] || ( uniformGroups[ groupName ] = [] ); + + groupSnippets.push( snippet ); + + } else { + + snippet = 'uniform ' + snippet; + + bindingSnippets.push( snippet ); + + } + + } + + let output = ''; + + for ( const name in uniformGroups ) { + + const groupSnippets = uniformGroups[ name ]; + + output += this._getGLSLUniformStruct( shaderStage + '_' + name, groupSnippets.join( '\n' ) ) + '\n'; + + } + + output += bindingSnippets.join( '\n' ); + + return output; + + } + + getTypeFromAttribute( attribute ) { + + let nodeType = super.getTypeFromAttribute( attribute ); + + if ( /^[iu]/.test( nodeType ) && attribute.gpuType !== IntType ) { + + let dataAttribute = attribute; + + if ( attribute.isInterleavedBufferAttribute ) dataAttribute = attribute.data; + + const array = dataAttribute.array; + + if ( ( array instanceof Uint32Array || array instanceof Int32Array ) === false ) { + + nodeType = nodeType.slice( 1 ); + + } + + } + + return nodeType; + + } + + getAttributes( shaderStage ) { + + let snippet = ''; + + if ( shaderStage === 'vertex' || shaderStage === 'compute' ) { + + const attributes = this.getAttributesArray(); + + let location = 0; + + for ( const attribute of attributes ) { + + snippet += `layout( location = ${ location ++ } ) in ${ attribute.type } ${ attribute.name };\n`; + + } + + } + + return snippet; + + } + + getStructMembers( struct ) { + + const snippets = []; + const members = struct.getMemberTypes(); + + for ( let i = 0; i < members.length; i ++ ) { + + const member = members[ i ]; + snippets.push( `layout( location = ${i} ) out ${ member} m${i};` ); + + } + + return snippets.join( '\n' ); + + } + + getStructs( shaderStage ) { + + const snippets = []; + const structs = this.structs[ shaderStage ]; + + if ( structs.length === 0 ) { + + return 'layout( location = 0 ) out vec4 fragColor;\n'; + + } + + for ( let index = 0, length = structs.length; index < length; index ++ ) { + + const struct = structs[ index ]; + + let snippet = '\n'; + snippet += this.getStructMembers( struct ); + snippet += '\n'; + + snippets.push( snippet ); + + } + + return snippets.join( '\n\n' ); + + } + + getVaryings( shaderStage ) { + + let snippet = ''; + + const varyings = this.varyings; + + if ( shaderStage === 'vertex' || shaderStage === 'compute' ) { + + for ( const varying of varyings ) { + + if ( shaderStage === 'compute' ) varying.needsInterpolation = true; + const type = varying.type; + const flat = type.includes( 'int' ) || type.includes( 'uv' ) || type.includes( 'iv' ) ? 'flat ' : ''; + + snippet += `${flat}${varying.needsInterpolation ? 'out' : '/*out*/'} ${type} ${varying.name};\n`; + + } + + } else if ( shaderStage === 'fragment' ) { + + for ( const varying of varyings ) { + + if ( varying.needsInterpolation ) { + + const type = varying.type; + const flat = type.includes( 'int' ) || type.includes( 'uv' ) || type.includes( 'iv' ) ? 'flat ' : ''; + + snippet += `${flat}in ${type} ${varying.name};\n`; + + } + + } + + } + + return snippet; + + } + + getVertexIndex() { + + return 'uint( gl_VertexID )'; + + } + + getInstanceIndex() { + + return 'uint( gl_InstanceID )'; + + } + + getInvocationLocalIndex() { + + const workgroupSize = this.object.workgroupSize; + + const size = workgroupSize.reduce( ( acc, curr ) => acc * curr, 1 ); + + return `uint( gl_InstanceID ) % ${size}u`; + + } + + getDrawIndex() { + + const extensions = this.renderer.backend.extensions; + + if ( extensions.has( 'WEBGL_multi_draw' ) ) { + + return 'uint( gl_DrawID )'; + + } + + return null; + + } + + getFrontFacing() { + + return 'gl_FrontFacing'; + + } + + getFragCoord() { + + return 'gl_FragCoord.xy'; + + } + + getFragDepth() { + + return 'gl_FragDepth'; + + } + + enableExtension( name, behavior, shaderStage = this.shaderStage ) { + + const map = this.extensions[ shaderStage ] || ( this.extensions[ shaderStage ] = new Map() ); + + if ( map.has( name ) === false ) { + + map.set( name, { + name, + behavior + } ); + + } + + } + + getExtensions( shaderStage ) { + + const snippets = []; + + if ( shaderStage === 'vertex' ) { + + const ext = this.renderer.backend.extensions; + const isBatchedMesh = this.object.isBatchedMesh; + + if ( isBatchedMesh && ext.has( 'WEBGL_multi_draw' ) ) { + + this.enableExtension( 'GL_ANGLE_multi_draw', 'require', shaderStage ); + + } + + } + + const extensions = this.extensions[ shaderStage ]; + + if ( extensions !== undefined ) { + + for ( const { name, behavior } of extensions.values() ) { + + snippets.push( `#extension ${name} : ${behavior}` ); + + } + + } + + return snippets.join( '\n' ); + + } + + isAvailable( name ) { + + let result = supports$1[ name ]; + + if ( result === undefined ) { + + if ( name === 'float32Filterable' ) { + + const extensions = this.renderer.backend.extensions; + + if ( extensions.has( 'OES_texture_float_linear' ) ) { + + extensions.get( 'OES_texture_float_linear' ); + result = true; + + } else { + + result = false; + + } + + } + + supports$1[ name ] = result; + + } + + return result; + + } + + isFlipY() { + + return true; + + } + + registerTransform( varyingName, attributeNode ) { + + this.transforms.push( { varyingName, attributeNode } ); + + } + + getTransforms( /* shaderStage */ ) { + + const transforms = this.transforms; + + let snippet = ''; + + for ( let i = 0; i < transforms.length; i ++ ) { + + const transform = transforms[ i ]; + + const attributeName = this.getPropertyName( transform.attributeNode ); + + snippet += `${ transform.varyingName } = ${ attributeName };\n\t`; + + } + + return snippet; + + } + + _getGLSLUniformStruct( name, vars ) { + + return ` +layout( std140 ) uniform ${name} { +${vars} +};`; + + } + + _getGLSLVertexCode( shaderData ) { + + return `#version 300 es + +${ this.getSignature() } + +// extensions +${shaderData.extensions} + +// precision +${ defaultPrecisions } + +// uniforms +${shaderData.uniforms} + +// varyings +${shaderData.varyings} + +// attributes +${shaderData.attributes} + +// codes +${shaderData.codes} + +void main() { + + // vars + ${shaderData.vars} + + // transforms + ${shaderData.transforms} + + // flow + ${shaderData.flow} + + gl_PointSize = 1.0; + +} +`; + + } + + _getGLSLFragmentCode( shaderData ) { + + return `#version 300 es + +${ this.getSignature() } + +// precision +${ defaultPrecisions } + +// uniforms +${shaderData.uniforms} + +// varyings +${shaderData.varyings} + +// codes +${shaderData.codes} + +${shaderData.structs} + +void main() { + + // vars + ${shaderData.vars} + + // flow + ${shaderData.flow} + +} +`; + + } + + buildCode() { + + const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; + + this.sortBindingGroups(); + + for ( const shaderStage in shadersData ) { + + let flow = '// code\n\n'; + flow += this.flowCode[ shaderStage ]; + + const flowNodes = this.flowNodes[ shaderStage ]; + const mainNode = flowNodes[ flowNodes.length - 1 ]; + + for ( const node of flowNodes ) { + + const flowSlotData = this.getFlowData( node/*, shaderStage*/ ); + const slotName = node.name; + + if ( slotName ) { + + if ( flow.length > 0 ) flow += '\n'; + + flow += `\t// flow -> ${ slotName }\n\t`; + + } + + flow += `${ flowSlotData.code }\n\t`; + + if ( node === mainNode && shaderStage !== 'compute' ) { + + flow += '// result\n\t'; + + if ( shaderStage === 'vertex' ) { + + flow += 'gl_Position = '; + flow += `${ flowSlotData.result };`; + + } else if ( shaderStage === 'fragment' ) { + + if ( ! node.outputNode.isOutputStructNode ) { + + flow += 'fragColor = '; + flow += `${ flowSlotData.result };`; + + } + + } + + } + + } + + const stageData = shadersData[ shaderStage ]; + + stageData.extensions = this.getExtensions( shaderStage ); + stageData.uniforms = this.getUniforms( shaderStage ); + stageData.attributes = this.getAttributes( shaderStage ); + stageData.varyings = this.getVaryings( shaderStage ); + stageData.vars = this.getVars( shaderStage ); + stageData.structs = this.getStructs( shaderStage ); + stageData.codes = this.getCodes( shaderStage ); + stageData.transforms = this.getTransforms( shaderStage ); + stageData.flow = flow; + + } + + if ( this.material !== null ) { + + this.vertexShader = this._getGLSLVertexCode( shadersData.vertex ); + this.fragmentShader = this._getGLSLFragmentCode( shadersData.fragment ); + + } else { + + this.computeShader = this._getGLSLVertexCode( shadersData.compute ); + + } + + } + + getUniformFromNode( node, type, shaderStage, name = null ) { + + const uniformNode = super.getUniformFromNode( node, type, shaderStage, name ); + const nodeData = this.getDataFromNode( node, shaderStage, this.globalCache ); + + let uniformGPU = nodeData.uniformGPU; + + if ( uniformGPU === undefined ) { + + const group = node.groupNode; + const groupName = group.name; + + const bindings = this.getBindGroupArray( groupName, shaderStage ); + + if ( type === 'texture' ) { + + uniformGPU = new NodeSampledTexture( uniformNode.name, uniformNode.node, group ); + bindings.push( uniformGPU ); + + } else if ( type === 'cubeTexture' ) { + + uniformGPU = new NodeSampledCubeTexture( uniformNode.name, uniformNode.node, group ); + bindings.push( uniformGPU ); + + } else if ( type === 'texture3D' ) { + + uniformGPU = new NodeSampledTexture3D( uniformNode.name, uniformNode.node, group ); + bindings.push( uniformGPU ); + + } else if ( type === 'buffer' ) { + + node.name = `NodeBuffer_${ node.id }`; + uniformNode.name = `buffer${ node.id }`; + + const buffer = new NodeUniformBuffer( node, group ); + buffer.name = node.name; + + bindings.push( buffer ); + + uniformGPU = buffer; + + } else { + + const uniformsStage = this.uniformGroups[ shaderStage ] || ( this.uniformGroups[ shaderStage ] = {} ); + + let uniformsGroup = uniformsStage[ groupName ]; + + if ( uniformsGroup === undefined ) { + + uniformsGroup = new NodeUniformsGroup( shaderStage + '_' + groupName, group ); + //uniformsGroup.setVisibility( gpuShaderStageLib[ shaderStage ] ); + + uniformsStage[ groupName ] = uniformsGroup; + + bindings.push( uniformsGroup ); + + } + + uniformGPU = this.getNodeUniform( uniformNode, type ); + + uniformsGroup.addUniform( uniformGPU ); + + } + + nodeData.uniformGPU = uniformGPU; + + } + + return uniformNode; + + } + +} + +let vector2 = null; +let vector4 = null; +let color4 = null; + +class Backend { + + constructor( parameters = {} ) { + + this.parameters = Object.assign( {}, parameters ); + this.data = new WeakMap(); + this.renderer = null; + this.domElement = null; + + } + + async init( renderer ) { + + this.renderer = renderer; + + } + + // render context + + begin( /*renderContext*/ ) { } + + finish( /*renderContext*/ ) { } + + // render object + + draw( /*renderObject, info*/ ) { } + + // program + + createProgram( /*program*/ ) { } + + destroyProgram( /*program*/ ) { } + + // bindings + + createBindings( /*bingGroup, bindings*/ ) { } + + updateBindings( /*bingGroup, bindings*/ ) { } + + // pipeline + + createRenderPipeline( /*renderObject*/ ) { } + + createComputePipeline( /*computeNode, pipeline*/ ) { } + + destroyPipeline( /*pipeline*/ ) { } + + // cache key + + needsRenderUpdate( /*renderObject*/ ) { } // return Boolean ( fast test ) + + getRenderCacheKey( /*renderObject*/ ) { } // return String + + // node builder + + createNodeBuilder( /*renderObject*/ ) { } // return NodeBuilder (ADD IT) + + // textures + + createSampler( /*texture*/ ) { } + + createDefaultTexture( /*texture*/ ) { } + + createTexture( /*texture*/ ) { } + + copyTextureToBuffer( /*texture, x, y, width, height*/ ) {} + + // attributes + + createAttribute( /*attribute*/ ) { } + + createIndexAttribute( /*attribute*/ ) { } + + updateAttribute( /*attribute*/ ) { } + + destroyAttribute( /*attribute*/ ) { } + + // canvas + + getContext() { } + + updateSize() { } + + // utils + + resolveTimestampAsync( /*renderContext, type*/ ) { } + + hasFeatureAsync( /*name*/ ) { } // return Boolean + + hasFeature( /*name*/ ) { } // return Boolean + + getInstanceCount( renderObject ) { + + const { object, geometry } = renderObject; + + return geometry.isInstancedBufferGeometry ? geometry.instanceCount : ( object.count > 1 ? object.count : 1 ); + + } + + getDrawingBufferSize() { + + vector2 = vector2 || new Vector2(); + + return this.renderer.getDrawingBufferSize( vector2 ); + + } + + getScissor() { + + vector4 = vector4 || new Vector4(); + + return this.renderer.getScissor( vector4 ); + + } + + setScissorTest( /*boolean*/ ) { } + + getClearColor() { + + const renderer = this.renderer; + + color4 = color4 || new Color4(); + + renderer.getClearColor( color4 ); + + color4.getRGB( color4, this.renderer.currentColorSpace ); + + return color4; + + } + + getDomElement() { + + let domElement = this.domElement; + + if ( domElement === null ) { + + domElement = ( this.parameters.canvas !== undefined ) ? this.parameters.canvas : createCanvasElement(); + + // OffscreenCanvas does not have setAttribute, see #22811 + if ( 'setAttribute' in domElement ) domElement.setAttribute( 'data-engine', `three.js r${REVISION} webgpu` ); + + this.domElement = domElement; + + } + + return domElement; + + } + + // resource properties + + set( object, value ) { + + this.data.set( object, value ); + + } + + get( object ) { + + let map = this.data.get( object ); + + if ( map === undefined ) { + + map = {}; + this.data.set( object, map ); + + } + + return map; + + } + + has( object ) { + + return this.data.has( object ); + + } + + delete( object ) { + + this.data.delete( object ); + + } + +} + +let _id$1 = 0; + +class DualAttributeData { + + constructor( attributeData, dualBuffer ) { + + this.buffers = [ attributeData.bufferGPU, dualBuffer ]; + this.type = attributeData.type; + this.bufferType = attributeData.bufferType; + this.pbo = attributeData.pbo; + this.byteLength = attributeData.byteLength; + this.bytesPerElement = attributeData.BYTES_PER_ELEMENT; + this.version = attributeData.version; + this.isInteger = attributeData.isInteger; + this.activeBufferIndex = 0; + this.baseId = attributeData.id; + + } + + + get id() { + + return `${ this.baseId }|${ this.activeBufferIndex }`; + + } + + get bufferGPU() { + + return this.buffers[ this.activeBufferIndex ]; + + } + + get transformBuffer() { + + return this.buffers[ this.activeBufferIndex ^ 1 ]; + + } + + switchBuffers() { + + this.activeBufferIndex ^= 1; + + } + +} + +class WebGLAttributeUtils { + + constructor( backend ) { + + this.backend = backend; + + } + + createAttribute( attribute, bufferType ) { + + const backend = this.backend; + const { gl } = backend; + + const array = attribute.array; + const usage = attribute.usage || gl.STATIC_DRAW; + + const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute; + const bufferData = backend.get( bufferAttribute ); + + let bufferGPU = bufferData.bufferGPU; + + if ( bufferGPU === undefined ) { + + bufferGPU = this._createBuffer( gl, bufferType, array, usage ); + + bufferData.bufferGPU = bufferGPU; + bufferData.bufferType = bufferType; + bufferData.version = bufferAttribute.version; + + } + + //attribute.onUploadCallback(); + + let type; + + if ( array instanceof Float32Array ) { + + type = gl.FLOAT; + + } else if ( array instanceof Uint16Array ) { + + if ( attribute.isFloat16BufferAttribute ) { + + type = gl.HALF_FLOAT; + + } else { + + type = gl.UNSIGNED_SHORT; + + } + + } else if ( array instanceof Int16Array ) { + + type = gl.SHORT; + + } else if ( array instanceof Uint32Array ) { + + type = gl.UNSIGNED_INT; + + } else if ( array instanceof Int32Array ) { + + type = gl.INT; + + } else if ( array instanceof Int8Array ) { + + type = gl.BYTE; + + } else if ( array instanceof Uint8Array ) { + + type = gl.UNSIGNED_BYTE; + + } else if ( array instanceof Uint8ClampedArray ) { + + type = gl.UNSIGNED_BYTE; + + } else { + + throw new Error( 'THREE.WebGLBackend: Unsupported buffer data format: ' + array ); + + } + + let attributeData = { + bufferGPU, + bufferType, + type, + byteLength: array.byteLength, + bytesPerElement: array.BYTES_PER_ELEMENT, + version: attribute.version, + pbo: attribute.pbo, + isInteger: type === gl.INT || type === gl.UNSIGNED_INT || attribute.gpuType === IntType, + id: _id$1 ++ + }; + + if ( attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute ) { + + // create buffer for tranform feedback use + const bufferGPUDual = this._createBuffer( gl, bufferType, array, usage ); + attributeData = new DualAttributeData( attributeData, bufferGPUDual ); + + } + + backend.set( attribute, attributeData ); + + } + + updateAttribute( attribute ) { + + const backend = this.backend; + const { gl } = backend; + + const array = attribute.array; + const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute; + const bufferData = backend.get( bufferAttribute ); + const bufferType = bufferData.bufferType; + const updateRanges = attribute.isInterleavedBufferAttribute ? attribute.data.updateRanges : attribute.updateRanges; + + gl.bindBuffer( bufferType, bufferData.bufferGPU ); + + if ( updateRanges.length === 0 ) { + + // Not using update ranges + + gl.bufferSubData( bufferType, 0, array ); + + } else { + + for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { + + const range = updateRanges[ i ]; + gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, + array, range.start, range.count ); + + } + + bufferAttribute.clearUpdateRanges(); + + } + + gl.bindBuffer( bufferType, null ); + + bufferData.version = bufferAttribute.version; + + } + + destroyAttribute( attribute ) { + + const backend = this.backend; + const { gl } = backend; + + if ( attribute.isInterleavedBufferAttribute ) { + + backend.delete( attribute.data ); + + } + + const attributeData = backend.get( attribute ); + + gl.deleteBuffer( attributeData.bufferGPU ); + + backend.delete( attribute ); + + } + + async getArrayBufferAsync( attribute ) { + + const backend = this.backend; + const { gl } = backend; + + const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute; + const { bufferGPU } = backend.get( bufferAttribute ); + + const array = attribute.array; + const byteLength = array.byteLength; + + gl.bindBuffer( gl.COPY_READ_BUFFER, bufferGPU ); + + const writeBuffer = gl.createBuffer(); + + gl.bindBuffer( gl.COPY_WRITE_BUFFER, writeBuffer ); + gl.bufferData( gl.COPY_WRITE_BUFFER, byteLength, gl.STREAM_READ ); + + gl.copyBufferSubData( gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, byteLength ); + + await backend.utils._clientWaitAsync(); + + const dstBuffer = new attribute.array.constructor( array.length ); + + // Ensure the buffer is bound before reading + gl.bindBuffer( gl.COPY_WRITE_BUFFER, writeBuffer ); + + gl.getBufferSubData( gl.COPY_WRITE_BUFFER, 0, dstBuffer ); + + gl.deleteBuffer( writeBuffer ); + + gl.bindBuffer( gl.COPY_READ_BUFFER, null ); + gl.bindBuffer( gl.COPY_WRITE_BUFFER, null ); + + return dstBuffer.buffer; + + } + + _createBuffer( gl, bufferType, array, usage ) { + + const bufferGPU = gl.createBuffer(); + + gl.bindBuffer( bufferType, bufferGPU ); + gl.bufferData( bufferType, array, usage ); + gl.bindBuffer( bufferType, null ); + + return bufferGPU; + + } + +} + +let initialized$1 = false, equationToGL, factorToGL; + +class WebGLState { + + constructor( backend ) { + + this.backend = backend; + + this.gl = this.backend.gl; + + this.enabled = {}; + this.currentFlipSided = null; + this.currentCullFace = null; + this.currentProgram = null; + this.currentBlendingEnabled = false; + this.currentBlending = null; + this.currentBlendSrc = null; + this.currentBlendDst = null; + this.currentBlendSrcAlpha = null; + this.currentBlendDstAlpha = null; + this.currentPremultipledAlpha = null; + this.currentPolygonOffsetFactor = null; + this.currentPolygonOffsetUnits = null; + this.currentColorMask = null; + this.currentDepthFunc = null; + this.currentDepthMask = null; + this.currentStencilFunc = null; + this.currentStencilRef = null; + this.currentStencilFuncMask = null; + this.currentStencilFail = null; + this.currentStencilZFail = null; + this.currentStencilZPass = null; + this.currentStencilMask = null; + this.currentLineWidth = null; + + this.currentBoundFramebuffers = {}; + this.currentDrawbuffers = new WeakMap(); + + this.maxTextures = this.gl.getParameter( this.gl.MAX_TEXTURE_IMAGE_UNITS ); + this.currentTextureSlot = null; + this.currentBoundTextures = {}; + this.currentBoundBufferBases = {}; + + if ( initialized$1 === false ) { + + this._init( this.gl ); + + initialized$1 = true; + + } + + } + + _init( gl ) { + + // Store only WebGL constants here. + + equationToGL = { + [ AddEquation ]: gl.FUNC_ADD, + [ SubtractEquation ]: gl.FUNC_SUBTRACT, + [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT + }; + + factorToGL = { + [ ZeroFactor ]: gl.ZERO, + [ OneFactor ]: gl.ONE, + [ SrcColorFactor ]: gl.SRC_COLOR, + [ SrcAlphaFactor ]: gl.SRC_ALPHA, + [ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE, + [ DstColorFactor ]: gl.DST_COLOR, + [ DstAlphaFactor ]: gl.DST_ALPHA, + [ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR, + [ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA, + [ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR, + [ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA + }; + + } + + enable( id ) { + + const { enabled } = this; + + if ( enabled[ id ] !== true ) { + + this.gl.enable( id ); + enabled[ id ] = true; + + } + + } + + disable( id ) { + + const { enabled } = this; + + if ( enabled[ id ] !== false ) { + + this.gl.disable( id ); + enabled[ id ] = false; + + } + + } + + setFlipSided( flipSided ) { + + if ( this.currentFlipSided !== flipSided ) { + + const { gl } = this; + + if ( flipSided ) { + + gl.frontFace( gl.CW ); + + } else { + + gl.frontFace( gl.CCW ); + + } + + this.currentFlipSided = flipSided; + + } + + } + + setCullFace( cullFace ) { + + const { gl } = this; + + if ( cullFace !== CullFaceNone ) { + + this.enable( gl.CULL_FACE ); + + if ( cullFace !== this.currentCullFace ) { + + if ( cullFace === CullFaceBack ) { + + gl.cullFace( gl.BACK ); + + } else if ( cullFace === CullFaceFront ) { + + gl.cullFace( gl.FRONT ); + + } else { + + gl.cullFace( gl.FRONT_AND_BACK ); + + } + + } + + } else { + + this.disable( gl.CULL_FACE ); + + } + + this.currentCullFace = cullFace; + + } + + setLineWidth( width ) { + + const { currentLineWidth, gl } = this; + + if ( width !== currentLineWidth ) { + + gl.lineWidth( width ); + + this.currentLineWidth = width; + + } + + } + + + setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { + + const { gl } = this; + + if ( blending === NoBlending ) { + + if ( this.currentBlendingEnabled === true ) { + + this.disable( gl.BLEND ); + this.currentBlendingEnabled = false; + + } + + return; + + } + + if ( this.currentBlendingEnabled === false ) { + + this.enable( gl.BLEND ); + this.currentBlendingEnabled = true; + + } + + if ( blending !== CustomBlending ) { + + if ( blending !== this.currentBlending || premultipliedAlpha !== this.currentPremultipledAlpha ) { + + if ( this.currentBlendEquation !== AddEquation || this.currentBlendEquationAlpha !== AddEquation ) { + + gl.blendEquation( gl.FUNC_ADD ); + + this.currentBlendEquation = AddEquation; + this.currentBlendEquationAlpha = AddEquation; + + } + + if ( premultipliedAlpha ) { + + switch ( blending ) { + + case NormalBlending: + gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); + break; + + case AdditiveBlending: + gl.blendFunc( gl.ONE, gl.ONE ); + break; + + case SubtractiveBlending: + gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); + break; + + case MultiplyBlending: + gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA ); + break; + + default: + console.error( 'THREE.WebGLState: Invalid blending: ', blending ); + break; + + } + + } else { + + switch ( blending ) { + + case NormalBlending: + gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); + break; + + case AdditiveBlending: + gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); + break; + + case SubtractiveBlending: + gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); + break; + + case MultiplyBlending: + gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); + break; + + default: + console.error( 'THREE.WebGLState: Invalid blending: ', blending ); + break; + + } + + } + + this.currentBlendSrc = null; + this.currentBlendDst = null; + this.currentBlendSrcAlpha = null; + this.currentBlendDstAlpha = null; + + this.currentBlending = blending; + this.currentPremultipledAlpha = premultipliedAlpha; + + } + + return; + + } + + // custom blending + + blendEquationAlpha = blendEquationAlpha || blendEquation; + blendSrcAlpha = blendSrcAlpha || blendSrc; + blendDstAlpha = blendDstAlpha || blendDst; + + if ( blendEquation !== this.currentBlendEquation || blendEquationAlpha !== this.currentBlendEquationAlpha ) { + + gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] ); + + this.currentBlendEquation = blendEquation; + this.currentBlendEquationAlpha = blendEquationAlpha; + + } + + if ( blendSrc !== this.currentBlendSrc || blendDst !== this.currentBlendDst || blendSrcAlpha !== this.currentBlendSrcAlpha || blendDstAlpha !== this.currentBlendDstAlpha ) { + + gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] ); + + this.currentBlendSrc = blendSrc; + this.currentBlendDst = blendDst; + this.currentBlendSrcAlpha = blendSrcAlpha; + this.currentBlendDstAlpha = blendDstAlpha; + + } + + this.currentBlending = blending; + this.currentPremultipledAlpha = false; + + } + + setColorMask( colorMask ) { + + if ( this.currentColorMask !== colorMask ) { + + this.gl.colorMask( colorMask, colorMask, colorMask, colorMask ); + this.currentColorMask = colorMask; + + } + + } + + setDepthTest( depthTest ) { + + const { gl } = this; + + if ( depthTest ) { + + this.enable( gl.DEPTH_TEST ); + + } else { + + this.disable( gl.DEPTH_TEST ); + + } + + } + + setDepthMask( depthMask ) { + + if ( this.currentDepthMask !== depthMask ) { + + this.gl.depthMask( depthMask ); + this.currentDepthMask = depthMask; + + } + + } + + setDepthFunc( depthFunc ) { + + if ( this.currentDepthFunc !== depthFunc ) { + + const { gl } = this; + + switch ( depthFunc ) { + + case NeverDepth: + + gl.depthFunc( gl.NEVER ); + break; + + case AlwaysDepth: + + gl.depthFunc( gl.ALWAYS ); + break; + + case LessDepth: + + gl.depthFunc( gl.LESS ); + break; + + case LessEqualDepth: + + gl.depthFunc( gl.LEQUAL ); + break; + + case EqualDepth: + + gl.depthFunc( gl.EQUAL ); + break; + + case GreaterEqualDepth: + + gl.depthFunc( gl.GEQUAL ); + break; + + case GreaterDepth: + + gl.depthFunc( gl.GREATER ); + break; + + case NotEqualDepth: + + gl.depthFunc( gl.NOTEQUAL ); + break; + + default: + + gl.depthFunc( gl.LEQUAL ); + + } + + this.currentDepthFunc = depthFunc; + + } + + } + + setStencilTest( stencilTest ) { + + const { gl } = this; + + if ( stencilTest ) { + + this.enable( gl.STENCIL_TEST ); + + } else { + + this.disable( gl.STENCIL_TEST ); + + } + + } + + setStencilMask( stencilMask ) { + + if ( this.currentStencilMask !== stencilMask ) { + + this.gl.stencilMask( stencilMask ); + this.currentStencilMask = stencilMask; + + } + + } + + setStencilFunc( stencilFunc, stencilRef, stencilMask ) { + + if ( this.currentStencilFunc !== stencilFunc || + this.currentStencilRef !== stencilRef || + this.currentStencilFuncMask !== stencilMask ) { + + this.gl.stencilFunc( stencilFunc, stencilRef, stencilMask ); + + this.currentStencilFunc = stencilFunc; + this.currentStencilRef = stencilRef; + this.currentStencilFuncMask = stencilMask; + + } + + } + + setStencilOp( stencilFail, stencilZFail, stencilZPass ) { + + if ( this.currentStencilFail !== stencilFail || + this.currentStencilZFail !== stencilZFail || + this.currentStencilZPass !== stencilZPass ) { + + this.gl.stencilOp( stencilFail, stencilZFail, stencilZPass ); + + this.currentStencilFail = stencilFail; + this.currentStencilZFail = stencilZFail; + this.currentStencilZPass = stencilZPass; + + } + + } + + setMaterial( material, frontFaceCW ) { + + const { gl } = this; + + material.side === DoubleSide + ? this.disable( gl.CULL_FACE ) + : this.enable( gl.CULL_FACE ); + + let flipSided = ( material.side === BackSide ); + if ( frontFaceCW ) flipSided = ! flipSided; + + this.setFlipSided( flipSided ); + + ( material.blending === NormalBlending && material.transparent === false ) + ? this.setBlending( NoBlending ) + : this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ); + + this.setDepthFunc( material.depthFunc ); + this.setDepthTest( material.depthTest ); + this.setDepthMask( material.depthWrite ); + this.setColorMask( material.colorWrite ); + + const stencilWrite = material.stencilWrite; + this.setStencilTest( stencilWrite ); + if ( stencilWrite ) { + + this.setStencilMask( material.stencilWriteMask ); + this.setStencilFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask ); + this.setStencilOp( material.stencilFail, material.stencilZFail, material.stencilZPass ); + + } + + this.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + + material.alphaToCoverage === true && this.backend.renderer.samples > 1 + ? this.enable( gl.SAMPLE_ALPHA_TO_COVERAGE ) + : this.disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); + + } + + setPolygonOffset( polygonOffset, factor, units ) { + + const { gl } = this; + + if ( polygonOffset ) { + + this.enable( gl.POLYGON_OFFSET_FILL ); + + if ( this.currentPolygonOffsetFactor !== factor || this.currentPolygonOffsetUnits !== units ) { + + gl.polygonOffset( factor, units ); + + this.currentPolygonOffsetFactor = factor; + this.currentPolygonOffsetUnits = units; + + } + + } else { + + this.disable( gl.POLYGON_OFFSET_FILL ); + + } + + } + + useProgram( program ) { + + if ( this.currentProgram !== program ) { + + this.gl.useProgram( program ); + + this.currentProgram = program; + + return true; + + } + + return false; + + } + + // framebuffer + + + bindFramebuffer( target, framebuffer ) { + + const { gl, currentBoundFramebuffers } = this; + + if ( currentBoundFramebuffers[ target ] !== framebuffer ) { + + gl.bindFramebuffer( target, framebuffer ); + + currentBoundFramebuffers[ target ] = framebuffer; + + // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER + + if ( target === gl.DRAW_FRAMEBUFFER ) { + + currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer; + + } + + if ( target === gl.FRAMEBUFFER ) { + + currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer; + + } + + return true; + + } + + return false; + + } + + drawBuffers( renderContext, framebuffer ) { + + const { gl } = this; + + let drawBuffers = []; + + let needsUpdate = false; + + if ( renderContext.textures !== null ) { + + drawBuffers = this.currentDrawbuffers.get( framebuffer ); + + if ( drawBuffers === undefined ) { + + drawBuffers = []; + this.currentDrawbuffers.set( framebuffer, drawBuffers ); + + } + + + const textures = renderContext.textures; + + if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { + + for ( let i = 0, il = textures.length; i < il; i ++ ) { + + drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i; + + } + + drawBuffers.length = textures.length; + + needsUpdate = true; + + } + + + } else { + + if ( drawBuffers[ 0 ] !== gl.BACK ) { + + drawBuffers[ 0 ] = gl.BACK; + + needsUpdate = true; + + } + + } + + if ( needsUpdate ) { + + gl.drawBuffers( drawBuffers ); + + } + + } + + + // texture + + activeTexture( webglSlot ) { + + const { gl, currentTextureSlot, maxTextures } = this; + + if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; + + if ( currentTextureSlot !== webglSlot ) { + + gl.activeTexture( webglSlot ); + this.currentTextureSlot = webglSlot; + + } + + } + + bindTexture( webglType, webglTexture, webglSlot ) { + + const { gl, currentTextureSlot, currentBoundTextures, maxTextures } = this; + + if ( webglSlot === undefined ) { + + if ( currentTextureSlot === null ) { + + webglSlot = gl.TEXTURE0 + maxTextures - 1; + + } else { + + webglSlot = currentTextureSlot; + + } + + } + + let boundTexture = currentBoundTextures[ webglSlot ]; + + if ( boundTexture === undefined ) { + + boundTexture = { type: undefined, texture: undefined }; + currentBoundTextures[ webglSlot ] = boundTexture; + + } + + if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { + + if ( currentTextureSlot !== webglSlot ) { + + gl.activeTexture( webglSlot ); + this.currentTextureSlot = webglSlot; + + } + + gl.bindTexture( webglType, webglTexture ); + + boundTexture.type = webglType; + boundTexture.texture = webglTexture; + + } + + } + + bindBufferBase( target, index, buffer ) { + + const { gl } = this; + + const key = `${target}-${index}`; + + if ( this.currentBoundBufferBases[ key ] !== buffer ) { + + gl.bindBufferBase( target, index, buffer ); + this.currentBoundBufferBases[ key ] = buffer; + + return true; + + } + + return false; + + } + + + unbindTexture() { + + const { gl, currentTextureSlot, currentBoundTextures } = this; + + const boundTexture = currentBoundTextures[ currentTextureSlot ]; + + if ( boundTexture !== undefined && boundTexture.type !== undefined ) { + + gl.bindTexture( boundTexture.type, null ); + + boundTexture.type = undefined; + boundTexture.texture = undefined; + + } + + } + +} + +class WebGLUtils { + + constructor( backend ) { + + this.backend = backend; + + this.gl = this.backend.gl; + this.extensions = backend.extensions; + + } + + convert( p, colorSpace = NoColorSpace ) { + + const { gl, extensions } = this; + + let extension; + + if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE; + if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4; + if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1; + if ( p === UnsignedInt5999Type ) return gl.UNSIGNED_INT_5_9_9_9_REV; + + if ( p === ByteType ) return gl.BYTE; + if ( p === ShortType ) return gl.SHORT; + if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT; + if ( p === IntType ) return gl.INT; + if ( p === UnsignedIntType ) return gl.UNSIGNED_INT; + if ( p === FloatType ) return gl.FLOAT; + + if ( p === HalfFloatType ) { + + return gl.HALF_FLOAT; + + } + + if ( p === AlphaFormat ) return gl.ALPHA; + if ( p === RGBFormat ) return gl.RGB; + if ( p === RGBAFormat ) return gl.RGBA; + if ( p === LuminanceFormat ) return gl.LUMINANCE; + if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA; + if ( p === DepthFormat ) return gl.DEPTH_COMPONENT; + if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL; + + // WebGL2 formats. + + if ( p === RedFormat ) return gl.RED; + if ( p === RedIntegerFormat ) return gl.RED_INTEGER; + if ( p === RGFormat ) return gl.RG; + if ( p === RGIntegerFormat ) return gl.RG_INTEGER; + if ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER; + + // S3TC + + if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { + + if ( colorSpace === SRGBColorSpace ) { + + extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' ); + + if ( extension !== null ) { + + if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT; + if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + + } else { + + return null; + + } + + } else { + + extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); + + if ( extension !== null ) { + + if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; + if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; + if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; + if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; + + } else { + + return null; + + } + + } + + } + + // PVRTC + + if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { + + extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); + + if ( extension !== null ) { + + if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + + } else { + + return null; + + } + + } + + // ETC + + if ( p === RGB_ETC1_Format || p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) { + + extension = extensions.get( 'WEBGL_compressed_texture_etc' ); + + if ( extension !== null ) { + + if ( p === RGB_ETC1_Format || p === RGB_ETC2_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; + if ( p === RGBA_ETC2_EAC_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; + + } else { + + return null; + + } + + } + + // ASTC + + if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || + p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || + p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || + p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || + p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) { + + extension = extensions.get( 'WEBGL_compressed_texture_astc' ); + + if ( extension !== null ) { + + if ( p === RGBA_ASTC_4x4_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; + if ( p === RGBA_ASTC_5x4_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; + if ( p === RGBA_ASTC_5x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; + if ( p === RGBA_ASTC_6x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; + if ( p === RGBA_ASTC_6x6_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; + if ( p === RGBA_ASTC_8x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; + if ( p === RGBA_ASTC_8x6_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; + if ( p === RGBA_ASTC_8x8_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; + if ( p === RGBA_ASTC_10x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; + if ( p === RGBA_ASTC_10x6_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; + if ( p === RGBA_ASTC_10x8_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; + if ( p === RGBA_ASTC_10x10_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; + if ( p === RGBA_ASTC_12x10_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; + if ( p === RGBA_ASTC_12x12_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; + + } else { + + return null; + + } + + } + + // BPTC + + if ( p === RGBA_BPTC_Format ) { + + extension = extensions.get( 'EXT_texture_compression_bptc' ); + + if ( extension !== null ) { + + if ( p === RGBA_BPTC_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; + + } else { + + return null; + + } + + } + + // RGTC + + if ( p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format ) { + + extension = extensions.get( 'EXT_texture_compression_rgtc' ); + + if ( extension !== null ) { + + if ( p === RGBA_BPTC_Format ) return extension.COMPRESSED_RED_RGTC1_EXT; + if ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT; + if ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT; + if ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT; + + } else { + + return null; + + } + + } + + // + + if ( p === UnsignedInt248Type ) { + + return gl.UNSIGNED_INT_24_8; + + } + + // if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats) + + return ( gl[ p ] !== undefined ) ? gl[ p ] : null; + + } + + _clientWaitAsync() { + + const { gl } = this; + + const sync = gl.fenceSync( gl.SYNC_GPU_COMMANDS_COMPLETE, 0 ); + + gl.flush(); + + return new Promise( ( resolve, reject ) => { + + function test() { + + const res = gl.clientWaitSync( sync, gl.SYNC_FLUSH_COMMANDS_BIT, 0 ); + + if ( res === gl.WAIT_FAILED ) { + + gl.deleteSync( sync ); + + reject(); + return; + + } + + if ( res === gl.TIMEOUT_EXPIRED ) { + + requestAnimationFrame( test ); + return; + + } + + gl.deleteSync( sync ); + + resolve(); + + } + + test(); + + } ); + + } + +} + +let initialized = false, wrappingToGL, filterToGL, compareToGL; + +class WebGLTextureUtils { + + constructor( backend ) { + + this.backend = backend; + + this.gl = backend.gl; + this.extensions = backend.extensions; + this.defaultTextures = {}; + + if ( initialized === false ) { + + this._init( this.gl ); + + initialized = true; + + } + + } + + _init( gl ) { + + // Store only WebGL constants here. + + wrappingToGL = { + [ RepeatWrapping ]: gl.REPEAT, + [ ClampToEdgeWrapping ]: gl.CLAMP_TO_EDGE, + [ MirroredRepeatWrapping ]: gl.MIRRORED_REPEAT + }; + + filterToGL = { + [ NearestFilter ]: gl.NEAREST, + [ NearestMipmapNearestFilter ]: gl.NEAREST_MIPMAP_NEAREST, + [ NearestMipmapLinearFilter ]: gl.NEAREST_MIPMAP_LINEAR, + + [ LinearFilter ]: gl.LINEAR, + [ LinearMipmapNearestFilter ]: gl.LINEAR_MIPMAP_NEAREST, + [ LinearMipmapLinearFilter ]: gl.LINEAR_MIPMAP_LINEAR + }; + + compareToGL = { + [ NeverCompare ]: gl.NEVER, + [ AlwaysCompare ]: gl.ALWAYS, + [ LessCompare ]: gl.LESS, + [ LessEqualCompare ]: gl.LEQUAL, + [ EqualCompare ]: gl.EQUAL, + [ GreaterEqualCompare ]: gl.GEQUAL, + [ GreaterCompare ]: gl.GREATER, + [ NotEqualCompare ]: gl.NOTEQUAL + }; + + } + + filterFallback( f ) { + + const { gl } = this; + + if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { + + return gl.NEAREST; + + } + + return gl.LINEAR; + + } + + getGLTextureType( texture ) { + + const { gl } = this; + + let glTextureType; + + if ( texture.isCubeTexture === true ) { + + glTextureType = gl.TEXTURE_CUBE_MAP; + + } else if ( texture.isDataArrayTexture === true || texture.isCompressedArrayTexture === true ) { + + glTextureType = gl.TEXTURE_2D_ARRAY; + + } else if ( texture.isData3DTexture === true ) { // TODO: isCompressed3DTexture, wait for #26642 + + glTextureType = gl.TEXTURE_3D; + + } else { + + glTextureType = gl.TEXTURE_2D; + + + } + + return glTextureType; + + } + + getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) { + + const { gl, extensions } = this; + + if ( internalFormatName !== null ) { + + if ( gl[ internalFormatName ] !== undefined ) return gl[ internalFormatName ]; + + console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' ); + + } + + let internalFormat = glFormat; + + if ( glFormat === gl.RED ) { + + if ( glType === gl.FLOAT ) internalFormat = gl.R32F; + if ( glType === gl.HALF_FLOAT ) internalFormat = gl.R16F; + if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.R8; + if ( glType === gl.UNSIGNED_SHORT ) internalFormat = gl.R16; + if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.R32UI; + if ( glType === gl.BYTE ) internalFormat = gl.R8I; + if ( glType === gl.SHORT ) internalFormat = gl.R16I; + if ( glType === gl.INT ) internalFormat = gl.R32I; + + } + + if ( glFormat === gl.RED_INTEGER ) { + + if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.R8UI; + if ( glType === gl.UNSIGNED_SHORT ) internalFormat = gl.R16UI; + if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.R32UI; + if ( glType === gl.BYTE ) internalFormat = gl.R8I; + if ( glType === gl.SHORT ) internalFormat = gl.R16I; + if ( glType === gl.INT ) internalFormat = gl.R32I; + + } + + if ( glFormat === gl.RG ) { + + if ( glType === gl.FLOAT ) internalFormat = gl.RG32F; + if ( glType === gl.HALF_FLOAT ) internalFormat = gl.RG16F; + if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.RG8; + if ( glType === gl.UNSIGNED_SHORT ) internalFormat = gl.RG16; + if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.RG32UI; + if ( glType === gl.BYTE ) internalFormat = gl.RG8I; + if ( glType === gl.SHORT ) internalFormat = gl.RG16I; + if ( glType === gl.INT ) internalFormat = gl.RG32I; + + } + + if ( glFormat === gl.RG_INTEGER ) { + + if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.RG8UI; + if ( glType === gl.UNSIGNED_SHORT ) internalFormat = gl.RG16UI; + if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.RG32UI; + if ( glType === gl.BYTE ) internalFormat = gl.RG8I; + if ( glType === gl.SHORT ) internalFormat = gl.RG16I; + if ( glType === gl.INT ) internalFormat = gl.RG32I; + + } + + if ( glFormat === gl.RGB ) { + + if ( glType === gl.FLOAT ) internalFormat = gl.RGB32F; + if ( glType === gl.HALF_FLOAT ) internalFormat = gl.RGB16F; + if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.RGB8; + if ( glType === gl.UNSIGNED_SHORT ) internalFormat = gl.RGB16; + if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.RGB32UI; + if ( glType === gl.BYTE ) internalFormat = gl.RGB8I; + if ( glType === gl.SHORT ) internalFormat = gl.RGB16I; + if ( glType === gl.INT ) internalFormat = gl.RGB32I; + if ( glType === gl.UNSIGNED_BYTE ) internalFormat = ( colorSpace === SRGBColorSpace && forceLinearTransfer === false ) ? gl.SRGB8 : gl.RGB8; + if ( glType === gl.UNSIGNED_SHORT_5_6_5 ) internalFormat = gl.RGB565; + if ( glType === gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = gl.RGB5_A1; + if ( glType === gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = gl.RGB4; + if ( glType === gl.UNSIGNED_INT_5_9_9_9_REV ) internalFormat = gl.RGB9_E5; + + } + + if ( glFormat === gl.RGB_INTEGER ) { + + if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.RGB8UI; + if ( glType === gl.UNSIGNED_SHORT ) internalFormat = gl.RGB16UI; + if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.RGB32UI; + if ( glType === gl.BYTE ) internalFormat = gl.RGB8I; + if ( glType === gl.SHORT ) internalFormat = gl.RGB16I; + if ( glType === gl.INT ) internalFormat = gl.RGB32I; + + } + + if ( glFormat === gl.RGBA ) { + + if ( glType === gl.FLOAT ) internalFormat = gl.RGBA32F; + if ( glType === gl.HALF_FLOAT ) internalFormat = gl.RGBA16F; + if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.RGBA8; + if ( glType === gl.UNSIGNED_SHORT ) internalFormat = gl.RGBA16; + if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.RGBA32UI; + if ( glType === gl.BYTE ) internalFormat = gl.RGBA8I; + if ( glType === gl.SHORT ) internalFormat = gl.RGBA16I; + if ( glType === gl.INT ) internalFormat = gl.RGBA32I; + if ( glType === gl.UNSIGNED_BYTE ) internalFormat = ( colorSpace === SRGBColorSpace && forceLinearTransfer === false ) ? gl.SRGB8_ALPHA8 : gl.RGBA8; + if ( glType === gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = gl.RGBA4; + if ( glType === gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = gl.RGB5_A1; + + } + + if ( glFormat === gl.RGBA_INTEGER ) { + + if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.RGBA8UI; + if ( glType === gl.UNSIGNED_SHORT ) internalFormat = gl.RGBA16UI; + if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.RGBA32UI; + if ( glType === gl.BYTE ) internalFormat = gl.RGBA8I; + if ( glType === gl.SHORT ) internalFormat = gl.RGBA16I; + if ( glType === gl.INT ) internalFormat = gl.RGBA32I; + + } + + if ( glFormat === gl.DEPTH_COMPONENT ) { + + if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.DEPTH24_STENCIL8; + if ( glType === gl.FLOAT ) internalFormat = gl.DEPTH_COMPONENT32F; + + } + + if ( glFormat === gl.DEPTH_STENCIL ) { + + if ( glType === gl.UNSIGNED_INT_24_8 ) internalFormat = gl.DEPTH24_STENCIL8; + + } + + if ( internalFormat === gl.R16F || internalFormat === gl.R32F || + internalFormat === gl.RG16F || internalFormat === gl.RG32F || + internalFormat === gl.RGBA16F || internalFormat === gl.RGBA32F ) { + + extensions.get( 'EXT_color_buffer_float' ); + + } + + return internalFormat; + + } + + setTextureParameters( textureType, texture ) { + + const { gl, extensions, backend } = this; + + + gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + gl.pixelStorei( gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); + gl.pixelStorei( gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + gl.pixelStorei( gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE ); + + gl.texParameteri( textureType, gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] ); + gl.texParameteri( textureType, gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] ); + + if ( textureType === gl.TEXTURE_3D || textureType === gl.TEXTURE_2D_ARRAY ) { + + gl.texParameteri( textureType, gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] ); + + } + + gl.texParameteri( textureType, gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] ); + + + const hasMipmaps = texture.mipmaps !== undefined && texture.mipmaps.length > 0; + + // follow WebGPU backend mapping for texture filtering + const minFilter = texture.minFilter === LinearFilter && hasMipmaps ? LinearMipmapLinearFilter : texture.minFilter; + + gl.texParameteri( textureType, gl.TEXTURE_MIN_FILTER, filterToGL[ minFilter ] ); + + if ( texture.compareFunction ) { + + gl.texParameteri( textureType, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE ); + gl.texParameteri( textureType, gl.TEXTURE_COMPARE_FUNC, compareToGL[ texture.compareFunction ] ); + + } + + if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { + + if ( texture.magFilter === NearestFilter ) return; + if ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return; + if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2 + + if ( texture.anisotropy > 1 ) { + + const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, backend.getMaxAnisotropy() ) ); + + } + + } + + } + + createDefaultTexture( texture ) { + + const { gl, backend, defaultTextures } = this; + + + const glTextureType = this.getGLTextureType( texture ); + + let textureGPU = defaultTextures[ glTextureType ]; + + if ( textureGPU === undefined ) { + + textureGPU = gl.createTexture(); + + backend.state.bindTexture( glTextureType, textureGPU ); + gl.texParameteri( glTextureType, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); + gl.texParameteri( glTextureType, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); + + // gl.texImage2D( glTextureType, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); + + defaultTextures[ glTextureType ] = textureGPU; + + } + + backend.set( texture, { + textureGPU, + glTextureType, + isDefault: true + } ); + + } + + createTexture( texture, options ) { + + const { gl, backend } = this; + const { levels, width, height, depth } = options; + + const glFormat = backend.utils.convert( texture.format, texture.colorSpace ); + const glType = backend.utils.convert( texture.type ); + const glInternalFormat = this.getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture ); + + const textureGPU = gl.createTexture(); + const glTextureType = this.getGLTextureType( texture ); + + backend.state.bindTexture( glTextureType, textureGPU ); + + this.setTextureParameters( glTextureType, texture ); + + if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { + + gl.texStorage3D( gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, width, height, depth ); + + } else if ( texture.isData3DTexture ) { + + gl.texStorage3D( gl.TEXTURE_3D, levels, glInternalFormat, width, height, depth ); + + } else if ( ! texture.isVideoTexture ) { + + gl.texStorage2D( glTextureType, levels, glInternalFormat, width, height ); + + } + + backend.set( texture, { + textureGPU, + glTextureType, + glFormat, + glType, + glInternalFormat + } ); + + } + + copyBufferToTexture( buffer, texture ) { + + const { gl, backend } = this; + + const { textureGPU, glTextureType, glFormat, glType } = backend.get( texture ); + + const { width, height } = texture.source.data; + + gl.bindBuffer( gl.PIXEL_UNPACK_BUFFER, buffer ); + + backend.state.bindTexture( glTextureType, textureGPU ); + + gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, false ); + gl.pixelStorei( gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false ); + gl.texSubImage2D( glTextureType, 0, 0, 0, width, height, glFormat, glType, 0 ); + + gl.bindBuffer( gl.PIXEL_UNPACK_BUFFER, null ); + + backend.state.unbindTexture(); + // debug + // const framebuffer = gl.createFramebuffer(); + // gl.bindFramebuffer( gl.FRAMEBUFFER, framebuffer ); + // gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, glTextureType, textureGPU, 0 ); + + // const readout = new Float32Array( width * height * 4 ); + + // const altFormat = gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_FORMAT ); + // const altType = gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_TYPE ); + + // gl.readPixels( 0, 0, width, height, altFormat, altType, readout ); + // gl.bindFramebuffer( gl.FRAMEBUFFER, null ); + // console.log( readout ); + + } + + updateTexture( texture, options ) { + + const { gl } = this; + const { width, height } = options; + const { textureGPU, glTextureType, glFormat, glType, glInternalFormat } = this.backend.get( texture ); + + if ( texture.isRenderTargetTexture || ( textureGPU === undefined /* unsupported texture format */ ) ) + return; + + const getImage = ( source ) => { + + if ( source.isDataTexture ) { + + return source.image.data; + + } else if ( source instanceof ImageBitmap || source instanceof OffscreenCanvas || source instanceof HTMLImageElement || source instanceof HTMLCanvasElement ) { + + return source; + + } + + return source.data; + + }; + + this.backend.state.bindTexture( glTextureType, textureGPU ); + + this.setTextureParameters( glTextureType, texture ); + + if ( texture.isCompressedTexture ) { + + const mipmaps = texture.mipmaps; + const image = options.image; + + for ( let i = 0; i < mipmaps.length; i ++ ) { + + const mipmap = mipmaps[ i ]; + + if ( texture.isCompressedArrayTexture ) { + + + if ( texture.format !== gl.RGBA ) { + + if ( glFormat !== null ) { + + gl.compressedTexSubImage3D( gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 ); + + + } else { + + console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); + + } + + } else { + + gl.texSubImage3D( gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data ); + + } + + } else { + + if ( glFormat !== null ) { + + gl.compressedTexSubImage2D( gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); + + } else { + + console.warn( 'Unsupported compressed texture format' ); + + } + + } + + } + + + } else if ( texture.isCubeTexture ) { + + const images = options.images; + + for ( let i = 0; i < 6; i ++ ) { + + const image = getImage( images[ i ] ); + + gl.texSubImage2D( gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, width, height, glFormat, glType, image ); + + } + + } else if ( texture.isDataArrayTexture ) { + + const image = options.image; + + gl.texSubImage3D( gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); + + } else if ( texture.isData3DTexture ) { + + const image = options.image; + + gl.texSubImage3D( gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); + + } else if ( texture.isVideoTexture ) { + + texture.update(); + + gl.texImage2D( glTextureType, 0, glInternalFormat, glFormat, glType, options.image ); + + + } else { + + const image = getImage( options.image ); + + gl.texSubImage2D( glTextureType, 0, 0, 0, width, height, glFormat, glType, image ); + + } + + } + + generateMipmaps( texture ) { + + const { gl, backend } = this; + const { textureGPU, glTextureType } = backend.get( texture ); + + backend.state.bindTexture( glTextureType, textureGPU ); + gl.generateMipmap( glTextureType ); + + } + + deallocateRenderBuffers( renderTarget ) { + + const { gl, backend } = this; + + // remove framebuffer reference + if ( renderTarget ) { + + const renderContextData = backend.get( renderTarget ); + + renderContextData.renderBufferStorageSetup = undefined; + + if ( renderContextData.framebuffers ) { + + for ( const cacheKey in renderContextData.framebuffers ) { + + gl.deleteFramebuffer( renderContextData.framebuffers[ cacheKey ] ); + + } + + delete renderContextData.framebuffers; + + } + + if ( renderContextData.depthRenderbuffer ) { + + gl.deleteRenderbuffer( renderContextData.depthRenderbuffer ); + delete renderContextData.depthRenderbuffer; + + } + + if ( renderContextData.stencilRenderbuffer ) { + + gl.deleteRenderbuffer( renderContextData.stencilRenderbuffer ); + delete renderContextData.stencilRenderbuffer; + + } + + if ( renderContextData.msaaFrameBuffer ) { + + gl.deleteFramebuffer( renderContextData.msaaFrameBuffer ); + delete renderContextData.msaaFrameBuffer; + + } + + if ( renderContextData.msaaRenderbuffers ) { + + for ( let i = 0; i < renderContextData.msaaRenderbuffers.length; i ++ ) { + + gl.deleteRenderbuffer( renderContextData.msaaRenderbuffers[ i ] ); + + } + + delete renderContextData.msaaRenderbuffers; + + } + + } + + } + + destroyTexture( texture ) { + + const { gl, backend } = this; + const { textureGPU, renderTarget } = backend.get( texture ); + + this.deallocateRenderBuffers( renderTarget ); + gl.deleteTexture( textureGPU ); + + backend.delete( texture ); + + } + + copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { + + const { gl, backend } = this; + const { state } = this.backend; + + const { textureGPU: dstTextureGPU, glTextureType, glType, glFormat } = backend.get( dstTexture ); + + + let width, height, minX, minY; + let dstX, dstY; + if ( srcRegion !== null ) { + + width = srcRegion.max.x - srcRegion.min.x; + height = srcRegion.max.y - srcRegion.min.y; + minX = srcRegion.min.x; + minY = srcRegion.min.y; + + } else { + + width = srcTexture.image.width; + height = srcTexture.image.height; + minX = 0; + minY = 0; + + } + + if ( dstPosition !== null ) { + + dstX = dstPosition.x; + dstY = dstPosition.y; + + } else { + + dstX = 0; + dstY = 0; + + } + + state.bindTexture( glTextureType, dstTextureGPU ); + + // As another texture upload may have changed pixelStorei + // parameters, make sure they are correct for the dstTexture + gl.pixelStorei( gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); + gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); + gl.pixelStorei( gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); + gl.pixelStorei( gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); + + const currentUnpackRowLen = gl.getParameter( gl.UNPACK_ROW_LENGTH ); + const currentUnpackImageHeight = gl.getParameter( gl.UNPACK_IMAGE_HEIGHT ); + const currentUnpackSkipPixels = gl.getParameter( gl.UNPACK_SKIP_PIXELS ); + const currentUnpackSkipRows = gl.getParameter( gl.UNPACK_SKIP_ROWS ); + const currentUnpackSkipImages = gl.getParameter( gl.UNPACK_SKIP_IMAGES ); + + const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image; + + gl.pixelStorei( gl.UNPACK_ROW_LENGTH, image.width ); + gl.pixelStorei( gl.UNPACK_IMAGE_HEIGHT, image.height ); + gl.pixelStorei( gl.UNPACK_SKIP_PIXELS, minX ); + gl.pixelStorei( gl.UNPACK_SKIP_ROWS, minY ); + + + if ( srcTexture.isDataTexture ) { + + gl.texSubImage2D( gl.TEXTURE_2D, level, dstX, dstY, width, height, glFormat, glType, image.data ); + + } else { + + if ( srcTexture.isCompressedTexture ) { + + gl.compressedTexSubImage2D( gl.TEXTURE_2D, level, dstX, dstY, image.width, image.height, glFormat, image.data ); + + } else { + + gl.texSubImage2D( gl.TEXTURE_2D, level, dstX, dstY, width, height, glFormat, glType, image ); + + } + + } + + gl.pixelStorei( gl.UNPACK_ROW_LENGTH, currentUnpackRowLen ); + gl.pixelStorei( gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight ); + gl.pixelStorei( gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels ); + gl.pixelStorei( gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows ); + gl.pixelStorei( gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages ); + + // Generate mipmaps only when copying level 0 + if ( level === 0 && dstTexture.generateMipmaps ) gl.generateMipmap( gl.TEXTURE_2D ); + + state.unbindTexture(); + + } + + copyFramebufferToTexture( texture, renderContext, rectangle ) { + + const { gl } = this; + const { state } = this.backend; + + const { textureGPU } = this.backend.get( texture ); + + const { x, y, z: width, w: height } = rectangle; + + const requireDrawFrameBuffer = texture.isDepthTexture === true || ( renderContext.renderTarget && renderContext.renderTarget.samples > 0 ); + + const srcHeight = renderContext.renderTarget ? renderContext.renderTarget.height : this.backend.gerDrawingBufferSize().y; + + if ( requireDrawFrameBuffer ) { + + const partial = ( x !== 0 || y !== 0 ); + let mask; + let attachment; + + if ( texture.isDepthTexture === true ) { + + mask = gl.DEPTH_BUFFER_BIT; + attachment = gl.DEPTH_ATTACHMENT; + + if ( renderContext.stencil ) { + + mask |= gl.STENCIL_BUFFER_BIT; + + } + + } else { + + mask = gl.COLOR_BUFFER_BIT; + attachment = gl.COLOR_ATTACHMENT0; + + } + + if ( partial ) { + + const renderTargetContextData = this.backend.get( renderContext.renderTarget ); + + const fb = renderTargetContextData.framebuffers[ renderContext.getCacheKey() ]; + const msaaFrameBuffer = renderTargetContextData.msaaFrameBuffer; + + state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb ); + state.bindFramebuffer( gl.READ_FRAMEBUFFER, msaaFrameBuffer ); + + const flippedY = srcHeight - y - height; + + gl.blitFramebuffer( x, flippedY, x + width, flippedY + height, x, flippedY, x + width, flippedY + height, mask, gl.NEAREST ); + + state.bindFramebuffer( gl.READ_FRAMEBUFFER, fb ); + + state.bindTexture( gl.TEXTURE_2D, textureGPU ); + + gl.copyTexSubImage2D( gl.TEXTURE_2D, 0, 0, 0, x, flippedY, width, height ); + + state.unbindTexture(); + + } else { + + const fb = gl.createFramebuffer(); + + state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb ); + + gl.framebufferTexture2D( gl.DRAW_FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureGPU, 0 ); + gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, gl.NEAREST ); + + gl.deleteFramebuffer( fb ); + + } + + } else { + + state.bindTexture( gl.TEXTURE_2D, textureGPU ); + gl.copyTexSubImage2D( gl.TEXTURE_2D, 0, 0, 0, x, srcHeight - height - y, width, height ); + + state.unbindTexture(); + + } + + if ( texture.generateMipmaps ) this.generateMipmaps( texture ); + + this.backend._setFramebuffer( renderContext ); + + } + + // Setup storage for internal depth/stencil buffers and bind to correct framebuffer + setupRenderBufferStorage( renderbuffer, renderContext ) { + + const { gl } = this; + const renderTarget = renderContext.renderTarget; + + const { samples, depthTexture, depthBuffer, stencilBuffer, width, height } = renderTarget; + + gl.bindRenderbuffer( gl.RENDERBUFFER, renderbuffer ); + + if ( depthBuffer && ! stencilBuffer ) { + + let glInternalFormat = gl.DEPTH_COMPONENT24; + + if ( samples > 0 ) { + + if ( depthTexture && depthTexture.isDepthTexture ) { + + if ( depthTexture.type === gl.FLOAT ) { + + glInternalFormat = gl.DEPTH_COMPONENT32F; + + } + + } + + gl.renderbufferStorageMultisample( gl.RENDERBUFFER, samples, glInternalFormat, width, height ); + + } else { + + gl.renderbufferStorage( gl.RENDERBUFFER, glInternalFormat, width, height ); + + } + + gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer ); + + } else if ( depthBuffer && stencilBuffer ) { + + if ( samples > 0 ) { + + gl.renderbufferStorageMultisample( gl.RENDERBUFFER, samples, gl.DEPTH24_STENCIL8, width, height ); + + } else { + + gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height ); + + } + + + gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, renderbuffer ); + + } + + } + + async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { + + const { backend, gl } = this; + + const { textureGPU, glFormat, glType } = this.backend.get( texture ); + + const fb = gl.createFramebuffer(); + + gl.bindFramebuffer( gl.READ_FRAMEBUFFER, fb ); + + const target = texture.isCubeTexture ? gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex : gl.TEXTURE_2D; + + gl.framebufferTexture2D( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, target, textureGPU, 0 ); + + const typedArrayType = this._getTypedArrayType( glType ); + const bytesPerTexel = this._getBytesPerTexel( glType, glFormat ); + + const elementCount = width * height; + const byteLength = elementCount * bytesPerTexel; + + const buffer = gl.createBuffer(); + + gl.bindBuffer( gl.PIXEL_PACK_BUFFER, buffer ); + gl.bufferData( gl.PIXEL_PACK_BUFFER, byteLength, gl.STREAM_READ ); + gl.readPixels( x, y, width, height, glFormat, glType, 0 ); + gl.bindBuffer( gl.PIXEL_PACK_BUFFER, null ); + + await backend.utils._clientWaitAsync(); + + const dstBuffer = new typedArrayType( byteLength / typedArrayType.BYTES_PER_ELEMENT ); + + gl.bindBuffer( gl.PIXEL_PACK_BUFFER, buffer ); + gl.getBufferSubData( gl.PIXEL_PACK_BUFFER, 0, dstBuffer ); + gl.bindBuffer( gl.PIXEL_PACK_BUFFER, null ); + + gl.deleteFramebuffer( fb ); + + return dstBuffer; + + } + + _getTypedArrayType( glType ) { + + const { gl } = this; + + if ( glType === gl.UNSIGNED_BYTE ) return Uint8Array; + + if ( glType === gl.UNSIGNED_SHORT_4_4_4_4 ) return Uint16Array; + if ( glType === gl.UNSIGNED_SHORT_5_5_5_1 ) return Uint16Array; + if ( glType === gl.UNSIGNED_SHORT_5_6_5 ) return Uint16Array; + if ( glType === gl.UNSIGNED_SHORT ) return Uint16Array; + if ( glType === gl.UNSIGNED_INT ) return Uint32Array; + + if ( glType === gl.HALF_FLOAT ) return Uint16Array; + if ( glType === gl.FLOAT ) return Float32Array; + + throw new Error( `Unsupported WebGL type: ${glType}` ); + + } + + _getBytesPerTexel( glType, glFormat ) { + + const { gl } = this; + + let bytesPerComponent = 0; + + if ( glType === gl.UNSIGNED_BYTE ) bytesPerComponent = 1; + + if ( glType === gl.UNSIGNED_SHORT_4_4_4_4 || + glType === gl.UNSIGNED_SHORT_5_5_5_1 || + glType === gl.UNSIGNED_SHORT_5_6_5 || + glType === gl.UNSIGNED_SHORT || + glType === gl.HALF_FLOAT ) bytesPerComponent = 2; + + if ( glType === gl.UNSIGNED_INT || + glType === gl.FLOAT ) bytesPerComponent = 4; + + if ( glFormat === gl.RGBA ) return bytesPerComponent * 4; + if ( glFormat === gl.RGB ) return bytesPerComponent * 3; + if ( glFormat === gl.ALPHA ) return bytesPerComponent; + + } + +} + +class WebGLExtensions { + + constructor( backend ) { + + this.backend = backend; + + this.gl = this.backend.gl; + this.availableExtensions = this.gl.getSupportedExtensions(); + + this.extensions = {}; + + } + + get( name ) { + + let extension = this.extensions[ name ]; + + if ( extension === undefined ) { + + extension = this.gl.getExtension( name ); + + this.extensions[ name ] = extension; + + } + + return extension; + + } + + has( name ) { + + return this.availableExtensions.includes( name ); + + } + +} + +class WebGLCapabilities { + + constructor( backend ) { + + this.backend = backend; + + this.maxAnisotropy = null; + + } + + getMaxAnisotropy() { + + if ( this.maxAnisotropy !== null ) return this.maxAnisotropy; + + const gl = this.backend.gl; + const extensions = this.backend.extensions; + + if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { + + const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + + this.maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); + + } else { + + this.maxAnisotropy = 0; + + } + + return this.maxAnisotropy; + + } + +} + +const GLFeatureName = { + + 'WEBGL_multi_draw': 'WEBGL_multi_draw', + 'WEBGL_compressed_texture_astc': 'texture-compression-astc', + 'WEBGL_compressed_texture_etc': 'texture-compression-etc2', + 'WEBGL_compressed_texture_etc1': 'texture-compression-etc1', + 'WEBGL_compressed_texture_pvrtc': 'texture-compression-pvrtc', + 'WEBKIT_WEBGL_compressed_texture_pvrtc': 'texture-compression-pvrtc', + 'WEBGL_compressed_texture_s3tc': 'texture-compression-bc', + 'EXT_texture_compression_bptc': 'texture-compression-bptc', + 'EXT_disjoint_timer_query_webgl2': 'timestamp-query', + +}; + +class WebGLBufferRenderer { + + constructor( backend ) { + + this.gl = backend.gl; + this.extensions = backend.extensions; + this.info = backend.renderer.info; + this.mode = null; + this.index = 0; + this.type = null; + this.object = null; + + } + + render( start, count ) { + + const { gl, mode, object, type, info, index } = this; + + if ( index !== 0 ) { + + gl.drawElements( mode, count, type, start ); + + } else { + + gl.drawArrays( mode, start, count ); + + } + + info.update( object, count, mode, 1 ); + + } + + renderInstances( start, count, primcount ) { + + const { gl, mode, type, index, object, info } = this; + + if ( primcount === 0 ) return; + + if ( index !== 0 ) { + + gl.drawElementsInstanced( mode, count, type, start, primcount ); + + } else { + + gl.drawArraysInstanced( mode, start, count, primcount ); + + } + + info.update( object, count, mode, primcount ); + + } + + renderMultiDraw( starts, counts, drawCount ) { + + const { extensions, mode, object, info } = this; + + if ( drawCount === 0 ) return; + + const extension = extensions.get( 'WEBGL_multi_draw' ); + + if ( extension === null ) { + + for ( let i = 0; i < drawCount; i ++ ) { + + this.render( starts[ i ], counts[ i ] ); + + } + + } else { + + if ( this.index !== 0 ) { + + extension.multiDrawElementsWEBGL( mode, counts, 0, this.type, starts, 0, drawCount ); + + } else { + + extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount ); + + } + + let elementCount = 0; + for ( let i = 0; i < drawCount; i ++ ) { + + elementCount += counts[ i ]; + + } + + info.update( object, elementCount, mode, 1 ); + + } + + } + + renderMultiDrawInstances( starts, counts, drawCount, primcount ) { + + const { extensions, mode, object, info } = this; + + if ( drawCount === 0 ) return; + + const extension = extensions.get( 'WEBGL_multi_draw' ); + + if ( extension === null ) { + + for ( let i = 0; i < drawCount; i ++ ) { + + this.renderInstances( starts[ i ], counts[ i ], primcount[ i ] ); + + } + + } else { + + if ( this.index !== 0 ) { + + extension.multiDrawElementsInstancedWEBGL( mode, counts, 0, this.type, starts, 0, primcount, 0, drawCount ); + + } else { + + extension.multiDrawArraysInstancedWEBGL( mode, starts, 0, counts, 0, primcount, 0, drawCount ); + + } + + let elementCount = 0; + + for ( let i = 0; i < drawCount; i ++ ) { + + elementCount += counts[ i ]; + + } + + for ( let i = 0; i < primcount.length; i ++ ) { + + info.update( object, elementCount, mode, primcount[ i ] ); + + } + + } + + } + + // + +} + +// + +class WebGLBackend extends Backend { + + constructor( parameters = {} ) { + + super( parameters ); + + this.isWebGLBackend = true; + + } + + init( renderer ) { + + super.init( renderer ); + + // + + const parameters = this.parameters; + + const glContext = ( parameters.context !== undefined ) ? parameters.context : renderer.domElement.getContext( 'webgl2' ); + + this.gl = glContext; + + this.extensions = new WebGLExtensions( this ); + this.capabilities = new WebGLCapabilities( this ); + this.attributeUtils = new WebGLAttributeUtils( this ); + this.textureUtils = new WebGLTextureUtils( this ); + this.bufferRenderer = new WebGLBufferRenderer( this ); + + this.state = new WebGLState( this ); + this.utils = new WebGLUtils( this ); + + this.vaoCache = {}; + this.transformFeedbackCache = {}; + this.discard = false; + this.trackTimestamp = ( parameters.trackTimestamp === true ); + + this.extensions.get( 'EXT_color_buffer_float' ); + this.extensions.get( 'WEBGL_clip_cull_distance' ); + this.extensions.get( 'OES_texture_float_linear' ); + this.extensions.get( 'EXT_color_buffer_half_float' ); + this.extensions.get( 'WEBGL_multisampled_render_to_texture' ); + this.extensions.get( 'WEBGL_render_shared_exponent' ); + this.extensions.get( 'WEBGL_multi_draw' ); + + this.disjoint = this.extensions.get( 'EXT_disjoint_timer_query_webgl2' ); + this.parallel = this.extensions.get( 'KHR_parallel_shader_compile' ); + + this._currentContext = null; + + } + + get coordinateSystem() { + + return WebGLCoordinateSystem; + + } + + async getArrayBufferAsync( attribute ) { + + return await this.attributeUtils.getArrayBufferAsync( attribute ); + + } + + + initTimestampQuery( renderContext ) { + + if ( ! this.disjoint || ! this.trackTimestamp ) return; + + const renderContextData = this.get( renderContext ); + + if ( this.queryRunning ) { + + if ( ! renderContextData.queryQueue ) renderContextData.queryQueue = []; + renderContextData.queryQueue.push( renderContext ); + return; + + } + + if ( renderContextData.activeQuery ) { + + this.gl.endQuery( this.disjoint.TIME_ELAPSED_EXT ); + renderContextData.activeQuery = null; + + } + + renderContextData.activeQuery = this.gl.createQuery(); + + if ( renderContextData.activeQuery !== null ) { + + this.gl.beginQuery( this.disjoint.TIME_ELAPSED_EXT, renderContextData.activeQuery ); + this.queryRunning = true; + + } + + } + + // timestamp utils + + prepareTimestampBuffer( renderContext ) { + + if ( ! this.disjoint || ! this.trackTimestamp ) return; + + const renderContextData = this.get( renderContext ); + + if ( renderContextData.activeQuery ) { + + this.gl.endQuery( this.disjoint.TIME_ELAPSED_EXT ); + + if ( ! renderContextData.gpuQueries ) renderContextData.gpuQueries = []; + renderContextData.gpuQueries.push( { query: renderContextData.activeQuery } ); + renderContextData.activeQuery = null; + this.queryRunning = false; + + if ( renderContextData.queryQueue && renderContextData.queryQueue.length > 0 ) { + + const nextRenderContext = renderContextData.queryQueue.shift(); + this.initTimestampQuery( nextRenderContext ); + + } + + } + + } + + async resolveTimestampAsync( renderContext, type = 'render' ) { + + if ( ! this.disjoint || ! this.trackTimestamp ) return; + + const renderContextData = this.get( renderContext ); + + if ( ! renderContextData.gpuQueries ) renderContextData.gpuQueries = []; + + for ( let i = 0; i < renderContextData.gpuQueries.length; i ++ ) { + + const queryInfo = renderContextData.gpuQueries[ i ]; + const available = this.gl.getQueryParameter( queryInfo.query, this.gl.QUERY_RESULT_AVAILABLE ); + const disjoint = this.gl.getParameter( this.disjoint.GPU_DISJOINT_EXT ); + + if ( available && ! disjoint ) { + + const elapsed = this.gl.getQueryParameter( queryInfo.query, this.gl.QUERY_RESULT ); + const duration = Number( elapsed ) / 1000000; // Convert nanoseconds to milliseconds + this.gl.deleteQuery( queryInfo.query ); + renderContextData.gpuQueries.splice( i, 1 ); // Remove the processed query + i --; + this.renderer.info.updateTimestamp( type, duration ); + + } + + } + + } + + getContext() { + + return this.gl; + + } + + beginRender( renderContext ) { + + const { gl } = this; + const renderContextData = this.get( renderContext ); + + // + + // + + this.initTimestampQuery( renderContext ); + + renderContextData.previousContext = this._currentContext; + this._currentContext = renderContext; + + this._setFramebuffer( renderContext ); + + this.clear( renderContext.clearColor, renderContext.clearDepth, renderContext.clearStencil, renderContext, false ); + + // + if ( renderContext.viewport ) { + + this.updateViewport( renderContext ); + + } else { + + gl.viewport( 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight ); + + } + + if ( renderContext.scissor ) { + + const { x, y, width, height } = renderContext.scissorValue; + + gl.scissor( x, renderContext.height - height - y, width, height ); + + } + + const occlusionQueryCount = renderContext.occlusionQueryCount; + + if ( occlusionQueryCount > 0 ) { + + // Get a reference to the array of objects with queries. The renderContextData property + // can be changed by another render pass before the async reading of all previous queries complete + renderContextData.currentOcclusionQueries = renderContextData.occlusionQueries; + renderContextData.currentOcclusionQueryObjects = renderContextData.occlusionQueryObjects; + + renderContextData.lastOcclusionObject = null; + renderContextData.occlusionQueries = new Array( occlusionQueryCount ); + renderContextData.occlusionQueryObjects = new Array( occlusionQueryCount ); + renderContextData.occlusionQueryIndex = 0; + + } + + } + + finishRender( renderContext ) { + + const { gl, state } = this; + const renderContextData = this.get( renderContext ); + const previousContext = renderContextData.previousContext; + + const occlusionQueryCount = renderContext.occlusionQueryCount; + + if ( occlusionQueryCount > 0 ) { + + if ( occlusionQueryCount > renderContextData.occlusionQueryIndex ) { + + gl.endQuery( gl.ANY_SAMPLES_PASSED ); + + } + + this.resolveOccludedAsync( renderContext ); + + } + + const textures = renderContext.textures; + + if ( textures !== null ) { + + for ( let i = 0; i < textures.length; i ++ ) { + + const texture = textures[ i ]; + + if ( texture.generateMipmaps ) { + + this.generateMipmaps( texture ); + + } + + } + + } + + this._currentContext = previousContext; + + if ( renderContext.textures !== null && renderContext.renderTarget ) { + + const renderTargetContextData = this.get( renderContext.renderTarget ); + + const { samples } = renderContext.renderTarget; + + if ( samples > 0 ) { + + const fb = renderTargetContextData.framebuffers[ renderContext.getCacheKey() ]; + + const mask = gl.COLOR_BUFFER_BIT; + + const msaaFrameBuffer = renderTargetContextData.msaaFrameBuffer; + + const textures = renderContext.textures; + + state.bindFramebuffer( gl.READ_FRAMEBUFFER, msaaFrameBuffer ); + state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb ); + + for ( let i = 0; i < textures.length; i ++ ) { + + // TODO Add support for MRT + + if ( renderContext.scissor ) { + + const { x, y, width, height } = renderContext.scissorValue; + + const viewY = renderContext.height - height - y; + + gl.blitFramebuffer( x, viewY, x + width, viewY + height, x, viewY, x + width, viewY + height, mask, gl.NEAREST ); + gl.invalidateSubFramebuffer( gl.READ_FRAMEBUFFER, renderTargetContextData.invalidationArray, x, viewY, width, height ); + + } else { + + gl.blitFramebuffer( 0, 0, renderContext.width, renderContext.height, 0, 0, renderContext.width, renderContext.height, mask, gl.NEAREST ); + gl.invalidateFramebuffer( gl.READ_FRAMEBUFFER, renderTargetContextData.invalidationArray ); + + } + + } + + } + + + } + + if ( previousContext !== null ) { + + this._setFramebuffer( previousContext ); + + if ( previousContext.viewport ) { + + this.updateViewport( previousContext ); + + } else { + + gl.viewport( 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight ); + + } + + } + + this.prepareTimestampBuffer( renderContext ); + + } + + resolveOccludedAsync( renderContext ) { + + const renderContextData = this.get( renderContext ); + + // handle occlusion query results + + const { currentOcclusionQueries, currentOcclusionQueryObjects } = renderContextData; + + if ( currentOcclusionQueries && currentOcclusionQueryObjects ) { + + const occluded = new WeakSet(); + const { gl } = this; + + renderContextData.currentOcclusionQueryObjects = null; + renderContextData.currentOcclusionQueries = null; + + const check = () => { + + let completed = 0; + + // check all queries and requeue as appropriate + for ( let i = 0; i < currentOcclusionQueries.length; i ++ ) { + + const query = currentOcclusionQueries[ i ]; + + if ( query === null ) continue; + + if ( gl.getQueryParameter( query, gl.QUERY_RESULT_AVAILABLE ) ) { + + if ( gl.getQueryParameter( query, gl.QUERY_RESULT ) > 0 ) occluded.add( currentOcclusionQueryObjects[ i ] ); + + currentOcclusionQueries[ i ] = null; + gl.deleteQuery( query ); + + completed ++; + + } + + } + + if ( completed < currentOcclusionQueries.length ) { + + requestAnimationFrame( check ); + + } else { + + renderContextData.occluded = occluded; + + } + + }; + + check(); + + } + + } + + isOccluded( renderContext, object ) { + + const renderContextData = this.get( renderContext ); + + return renderContextData.occluded && renderContextData.occluded.has( object ); + + } + + updateViewport( renderContext ) { + + const gl = this.gl; + const { x, y, width, height } = renderContext.viewportValue; + + gl.viewport( x, renderContext.height - height - y, width, height ); + + } + + setScissorTest( boolean ) { + + const gl = this.gl; + + if ( boolean ) { + + gl.enable( gl.SCISSOR_TEST ); + + } else { + + gl.disable( gl.SCISSOR_TEST ); + + } + + } + + clear( color, depth, stencil, descriptor = null, setFrameBuffer = true ) { + + const { gl } = this; + + if ( descriptor === null ) { + + descriptor = { + textures: null, + clearColorValue: this.getClearColor() + }; + + } + + // + + let clear = 0; + + if ( color ) clear |= gl.COLOR_BUFFER_BIT; + if ( depth ) clear |= gl.DEPTH_BUFFER_BIT; + if ( stencil ) clear |= gl.STENCIL_BUFFER_BIT; + + if ( clear !== 0 ) { + + const clearColor = descriptor.clearColorValue || this.getClearColor(); + + // premultiply alpha + + clearColor.r *= clearColor.a; + clearColor.g *= clearColor.a; + clearColor.b *= clearColor.a; + + if ( depth ) this.state.setDepthMask( true ); + + if ( descriptor.textures === null ) { + + gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearColor.a ); + gl.clear( clear ); + + } else { + + if ( setFrameBuffer ) this._setFramebuffer( descriptor ); + + if ( color ) { + + for ( let i = 0; i < descriptor.textures.length; i ++ ) { + + gl.clearBufferfv( gl.COLOR, i, [ clearColor.r, clearColor.g, clearColor.b, clearColor.a ] ); + + } + + } + + if ( depth && stencil ) { + + gl.clearBufferfi( gl.DEPTH_STENCIL, 0, 1, 0 ); + + } else if ( depth ) { + + gl.clearBufferfv( gl.DEPTH, 0, [ 1.0 ] ); + + } else if ( stencil ) { + + gl.clearBufferiv( gl.STENCIL, 0, [ 0 ] ); + + } + + } + + } + + } + + beginCompute( computeGroup ) { + + const { state, gl } = this; + + state.bindFramebuffer( gl.FRAMEBUFFER, null ); + this.initTimestampQuery( computeGroup ); + + } + + compute( computeGroup, computeNode, bindings, pipeline ) { + + const { state, gl } = this; + + if ( ! this.discard ) { + + // required here to handle async behaviour of render.compute() + gl.enable( gl.RASTERIZER_DISCARD ); + this.discard = true; + + } + + const { programGPU, transformBuffers, attributes } = this.get( pipeline ); + + const vaoKey = this._getVaoKey( null, attributes ); + + const vaoGPU = this.vaoCache[ vaoKey ]; + + if ( vaoGPU === undefined ) { + + this._createVao( null, attributes ); + + } else { + + gl.bindVertexArray( vaoGPU ); + + } + + state.useProgram( programGPU ); + + this._bindUniforms( bindings ); + + const transformFeedbackGPU = this._getTransformFeedback( transformBuffers ); + + gl.bindTransformFeedback( gl.TRANSFORM_FEEDBACK, transformFeedbackGPU ); + gl.beginTransformFeedback( gl.POINTS ); + + if ( attributes[ 0 ].isStorageInstancedBufferAttribute ) { + + gl.drawArraysInstanced( gl.POINTS, 0, 1, computeNode.count ); + + } else { + + gl.drawArrays( gl.POINTS, 0, computeNode.count ); + + } + + gl.endTransformFeedback(); + gl.bindTransformFeedback( gl.TRANSFORM_FEEDBACK, null ); + + // switch active buffers + + for ( let i = 0; i < transformBuffers.length; i ++ ) { + + const dualAttributeData = transformBuffers[ i ]; + + if ( dualAttributeData.pbo ) { + + this.textureUtils.copyBufferToTexture( dualAttributeData.transformBuffer, dualAttributeData.pbo ); + + } + + dualAttributeData.switchBuffers(); + + + } + + } + + finishCompute( computeGroup ) { + + const gl = this.gl; + + this.discard = false; + + gl.disable( gl.RASTERIZER_DISCARD ); + + this.prepareTimestampBuffer( computeGroup ); + + } + + draw( renderObject/*, info*/ ) { + + const { object, pipeline, material, context } = renderObject; + const { programGPU } = this.get( pipeline ); + + const { gl, state } = this; + + const contextData = this.get( context ); + + const drawParms = renderObject.getDrawParameters(); + + if ( drawParms === null ) return; + + // + + this._bindUniforms( renderObject.getBindings() ); + + const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); + + state.setMaterial( material, frontFaceCW ); + + state.useProgram( programGPU ); + + // + + let vaoGPU = renderObject.staticVao; + + if ( vaoGPU === undefined ) { + + const vaoKey = this._getVaoKey( renderObject.getIndex(), renderObject.getAttributes() ); + + vaoGPU = this.vaoCache[ vaoKey ]; + + if ( vaoGPU === undefined ) { + + let staticVao; + + ( { vaoGPU, staticVao } = this._createVao( renderObject.getIndex(), renderObject.getAttributes() ) ); + + if ( staticVao ) renderObject.staticVao = vaoGPU; + + } + + } + + gl.bindVertexArray( vaoGPU ); + + // + + const index = renderObject.getIndex(); + + // + + const lastObject = contextData.lastOcclusionObject; + + if ( lastObject !== object && lastObject !== undefined ) { + + if ( lastObject !== null && lastObject.occlusionTest === true ) { + + gl.endQuery( gl.ANY_SAMPLES_PASSED ); + + contextData.occlusionQueryIndex ++; + + } + + if ( object.occlusionTest === true ) { + + const query = gl.createQuery(); + + gl.beginQuery( gl.ANY_SAMPLES_PASSED, query ); + + contextData.occlusionQueries[ contextData.occlusionQueryIndex ] = query; + contextData.occlusionQueryObjects[ contextData.occlusionQueryIndex ] = object; + + } + + contextData.lastOcclusionObject = object; + + } + + // + const renderer = this.bufferRenderer; + + if ( object.isPoints ) renderer.mode = gl.POINTS; + else if ( object.isLineSegments ) renderer.mode = gl.LINES; + else if ( object.isLine ) renderer.mode = gl.LINE_STRIP; + else if ( object.isLineLoop ) renderer.mode = gl.LINE_LOOP; + else { + + if ( material.wireframe === true ) { + + state.setLineWidth( material.wireframeLinewidth * this.renderer.getPixelRatio() ); + renderer.mode = gl.LINES; + + } else { + + renderer.mode = gl.TRIANGLES; + + } + + } + + // + + const { vertexCount, instanceCount } = drawParms; + let { firstVertex } = drawParms; + + renderer.object = object; + + if ( index !== null ) { + + firstVertex *= index.array.BYTES_PER_ELEMENT; + + const indexData = this.get( index ); + + renderer.index = index.count; + renderer.type = indexData.type; + + } else { + + renderer.index = 0; + + } + + if ( object.isBatchedMesh ) { + + if ( object._multiDrawInstances !== null ) { + + renderer.renderMultiDrawInstances( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount, object._multiDrawInstances ); + + } else if ( ! this.hasFeature( 'WEBGL_multi_draw' ) ) { + + warnOnce( 'THREE.WebGLRenderer: WEBGL_multi_draw not supported.' ); + + } else { + + renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount ); + + } + + } else if ( instanceCount > 1 ) { + + renderer.renderInstances( firstVertex, vertexCount, instanceCount ); + + } else { + + renderer.render( firstVertex, vertexCount ); + + } + // + + gl.bindVertexArray( null ); + + } + + needsRenderUpdate( /*renderObject*/ ) { + + return false; + + } + + getRenderCacheKey( /*renderObject*/ ) { + + return ''; + + } + + // textures + + createDefaultTexture( texture ) { + + this.textureUtils.createDefaultTexture( texture ); + + } + + createTexture( texture, options ) { + + this.textureUtils.createTexture( texture, options ); + + } + + updateTexture( texture, options ) { + + this.textureUtils.updateTexture( texture, options ); + + } + + generateMipmaps( texture ) { + + this.textureUtils.generateMipmaps( texture ); + + } + + + destroyTexture( texture ) { + + this.textureUtils.destroyTexture( texture ); + + } + + copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { + + return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height, faceIndex ); + + } + + createSampler( /*texture*/ ) { + + //console.warn( 'Abstract class.' ); + + } + + destroySampler() {} + + // node builder + + createNodeBuilder( object, renderer ) { + + return new GLSLNodeBuilder( object, renderer ); + + } + + // program + + createProgram( program ) { + + const gl = this.gl; + const { stage, code } = program; + + const shader = stage === 'fragment' ? gl.createShader( gl.FRAGMENT_SHADER ) : gl.createShader( gl.VERTEX_SHADER ); + + gl.shaderSource( shader, code ); + gl.compileShader( shader ); + + this.set( program, { + shaderGPU: shader + } ); + + } + + destroyProgram( /*program*/ ) { + + console.warn( 'Abstract class.' ); + + } + + createRenderPipeline( renderObject, promises ) { + + const gl = this.gl; + const pipeline = renderObject.pipeline; + + // Program + + const { fragmentProgram, vertexProgram } = pipeline; + + const programGPU = gl.createProgram(); + + const fragmentShader = this.get( fragmentProgram ).shaderGPU; + const vertexShader = this.get( vertexProgram ).shaderGPU; + + gl.attachShader( programGPU, fragmentShader ); + gl.attachShader( programGPU, vertexShader ); + gl.linkProgram( programGPU ); + + this.set( pipeline, { + programGPU, + fragmentShader, + vertexShader + } ); + + if ( promises !== null && this.parallel ) { + + const p = new Promise( ( resolve /*, reject*/ ) => { + + const parallel = this.parallel; + const checkStatus = () => { + + if ( gl.getProgramParameter( programGPU, parallel.COMPLETION_STATUS_KHR ) ) { + + this._completeCompile( renderObject, pipeline ); + resolve(); + + } else { + + requestAnimationFrame( checkStatus ); + + } + + }; + + checkStatus(); + + } ); + + promises.push( p ); + + return; + + } + + this._completeCompile( renderObject, pipeline ); + + } + + _handleSource( string, errorLine ) { + + const lines = string.split( '\n' ); + const lines2 = []; + + const from = Math.max( errorLine - 6, 0 ); + const to = Math.min( errorLine + 6, lines.length ); + + for ( let i = from; i < to; i ++ ) { + + const line = i + 1; + lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` ); + + } + + return lines2.join( '\n' ); + + } + + _getShaderErrors( gl, shader, type ) { + + const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS ); + const errors = gl.getShaderInfoLog( shader ).trim(); + + if ( status && errors === '' ) return ''; + + const errorMatches = /ERROR: 0:(\d+)/.exec( errors ); + if ( errorMatches ) { + + const errorLine = parseInt( errorMatches[ 1 ] ); + return type.toUpperCase() + '\n\n' + errors + '\n\n' + this._handleSource( gl.getShaderSource( shader ), errorLine ); + + } else { + + return errors; + + } + + } + + _logProgramError( programGPU, glFragmentShader, glVertexShader ) { + + if ( this.renderer.debug.checkShaderErrors ) { + + const gl = this.gl; + + const programLog = gl.getProgramInfoLog( programGPU ).trim(); + + if ( gl.getProgramParameter( programGPU, gl.LINK_STATUS ) === false ) { + + + if ( typeof this.renderer.debug.onShaderError === 'function' ) { + + this.renderer.debug.onShaderError( gl, programGPU, glVertexShader, glFragmentShader ); + + } else { + + // default error reporting + + const vertexErrors = this._getShaderErrors( gl, glVertexShader, 'vertex' ); + const fragmentErrors = this._getShaderErrors( gl, glFragmentShader, 'fragment' ); + + console.error( + 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + + 'VALIDATE_STATUS ' + gl.getProgramParameter( programGPU, gl.VALIDATE_STATUS ) + '\n\n' + + 'Program Info Log: ' + programLog + '\n' + + vertexErrors + '\n' + + fragmentErrors + ); + + } + + } else if ( programLog !== '' ) { + + console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); + + } + + } + + } + + _completeCompile( renderObject, pipeline ) { + + const { state, gl } = this; + const pipelineData = this.get( pipeline ); + const { programGPU, fragmentShader, vertexShader } = pipelineData; + + if ( gl.getProgramParameter( programGPU, gl.LINK_STATUS ) === false ) { + + this._logProgramError( programGPU, fragmentShader, vertexShader ); + + } + + state.useProgram( programGPU ); + + // Bindings + + const bindings = renderObject.getBindings(); + + this._setupBindings( bindings, programGPU ); + + // + + this.set( pipeline, { + programGPU + } ); + + } + + createComputePipeline( computePipeline, bindings ) { + + const { state, gl } = this; + + // Program + + const fragmentProgram = { + stage: 'fragment', + code: '#version 300 es\nprecision highp float;\nvoid main() {}' + }; + + this.createProgram( fragmentProgram ); + + const { computeProgram } = computePipeline; + + const programGPU = gl.createProgram(); + + const fragmentShader = this.get( fragmentProgram ).shaderGPU; + const vertexShader = this.get( computeProgram ).shaderGPU; + + const transforms = computeProgram.transforms; + + const transformVaryingNames = []; + const transformAttributeNodes = []; + + for ( let i = 0; i < transforms.length; i ++ ) { + + const transform = transforms[ i ]; + + transformVaryingNames.push( transform.varyingName ); + transformAttributeNodes.push( transform.attributeNode ); + + } + + gl.attachShader( programGPU, fragmentShader ); + gl.attachShader( programGPU, vertexShader ); + + gl.transformFeedbackVaryings( + programGPU, + transformVaryingNames, + gl.SEPARATE_ATTRIBS + ); + + gl.linkProgram( programGPU ); + + if ( gl.getProgramParameter( programGPU, gl.LINK_STATUS ) === false ) { + + this._logProgramError( programGPU, fragmentShader, vertexShader ); + + + } + + state.useProgram( programGPU ); + + // Bindings + + this.createBindings( null, bindings ); + + this._setupBindings( bindings, programGPU ); + + const attributeNodes = computeProgram.attributes; + const attributes = []; + const transformBuffers = []; + + for ( let i = 0; i < attributeNodes.length; i ++ ) { + + const attribute = attributeNodes[ i ].node.attribute; + + attributes.push( attribute ); + + if ( ! this.has( attribute ) ) this.attributeUtils.createAttribute( attribute, gl.ARRAY_BUFFER ); + + } + + for ( let i = 0; i < transformAttributeNodes.length; i ++ ) { + + const attribute = transformAttributeNodes[ i ].attribute; + + if ( ! this.has( attribute ) ) this.attributeUtils.createAttribute( attribute, gl.ARRAY_BUFFER ); + + const attributeData = this.get( attribute ); + + transformBuffers.push( attributeData ); + + } + + // + + this.set( computePipeline, { + programGPU, + transformBuffers, + attributes + } ); + + } + + createBindings( bindGroup, bindings ) { + + this.updateBindings( bindGroup, bindings ); + + } + + updateBindings( bindGroup, bindings ) { + + if ( ! bindGroup ) return; + + const { gl } = this; + + const bindingsData = this.get( bindings ); + const bindGroupData = this.get( bindGroup ); + + if ( bindingsData.textureIndex === undefined ) bindingsData.textureIndex = 0; + + if ( bindGroupData.textureIndex === undefined ) { + + bindGroupData.textureIndex = bindingsData.textureIndex; + + } else { + + // reset textureIndex to match previous mappimgs when rebuilt + bindingsData.textureIndex = bindGroupData.textureIndex; + + } + + let i = 0; + + for ( const binding of bindGroup.bindings ) { + + if ( binding.isUniformsGroup || binding.isUniformBuffer ) { + + const data = binding.buffer; + const bufferGPU = gl.createBuffer(); + + gl.bindBuffer( gl.UNIFORM_BUFFER, bufferGPU ); + gl.bufferData( gl.UNIFORM_BUFFER, data, gl.DYNAMIC_DRAW ); + + this.set( binding, { + index: bindGroup.index * 2 + i ++, + bufferGPU + } ); + + } else if ( binding.isSampledTexture ) { + + const { textureGPU, glTextureType } = this.get( binding.texture ); + + this.set( binding, { + index: bindingsData.textureIndex ++, + textureGPU, + glTextureType + } ); + + } + + } + + } + + updateBinding( binding ) { + + const gl = this.gl; + + if ( binding.isUniformsGroup || binding.isUniformBuffer ) { + + const bindingData = this.get( binding ); + const bufferGPU = bindingData.bufferGPU; + const data = binding.buffer; + + gl.bindBuffer( gl.UNIFORM_BUFFER, bufferGPU ); + gl.bufferData( gl.UNIFORM_BUFFER, data, gl.DYNAMIC_DRAW ); + + } + + } + + // attributes + + createIndexAttribute( attribute ) { + + const gl = this.gl; + + this.attributeUtils.createAttribute( attribute, gl.ELEMENT_ARRAY_BUFFER ); + + } + + createAttribute( attribute ) { + + if ( this.has( attribute ) ) return; + + const gl = this.gl; + + this.attributeUtils.createAttribute( attribute, gl.ARRAY_BUFFER ); + + } + + createStorageAttribute( attribute ) { + + if ( this.has( attribute ) ) return; + + const gl = this.gl; + + this.attributeUtils.createAttribute( attribute, gl.ARRAY_BUFFER ); + + } + + updateAttribute( attribute ) { + + this.attributeUtils.updateAttribute( attribute ); + + } + + destroyAttribute( attribute ) { + + this.attributeUtils.destroyAttribute( attribute ); + + } + + updateSize() { + + //console.warn( 'Abstract class.' ); + + } + + hasFeature( name ) { + + const keysMatching = Object.keys( GLFeatureName ).filter( key => GLFeatureName[ key ] === name ); + + const extensions = this.extensions; + + for ( let i = 0; i < keysMatching.length; i ++ ) { + + if ( extensions.has( keysMatching[ i ] ) ) return true; + + } + + return false; + + } + + getMaxAnisotropy() { + + return this.capabilities.getMaxAnisotropy(); + + } + + copyTextureToTexture( position, srcTexture, dstTexture, level ) { + + this.textureUtils.copyTextureToTexture( position, srcTexture, dstTexture, level ); + + } + + copyFramebufferToTexture( texture, renderContext, rectangle ) { + + this.textureUtils.copyFramebufferToTexture( texture, renderContext, rectangle ); + + } + + _setFramebuffer( descriptor ) { + + const { gl, state } = this; + + let currentFrameBuffer = null; + + if ( descriptor.textures !== null ) { + + const renderTarget = descriptor.renderTarget; + const renderTargetContextData = this.get( renderTarget ); + const { samples, depthBuffer, stencilBuffer } = renderTarget; + + const isCube = renderTarget.isWebGLCubeRenderTarget === true; + + let msaaFb = renderTargetContextData.msaaFrameBuffer; + let depthRenderbuffer = renderTargetContextData.depthRenderbuffer; + + const cacheKey = getCacheKey( descriptor ); + + let fb; + + if ( isCube ) { + + renderTargetContextData.cubeFramebuffers || ( renderTargetContextData.cubeFramebuffers = {} ); + + fb = renderTargetContextData.cubeFramebuffers[ cacheKey ]; + + } else { + + renderTargetContextData.framebuffers || ( renderTargetContextData.framebuffers = {} ); + + fb = renderTargetContextData.framebuffers[ cacheKey ]; + + } + + if ( fb === undefined ) { + + fb = gl.createFramebuffer(); + + state.bindFramebuffer( gl.FRAMEBUFFER, fb ); + + const textures = descriptor.textures; + + if ( isCube ) { + + renderTargetContextData.cubeFramebuffers[ cacheKey ] = fb; + + const { textureGPU } = this.get( textures[ 0 ] ); + + const cubeFace = this.renderer._activeCubeFace; + + gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + cubeFace, textureGPU, 0 ); + + } else { + + renderTargetContextData.framebuffers[ cacheKey ] = fb; + + for ( let i = 0; i < textures.length; i ++ ) { + + const texture = textures[ i ]; + const textureData = this.get( texture ); + textureData.renderTarget = descriptor.renderTarget; + + const attachment = gl.COLOR_ATTACHMENT0 + i; + + gl.framebufferTexture2D( gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureData.textureGPU, 0 ); + + } + + state.drawBuffers( descriptor, fb ); + + } + + if ( descriptor.depthTexture !== null ) { + + const textureData = this.get( descriptor.depthTexture ); + const depthStyle = stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT; + + gl.framebufferTexture2D( gl.FRAMEBUFFER, depthStyle, gl.TEXTURE_2D, textureData.textureGPU, 0 ); + + } + + } + + if ( samples > 0 ) { + + if ( msaaFb === undefined ) { + + const invalidationArray = []; + + msaaFb = gl.createFramebuffer(); + + state.bindFramebuffer( gl.FRAMEBUFFER, msaaFb ); + + const msaaRenderbuffers = []; + + const textures = descriptor.textures; + + for ( let i = 0; i < textures.length; i ++ ) { + + msaaRenderbuffers[ i ] = gl.createRenderbuffer(); + + gl.bindRenderbuffer( gl.RENDERBUFFER, msaaRenderbuffers[ i ] ); + + invalidationArray.push( gl.COLOR_ATTACHMENT0 + i ); + + if ( depthBuffer ) { + + const depthStyle = stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT; + invalidationArray.push( depthStyle ); + + } + + const texture = descriptor.textures[ i ]; + const textureData = this.get( texture ); + + gl.renderbufferStorageMultisample( gl.RENDERBUFFER, samples, textureData.glInternalFormat, descriptor.width, descriptor.height ); + gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.RENDERBUFFER, msaaRenderbuffers[ i ] ); + + + } + + renderTargetContextData.msaaFrameBuffer = msaaFb; + renderTargetContextData.msaaRenderbuffers = msaaRenderbuffers; + + if ( depthRenderbuffer === undefined ) { + + depthRenderbuffer = gl.createRenderbuffer(); + this.textureUtils.setupRenderBufferStorage( depthRenderbuffer, descriptor ); + + renderTargetContextData.depthRenderbuffer = depthRenderbuffer; + + const depthStyle = stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT; + invalidationArray.push( depthStyle ); + + } + + renderTargetContextData.invalidationArray = invalidationArray; + + } + + currentFrameBuffer = renderTargetContextData.msaaFrameBuffer; + + } else { + + currentFrameBuffer = fb; + + } + + } + + state.bindFramebuffer( gl.FRAMEBUFFER, currentFrameBuffer ); + + } + + + _getVaoKey( index, attributes ) { + + let key = []; + + if ( index !== null ) { + + const indexData = this.get( index ); + + key += ':' + indexData.id; + + } + + for ( let i = 0; i < attributes.length; i ++ ) { + + const attributeData = this.get( attributes[ i ] ); + + key += ':' + attributeData.id; + + } + + return key; + + } + + _createVao( index, attributes ) { + + const { gl } = this; + + const vaoGPU = gl.createVertexArray(); + let key = ''; + + let staticVao = true; + + gl.bindVertexArray( vaoGPU ); + + if ( index !== null ) { + + const indexData = this.get( index ); + + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, indexData.bufferGPU ); + + key += ':' + indexData.id; + + } + + for ( let i = 0; i < attributes.length; i ++ ) { + + const attribute = attributes[ i ]; + const attributeData = this.get( attribute ); + + key += ':' + attributeData.id; + + gl.bindBuffer( gl.ARRAY_BUFFER, attributeData.bufferGPU ); + gl.enableVertexAttribArray( i ); + + if ( attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute ) staticVao = false; + + let stride, offset; + + if ( attribute.isInterleavedBufferAttribute === true ) { + + stride = attribute.data.stride * attributeData.bytesPerElement; + offset = attribute.offset * attributeData.bytesPerElement; + + } else { + + stride = 0; + offset = 0; + + } + + if ( attributeData.isInteger ) { + + gl.vertexAttribIPointer( i, attribute.itemSize, attributeData.type, stride, offset ); + + } else { + + gl.vertexAttribPointer( i, attribute.itemSize, attributeData.type, attribute.normalized, stride, offset ); + + } + + if ( attribute.isInstancedBufferAttribute && ! attribute.isInterleavedBufferAttribute ) { + + gl.vertexAttribDivisor( i, attribute.meshPerAttribute ); + + } else if ( attribute.isInterleavedBufferAttribute && attribute.data.isInstancedInterleavedBuffer ) { + + gl.vertexAttribDivisor( i, attribute.data.meshPerAttribute ); + + } + + } + + gl.bindBuffer( gl.ARRAY_BUFFER, null ); + + this.vaoCache[ key ] = vaoGPU; + + return { vaoGPU, staticVao }; + + } + + _getTransformFeedback( transformBuffers ) { + + let key = ''; + + for ( let i = 0; i < transformBuffers.length; i ++ ) { + + key += ':' + transformBuffers[ i ].id; + + } + + let transformFeedbackGPU = this.transformFeedbackCache[ key ]; + + if ( transformFeedbackGPU !== undefined ) { + + return transformFeedbackGPU; + + } + + const { gl } = this; + + transformFeedbackGPU = gl.createTransformFeedback(); + + gl.bindTransformFeedback( gl.TRANSFORM_FEEDBACK, transformFeedbackGPU ); + + for ( let i = 0; i < transformBuffers.length; i ++ ) { + + const attributeData = transformBuffers[ i ]; + + gl.bindBufferBase( gl.TRANSFORM_FEEDBACK_BUFFER, i, attributeData.transformBuffer ); + + } + + gl.bindTransformFeedback( gl.TRANSFORM_FEEDBACK, null ); + + this.transformFeedbackCache[ key ] = transformFeedbackGPU; + + return transformFeedbackGPU; + + } + + + _setupBindings( bindings, programGPU ) { + + const gl = this.gl; + + for ( const bindGroup of bindings ) { + + for ( const binding of bindGroup.bindings ) { + + const bindingData = this.get( binding ); + const index = bindingData.index; + + if ( binding.isUniformsGroup || binding.isUniformBuffer ) { + + const location = gl.getUniformBlockIndex( programGPU, binding.name ); + gl.uniformBlockBinding( programGPU, location, index ); + + } else if ( binding.isSampledTexture ) { + + const location = gl.getUniformLocation( programGPU, binding.name ); + gl.uniform1i( location, index ); + + } + + } + + } + + } + + _bindUniforms( bindings ) { + + const { gl, state } = this; + + for ( const bindGroup of bindings ) { + + for ( const binding of bindGroup.bindings ) { + + const bindingData = this.get( binding ); + const index = bindingData.index; + + if ( binding.isUniformsGroup || binding.isUniformBuffer ) { + + // TODO USE bindBufferRange to group multiple uniform buffers + state.bindBufferBase( gl.UNIFORM_BUFFER, index, bindingData.bufferGPU ); + + } else if ( binding.isSampledTexture ) { + + state.bindTexture( bindingData.glTextureType, bindingData.textureGPU, gl.TEXTURE0 + index ); + + } + + } + + } + + } + +} + +class Sampler extends Binding { + + constructor( name, texture ) { + + super( name ); + + this.texture = texture; + this.version = texture ? texture.version : 0; + + this.isSampler = true; + + } + +} + +class NodeSampler extends Sampler { + + constructor( name, textureNode, groupNode ) { + + super( name, textureNode ? textureNode.value : null ); + + this.textureNode = textureNode; + this.groupNode = groupNode; + + } + + update() { + + this.texture = this.textureNode.value; + + } + +} + +class StorageBuffer extends Buffer { + + constructor( name, attribute ) { + + super( name, attribute ? attribute.array : null ); + + this.attribute = attribute; + + this.isStorageBuffer = true; + + } + +} + +let _id = 0; + +class NodeStorageBuffer extends StorageBuffer { + + constructor( nodeUniform, groupNode ) { + + super( 'StorageBuffer_' + _id ++, nodeUniform ? nodeUniform.value : null ); + + this.nodeUniform = nodeUniform; + this.access = nodeUniform ? nodeUniform.access : GPUBufferBindingType.Storage; + this.groupNode = groupNode; + + + } + + get buffer() { + + return this.nodeUniform.value; + + } + +} + +class WebGPUTexturePassUtils extends DataMap { + + constructor( device ) { + + super(); + + this.device = device; + + const mipmapVertexSource = ` +struct VarysStruct { + @builtin( position ) Position: vec4, + @location( 0 ) vTex : vec2 +}; + +@vertex +fn main( @builtin( vertex_index ) vertexIndex : u32 ) -> VarysStruct { + + var Varys : VarysStruct; + + var pos = array< vec2, 4 >( + vec2( -1.0, 1.0 ), + vec2( 1.0, 1.0 ), + vec2( -1.0, -1.0 ), + vec2( 1.0, -1.0 ) + ); + + var tex = array< vec2, 4 >( + vec2( 0.0, 0.0 ), + vec2( 1.0, 0.0 ), + vec2( 0.0, 1.0 ), + vec2( 1.0, 1.0 ) + ); + + Varys.vTex = tex[ vertexIndex ]; + Varys.Position = vec4( pos[ vertexIndex ], 0.0, 1.0 ); + + return Varys; + +} +`; + + const mipmapFragmentSource = ` +@group( 0 ) @binding( 0 ) +var imgSampler : sampler; + +@group( 0 ) @binding( 1 ) +var img : texture_2d; + +@fragment +fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { + + return textureSample( img, imgSampler, vTex ); + +} +`; + + const flipYFragmentSource = ` +@group( 0 ) @binding( 0 ) +var imgSampler : sampler; + +@group( 0 ) @binding( 1 ) +var img : texture_2d; + +@fragment +fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { + + return textureSample( img, imgSampler, vec2( vTex.x, 1.0 - vTex.y ) ); + +} +`; + this.mipmapSampler = device.createSampler( { minFilter: GPUFilterMode.Linear } ); + this.flipYSampler = device.createSampler( { minFilter: GPUFilterMode.Nearest } ); //@TODO?: Consider using textureLoad() + + // We'll need a new pipeline for every texture format used. + this.transferPipelines = {}; + this.flipYPipelines = {}; + + this.mipmapVertexShaderModule = device.createShaderModule( { + label: 'mipmapVertex', + code: mipmapVertexSource + } ); + + this.mipmapFragmentShaderModule = device.createShaderModule( { + label: 'mipmapFragment', + code: mipmapFragmentSource + } ); + + this.flipYFragmentShaderModule = device.createShaderModule( { + label: 'flipYFragment', + code: flipYFragmentSource + } ); + + } + + getTransferPipeline( format ) { + + let pipeline = this.transferPipelines[ format ]; + + if ( pipeline === undefined ) { + + pipeline = this.device.createRenderPipeline( { + label: `mipmap-${ format }`, + vertex: { + module: this.mipmapVertexShaderModule, + entryPoint: 'main' + }, + fragment: { + module: this.mipmapFragmentShaderModule, + entryPoint: 'main', + targets: [ { format } ] + }, + primitive: { + topology: GPUPrimitiveTopology.TriangleStrip, + stripIndexFormat: GPUIndexFormat.Uint32 + }, + layout: 'auto' + } ); + + this.transferPipelines[ format ] = pipeline; + + } + + return pipeline; + + } + + getFlipYPipeline( format ) { + + let pipeline = this.flipYPipelines[ format ]; + + if ( pipeline === undefined ) { + + pipeline = this.device.createRenderPipeline( { + label: `flipY-${ format }`, + vertex: { + module: this.mipmapVertexShaderModule, + entryPoint: 'main' + }, + fragment: { + module: this.flipYFragmentShaderModule, + entryPoint: 'main', + targets: [ { format } ] + }, + primitive: { + topology: GPUPrimitiveTopology.TriangleStrip, + stripIndexFormat: GPUIndexFormat.Uint32 + }, + layout: 'auto' + } ); + + this.flipYPipelines[ format ] = pipeline; + + } + + return pipeline; + + } + + flipY( textureGPU, textureGPUDescriptor, baseArrayLayer = 0 ) { + + const format = textureGPUDescriptor.format; + const { width, height } = textureGPUDescriptor.size; + + const transferPipeline = this.getTransferPipeline( format ); + const flipYPipeline = this.getFlipYPipeline( format ); + + const tempTexture = this.device.createTexture( { + size: { width, height, depthOrArrayLayers: 1 }, + format, + usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING + } ); + + const srcView = textureGPU.createView( { + baseMipLevel: 0, + mipLevelCount: 1, + dimension: GPUTextureViewDimension.TwoD, + baseArrayLayer + } ); + + const dstView = tempTexture.createView( { + baseMipLevel: 0, + mipLevelCount: 1, + dimension: GPUTextureViewDimension.TwoD, + baseArrayLayer: 0 + } ); + + const commandEncoder = this.device.createCommandEncoder( {} ); + + const pass = ( pipeline, sourceView, destinationView ) => { + + const bindGroupLayout = pipeline.getBindGroupLayout( 0 ); // @TODO: Consider making this static. + + const bindGroup = this.device.createBindGroup( { + layout: bindGroupLayout, + entries: [ { + binding: 0, + resource: this.flipYSampler + }, { + binding: 1, + resource: sourceView + } ] + } ); + + const passEncoder = commandEncoder.beginRenderPass( { + colorAttachments: [ { + view: destinationView, + loadOp: GPULoadOp.Clear, + storeOp: GPUStoreOp.Store, + clearValue: [ 0, 0, 0, 0 ] + } ] + } ); + + passEncoder.setPipeline( pipeline ); + passEncoder.setBindGroup( 0, bindGroup ); + passEncoder.draw( 4, 1, 0, 0 ); + passEncoder.end(); + + }; + + pass( transferPipeline, srcView, dstView ); + pass( flipYPipeline, dstView, srcView ); + + this.device.queue.submit( [ commandEncoder.finish() ] ); + + tempTexture.destroy(); + + } + + generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer = 0 ) { + + const textureData = this.get( textureGPU ); + + if ( textureData.useCount === undefined ) { + + textureData.useCount = 0; + textureData.layers = []; + + } + + const passes = textureData.layers[ baseArrayLayer ] || this._mipmapCreateBundles( textureGPU, textureGPUDescriptor, baseArrayLayer ); + + const commandEncoder = this.device.createCommandEncoder( {} ); + + this._mipmapRunBundles( commandEncoder, passes ); + + this.device.queue.submit( [ commandEncoder.finish() ] ); + + if ( textureData.useCount !== 0 ) textureData.layers[ baseArrayLayer ] = passes; + + textureData.useCount ++; + + } + + _mipmapCreateBundles( textureGPU, textureGPUDescriptor, baseArrayLayer ) { + + const pipeline = this.getTransferPipeline( textureGPUDescriptor.format ); + + const bindGroupLayout = pipeline.getBindGroupLayout( 0 ); // @TODO: Consider making this static. + + let srcView = textureGPU.createView( { + baseMipLevel: 0, + mipLevelCount: 1, + dimension: GPUTextureViewDimension.TwoD, + baseArrayLayer + } ); + + const passes = []; + + for ( let i = 1; i < textureGPUDescriptor.mipLevelCount; i ++ ) { + + const bindGroup = this.device.createBindGroup( { + layout: bindGroupLayout, + entries: [ { + binding: 0, + resource: this.mipmapSampler + }, { + binding: 1, + resource: srcView + } ] + } ); + + const dstView = textureGPU.createView( { + baseMipLevel: i, + mipLevelCount: 1, + dimension: GPUTextureViewDimension.TwoD, + baseArrayLayer + } ); + + const passDescriptor = { + colorAttachments: [ { + view: dstView, + loadOp: GPULoadOp.Clear, + storeOp: GPUStoreOp.Store, + clearValue: [ 0, 0, 0, 0 ] + } ] + }; + + const passEncoder = this.device.createRenderBundleEncoder( { + colorFormats: [ textureGPUDescriptor.format ] + } ); + + passEncoder.setPipeline( pipeline ); + passEncoder.setBindGroup( 0, bindGroup ); + passEncoder.draw( 4, 1, 0, 0 ); + + passes.push( { + renderBundles: [ passEncoder.finish() ], + passDescriptor + } ); + + srcView = dstView; + + } + + return passes; + + } + + _mipmapRunBundles( commandEncoder, passes ) { + + const levels = passes.length; + + for ( let i = 0; i < levels; i ++ ) { + + const pass = passes[ i ]; + + const passEncoder = commandEncoder.beginRenderPass( pass.passDescriptor ); + + passEncoder.executeBundles( pass.renderBundles ); + + passEncoder.end(); + + } + + } + +} + +const _compareToWebGPU = { + [ NeverCompare ]: 'never', + [ LessCompare ]: 'less', + [ EqualCompare ]: 'equal', + [ LessEqualCompare ]: 'less-equal', + [ GreaterCompare ]: 'greater', + [ GreaterEqualCompare ]: 'greater-equal', + [ AlwaysCompare ]: 'always', + [ NotEqualCompare ]: 'not-equal' +}; + +const _flipMap = [ 0, 1, 3, 2, 4, 5 ]; + +class WebGPUTextureUtils { + + constructor( backend ) { + + this.backend = backend; + + this._passUtils = null; + + this.defaultTexture = {}; + this.defaultCubeTexture = {}; + this.defaultVideoFrame = null; + + this.colorBuffer = null; + + this.depthTexture = new DepthTexture(); + this.depthTexture.name = 'depthBuffer'; + + } + + createSampler( texture ) { + + const backend = this.backend; + const device = backend.device; + + const textureGPU = backend.get( texture ); + + const samplerDescriptorGPU = { + addressModeU: this._convertAddressMode( texture.wrapS ), + addressModeV: this._convertAddressMode( texture.wrapT ), + addressModeW: this._convertAddressMode( texture.wrapR ), + magFilter: this._convertFilterMode( texture.magFilter ), + minFilter: this._convertFilterMode( texture.minFilter ), + mipmapFilter: this._convertFilterMode( texture.minFilter ), + maxAnisotropy: texture.anisotropy + }; + + if ( texture.isDepthTexture && texture.compareFunction !== null ) { + + samplerDescriptorGPU.compare = _compareToWebGPU[ texture.compareFunction ]; + + } + + textureGPU.sampler = device.createSampler( samplerDescriptorGPU ); + + } + + createDefaultTexture( texture ) { + + let textureGPU; + + const format = getFormat( texture ); + + if ( texture.isCubeTexture ) { + + textureGPU = this._getDefaultCubeTextureGPU( format ); + + } else if ( texture.isVideoTexture ) { + + this.backend.get( texture ).externalTexture = this._getDefaultVideoFrame(); + + } else { + + textureGPU = this._getDefaultTextureGPU( format ); + + } + + this.backend.get( texture ).texture = textureGPU; + + } + + createTexture( texture, options = {} ) { + + const backend = this.backend; + const textureData = backend.get( texture ); + + if ( textureData.initialized ) { + + throw new Error( 'WebGPUTextureUtils: Texture already initialized.' ); + + } + + if ( options.needsMipmaps === undefined ) options.needsMipmaps = false; + if ( options.levels === undefined ) options.levels = 1; + if ( options.depth === undefined ) options.depth = 1; + + const { width, height, depth, levels } = options; + + const dimension = this._getDimension( texture ); + const format = texture.internalFormat || options.format || getFormat( texture, backend.device ); + + textureData.format = format; + + let sampleCount = options.sampleCount !== undefined ? options.sampleCount : 1; + + sampleCount = backend.utils.getSampleCount( sampleCount ); + + const primarySampleCount = texture.isRenderTargetTexture && ! texture.isMultisampleRenderTargetTexture ? 1 : sampleCount; + + let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC; + + if ( texture.isStorageTexture === true ) { + + usage |= GPUTextureUsage.STORAGE_BINDING; + + } + + if ( texture.isCompressedTexture !== true && texture.isCompressedArrayTexture !== true ) { + + usage |= GPUTextureUsage.RENDER_ATTACHMENT; + + } + + const textureDescriptorGPU = { + label: texture.name, + size: { + width: width, + height: height, + depthOrArrayLayers: depth, + }, + mipLevelCount: levels, + sampleCount: primarySampleCount, + dimension: dimension, + format: format, + usage: usage + }; + + // texture creation + + if ( texture.isVideoTexture ) { + + const video = texture.source.data; + const videoFrame = new VideoFrame( video ); + + textureDescriptorGPU.size.width = videoFrame.displayWidth; + textureDescriptorGPU.size.height = videoFrame.displayHeight; + + videoFrame.close(); + + textureData.externalTexture = video; + + } else { + + if ( format === undefined ) { + + console.warn( 'WebGPURenderer: Texture format not supported.' ); + + return this.createDefaultTexture( texture ); + + } + + textureData.texture = backend.device.createTexture( textureDescriptorGPU ); + + } + + if ( texture.isRenderTargetTexture && sampleCount > 1 && ! texture.isMultisampleRenderTargetTexture ) { + + const msaaTextureDescriptorGPU = Object.assign( {}, textureDescriptorGPU ); + + msaaTextureDescriptorGPU.label = msaaTextureDescriptorGPU.label + '-msaa'; + msaaTextureDescriptorGPU.sampleCount = sampleCount; + + textureData.msaaTexture = backend.device.createTexture( msaaTextureDescriptorGPU ); + + } + + textureData.initialized = true; + + textureData.textureDescriptorGPU = textureDescriptorGPU; + + } + + destroyTexture( texture ) { + + const backend = this.backend; + const textureData = backend.get( texture ); + + textureData.texture.destroy(); + + if ( textureData.msaaTexture !== undefined ) textureData.msaaTexture.destroy(); + + backend.delete( texture ); + + } + + destroySampler( texture ) { + + const backend = this.backend; + const textureData = backend.get( texture ); + + delete textureData.sampler; + + } + + generateMipmaps( texture ) { + + const textureData = this.backend.get( texture ); + + if ( texture.isCubeTexture ) { + + for ( let i = 0; i < 6; i ++ ) { + + this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i ); + + } + + } else { + + const depth = texture.image.depth || 1; + + for ( let i = 0; i < depth; i ++ ) { + + this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i ); + + } + + } + + } + + getColorBuffer() { + + if ( this.colorBuffer ) this.colorBuffer.destroy(); + + const backend = this.backend; + const { width, height } = backend.getDrawingBufferSize(); + + this.colorBuffer = backend.device.createTexture( { + label: 'colorBuffer', + size: { + width: width, + height: height, + depthOrArrayLayers: 1 + }, + sampleCount: backend.utils.getSampleCount( backend.renderer.samples ), + format: backend.utils.getPreferredCanvasFormat(), + usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC + } ); + + return this.colorBuffer; + + } + + getDepthBuffer( depth = true, stencil = false ) { + + const backend = this.backend; + const { width, height } = backend.getDrawingBufferSize(); + + const depthTexture = this.depthTexture; + const depthTextureGPU = backend.get( depthTexture ).texture; + + let format, type; + + if ( stencil ) { + + format = DepthStencilFormat; + type = UnsignedInt248Type; + + } else if ( depth ) { + + format = DepthFormat; + type = UnsignedIntType; + + } + + if ( depthTextureGPU !== undefined ) { + + if ( depthTexture.image.width === width && depthTexture.image.height === height && depthTexture.format === format && depthTexture.type === type ) { + + return depthTextureGPU; + + } + + this.destroyTexture( depthTexture ); + + } + + depthTexture.name = 'depthBuffer'; + depthTexture.format = format; + depthTexture.type = type; + depthTexture.image.width = width; + depthTexture.image.height = height; + + this.createTexture( depthTexture, { sampleCount: backend.utils.getSampleCount( backend.renderer.samples ), width, height } ); + + return backend.get( depthTexture ).texture; + + } + + updateTexture( texture, options ) { + + const textureData = this.backend.get( texture ); + + const { textureDescriptorGPU } = textureData; + + if ( texture.isRenderTargetTexture || ( textureDescriptorGPU === undefined /* unsupported texture format */ ) ) + return; + + // transfer texture data + + if ( texture.isDataTexture ) { + + this._copyBufferToTexture( options.image, textureData.texture, textureDescriptorGPU, 0, texture.flipY ); + + } else if ( texture.isDataArrayTexture || texture.isData3DTexture ) { + + for ( let i = 0; i < options.image.depth; i ++ ) { + + this._copyBufferToTexture( options.image, textureData.texture, textureDescriptorGPU, i, texture.flipY, i ); + + } + + } else if ( texture.isCompressedTexture || texture.isCompressedArrayTexture ) { + + this._copyCompressedBufferToTexture( texture.mipmaps, textureData.texture, textureDescriptorGPU ); + + } else if ( texture.isCubeTexture ) { + + this._copyCubeMapToTexture( options.images, textureData.texture, textureDescriptorGPU, texture.flipY ); + + } else if ( texture.isVideoTexture ) { + + const video = texture.source.data; + + textureData.externalTexture = video; + + } else { + + this._copyImageToTexture( options.image, textureData.texture, textureDescriptorGPU, 0, texture.flipY ); + + } + + // + + textureData.version = texture.version; + + if ( texture.onUpdate ) texture.onUpdate( texture ); + + } + + async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { + + const device = this.backend.device; + + const textureData = this.backend.get( texture ); + const textureGPU = textureData.texture; + const format = textureData.textureDescriptorGPU.format; + const bytesPerTexel = this._getBytesPerTexel( format ); + + let bytesPerRow = width * bytesPerTexel; + bytesPerRow = Math.ceil( bytesPerRow / 256 ) * 256; // Align to 256 bytes + + const readBuffer = device.createBuffer( + { + size: width * height * bytesPerTexel, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ + } + ); + + const encoder = device.createCommandEncoder(); + + encoder.copyTextureToBuffer( + { + texture: textureGPU, + origin: { x, y, z: faceIndex }, + }, + { + buffer: readBuffer, + bytesPerRow: bytesPerRow + }, + { + width: width, + height: height + } + + ); + + const typedArrayType = this._getTypedArrayType( format ); + + device.queue.submit( [ encoder.finish() ] ); + + await readBuffer.mapAsync( GPUMapMode.READ ); + + const buffer = readBuffer.getMappedRange(); + + return new typedArrayType( buffer ); + + } + + _isEnvironmentTexture( texture ) { + + const mapping = texture.mapping; + + return ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) || ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping ); + + } + + _getDefaultTextureGPU( format ) { + + let defaultTexture = this.defaultTexture[ format ]; + + if ( defaultTexture === undefined ) { + + const texture = new Texture(); + texture.minFilter = NearestFilter; + texture.magFilter = NearestFilter; + + this.createTexture( texture, { width: 1, height: 1, format } ); + + this.defaultTexture[ format ] = defaultTexture = texture; + + } + + return this.backend.get( defaultTexture ).texture; + + } + + _getDefaultCubeTextureGPU( format ) { + + let defaultCubeTexture = this.defaultTexture[ format ]; + + if ( defaultCubeTexture === undefined ) { + + const texture = new CubeTexture(); + texture.minFilter = NearestFilter; + texture.magFilter = NearestFilter; + + this.createTexture( texture, { width: 1, height: 1, depth: 6 } ); + + this.defaultCubeTexture[ format ] = defaultCubeTexture = texture; + + } + + return this.backend.get( defaultCubeTexture ).texture; + + } + + _getDefaultVideoFrame() { + + let defaultVideoFrame = this.defaultVideoFrame; + + if ( defaultVideoFrame === null ) { + + const init = { + timestamp: 0, + codedWidth: 1, + codedHeight: 1, + format: 'RGBA', + }; + + this.defaultVideoFrame = defaultVideoFrame = new VideoFrame( new Uint8Array( [ 0, 0, 0, 0xff ] ), init ); + + } + + return defaultVideoFrame; + + } + + _copyCubeMapToTexture( images, textureGPU, textureDescriptorGPU, flipY ) { + + for ( let i = 0; i < 6; i ++ ) { + + const image = images[ i ]; + + const flipIndex = flipY === true ? _flipMap[ i ] : i; + + if ( image.isDataTexture ) { + + this._copyBufferToTexture( image.image, textureGPU, textureDescriptorGPU, flipIndex, flipY ); + + } else { + + this._copyImageToTexture( image, textureGPU, textureDescriptorGPU, flipIndex, flipY ); + + } + + } + + } + + _copyImageToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY ) { + + const device = this.backend.device; + + device.queue.copyExternalImageToTexture( + { + source: image + }, { + texture: textureGPU, + mipLevel: 0, + origin: { x: 0, y: 0, z: originDepth } + }, { + width: image.width, + height: image.height, + depthOrArrayLayers: 1 + } + ); + + if ( flipY === true ) { + + this._flipY( textureGPU, textureDescriptorGPU, originDepth ); + + } + + } + + _getPassUtils() { + + let passUtils = this._passUtils; + + if ( passUtils === null ) { + + this._passUtils = passUtils = new WebGPUTexturePassUtils( this.backend.device ); + + } + + return passUtils; + + } + + _generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer = 0 ) { + + this._getPassUtils().generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer ); + + } + + _flipY( textureGPU, textureDescriptorGPU, originDepth = 0 ) { + + this._getPassUtils().flipY( textureGPU, textureDescriptorGPU, originDepth ); + + } + + _copyBufferToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY, depth = 0 ) { + + // @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture() + // @TODO: Consider to support valid buffer layouts with other formats like RGB + + const device = this.backend.device; + + const data = image.data; + + const bytesPerTexel = this._getBytesPerTexel( textureDescriptorGPU.format ); + const bytesPerRow = image.width * bytesPerTexel; + + device.queue.writeTexture( + { + texture: textureGPU, + mipLevel: 0, + origin: { x: 0, y: 0, z: originDepth } + }, + data, + { + offset: image.width * image.height * bytesPerTexel * depth, + bytesPerRow + }, + { + width: image.width, + height: image.height, + depthOrArrayLayers: 1 + } ); + + if ( flipY === true ) { + + this._flipY( textureGPU, textureDescriptorGPU, originDepth ); + + } + + } + + _copyCompressedBufferToTexture( mipmaps, textureGPU, textureDescriptorGPU ) { + + // @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture() + + const device = this.backend.device; + + const blockData = this._getBlockData( textureDescriptorGPU.format ); + const isTextureArray = textureDescriptorGPU.size.depthOrArrayLayers > 1; + + for ( let i = 0; i < mipmaps.length; i ++ ) { + + const mipmap = mipmaps[ i ]; + + const width = mipmap.width; + const height = mipmap.height; + const depth = isTextureArray ? textureDescriptorGPU.size.depthOrArrayLayers : 1; + + const bytesPerRow = Math.ceil( width / blockData.width ) * blockData.byteLength; + const bytesPerImage = bytesPerRow * Math.ceil( height / blockData.height ); + + for ( let j = 0; j < depth; j ++ ) { + + device.queue.writeTexture( + { + texture: textureGPU, + mipLevel: i, + origin: { x: 0, y: 0, z: j } + }, + mipmap.data, + { + offset: j * bytesPerImage, + bytesPerRow, + rowsPerImage: Math.ceil( height / blockData.height ) + }, + { + width: Math.ceil( width / blockData.width ) * blockData.width, + height: Math.ceil( height / blockData.height ) * blockData.height, + depthOrArrayLayers: 1 + } + ); + + } + + } + + } + + _getBlockData( format ) { + + // this method is only relevant for compressed texture formats + + if ( format === GPUTextureFormat.BC1RGBAUnorm || format === GPUTextureFormat.BC1RGBAUnormSRGB ) return { byteLength: 8, width: 4, height: 4 }; // DXT1 + if ( format === GPUTextureFormat.BC2RGBAUnorm || format === GPUTextureFormat.BC2RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // DXT3 + if ( format === GPUTextureFormat.BC3RGBAUnorm || format === GPUTextureFormat.BC3RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // DXT5 + if ( format === GPUTextureFormat.BC4RUnorm || format === GPUTextureFormat.BC4RSNorm ) return { byteLength: 8, width: 4, height: 4 }; // RGTC1 + if ( format === GPUTextureFormat.BC5RGUnorm || format === GPUTextureFormat.BC5RGSnorm ) return { byteLength: 16, width: 4, height: 4 }; // RGTC2 + if ( format === GPUTextureFormat.BC6HRGBUFloat || format === GPUTextureFormat.BC6HRGBFloat ) return { byteLength: 16, width: 4, height: 4 }; // BPTC (float) + if ( format === GPUTextureFormat.BC7RGBAUnorm || format === GPUTextureFormat.BC7RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // BPTC (unorm) + + if ( format === GPUTextureFormat.ETC2RGB8Unorm || format === GPUTextureFormat.ETC2RGB8UnormSRGB ) return { byteLength: 8, width: 4, height: 4 }; + if ( format === GPUTextureFormat.ETC2RGB8A1Unorm || format === GPUTextureFormat.ETC2RGB8A1UnormSRGB ) return { byteLength: 8, width: 4, height: 4 }; + if ( format === GPUTextureFormat.ETC2RGBA8Unorm || format === GPUTextureFormat.ETC2RGBA8UnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; + if ( format === GPUTextureFormat.EACR11Unorm ) return { byteLength: 8, width: 4, height: 4 }; + if ( format === GPUTextureFormat.EACR11Snorm ) return { byteLength: 8, width: 4, height: 4 }; + if ( format === GPUTextureFormat.EACRG11Unorm ) return { byteLength: 16, width: 4, height: 4 }; + if ( format === GPUTextureFormat.EACRG11Snorm ) return { byteLength: 16, width: 4, height: 4 }; + + if ( format === GPUTextureFormat.ASTC4x4Unorm || format === GPUTextureFormat.ASTC4x4UnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; + if ( format === GPUTextureFormat.ASTC5x4Unorm || format === GPUTextureFormat.ASTC5x4UnormSRGB ) return { byteLength: 16, width: 5, height: 4 }; + if ( format === GPUTextureFormat.ASTC5x5Unorm || format === GPUTextureFormat.ASTC5x5UnormSRGB ) return { byteLength: 16, width: 5, height: 5 }; + if ( format === GPUTextureFormat.ASTC6x5Unorm || format === GPUTextureFormat.ASTC6x5UnormSRGB ) return { byteLength: 16, width: 6, height: 5 }; + if ( format === GPUTextureFormat.ASTC6x6Unorm || format === GPUTextureFormat.ASTC6x6UnormSRGB ) return { byteLength: 16, width: 6, height: 6 }; + if ( format === GPUTextureFormat.ASTC8x5Unorm || format === GPUTextureFormat.ASTC8x5UnormSRGB ) return { byteLength: 16, width: 8, height: 5 }; + if ( format === GPUTextureFormat.ASTC8x6Unorm || format === GPUTextureFormat.ASTC8x6UnormSRGB ) return { byteLength: 16, width: 8, height: 6 }; + if ( format === GPUTextureFormat.ASTC8x8Unorm || format === GPUTextureFormat.ASTC8x8UnormSRGB ) return { byteLength: 16, width: 8, height: 8 }; + if ( format === GPUTextureFormat.ASTC10x5Unorm || format === GPUTextureFormat.ASTC10x5UnormSRGB ) return { byteLength: 16, width: 10, height: 5 }; + if ( format === GPUTextureFormat.ASTC10x6Unorm || format === GPUTextureFormat.ASTC10x6UnormSRGB ) return { byteLength: 16, width: 10, height: 6 }; + if ( format === GPUTextureFormat.ASTC10x8Unorm || format === GPUTextureFormat.ASTC10x8UnormSRGB ) return { byteLength: 16, width: 10, height: 8 }; + if ( format === GPUTextureFormat.ASTC10x10Unorm || format === GPUTextureFormat.ASTC10x10UnormSRGB ) return { byteLength: 16, width: 10, height: 10 }; + if ( format === GPUTextureFormat.ASTC12x10Unorm || format === GPUTextureFormat.ASTC12x10UnormSRGB ) return { byteLength: 16, width: 12, height: 10 }; + if ( format === GPUTextureFormat.ASTC12x12Unorm || format === GPUTextureFormat.ASTC12x12UnormSRGB ) return { byteLength: 16, width: 12, height: 12 }; + + } + + _convertAddressMode( value ) { + + let addressMode = GPUAddressMode.ClampToEdge; + + if ( value === RepeatWrapping ) { + + addressMode = GPUAddressMode.Repeat; + + } else if ( value === MirroredRepeatWrapping ) { + + addressMode = GPUAddressMode.MirrorRepeat; + + } + + return addressMode; + + } + + _convertFilterMode( value ) { + + let filterMode = GPUFilterMode.Linear; + + if ( value === NearestFilter || value === NearestMipmapNearestFilter || value === NearestMipmapLinearFilter ) { + + filterMode = GPUFilterMode.Nearest; + + } + + return filterMode; + + } + + _getBytesPerTexel( format ) { + + // 8-bit formats + if ( format === GPUTextureFormat.R8Unorm || + format === GPUTextureFormat.R8Snorm || + format === GPUTextureFormat.R8Uint || + format === GPUTextureFormat.R8Sint ) return 1; + + // 16-bit formats + if ( format === GPUTextureFormat.R16Uint || + format === GPUTextureFormat.R16Sint || + format === GPUTextureFormat.R16Float || + format === GPUTextureFormat.RG8Unorm || + format === GPUTextureFormat.RG8Snorm || + format === GPUTextureFormat.RG8Uint || + format === GPUTextureFormat.RG8Sint ) return 2; + + // 32-bit formats + if ( format === GPUTextureFormat.R32Uint || + format === GPUTextureFormat.R32Sint || + format === GPUTextureFormat.R32Float || + format === GPUTextureFormat.RG16Uint || + format === GPUTextureFormat.RG16Sint || + format === GPUTextureFormat.RG16Float || + format === GPUTextureFormat.RGBA8Unorm || + format === GPUTextureFormat.RGBA8UnormSRGB || + format === GPUTextureFormat.RGBA8Snorm || + format === GPUTextureFormat.RGBA8Uint || + format === GPUTextureFormat.RGBA8Sint || + format === GPUTextureFormat.BGRA8Unorm || + format === GPUTextureFormat.BGRA8UnormSRGB || + // Packed 32-bit formats + format === GPUTextureFormat.RGB9E5UFloat || + format === GPUTextureFormat.RGB10A2Unorm || + format === GPUTextureFormat.RG11B10UFloat || + format === GPUTextureFormat.Depth32Float || + format === GPUTextureFormat.Depth24Plus || + format === GPUTextureFormat.Depth24PlusStencil8 || + format === GPUTextureFormat.Depth32FloatStencil8 ) return 4; + + // 64-bit formats + if ( format === GPUTextureFormat.RG32Uint || + format === GPUTextureFormat.RG32Sint || + format === GPUTextureFormat.RG32Float || + format === GPUTextureFormat.RGBA16Uint || + format === GPUTextureFormat.RGBA16Sint || + format === GPUTextureFormat.RGBA16Float ) return 8; + + // 128-bit formats + if ( format === GPUTextureFormat.RGBA32Uint || + format === GPUTextureFormat.RGBA32Sint || + format === GPUTextureFormat.RGBA32Float ) return 16; + + + } + + _getTypedArrayType( format ) { + + if ( format === GPUTextureFormat.R8Uint ) return Uint8Array; + if ( format === GPUTextureFormat.R8Sint ) return Int8Array; + if ( format === GPUTextureFormat.R8Unorm ) return Uint8Array; + if ( format === GPUTextureFormat.R8Snorm ) return Int8Array; + if ( format === GPUTextureFormat.RG8Uint ) return Uint8Array; + if ( format === GPUTextureFormat.RG8Sint ) return Int8Array; + if ( format === GPUTextureFormat.RG8Unorm ) return Uint8Array; + if ( format === GPUTextureFormat.RG8Snorm ) return Int8Array; + if ( format === GPUTextureFormat.RGBA8Uint ) return Uint8Array; + if ( format === GPUTextureFormat.RGBA8Sint ) return Int8Array; + if ( format === GPUTextureFormat.RGBA8Unorm ) return Uint8Array; + if ( format === GPUTextureFormat.RGBA8Snorm ) return Int8Array; + + + if ( format === GPUTextureFormat.R16Uint ) return Uint16Array; + if ( format === GPUTextureFormat.R16Sint ) return Int16Array; + if ( format === GPUTextureFormat.RG16Uint ) return Uint16Array; + if ( format === GPUTextureFormat.RG16Sint ) return Int16Array; + if ( format === GPUTextureFormat.RGBA16Uint ) return Uint16Array; + if ( format === GPUTextureFormat.RGBA16Sint ) return Int16Array; + if ( format === GPUTextureFormat.R16Float ) return Uint16Array; + if ( format === GPUTextureFormat.RG16Float ) return Uint16Array; + if ( format === GPUTextureFormat.RGBA16Float ) return Uint16Array; + + + if ( format === GPUTextureFormat.R32Uint ) return Uint32Array; + if ( format === GPUTextureFormat.R32Sint ) return Int32Array; + if ( format === GPUTextureFormat.R32Float ) return Float32Array; + if ( format === GPUTextureFormat.RG32Uint ) return Uint32Array; + if ( format === GPUTextureFormat.RG32Sint ) return Int32Array; + if ( format === GPUTextureFormat.RG32Float ) return Float32Array; + if ( format === GPUTextureFormat.RGBA32Uint ) return Uint32Array; + if ( format === GPUTextureFormat.RGBA32Sint ) return Int32Array; + if ( format === GPUTextureFormat.RGBA32Float ) return Float32Array; + + if ( format === GPUTextureFormat.BGRA8Unorm ) return Uint8Array; + if ( format === GPUTextureFormat.BGRA8UnormSRGB ) return Uint8Array; + if ( format === GPUTextureFormat.RGB10A2Unorm ) return Uint32Array; + if ( format === GPUTextureFormat.RGB9E5UFloat ) return Uint32Array; + if ( format === GPUTextureFormat.RG11B10UFloat ) return Uint32Array; + + if ( format === GPUTextureFormat.Depth32Float ) return Float32Array; + if ( format === GPUTextureFormat.Depth24Plus ) return Uint32Array; + if ( format === GPUTextureFormat.Depth24PlusStencil8 ) return Uint32Array; + if ( format === GPUTextureFormat.Depth32FloatStencil8 ) return Float32Array; + + } + + _getDimension( texture ) { + + let dimension; + + if ( texture.isData3DTexture ) { + + dimension = GPUTextureDimension.ThreeD; + + } else { + + dimension = GPUTextureDimension.TwoD; + + } + + return dimension; + + } + +} + +function getFormat( texture, device = null ) { + + const format = texture.format; + const type = texture.type; + const colorSpace = texture.colorSpace; + + let formatGPU; + + if ( texture.isFramebufferTexture === true && texture.type === UnsignedByteType ) { + + formatGPU = GPUTextureFormat.BGRA8Unorm; + + } else if ( texture.isCompressedTexture === true || texture.isCompressedArrayTexture === true ) { + + switch ( format ) { + + case RGBA_S3TC_DXT1_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.BC1RGBAUnormSRGB : GPUTextureFormat.BC1RGBAUnorm; + break; + + case RGBA_S3TC_DXT3_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.BC2RGBAUnormSRGB : GPUTextureFormat.BC2RGBAUnorm; + break; + + case RGBA_S3TC_DXT5_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.BC3RGBAUnormSRGB : GPUTextureFormat.BC3RGBAUnorm; + break; + + case RGB_ETC2_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ETC2RGB8UnormSRGB : GPUTextureFormat.ETC2RGB8Unorm; + break; + + case RGBA_ETC2_EAC_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ETC2RGBA8UnormSRGB : GPUTextureFormat.ETC2RGBA8Unorm; + break; + + case RGBA_ASTC_4x4_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC4x4UnormSRGB : GPUTextureFormat.ASTC4x4Unorm; + break; + + case RGBA_ASTC_5x4_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC5x4UnormSRGB : GPUTextureFormat.ASTC5x4Unorm; + break; + + case RGBA_ASTC_5x5_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC5x5UnormSRGB : GPUTextureFormat.ASTC5x5Unorm; + break; + + case RGBA_ASTC_6x5_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC6x5UnormSRGB : GPUTextureFormat.ASTC6x5Unorm; + break; + + case RGBA_ASTC_6x6_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC6x6UnormSRGB : GPUTextureFormat.ASTC6x6Unorm; + break; + + case RGBA_ASTC_8x5_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC8x5UnormSRGB : GPUTextureFormat.ASTC8x5Unorm; + break; + + case RGBA_ASTC_8x6_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC8x6UnormSRGB : GPUTextureFormat.ASTC8x6Unorm; + break; + + case RGBA_ASTC_8x8_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC8x8UnormSRGB : GPUTextureFormat.ASTC8x8Unorm; + break; + + case RGBA_ASTC_10x5_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC10x5UnormSRGB : GPUTextureFormat.ASTC10x5Unorm; + break; + + case RGBA_ASTC_10x6_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC10x6UnormSRGB : GPUTextureFormat.ASTC10x6Unorm; + break; + + case RGBA_ASTC_10x8_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC10x8UnormSRGB : GPUTextureFormat.ASTC10x8Unorm; + break; + + case RGBA_ASTC_10x10_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC10x10UnormSRGB : GPUTextureFormat.ASTC10x10Unorm; + break; + + case RGBA_ASTC_12x10_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC12x10UnormSRGB : GPUTextureFormat.ASTC12x10Unorm; + break; + + case RGBA_ASTC_12x12_Format: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC12x12UnormSRGB : GPUTextureFormat.ASTC12x12Unorm; + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture format.', format ); + + } + + } else { + + switch ( format ) { + + case RGBAFormat: + + switch ( type ) { + + case ByteType: + formatGPU = GPUTextureFormat.RGBA8Snorm; + break; + + case ShortType: + formatGPU = GPUTextureFormat.RGBA16Sint; + break; + + case UnsignedShortType: + formatGPU = GPUTextureFormat.RGBA16Uint; + break; + case UnsignedIntType: + formatGPU = GPUTextureFormat.RGBA32Uint; + break; + + case IntType: + formatGPU = GPUTextureFormat.RGBA32Sint; + break; + + case UnsignedByteType: + formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.RGBA8UnormSRGB : GPUTextureFormat.RGBA8Unorm; + break; + + case HalfFloatType: + formatGPU = GPUTextureFormat.RGBA16Float; + break; + + case FloatType: + formatGPU = GPUTextureFormat.RGBA32Float; + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture type with RGBAFormat.', type ); + + } + + break; + + case RGBFormat: + + switch ( type ) { + + case UnsignedInt5999Type: + formatGPU = GPUTextureFormat.RGB9E5UFloat; + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture type with RGBFormat.', type ); + + } + + break; + + case RedFormat: + + switch ( type ) { + + case ByteType: + formatGPU = GPUTextureFormat.R8Snorm; + break; + + case ShortType: + formatGPU = GPUTextureFormat.R16Sint; + break; + + case UnsignedShortType: + formatGPU = GPUTextureFormat.R16Uint; + break; + + case UnsignedIntType: + formatGPU = GPUTextureFormat.R32Uint; + break; + + case IntType: + formatGPU = GPUTextureFormat.R32Sint; + break; + + case UnsignedByteType: + formatGPU = GPUTextureFormat.R8Unorm; + break; + + case HalfFloatType: + formatGPU = GPUTextureFormat.R16Float; + break; + + case FloatType: + formatGPU = GPUTextureFormat.R32Float; + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture type with RedFormat.', type ); + + } + + break; + + case RGFormat: + + switch ( type ) { + + case ByteType: + formatGPU = GPUTextureFormat.RG8Snorm; + break; + + case ShortType: + formatGPU = GPUTextureFormat.RG16Sint; + break; + + case UnsignedShortType: + formatGPU = GPUTextureFormat.RG16Uint; + break; + + case UnsignedIntType: + formatGPU = GPUTextureFormat.RG32Uint; + break; + + case IntType: + formatGPU = GPUTextureFormat.RG32Sint; + break; + + case UnsignedByteType: + formatGPU = GPUTextureFormat.RG8Unorm; + break; + + case HalfFloatType: + formatGPU = GPUTextureFormat.RG16Float; + break; + + case FloatType: + formatGPU = GPUTextureFormat.RG32Float; + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture type with RGFormat.', type ); + + } + + break; + + case DepthFormat: + + switch ( type ) { + + case UnsignedShortType: + formatGPU = GPUTextureFormat.Depth16Unorm; + break; + + case UnsignedIntType: + formatGPU = GPUTextureFormat.Depth24Plus; + break; + + case FloatType: + formatGPU = GPUTextureFormat.Depth32Float; + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture type with DepthFormat.', type ); + + } + + break; + + case DepthStencilFormat: + + switch ( type ) { + + case UnsignedInt248Type: + formatGPU = GPUTextureFormat.Depth24PlusStencil8; + break; + + case FloatType: + + if ( device && device.features.has( GPUFeatureName.Depth32FloatStencil8 ) === false ) { + + console.error( 'WebGPURenderer: Depth textures with DepthStencilFormat + FloatType can only be used with the "depth32float-stencil8" GPU feature.' ); + + } + + formatGPU = GPUTextureFormat.Depth32FloatStencil8; + + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture type with DepthStencilFormat.', type ); + + } + + break; + + case RedIntegerFormat: + + switch ( type ) { + + case IntType: + formatGPU = GPUTextureFormat.R32Sint; + break; + + case UnsignedIntType: + formatGPU = GPUTextureFormat.R32Uint; + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture type with RedIntegerFormat.', type ); + + } + + break; + + case RGIntegerFormat: + + switch ( type ) { + + case IntType: + formatGPU = GPUTextureFormat.RG32Sint; + break; + + case UnsignedIntType: + formatGPU = GPUTextureFormat.RG32Uint; + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture type with RGIntegerFormat.', type ); + + } + + break; + + case RGBAIntegerFormat: + + switch ( type ) { + + case IntType: + formatGPU = GPUTextureFormat.RGBA32Sint; + break; + + case UnsignedIntType: + formatGPU = GPUTextureFormat.RGBA32Uint; + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture type with RGBAIntegerFormat.', type ); + + } + + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture format.', format ); + + } + + } + + return formatGPU; + +} + +const declarationRegexp = /^[fn]*\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)\s*[\-\>]*\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/i; +const propertiesRegexp = /([a-z_0-9]+)\s*:\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/ig; + +const wgslTypeLib$1 = { + 'f32': 'float', + 'i32': 'int', + 'u32': 'uint', + 'bool': 'bool', + + 'vec2': 'vec2', + 'vec2': 'ivec2', + 'vec2': 'uvec2', + 'vec2': 'bvec2', + + 'vec2f': 'vec2', + 'vec2i': 'ivec2', + 'vec2u': 'uvec2', + 'vec2b': 'bvec2', + + 'vec3': 'vec3', + 'vec3': 'ivec3', + 'vec3': 'uvec3', + 'vec3': 'bvec3', + + 'vec3f': 'vec3', + 'vec3i': 'ivec3', + 'vec3u': 'uvec3', + 'vec3b': 'bvec3', + + 'vec4': 'vec4', + 'vec4': 'ivec4', + 'vec4': 'uvec4', + 'vec4': 'bvec4', + + 'vec4f': 'vec4', + 'vec4i': 'ivec4', + 'vec4u': 'uvec4', + 'vec4b': 'bvec4', + + 'mat2x2': 'mat2', + 'mat2x2f': 'mat2', + + 'mat3x3': 'mat3', + 'mat3x3f': 'mat3', + + 'mat4x4': 'mat4', + 'mat4x4f': 'mat4', + + 'sampler': 'sampler', + + 'texture_1d': 'texture', + + 'texture_2d': 'texture', + 'texture_2d_array': 'texture', + 'texture_multisampled_2d': 'cubeTexture', + + 'texture_depth_2d': 'depthTexture', + + 'texture_3d': 'texture3D', + + 'texture_cube': 'cubeTexture', + 'texture_cube_array': 'cubeTexture', + + 'texture_storage_1d': 'storageTexture', + 'texture_storage_2d': 'storageTexture', + 'texture_storage_2d_array': 'storageTexture', + 'texture_storage_3d': 'storageTexture' + +}; + +const parse = ( source ) => { + + source = source.trim(); + + const declaration = source.match( declarationRegexp ); + + if ( declaration !== null && declaration.length === 4 ) { + + const inputsCode = declaration[ 2 ]; + const propsMatches = []; + let match = null; + + while ( ( match = propertiesRegexp.exec( inputsCode ) ) !== null ) { + + propsMatches.push( { name: match[ 1 ], type: match[ 2 ] } ); + + } + + // Process matches to correctly pair names and types + const inputs = []; + for ( let i = 0; i < propsMatches.length; i ++ ) { + + const { name, type } = propsMatches[ i ]; + + let resolvedType = type; + + if ( resolvedType.startsWith( 'texture' ) ) { + + resolvedType = type.split( '<' )[ 0 ]; + + } + + resolvedType = wgslTypeLib$1[ resolvedType ] || resolvedType; + + inputs.push( new NodeFunctionInput( resolvedType, name ) ); + + } + + const blockCode = source.substring( declaration[ 0 ].length ); + const outputType = declaration[ 3 ] || 'void'; + + const name = declaration[ 1 ] !== undefined ? declaration[ 1 ] : ''; + const type = wgslTypeLib$1[ outputType ] || outputType; + + return { + type, + inputs, + name, + inputsCode, + blockCode, + outputType + }; + + } else { + + throw new Error( 'FunctionNode: Function is not a WGSL code.' ); + + } + +}; + +class WGSLNodeFunction extends NodeFunction { + + constructor( source ) { + + const { type, inputs, name, inputsCode, blockCode, outputType } = parse( source ); + + super( type, inputs, name ); + + this.inputsCode = inputsCode; + this.blockCode = blockCode; + this.outputType = outputType; + + } + + getCode( name = this.name ) { + + const outputType = this.outputType !== 'void' ? '-> ' + this.outputType : ''; + + return `fn ${ name } ( ${ this.inputsCode.trim() } ) ${ outputType }` + this.blockCode; + + } + +} + +class WGSLNodeParser extends NodeParser { + + parseFunction( source ) { + + return new WGSLNodeFunction( source ); + + } + +} + +// GPUShaderStage is not defined in browsers not supporting WebGPU +const GPUShaderStage = self.GPUShaderStage; + +const gpuShaderStageLib = { + 'vertex': GPUShaderStage ? GPUShaderStage.VERTEX : 1, + 'fragment': GPUShaderStage ? GPUShaderStage.FRAGMENT : 2, + 'compute': GPUShaderStage ? GPUShaderStage.COMPUTE : 4 +}; + +const supports = { + instance: true, + swizzleAssign: false, + storageBuffer: true +}; + +const wgslFnOpLib = { + '^^': 'tsl_xor' +}; + +const wgslTypeLib = { + float: 'f32', + int: 'i32', + uint: 'u32', + bool: 'bool', + color: 'vec3', + + vec2: 'vec2', + ivec2: 'vec2', + uvec2: 'vec2', + bvec2: 'vec2', + + vec3: 'vec3', + ivec3: 'vec3', + uvec3: 'vec3', + bvec3: 'vec3', + + vec4: 'vec4', + ivec4: 'vec4', + uvec4: 'vec4', + bvec4: 'vec4', + + mat2: 'mat2x2', + imat2: 'mat2x2', + umat2: 'mat2x2', + bmat2: 'mat2x2', + + mat3: 'mat3x3', + imat3: 'mat3x3', + umat3: 'mat3x3', + bmat3: 'mat3x3', + + mat4: 'mat4x4', + imat4: 'mat4x4', + umat4: 'mat4x4', + bmat4: 'mat4x4' +}; + +const wgslPolyfill = { + tsl_xor: new CodeNode( 'fn tsl_xor( a : bool, b : bool ) -> bool { return ( a || b ) && !( a && b ); }' ), + mod_float: new CodeNode( 'fn tsl_mod_float( x : f32, y : f32 ) -> f32 { return x - y * floor( x / y ); }' ), + mod_vec2: new CodeNode( 'fn tsl_mod_vec2( x : vec2f, y : vec2f ) -> vec2f { return x - y * floor( x / y ); }' ), + mod_vec3: new CodeNode( 'fn tsl_mod_vec3( x : vec3f, y : vec3f ) -> vec3f { return x - y * floor( x / y ); }' ), + mod_vec4: new CodeNode( 'fn tsl_mod_vec4( x : vec4f, y : vec4f ) -> vec4f { return x - y * floor( x / y ); }' ), + equals_bool: new CodeNode( 'fn tsl_equals_bool( a : bool, b : bool ) -> bool { return a == b; }' ), + equals_bvec2: new CodeNode( 'fn tsl_equals_bvec2( a : vec2f, b : vec2f ) -> vec2 { return vec2( a.x == b.x, a.y == b.y ); }' ), + equals_bvec3: new CodeNode( 'fn tsl_equals_bvec3( a : vec3f, b : vec3f ) -> vec3 { return vec3( a.x == b.x, a.y == b.y, a.z == b.z ); }' ), + equals_bvec4: new CodeNode( 'fn tsl_equals_bvec4( a : vec4f, b : vec4f ) -> vec4 { return vec4( a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w ); }' ), + repeatWrapping: new CodeNode( ` +fn tsl_repeatWrapping( uv : vec2, dimension : vec2 ) -> vec2 { + + let uvScaled = vec2( uv * vec2( dimension ) ); + + return ( ( uvScaled % dimension ) + dimension ) % dimension; + +} +` ), + biquadraticTexture: new CodeNode( ` +fn tsl_biquadraticTexture( map : texture_2d, coord : vec2f, level : i32 ) -> vec4f { + + let iRes = vec2i( textureDimensions( map, level ) ); + let res = vec2f( iRes ); + + let uvScaled = coord * res; + let uvWrapping = ( ( uvScaled % res ) + res ) % res; + + // https://www.shadertoy.com/view/WtyXRy + + let uv = uvWrapping - 0.5; + let iuv = floor( uv ); + let f = fract( uv ); + + let rg1 = textureLoad( map, vec2i( iuv + vec2( 0.5, 0.5 ) ) % iRes, level ); + let rg2 = textureLoad( map, vec2i( iuv + vec2( 1.5, 0.5 ) ) % iRes, level ); + let rg3 = textureLoad( map, vec2i( iuv + vec2( 0.5, 1.5 ) ) % iRes, level ); + let rg4 = textureLoad( map, vec2i( iuv + vec2( 1.5, 1.5 ) ) % iRes, level ); + + return mix( mix( rg1, rg2, f.x ), mix( rg3, rg4, f.x ), f.y ); + +} +` ) +}; + +const wgslMethods = { + dFdx: 'dpdx', + dFdy: '- dpdy', + mod_float: 'tsl_mod_float', + mod_vec2: 'tsl_mod_vec2', + mod_vec3: 'tsl_mod_vec3', + mod_vec4: 'tsl_mod_vec4', + equals_bool: 'tsl_equals_bool', + equals_bvec2: 'tsl_equals_bvec2', + equals_bvec3: 'tsl_equals_bvec3', + equals_bvec4: 'tsl_equals_bvec4', + inversesqrt: 'inverseSqrt', + bitcast: 'bitcast' +}; + +// WebGPU issue: does not support pow() with negative base on Windows + +if ( /Windows/g.test( navigator.userAgent ) ) { + + wgslPolyfill.pow_float = new CodeNode( 'fn tsl_pow_float( a : f32, b : f32 ) -> f32 { return select( -pow( -a, b ), pow( a, b ), a > 0.0 ); }' ); + wgslPolyfill.pow_vec2 = new CodeNode( 'fn tsl_pow_vec2( a : vec2f, b : vec2f ) -> vec2f { return vec2f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ) ); }', [ wgslPolyfill.pow_float ] ); + wgslPolyfill.pow_vec3 = new CodeNode( 'fn tsl_pow_vec3( a : vec3f, b : vec3f ) -> vec3f { return vec3f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ), tsl_pow_float( a.z, b.z ) ); }', [ wgslPolyfill.pow_float ] ); + wgslPolyfill.pow_vec4 = new CodeNode( 'fn tsl_pow_vec4( a : vec4f, b : vec4f ) -> vec4f { return vec4f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ), tsl_pow_float( a.z, b.z ), tsl_pow_float( a.w, b.w ) ); }', [ wgslPolyfill.pow_float ] ); + + wgslMethods.pow_float = 'tsl_pow_float'; + wgslMethods.pow_vec2 = 'tsl_pow_vec2'; + wgslMethods.pow_vec3 = 'tsl_pow_vec3'; + wgslMethods.pow_vec4 = 'tsl_pow_vec4'; + +} + +// + +let diagnostics = ''; + +if ( /Firefox/g.test( navigator.userAgent ) !== true ) { + + diagnostics += 'diagnostic( off, derivative_uniformity );\n'; + +} + +// + +class WGSLNodeBuilder extends NodeBuilder { + + constructor( object, renderer ) { + + super( object, renderer, new WGSLNodeParser() ); + + this.uniformGroups = {}; + + this.builtins = {}; + + this.directives = {}; + + this.scopedArrays = new Map(); + + } + + needsToWorkingColorSpace( texture ) { + + return texture.isVideoTexture === true && texture.colorSpace !== NoColorSpace; + + } + + _generateTextureSample( texture, textureProperty, uvSnippet, depthSnippet, shaderStage = this.shaderStage ) { + + if ( shaderStage === 'fragment' ) { + + if ( depthSnippet ) { + + return `textureSample( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ depthSnippet } )`; + + } else { + + return `textureSample( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet } )`; + + } + + } else if ( this.isFilteredTexture( texture ) ) { + + return this.generateFilteredTexture( texture, textureProperty, uvSnippet ); + + } else { + + return this.generateTextureLod( texture, textureProperty, uvSnippet, '0' ); + + } + + } + + _generateVideoSample( textureProperty, uvSnippet, shaderStage = this.shaderStage ) { + + if ( shaderStage === 'fragment' ) { + + return `textureSampleBaseClampToEdge( ${ textureProperty }, ${ textureProperty }_sampler, vec2( ${ uvSnippet }.x, 1.0 - ${ uvSnippet }.y ) )`; + + } else { + + console.error( `WebGPURenderer: THREE.VideoTexture does not support ${ shaderStage } shader.` ); + + } + + } + + _generateTextureSampleLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, shaderStage = this.shaderStage ) { + + if ( shaderStage === 'fragment' && this.isUnfilterable( texture ) === false ) { + + return `textureSampleLevel( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ levelSnippet } )`; + + } else if ( this.isFilteredTexture( texture ) ) { + + return this.generateFilteredTexture( texture, textureProperty, uvSnippet, levelSnippet ); + + } else { + + return this.generateTextureLod( texture, textureProperty, uvSnippet, levelSnippet ); + + } + + } + + generateFilteredTexture( texture, textureProperty, uvSnippet, levelSnippet = '0' ) { + + this._include( 'biquadraticTexture' ); + + return `tsl_biquadraticTexture( ${ textureProperty }, ${ uvSnippet }, i32( ${ levelSnippet } ) )`; + + } + + generateTextureLod( texture, textureProperty, uvSnippet, levelSnippet = '0' ) { + + this._include( 'repeatWrapping' ); + + const dimension = texture.isMultisampleRenderTargetTexture === true ? `textureDimensions( ${ textureProperty } )` : `textureDimensions( ${ textureProperty }, 0 )`; + + return `textureLoad( ${ textureProperty }, tsl_repeatWrapping( ${ uvSnippet }, ${ dimension } ), i32( ${ levelSnippet } ) )`; + + } + + generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0u' ) { + + if ( depthSnippet ) { + + return `textureLoad( ${ textureProperty }, ${ uvIndexSnippet }, ${ depthSnippet }, ${ levelSnippet } )`; + + } else { + + return `textureLoad( ${ textureProperty }, ${ uvIndexSnippet }, ${ levelSnippet } )`; + + } + + } + + generateTextureStore( texture, textureProperty, uvIndexSnippet, valueSnippet ) { + + return `textureStore( ${ textureProperty }, ${ uvIndexSnippet }, ${ valueSnippet } )`; + + } + + isUnfilterable( texture ) { + + return this.getComponentTypeFromTexture( texture ) !== 'float' || ( ! this.isAvailable( 'float32Filterable' ) && texture.isDataTexture === true && texture.type === FloatType ) || texture.isMultisampleRenderTargetTexture === true; + + } + + generateTexture( texture, textureProperty, uvSnippet, depthSnippet, shaderStage = this.shaderStage ) { + + let snippet = null; + + if ( texture.isVideoTexture === true ) { + + snippet = this._generateVideoSample( textureProperty, uvSnippet, shaderStage ); + + } else if ( this.isUnfilterable( texture ) ) { + + snippet = this.generateTextureLod( texture, textureProperty, uvSnippet, '0', depthSnippet, shaderStage ); + + } else { + + snippet = this._generateTextureSample( texture, textureProperty, uvSnippet, depthSnippet, shaderStage ); + + } + + return snippet; + + } + + generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet, shaderStage = this.shaderStage ) { + + if ( shaderStage === 'fragment' ) { + + // TODO handle i32 or u32 --> uvSnippet, array_index: A, ddx, ddy + return `textureSampleGrad( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ gradSnippet[ 0 ] }, ${ gradSnippet[ 1 ] } )`; + + } else { + + console.error( `WebGPURenderer: THREE.TextureNode.gradient() does not support ${ shaderStage } shader.` ); + + } + + } + + generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, shaderStage = this.shaderStage ) { + + if ( shaderStage === 'fragment' ) { + + return `textureSampleCompare( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ compareSnippet } )`; + + } else { + + console.error( `WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${ shaderStage } shader.` ); + + } + + } + + generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, shaderStage = this.shaderStage ) { + + let snippet = null; + + if ( texture.isVideoTexture === true ) { + + snippet = this._generateVideoSample( textureProperty, uvSnippet, shaderStage ); + + } else { + + snippet = this._generateTextureSampleLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, shaderStage ); + + } + + return snippet; + + } + + generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet, shaderStage = this.shaderStage ) { + + if ( shaderStage === 'fragment' ) { + + return `textureSampleBias( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ biasSnippet } )`; + + } else { + + console.error( `WebGPURenderer: THREE.TextureNode.biasNode does not support ${ shaderStage } shader.` ); + + } + + } + + getPropertyName( node, shaderStage = this.shaderStage ) { + + if ( node.isNodeVarying === true && node.needsInterpolation === true ) { + + if ( shaderStage === 'vertex' ) { + + return `varyings.${ node.name }`; + + } + + } else if ( node.isNodeUniform === true ) { + + const name = node.name; + const type = node.type; + + if ( type === 'texture' || type === 'cubeTexture' || type === 'storageTexture' || type === 'texture3D' ) { + + return name; + + } else if ( type === 'buffer' || type === 'storageBuffer' ) { + + return `NodeBuffer_${ node.id }.${name}`; + + } else { + + return node.groupNode.name + '.' + name; + + } + + } + + return super.getPropertyName( node ); + + } + + getOutputStructName() { + + return 'output'; + + } + + _getUniformGroupCount( shaderStage ) { + + return Object.keys( this.uniforms[ shaderStage ] ).length; + + } + + getFunctionOperator( op ) { + + const fnOp = wgslFnOpLib[ op ]; + + if ( fnOp !== undefined ) { + + this._include( fnOp ); + + return fnOp; + + } + + return null; + + } + + getStorageAccess( node ) { + + if ( node.isStorageTextureNode ) { + + switch ( node.access ) { + + case GPUStorageTextureAccess.ReadOnly: + + return 'read'; + + case GPUStorageTextureAccess.WriteOnly: + + return 'write'; + + default: + + return 'read_write'; + + } + + } else { + + switch ( node.access ) { + + case GPUBufferBindingType.Storage: + + return 'read_write'; + + + case GPUBufferBindingType.ReadOnlyStorage: + + return 'read'; + + default: + + return 'write'; + + } + + } + + } + + getUniformFromNode( node, type, shaderStage, name = null ) { + + const uniformNode = super.getUniformFromNode( node, type, shaderStage, name ); + const nodeData = this.getDataFromNode( node, shaderStage, this.globalCache ); + + if ( nodeData.uniformGPU === undefined ) { + + let uniformGPU; + + const group = node.groupNode; + const groupName = group.name; + + const bindings = this.getBindGroupArray( groupName, shaderStage ); + + if ( type === 'texture' || type === 'cubeTexture' || type === 'storageTexture' || type === 'texture3D' ) { + + let texture = null; + + if ( type === 'texture' || type === 'storageTexture' ) { + + texture = new NodeSampledTexture( uniformNode.name, uniformNode.node, group, node.access ? node.access : null ); + + } else if ( type === 'cubeTexture' ) { + + texture = new NodeSampledCubeTexture( uniformNode.name, uniformNode.node, group, node.access ? node.access : null ); + + } else if ( type === 'texture3D' ) { + + texture = new NodeSampledTexture3D( uniformNode.name, uniformNode.node, group, node.access ? node.access : null ); + + } + + texture.store = node.isStorageTextureNode === true; + texture.setVisibility( gpuShaderStageLib[ shaderStage ] ); + + if ( shaderStage === 'fragment' && this.isUnfilterable( node.value ) === false && texture.store === false ) { + + const sampler = new NodeSampler( `${uniformNode.name}_sampler`, uniformNode.node, group ); + sampler.setVisibility( gpuShaderStageLib[ shaderStage ] ); + + bindings.push( sampler, texture ); + + uniformGPU = [ sampler, texture ]; + + } else { + + bindings.push( texture ); + + uniformGPU = [ texture ]; + + } + + } else if ( type === 'buffer' || type === 'storageBuffer' ) { + + const bufferClass = type === 'storageBuffer' ? NodeStorageBuffer : NodeUniformBuffer; + const buffer = new bufferClass( node, group ); + buffer.setVisibility( gpuShaderStageLib[ shaderStage ] ); + + bindings.push( buffer ); + + uniformGPU = buffer; + + } else { + + const uniformsStage = this.uniformGroups[ shaderStage ] || ( this.uniformGroups[ shaderStage ] = {} ); + + let uniformsGroup = uniformsStage[ groupName ]; + + if ( uniformsGroup === undefined ) { + + uniformsGroup = new NodeUniformsGroup( groupName, group ); + uniformsGroup.setVisibility( gpuShaderStageLib[ shaderStage ] ); + + uniformsStage[ groupName ] = uniformsGroup; + + bindings.push( uniformsGroup ); + + } + + uniformGPU = this.getNodeUniform( uniformNode, type ); + + uniformsGroup.addUniform( uniformGPU ); + + } + + nodeData.uniformGPU = uniformGPU; + + } + + return uniformNode; + + } + + getBuiltin( name, property, type, shaderStage = this.shaderStage ) { + + const map = this.builtins[ shaderStage ] || ( this.builtins[ shaderStage ] = new Map() ); + + if ( map.has( name ) === false ) { + + map.set( name, { + name, + property, + type + } ); + + } + + return property; + + } + + hasBuiltin( name, shaderStage = this.shaderStage ) { + + return ( this.builtins[ shaderStage ] !== undefined && this.builtins[ shaderStage ].has( name ) ); + + } + + getVertexIndex() { + + if ( this.shaderStage === 'vertex' ) { + + return this.getBuiltin( 'vertex_index', 'vertexIndex', 'u32', 'attribute' ); + + } + + return 'vertexIndex'; + + } + + buildFunctionCode( shaderNode ) { + + const layout = shaderNode.layout; + const flowData = this.flowShaderNode( shaderNode ); + + const parameters = []; + + for ( const input of layout.inputs ) { + + parameters.push( input.name + ' : ' + this.getType( input.type ) ); + + } + + // + + let code = `fn ${ layout.name }( ${ parameters.join( ', ' ) } ) -> ${ this.getType( layout.type ) } { +${ flowData.vars } +${ flowData.code } +`; + + if ( flowData.result ) { + + code += `\treturn ${ flowData.result };\n`; + + } + + code += '\n}\n'; + + // + + return code; + + } + + getInstanceIndex() { + + if ( this.shaderStage === 'vertex' ) { + + return this.getBuiltin( 'instance_index', 'instanceIndex', 'u32', 'attribute' ); + + } + + return 'instanceIndex'; + + } + + getInvocationLocalIndex() { + + return this.getBuiltin( 'local_invocation_index', 'invocationLocalIndex', 'u32', 'attribute' ); + + } + + getSubgroupSize() { + + this.enableSubGroups(); + + return this.getBuiltin( 'subgroup_size', 'subgroupSize', 'u32', 'attribute' ); + + } + + getInvocationSubgroupIndex() { + + this.enableSubGroups(); + + return this.getBuiltin( 'subgroup_invocation_id', 'invocationSubgroupIndex', 'u32', 'attribute' ); + + } + + getSubgroupIndex() { + + this.enableSubGroups(); + + return this.getBuiltin( 'subgroup_id', 'subgroupIndex', 'u32', 'attribute' ); + + } + + getDrawIndex() { + + return null; + + } + + getFrontFacing() { + + return this.getBuiltin( 'front_facing', 'isFront', 'bool' ); + + } + + getFragCoord() { + + return this.getBuiltin( 'position', 'fragCoord', 'vec4' ) + '.xy'; + + } + + getFragDepth() { + + return 'output.' + this.getBuiltin( 'frag_depth', 'depth', 'f32', 'output' ); + + } + + isFlipY() { + + return false; + + } + + enableDirective( name, shaderStage = this.shaderStage ) { + + const stage = this.directives[ shaderStage ] || ( this.directives[ shaderStage ] = new Set() ); + stage.add( name ); + + } + + getDirectives( shaderStage ) { + + const snippets = []; + const directives = this.directives[ shaderStage ]; + + if ( directives !== undefined ) { + + for ( const directive of directives ) { + + snippets.push( `enable ${directive};` ); + + } + + } + + return snippets.join( '\n' ); + + } + + enableSubGroups() { + + this.enableDirective( 'subgroups' ); + + } + + enableSubgroupsF16() { + + this.enableDirective( 'subgroups-f16' ); + + } + + enableClipDistances() { + + this.enableDirective( 'clip_distances' ); + + } + + enableShaderF16() { + + this.enableDirective( 'f16' ); + + } + + enableDualSourceBlending() { + + this.enableDirective( 'dual_source_blending' ); + + } + + getBuiltins( shaderStage ) { + + const snippets = []; + const builtins = this.builtins[ shaderStage ]; + + if ( builtins !== undefined ) { + + for ( const { name, property, type } of builtins.values() ) { + + snippets.push( `@builtin( ${name} ) ${property} : ${type}` ); + + } + + } + + return snippets.join( ',\n\t' ); + + } + + getScopedArray( name, scope, bufferType, bufferCount ) { + + if ( this.scopedArrays.has( name ) === false ) { + + this.scopedArrays.set( name, { + name, + scope, + bufferType, + bufferCount + } ); + + } + + return name; + + } + + getScopedArrays( shaderStage ) { + + if ( shaderStage !== 'compute' ) { + + return; + + } + + const snippets = []; + + for ( const { name, scope, bufferType, bufferCount } of this.scopedArrays.values() ) { + + const type = this.getType( bufferType ); + + snippets.push( `var<${scope}> ${name}: array< ${type}, ${bufferCount} >;` ); + + } + + return snippets.join( '\n' ); + + } + + getAttributes( shaderStage ) { + + const snippets = []; + + if ( shaderStage === 'compute' ) { + + this.getBuiltin( 'global_invocation_id', 'id', 'vec3', 'attribute' ); + this.getBuiltin( 'workgroup_id', 'workgroupId', 'vec3', 'attribute' ); + this.getBuiltin( 'local_invocation_id', 'localId', 'vec3', 'attribute' ); + this.getBuiltin( 'num_workgroups', 'numWorkgroups', 'vec3', 'attribute' ); + + if ( this.renderer.hasFeature( 'subgroups' ) ) { + + this.enableDirective( 'subgroups', shaderStage ); + this.getBuiltin( 'subgroup_size', 'subgroupSize', 'u32', 'attribute' ); + + } + + } + + if ( shaderStage === 'vertex' || shaderStage === 'compute' ) { + + const builtins = this.getBuiltins( 'attribute' ); + + if ( builtins ) snippets.push( builtins ); + + const attributes = this.getAttributesArray(); + + for ( let index = 0, length = attributes.length; index < length; index ++ ) { + + const attribute = attributes[ index ]; + const name = attribute.name; + const type = this.getType( attribute.type ); + + snippets.push( `@location( ${index} ) ${ name } : ${ type }` ); + + } + + } + + return snippets.join( ',\n\t' ); + + } + + getStructMembers( struct ) { + + const snippets = []; + const members = struct.getMemberTypes(); + + for ( let i = 0; i < members.length; i ++ ) { + + const member = members[ i ]; + snippets.push( `\t@location( ${i} ) m${i} : ${ member }` ); + + } + + const builtins = this.getBuiltins( 'output' ); + + if ( builtins ) snippets.push( '\t' + builtins ); + + return snippets.join( ',\n' ); + + } + + getStructs( shaderStage ) { + + const snippets = []; + const structs = this.structs[ shaderStage ]; + + for ( let index = 0, length = structs.length; index < length; index ++ ) { + + const struct = structs[ index ]; + const name = struct.name; + + let snippet = `\struct ${ name } {\n`; + snippet += this.getStructMembers( struct ); + snippet += '\n}'; + + + snippets.push( snippet ); + + snippets.push( `\nvar output : ${ name };\n\n` ); + + } + + return snippets.join( '\n\n' ); + + } + + getVar( type, name ) { + + return `var ${ name } : ${ this.getType( type ) }`; + + } + + getVars( shaderStage ) { + + const snippets = []; + const vars = this.vars[ shaderStage ]; + + if ( vars !== undefined ) { + + for ( const variable of vars ) { + + snippets.push( `\t${ this.getVar( variable.type, variable.name ) };` ); + + } + + } + + return `\n${ snippets.join( '\n' ) }\n`; + + } + + getVaryings( shaderStage ) { + + const snippets = []; + + if ( shaderStage === 'vertex' ) { + + this.getBuiltin( 'position', 'Vertex', 'vec4', 'vertex' ); + + } + + if ( shaderStage === 'vertex' || shaderStage === 'fragment' ) { + + const varyings = this.varyings; + const vars = this.vars[ shaderStage ]; + + for ( let index = 0; index < varyings.length; index ++ ) { + + const varying = varyings[ index ]; + + if ( varying.needsInterpolation ) { + + let attributesSnippet = `@location( ${index} )`; + + if ( /^(int|uint|ivec|uvec)/.test( varying.type ) ) { + + attributesSnippet += ' @interpolate( flat )'; + + + } + + snippets.push( `${ attributesSnippet } ${ varying.name } : ${ this.getType( varying.type ) }` ); + + } else if ( shaderStage === 'vertex' && vars.includes( varying ) === false ) { + + vars.push( varying ); + + } + + } + + } + + const builtins = this.getBuiltins( shaderStage ); + + if ( builtins ) snippets.push( builtins ); + + const code = snippets.join( ',\n\t' ); + + return shaderStage === 'vertex' ? this._getWGSLStruct( 'VaryingsStruct', '\t' + code ) : code; + + } + + getUniforms( shaderStage ) { + + const uniforms = this.uniforms[ shaderStage ]; + + const bindingSnippets = []; + const bufferSnippets = []; + const structSnippets = []; + const uniformGroups = {}; + + for ( const uniform of uniforms ) { + + const groupName = uniform.groupNode.name; + const uniformIndexes = this.bindingsIndexes[ groupName ]; + + if ( uniform.type === 'texture' || uniform.type === 'cubeTexture' || uniform.type === 'storageTexture' || uniform.type === 'texture3D' ) { + + const texture = uniform.node.value; + + if ( shaderStage === 'fragment' && this.isUnfilterable( texture ) === false && uniform.node.isStorageTextureNode !== true ) { + + if ( texture.isDepthTexture === true && texture.compareFunction !== null ) { + + bindingSnippets.push( `@binding( ${ uniformIndexes.binding ++ } ) @group( ${ uniformIndexes.group } ) var ${ uniform.name }_sampler : sampler_comparison;` ); + + } else { + + bindingSnippets.push( `@binding( ${ uniformIndexes.binding ++ } ) @group( ${ uniformIndexes.group } ) var ${ uniform.name }_sampler : sampler;` ); + + } + + } + + let textureType; + + let multisampled = ''; + + if ( texture.isMultisampleRenderTargetTexture === true ) { + + multisampled = '_multisampled'; + + } + + if ( texture.isCubeTexture === true ) { + + textureType = 'texture_cube'; + + } else if ( texture.isDataArrayTexture === true || texture.isCompressedArrayTexture === true ) { + + textureType = 'texture_2d_array'; + + } else if ( texture.isDepthTexture === true ) { + + textureType = `texture_depth${multisampled}_2d`; + + } else if ( texture.isVideoTexture === true ) { + + textureType = 'texture_external'; + + } else if ( texture.isData3DTexture === true ) { + + textureType = 'texture_3d'; + + } else if ( uniform.node.isStorageTextureNode === true ) { + + const format = getFormat( texture ); + const access = this.getStorageAccess( uniform.node ); + + textureType = `texture_storage_2d<${ format }, ${ access }>`; + + } else { + + const componentPrefix = this.getComponentTypeFromTexture( texture ).charAt( 0 ); + + textureType = `texture${multisampled}_2d<${ componentPrefix }32>`; + + } + + bindingSnippets.push( `@binding( ${ uniformIndexes.binding ++ } ) @group( ${ uniformIndexes.group } ) var ${ uniform.name } : ${ textureType };` ); + + } else if ( uniform.type === 'buffer' || uniform.type === 'storageBuffer' ) { + + const bufferNode = uniform.node; + const bufferType = this.getType( bufferNode.bufferType ); + const bufferCount = bufferNode.bufferCount; + + const bufferCountSnippet = bufferCount > 0 ? ', ' + bufferCount : ''; + const bufferTypeSnippet = bufferNode.isAtomic ? `atomic<${bufferType}>` : `${bufferType}`; + const bufferSnippet = `\t${ uniform.name } : array< ${ bufferTypeSnippet }${ bufferCountSnippet } >\n`; + const bufferAccessMode = bufferNode.isStorageBufferNode ? `storage, ${ this.getStorageAccess( bufferNode ) }` : 'uniform'; + + bufferSnippets.push( this._getWGSLStructBinding( 'NodeBuffer_' + bufferNode.id, bufferSnippet, bufferAccessMode, uniformIndexes.binding ++, uniformIndexes.group ) ); + + } else { + + const vectorType = this.getType( this.getVectorType( uniform.type ) ); + const groupName = uniform.groupNode.name; + + const group = uniformGroups[ groupName ] || ( uniformGroups[ groupName ] = { + index: uniformIndexes.binding ++, + id: uniformIndexes.group, + snippets: [] + } ); + + group.snippets.push( `\t${ uniform.name } : ${ vectorType }` ); + + } + + } + + for ( const name in uniformGroups ) { + + const group = uniformGroups[ name ]; + + structSnippets.push( this._getWGSLStructBinding( name, group.snippets.join( ',\n' ), 'uniform', group.index, group.id ) ); + + } + + let code = bindingSnippets.join( '\n' ); + code += bufferSnippets.join( '\n' ); + code += structSnippets.join( '\n' ); + + return code; + + } + + buildCode() { + + const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; + + this.sortBindingGroups(); + + for ( const shaderStage in shadersData ) { + + const stageData = shadersData[ shaderStage ]; + stageData.uniforms = this.getUniforms( shaderStage ); + stageData.attributes = this.getAttributes( shaderStage ); + stageData.varyings = this.getVaryings( shaderStage ); + stageData.structs = this.getStructs( shaderStage ); + stageData.vars = this.getVars( shaderStage ); + stageData.codes = this.getCodes( shaderStage ); + stageData.directives = this.getDirectives( shaderStage ); + stageData.scopedArrays = this.getScopedArrays( shaderStage ); + + // + + let flow = '// code\n\n'; + flow += this.flowCode[ shaderStage ]; + + const flowNodes = this.flowNodes[ shaderStage ]; + const mainNode = flowNodes[ flowNodes.length - 1 ]; + + const outputNode = mainNode.outputNode; + const isOutputStruct = ( outputNode !== undefined && outputNode.isOutputStructNode === true ); + + for ( const node of flowNodes ) { + + const flowSlotData = this.getFlowData( node/*, shaderStage*/ ); + const slotName = node.name; + + if ( slotName ) { + + if ( flow.length > 0 ) flow += '\n'; + + flow += `\t// flow -> ${ slotName }\n\t`; + + } + + flow += `${ flowSlotData.code }\n\t`; + + if ( node === mainNode && shaderStage !== 'compute' ) { + + flow += '// result\n\n\t'; + + if ( shaderStage === 'vertex' ) { + + flow += `varyings.Vertex = ${ flowSlotData.result };`; + + } else if ( shaderStage === 'fragment' ) { + + if ( isOutputStruct ) { + + stageData.returnType = outputNode.nodeType; + + flow += `return ${ flowSlotData.result };`; + + } else { + + let structSnippet = '\t@location(0) color: vec4'; + + const builtins = this.getBuiltins( 'output' ); + + if ( builtins ) structSnippet += ',\n\t' + builtins; + + stageData.returnType = 'OutputStruct'; + stageData.structs += this._getWGSLStruct( 'OutputStruct', structSnippet ); + stageData.structs += '\nvar output : OutputStruct;\n\n'; + + flow += `output.color = ${ flowSlotData.result };\n\n\treturn output;`; + + } + + } + + } + + } + + stageData.flow = flow; + + + } + + if ( this.material !== null ) { + + this.vertexShader = this._getWGSLVertexCode( shadersData.vertex ); + this.fragmentShader = this._getWGSLFragmentCode( shadersData.fragment ); + + } else { + + this.computeShader = this._getWGSLComputeCode( shadersData.compute, ( this.object.workgroupSize || [ 64 ] ).join( ', ' ) ); + + } + + } + + getMethod( method, output = null ) { + + let wgslMethod; + + if ( output !== null ) { + + wgslMethod = this._getWGSLMethod( method + '_' + output ); + + } + + if ( wgslMethod === undefined ) { + + wgslMethod = this._getWGSLMethod( method ); + + } + + return wgslMethod || method; + + } + + getType( type ) { + + return wgslTypeLib[ type ] || type; + + } + + isAvailable( name ) { + + let result = supports[ name ]; + + if ( result === undefined ) { + + if ( name === 'float32Filterable' ) { + + result = this.renderer.hasFeature( 'float32-filterable' ); + + } + + supports[ name ] = result; + + } + + return result; + + } + + _getWGSLMethod( method ) { + + if ( wgslPolyfill[ method ] !== undefined ) { + + this._include( method ); + + } + + return wgslMethods[ method ]; + + } + + _include( name ) { + + const codeNode = wgslPolyfill[ name ]; + codeNode.build( this ); + + if ( this.currentFunctionNode !== null ) { + + this.currentFunctionNode.includes.push( codeNode ); + + } + + return codeNode; + + } + + _getWGSLVertexCode( shaderData ) { + + return `${ this.getSignature() } +// directives +${shaderData.directives} + +// uniforms +${shaderData.uniforms} + +// varyings +${shaderData.varyings} +var varyings : VaryingsStruct; + +// codes +${shaderData.codes} + +@vertex +fn main( ${shaderData.attributes} ) -> VaryingsStruct { + + // vars + ${shaderData.vars} + + // flow + ${shaderData.flow} + + return varyings; + +} +`; + + } + + _getWGSLFragmentCode( shaderData ) { + + return `${ this.getSignature() } +// global +${ diagnostics } + +// uniforms +${shaderData.uniforms} + +// structs +${shaderData.structs} + +// codes +${shaderData.codes} + +@fragment +fn main( ${shaderData.varyings} ) -> ${shaderData.returnType} { + + // vars + ${shaderData.vars} + + // flow + ${shaderData.flow} + +} +`; + + } + + _getWGSLComputeCode( shaderData, workgroupSize ) { + + return `${ this.getSignature() } +// directives +${shaderData.directives} + +// system +var instanceIndex : u32; + +// locals +${shaderData.scopedArrays} + +// uniforms +${shaderData.uniforms} + +// codes +${shaderData.codes} + +@compute @workgroup_size( ${workgroupSize} ) +fn main( ${shaderData.attributes} ) { + + // system + instanceIndex = id.x + id.y * numWorkgroups.x * u32(${workgroupSize}) + id.z * numWorkgroups.x * numWorkgroups.y * u32(${workgroupSize}); + + // vars + ${shaderData.vars} + + // flow + ${shaderData.flow} + +} +`; + + } + + _getWGSLStruct( name, vars ) { + + return ` +struct ${name} { +${vars} +};`; + + } + + _getWGSLStructBinding( name, vars, access, binding = 0, group = 0 ) { + + const structName = name + 'Struct'; + const structSnippet = this._getWGSLStruct( structName, vars ); + + return `${structSnippet} +@binding( ${binding} ) @group( ${group} ) +var<${access}> ${name} : ${structName};`; + + } + +} + +class WebGPUUtils { + + constructor( backend ) { + + this.backend = backend; + + } + + getCurrentDepthStencilFormat( renderContext ) { + + let format; + + if ( renderContext.depthTexture !== null ) { + + format = this.getTextureFormatGPU( renderContext.depthTexture ); + + } else if ( renderContext.depth && renderContext.stencil ) { + + format = GPUTextureFormat.Depth24PlusStencil8; + + } else if ( renderContext.depth ) { + + format = GPUTextureFormat.Depth24Plus; + + } + + return format; + + } + + getTextureFormatGPU( texture ) { + + return this.backend.get( texture ).format; + + } + + getCurrentColorFormat( renderContext ) { + + let format; + + if ( renderContext.textures !== null ) { + + format = this.getTextureFormatGPU( renderContext.textures[ 0 ] ); + + + } else { + + format = this.getPreferredCanvasFormat(); // default context format + + } + + return format; + + } + + getCurrentColorSpace( renderContext ) { + + if ( renderContext.textures !== null ) { + + return renderContext.textures[ 0 ].colorSpace; + + } + + return this.backend.renderer.outputColorSpace; + + } + + getPrimitiveTopology( object, material ) { + + if ( object.isPoints ) return GPUPrimitiveTopology.PointList; + else if ( object.isLineSegments || ( object.isMesh && material.wireframe === true ) ) return GPUPrimitiveTopology.LineList; + else if ( object.isLine ) return GPUPrimitiveTopology.LineStrip; + else if ( object.isMesh ) return GPUPrimitiveTopology.TriangleList; + + } + + getSampleCount( sampleCount ) { + + let count = 1; + + if ( sampleCount > 1 ) { + + // WebGPU only supports power-of-two sample counts and 2 is not a valid value + count = Math.pow( 2, Math.floor( Math.log2( sampleCount ) ) ); + + if ( count === 2 ) { + + count = 4; + + } + + } + + return count; + + } + + getSampleCountRenderContext( renderContext ) { + + if ( renderContext.textures !== null ) { + + return this.getSampleCount( renderContext.sampleCount ); + + } + + return this.getSampleCount( this.backend.renderer.samples ); + + } + + getPreferredCanvasFormat() { + + // TODO: Remove this check when Quest 34.5 is out + // https://github.com/mrdoob/three.js/pull/29221/files#r1731833949 + + if ( navigator.userAgent.includes( 'Quest' ) ) { + + return GPUTextureFormat.BGRA8Unorm; + + } else { + + return navigator.gpu.getPreferredCanvasFormat(); + + } + + } + +} + +const typedArraysToVertexFormatPrefix = new Map( [ + [ Int8Array, [ 'sint8', 'snorm8' ]], + [ Uint8Array, [ 'uint8', 'unorm8' ]], + [ Int16Array, [ 'sint16', 'snorm16' ]], + [ Uint16Array, [ 'uint16', 'unorm16' ]], + [ Int32Array, [ 'sint32', 'snorm32' ]], + [ Uint32Array, [ 'uint32', 'unorm32' ]], + [ Float32Array, [ 'float32', ]], +] ); + +const typedAttributeToVertexFormatPrefix = new Map( [ + [ Float16BufferAttribute, [ 'float16', ]], +] ); + +const typeArraysToVertexFormatPrefixForItemSize1 = new Map( [ + [ Int32Array, 'sint32' ], + [ Int16Array, 'sint32' ], // patch for INT16 + [ Uint32Array, 'uint32' ], + [ Uint16Array, 'uint32' ], // patch for UINT16 + [ Float32Array, 'float32' ] +] ); + +class WebGPUAttributeUtils { + + constructor( backend ) { + + this.backend = backend; + + } + + createAttribute( attribute, usage ) { + + const bufferAttribute = this._getBufferAttribute( attribute ); + + const backend = this.backend; + const bufferData = backend.get( bufferAttribute ); + + let buffer = bufferData.buffer; + + if ( buffer === undefined ) { + + const device = backend.device; + + let array = bufferAttribute.array; + + // patch for INT16 and UINT16 + if ( attribute.normalized === false && ( array.constructor === Int16Array || array.constructor === Uint16Array ) ) { + + const tempArray = new Uint32Array( array.length ); + for ( let i = 0; i < array.length; i ++ ) { + + tempArray[ i ] = array[ i ]; + + } + + array = tempArray; + + } + + bufferAttribute.array = array; + + if ( ( bufferAttribute.isStorageBufferAttribute || bufferAttribute.isStorageInstancedBufferAttribute ) && bufferAttribute.itemSize === 3 ) { + + array = new array.constructor( bufferAttribute.count * 4 ); + + for ( let i = 0; i < bufferAttribute.count; i ++ ) { + + array.set( bufferAttribute.array.subarray( i * 3, i * 3 + 3 ), i * 4 ); + + } + + // Update BufferAttribute + bufferAttribute.itemSize = 4; + bufferAttribute.array = array; + + } + + const size = array.byteLength + ( ( 4 - ( array.byteLength % 4 ) ) % 4 ); // ensure 4 byte alignment, see #20441 + + buffer = device.createBuffer( { + label: bufferAttribute.name, + size: size, + usage: usage, + mappedAtCreation: true + } ); + + new array.constructor( buffer.getMappedRange() ).set( array ); + + buffer.unmap(); + + bufferData.buffer = buffer; + + } + + } + + updateAttribute( attribute ) { + + const bufferAttribute = this._getBufferAttribute( attribute ); + + const backend = this.backend; + const device = backend.device; + + const buffer = backend.get( bufferAttribute ).buffer; + + const array = bufferAttribute.array; + const updateRanges = bufferAttribute.updateRanges; + + if ( updateRanges.length === 0 ) { + + // Not using update ranges + + device.queue.writeBuffer( + buffer, + 0, + array, + 0 + ); + + } else { + + for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { + + const range = updateRanges[ i ]; + device.queue.writeBuffer( + buffer, + 0, + array, + range.start * array.BYTES_PER_ELEMENT, + range.count * array.BYTES_PER_ELEMENT + ); + + } + + bufferAttribute.clearUpdateRanges(); + + } + + } + + createShaderVertexBuffers( renderObject ) { + + const attributes = renderObject.getAttributes(); + const vertexBuffers = new Map(); + + for ( let slot = 0; slot < attributes.length; slot ++ ) { + + const geometryAttribute = attributes[ slot ]; + const bytesPerElement = geometryAttribute.array.BYTES_PER_ELEMENT; + const bufferAttribute = this._getBufferAttribute( geometryAttribute ); + + let vertexBufferLayout = vertexBuffers.get( bufferAttribute ); + + if ( vertexBufferLayout === undefined ) { + + let arrayStride, stepMode; + + if ( geometryAttribute.isInterleavedBufferAttribute === true ) { + + arrayStride = geometryAttribute.data.stride * bytesPerElement; + stepMode = geometryAttribute.data.isInstancedInterleavedBuffer ? GPUInputStepMode.Instance : GPUInputStepMode.Vertex; + + } else { + + arrayStride = geometryAttribute.itemSize * bytesPerElement; + stepMode = geometryAttribute.isInstancedBufferAttribute ? GPUInputStepMode.Instance : GPUInputStepMode.Vertex; + + } + + // patch for INT16 and UINT16 + if ( geometryAttribute.normalized === false && ( geometryAttribute.array.constructor === Int16Array || geometryAttribute.array.constructor === Uint16Array ) ) { + + arrayStride = 4; + + } + + vertexBufferLayout = { + arrayStride, + attributes: [], + stepMode + }; + + vertexBuffers.set( bufferAttribute, vertexBufferLayout ); + + } + + const format = this._getVertexFormat( geometryAttribute ); + const offset = ( geometryAttribute.isInterleavedBufferAttribute === true ) ? geometryAttribute.offset * bytesPerElement : 0; + + vertexBufferLayout.attributes.push( { + shaderLocation: slot, + offset, + format + } ); + + } + + return Array.from( vertexBuffers.values() ); + + } + + destroyAttribute( attribute ) { + + const backend = this.backend; + const data = backend.get( this._getBufferAttribute( attribute ) ); + + data.buffer.destroy(); + + backend.delete( attribute ); + + } + + async getArrayBufferAsync( attribute ) { + + const backend = this.backend; + const device = backend.device; + + const data = backend.get( this._getBufferAttribute( attribute ) ); + + const bufferGPU = data.buffer; + const size = bufferGPU.size; + + const readBufferGPU = device.createBuffer( { + label: attribute.name, + size, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ + } ); + + + const cmdEncoder = device.createCommandEncoder( {} ); + + cmdEncoder.copyBufferToBuffer( + bufferGPU, + 0, + readBufferGPU, + 0, + size + ); + + readBufferGPU.unmap(); + + const gpuCommands = cmdEncoder.finish(); + device.queue.submit( [ gpuCommands ] ); + + await readBufferGPU.mapAsync( GPUMapMode.READ ); + + const arrayBuffer = readBufferGPU.getMappedRange(); + + return arrayBuffer; + + } + + _getVertexFormat( geometryAttribute ) { + + const { itemSize, normalized } = geometryAttribute; + const ArrayType = geometryAttribute.array.constructor; + const AttributeType = geometryAttribute.constructor; + + let format; + + if ( itemSize == 1 ) { + + format = typeArraysToVertexFormatPrefixForItemSize1.get( ArrayType ); + + } else { + + const prefixOptions = typedAttributeToVertexFormatPrefix.get( AttributeType ) || typedArraysToVertexFormatPrefix.get( ArrayType ); + const prefix = prefixOptions[ normalized ? 1 : 0 ]; + + if ( prefix ) { + + const bytesPerUnit = ArrayType.BYTES_PER_ELEMENT * itemSize; + const paddedBytesPerUnit = Math.floor( ( bytesPerUnit + 3 ) / 4 ) * 4; + const paddedItemSize = paddedBytesPerUnit / ArrayType.BYTES_PER_ELEMENT; + + if ( paddedItemSize % 1 ) { + + throw new Error( 'THREE.WebGPUAttributeUtils: Bad vertex format item size.' ); + + } + + format = `${prefix}x${paddedItemSize}`; + + } + + } + + if ( ! format ) { + + console.error( 'THREE.WebGPUAttributeUtils: Vertex format not supported yet.' ); + + } + + return format; + + } + + _getBufferAttribute( attribute ) { + + if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; + + return attribute; + + } + +} + +class WebGPUBindingUtils { + + constructor( backend ) { + + this.backend = backend; + this.bindGroupLayoutCache = new WeakMap(); + + } + + createBindingsLayout( bindGroup ) { + + const backend = this.backend; + const device = backend.device; + + const entries = []; + + let index = 0; + + for ( const binding of bindGroup.bindings ) { + + const bindingGPU = { + binding: index ++, + visibility: binding.visibility + }; + + if ( binding.isUniformBuffer || binding.isStorageBuffer ) { + + const buffer = {}; // GPUBufferBindingLayout + + if ( binding.isStorageBuffer ) { + + buffer.type = binding.access; + + } + + bindingGPU.buffer = buffer; + + } else if ( binding.isSampler ) { + + const sampler = {}; // GPUSamplerBindingLayout + + if ( binding.texture.isDepthTexture ) { + + if ( binding.texture.compareFunction !== null ) { + + sampler.type = 'comparison'; + + } + + } + + bindingGPU.sampler = sampler; + + } else if ( binding.isSampledTexture && binding.texture.isVideoTexture ) { + + bindingGPU.externalTexture = {}; // GPUExternalTextureBindingLayout + + } else if ( binding.isSampledTexture && binding.store ) { + + const format = this.backend.get( binding.texture ).texture.format; + const access = binding.access; + + bindingGPU.storageTexture = { format, access }; // GPUStorageTextureBindingLayout + + } else if ( binding.isSampledTexture ) { + + const texture = {}; // GPUTextureBindingLayout + + if ( binding.texture.isMultisampleRenderTargetTexture === true ) { + + texture.multisampled = true; + + } + + if ( binding.texture.isDepthTexture ) { + + texture.sampleType = GPUTextureSampleType.Depth; + + } else if ( binding.texture.isDataTexture || binding.texture.isDataArrayTexture || binding.texture.isData3DTexture ) { + + const type = binding.texture.type; + + if ( type === IntType ) { + + texture.sampleType = GPUTextureSampleType.SInt; + + } else if ( type === UnsignedIntType ) { + + texture.sampleType = GPUTextureSampleType.UInt; + + } else if ( type === FloatType ) { + + if ( this.backend.hasFeature( 'float32-filterable' ) ) { + + texture.sampleType = GPUTextureSampleType.Float; + + } else { + + texture.sampleType = GPUTextureSampleType.UnfilterableFloat; + + } + + } + + } + + if ( binding.isSampledCubeTexture ) { + + texture.viewDimension = GPUTextureViewDimension.Cube; + + } else if ( binding.texture.isDataArrayTexture || binding.texture.isCompressedArrayTexture ) { + + texture.viewDimension = GPUTextureViewDimension.TwoDArray; + + } else if ( binding.isSampledTexture3D ) { + + texture.viewDimension = GPUTextureViewDimension.ThreeD; + + } + + bindingGPU.texture = texture; + + } else { + + console.error( `WebGPUBindingUtils: Unsupported binding "${ binding }".` ); + + } + + entries.push( bindingGPU ); + + } + + return device.createBindGroupLayout( { entries } ); + + } + + createBindings( bindGroup ) { + + const { backend, bindGroupLayoutCache } = this; + const bindingsData = backend.get( bindGroup ); + + // setup (static) binding layout and (dynamic) binding group + + let bindLayoutGPU = bindGroupLayoutCache.get( bindGroup.bindingsReference ); + + if ( bindLayoutGPU === undefined ) { + + bindLayoutGPU = this.createBindingsLayout( bindGroup ); + bindGroupLayoutCache.set( bindGroup.bindingsReference, bindLayoutGPU ); + + } + + const bindGroupGPU = this.createBindGroup( bindGroup, bindLayoutGPU ); + + bindingsData.layout = bindLayoutGPU; + bindingsData.group = bindGroupGPU; + + } + + updateBinding( binding ) { + + const backend = this.backend; + const device = backend.device; + + const buffer = binding.buffer; + const bufferGPU = backend.get( binding ).buffer; + + device.queue.writeBuffer( bufferGPU, 0, buffer, 0 ); + + } + + createBindGroup( bindGroup, layoutGPU ) { + + const backend = this.backend; + const device = backend.device; + + let bindingPoint = 0; + const entriesGPU = []; + + for ( const binding of bindGroup.bindings ) { + + if ( binding.isUniformBuffer ) { + + const bindingData = backend.get( binding ); + + if ( bindingData.buffer === undefined ) { + + const byteLength = binding.byteLength; + + const usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST; + + const bufferGPU = device.createBuffer( { + label: 'bindingBuffer_' + binding.name, + size: byteLength, + usage: usage + } ); + + bindingData.buffer = bufferGPU; + + } + + entriesGPU.push( { binding: bindingPoint, resource: { buffer: bindingData.buffer } } ); + + } else if ( binding.isStorageBuffer ) { + + const bindingData = backend.get( binding ); + + if ( bindingData.buffer === undefined ) { + + const attribute = binding.attribute; + //const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX | /*GPUBufferUsage.COPY_SRC |*/ GPUBufferUsage.COPY_DST; + + //backend.attributeUtils.createAttribute( attribute, usage ); // @TODO: Move it to universal renderer + + bindingData.buffer = backend.get( attribute ).buffer; + + } + + entriesGPU.push( { binding: bindingPoint, resource: { buffer: bindingData.buffer } } ); + + } else if ( binding.isSampler ) { + + const textureGPU = backend.get( binding.texture ); + + entriesGPU.push( { binding: bindingPoint, resource: textureGPU.sampler } ); + + } else if ( binding.isSampledTexture ) { + + const textureData = backend.get( binding.texture ); + + let resourceGPU; + + if ( textureData.externalTexture !== undefined ) { + + resourceGPU = device.importExternalTexture( { source: textureData.externalTexture } ); + + } else { + + const mipLevelCount = binding.store ? 1 : textureData.texture.mipLevelCount; + const propertyName = `view-${ textureData.texture.width }-${ textureData.texture.height }-${ mipLevelCount }`; + + resourceGPU = textureData[ propertyName ]; + + if ( resourceGPU === undefined ) { + + const aspectGPU = GPUTextureAspect.All; + + let dimensionViewGPU; + + if ( binding.isSampledCubeTexture ) { + + dimensionViewGPU = GPUTextureViewDimension.Cube; + + } else if ( binding.isSampledTexture3D ) { + + dimensionViewGPU = GPUTextureViewDimension.ThreeD; + + } else if ( binding.texture.isDataArrayTexture || binding.texture.isCompressedArrayTexture ) { + + dimensionViewGPU = GPUTextureViewDimension.TwoDArray; + + } else { + + dimensionViewGPU = GPUTextureViewDimension.TwoD; + + } + + resourceGPU = textureData[ propertyName ] = textureData.texture.createView( { aspect: aspectGPU, dimension: dimensionViewGPU, mipLevelCount } ); + + } + + } + + entriesGPU.push( { binding: bindingPoint, resource: resourceGPU } ); + + } + + bindingPoint ++; + + } + + return device.createBindGroup( { + label: 'bindGroup_' + bindGroup.name, + layout: layoutGPU, + entries: entriesGPU + } ); + + } + +} + +class WebGPUPipelineUtils { + + constructor( backend ) { + + this.backend = backend; + + } + + _getSampleCount( renderObjectContext ) { + + return this.backend.utils.getSampleCountRenderContext( renderObjectContext ); + + } + + createRenderPipeline( renderObject, promises ) { + + const { object, material, geometry, pipeline } = renderObject; + const { vertexProgram, fragmentProgram } = pipeline; + + const backend = this.backend; + const device = backend.device; + const utils = backend.utils; + + const pipelineData = backend.get( pipeline ); + + // bind group layouts + + const bindGroupLayouts = []; + + for ( const bindGroup of renderObject.getBindings() ) { + + const bindingsData = backend.get( bindGroup ); + + bindGroupLayouts.push( bindingsData.layout ); + + } + + // vertex buffers + + const vertexBuffers = backend.attributeUtils.createShaderVertexBuffers( renderObject ); + + // blending + + let blending; + + if ( material.transparent === true && material.blending !== NoBlending ) { + + blending = this._getBlending( material ); + + } + + // stencil + + let stencilFront = {}; + + if ( material.stencilWrite === true ) { + + stencilFront = { + compare: this._getStencilCompare( material ), + failOp: this._getStencilOperation( material.stencilFail ), + depthFailOp: this._getStencilOperation( material.stencilZFail ), + passOp: this._getStencilOperation( material.stencilZPass ) + }; + + } + + const colorWriteMask = this._getColorWriteMask( material ); + + const targets = []; + + if ( renderObject.context.textures !== null ) { + + const textures = renderObject.context.textures; + + for ( let i = 0; i < textures.length; i ++ ) { + + const colorFormat = utils.getTextureFormatGPU( textures[ i ] ); + + targets.push( { + format: colorFormat, + blend: blending, + writeMask: colorWriteMask + } ); + + } + + } else { + + const colorFormat = utils.getCurrentColorFormat( renderObject.context ); + + targets.push( { + format: colorFormat, + blend: blending, + writeMask: colorWriteMask + } ); + + } + + const vertexModule = backend.get( vertexProgram ).module; + const fragmentModule = backend.get( fragmentProgram ).module; + + const primitiveState = this._getPrimitiveState( object, geometry, material ); + const depthCompare = this._getDepthCompare( material ); + const depthStencilFormat = utils.getCurrentDepthStencilFormat( renderObject.context ); + + const sampleCount = this._getSampleCount( renderObject.context ); + + const pipelineDescriptor = { + label: `renderPipeline_${ material.name || material.type }_${ material.id }`, + vertex: Object.assign( {}, vertexModule, { buffers: vertexBuffers } ), + fragment: Object.assign( {}, fragmentModule, { targets } ), + primitive: primitiveState, + depthStencil: { + format: depthStencilFormat, + depthWriteEnabled: material.depthWrite, + depthCompare: depthCompare, + stencilFront: stencilFront, + stencilBack: {}, // three.js does not provide an API to configure the back function (gl.stencilFuncSeparate() was never used) + stencilReadMask: material.stencilFuncMask, + stencilWriteMask: material.stencilWriteMask + }, + multisample: { + count: sampleCount, + alphaToCoverageEnabled: material.alphaToCoverage && sampleCount > 1 + }, + layout: device.createPipelineLayout( { + bindGroupLayouts + } ) + }; + + if ( promises === null ) { + + pipelineData.pipeline = device.createRenderPipeline( pipelineDescriptor ); + + } else { + + const p = new Promise( ( resolve /*, reject*/ ) => { + + device.createRenderPipelineAsync( pipelineDescriptor ).then( pipeline => { + + pipelineData.pipeline = pipeline; + resolve(); + + } ); + + } ); + + promises.push( p ); + + } + + } + + createBundleEncoder( renderContext ) { + + const backend = this.backend; + const { utils, device } = backend; + + const depthStencilFormat = utils.getCurrentDepthStencilFormat( renderContext ); + const colorFormat = utils.getCurrentColorFormat( renderContext ); + const sampleCount = this._getSampleCount( renderContext ); + + const descriptor = { + label: 'renderBundleEncoder', + colorFormats: [ colorFormat ], + depthStencilFormat, + sampleCount + }; + + return device.createRenderBundleEncoder( descriptor ); + + } + + createComputePipeline( pipeline, bindings ) { + + const backend = this.backend; + const device = backend.device; + + const computeProgram = backend.get( pipeline.computeProgram ).module; + + const pipelineGPU = backend.get( pipeline ); + + // bind group layouts + + const bindGroupLayouts = []; + + for ( const bindingsGroup of bindings ) { + + const bindingsData = backend.get( bindingsGroup ); + + bindGroupLayouts.push( bindingsData.layout ); + + } + + pipelineGPU.pipeline = device.createComputePipeline( { + compute: computeProgram, + layout: device.createPipelineLayout( { + bindGroupLayouts + } ) + } ); + + } + + _getBlending( material ) { + + let color, alpha; + + const blending = material.blending; + const blendSrc = material.blendSrc; + const blendDst = material.blendDst; + const blendEquation = material.blendEquation; + + + if ( blending === CustomBlending ) { + + const blendSrcAlpha = material.blendSrcAlpha !== null ? material.blendSrcAlpha : blendSrc; + const blendDstAlpha = material.blendDstAlpha !== null ? material.blendDstAlpha : blendDst; + const blendEquationAlpha = material.blendEquationAlpha !== null ? material.blendEquationAlpha : blendEquation; + + color = { + srcFactor: this._getBlendFactor( blendSrc ), + dstFactor: this._getBlendFactor( blendDst ), + operation: this._getBlendOperation( blendEquation ) + }; + + alpha = { + srcFactor: this._getBlendFactor( blendSrcAlpha ), + dstFactor: this._getBlendFactor( blendDstAlpha ), + operation: this._getBlendOperation( blendEquationAlpha ) + }; + + } else { + + const premultipliedAlpha = material.premultipliedAlpha; + + const setBlend = ( srcRGB, dstRGB, srcAlpha, dstAlpha ) => { + + color = { + srcFactor: srcRGB, + dstFactor: dstRGB, + operation: GPUBlendOperation.Add + }; + + alpha = { + srcFactor: srcAlpha, + dstFactor: dstAlpha, + operation: GPUBlendOperation.Add + }; + + }; + + if ( premultipliedAlpha ) { + + switch ( blending ) { + + case NormalBlending: + setBlend( GPUBlendFactor.One, GPUBlendFactor.OneMinusSrcAlpha, GPUBlendFactor.One, GPUBlendFactor.OneMinusSrcAlpha ); + break; + + case AdditiveBlending: + setBlend( GPUBlendFactor.One, GPUBlendFactor.One, GPUBlendFactor.One, GPUBlendFactor.One ); + break; + + case SubtractiveBlending: + setBlend( GPUBlendFactor.Zero, GPUBlendFactor.OneMinusSrc, GPUBlendFactor.Zero, GPUBlendFactor.One ); + break; + + case MultiplyBlending: + setBlend( GPUBlendFactor.Zero, GPUBlendFactor.Src, GPUBlendFactor.Zero, GPUBlendFactor.SrcAlpha ); + break; + + } + + } else { + + switch ( blending ) { + + case NormalBlending: + setBlend( GPUBlendFactor.SrcAlpha, GPUBlendFactor.OneMinusSrcAlpha, GPUBlendFactor.One, GPUBlendFactor.OneMinusSrcAlpha ); + break; + + case AdditiveBlending: + setBlend( GPUBlendFactor.SrcAlpha, GPUBlendFactor.One, GPUBlendFactor.SrcAlpha, GPUBlendFactor.One ); + break; + + case SubtractiveBlending: + setBlend( GPUBlendFactor.Zero, GPUBlendFactor.OneMinusSrc, GPUBlendFactor.Zero, GPUBlendFactor.One ); + break; + + case MultiplyBlending: + setBlend( GPUBlendFactor.Zero, GPUBlendFactor.Src, GPUBlendFactor.Zero, GPUBlendFactor.Src ); + break; + + } + + } + + } + + if ( color !== undefined && alpha !== undefined ) { + + return { color, alpha }; + + } else { + + console.error( 'THREE.WebGPURenderer: Invalid blending: ', blending ); + + } + + } + + _getBlendFactor( blend ) { + + let blendFactor; + + switch ( blend ) { + + case ZeroFactor: + blendFactor = GPUBlendFactor.Zero; + break; + + case OneFactor: + blendFactor = GPUBlendFactor.One; + break; + + case SrcColorFactor: + blendFactor = GPUBlendFactor.Src; + break; + + case OneMinusSrcColorFactor: + blendFactor = GPUBlendFactor.OneMinusSrc; + break; + + case SrcAlphaFactor: + blendFactor = GPUBlendFactor.SrcAlpha; + break; + + case OneMinusSrcAlphaFactor: + blendFactor = GPUBlendFactor.OneMinusSrcAlpha; + break; + + case DstColorFactor: + blendFactor = GPUBlendFactor.Dst; + break; + + case OneMinusDstColorFactor: + blendFactor = GPUBlendFactor.OneMinusDstColor; + break; + + case DstAlphaFactor: + blendFactor = GPUBlendFactor.DstAlpha; + break; + + case OneMinusDstAlphaFactor: + blendFactor = GPUBlendFactor.OneMinusDstAlpha; + break; + + case SrcAlphaSaturateFactor: + blendFactor = GPUBlendFactor.SrcAlphaSaturated; + break; + + case BlendColorFactor: + blendFactor = GPUBlendFactor.Constant; + break; + + case OneMinusBlendColorFactor: + blendFactor = GPUBlendFactor.OneMinusConstant; + break; + + default: + console.error( 'THREE.WebGPURenderer: Blend factor not supported.', blend ); + + } + + return blendFactor; + + } + + _getStencilCompare( material ) { + + let stencilCompare; + + const stencilFunc = material.stencilFunc; + + switch ( stencilFunc ) { + + case NeverStencilFunc: + stencilCompare = GPUCompareFunction.Never; + break; + + case AlwaysStencilFunc: + stencilCompare = GPUCompareFunction.Always; + break; + + case LessStencilFunc: + stencilCompare = GPUCompareFunction.Less; + break; + + case LessEqualStencilFunc: + stencilCompare = GPUCompareFunction.LessEqual; + break; + + case EqualStencilFunc: + stencilCompare = GPUCompareFunction.Equal; + break; + + case GreaterEqualStencilFunc: + stencilCompare = GPUCompareFunction.GreaterEqual; + break; + + case GreaterStencilFunc: + stencilCompare = GPUCompareFunction.Greater; + break; + + case NotEqualStencilFunc: + stencilCompare = GPUCompareFunction.NotEqual; + break; + + default: + console.error( 'THREE.WebGPURenderer: Invalid stencil function.', stencilFunc ); + + } + + return stencilCompare; + + } + + _getStencilOperation( op ) { + + let stencilOperation; + + switch ( op ) { + + case KeepStencilOp: + stencilOperation = GPUStencilOperation.Keep; + break; + + case ZeroStencilOp: + stencilOperation = GPUStencilOperation.Zero; + break; + + case ReplaceStencilOp: + stencilOperation = GPUStencilOperation.Replace; + break; + + case InvertStencilOp: + stencilOperation = GPUStencilOperation.Invert; + break; + + case IncrementStencilOp: + stencilOperation = GPUStencilOperation.IncrementClamp; + break; + + case DecrementStencilOp: + stencilOperation = GPUStencilOperation.DecrementClamp; + break; + + case IncrementWrapStencilOp: + stencilOperation = GPUStencilOperation.IncrementWrap; + break; + + case DecrementWrapStencilOp: + stencilOperation = GPUStencilOperation.DecrementWrap; + break; + + default: + console.error( 'THREE.WebGPURenderer: Invalid stencil operation.', stencilOperation ); + + } + + return stencilOperation; + + } + + _getBlendOperation( blendEquation ) { + + let blendOperation; + + switch ( blendEquation ) { + + case AddEquation: + blendOperation = GPUBlendOperation.Add; + break; + + case SubtractEquation: + blendOperation = GPUBlendOperation.Subtract; + break; + + case ReverseSubtractEquation: + blendOperation = GPUBlendOperation.ReverseSubtract; + break; + + case MinEquation: + blendOperation = GPUBlendOperation.Min; + break; + + case MaxEquation: + blendOperation = GPUBlendOperation.Max; + break; + + default: + console.error( 'THREE.WebGPUPipelineUtils: Blend equation not supported.', blendEquation ); + + } + + return blendOperation; + + } + + _getPrimitiveState( object, geometry, material ) { + + const descriptor = {}; + const utils = this.backend.utils; + + descriptor.topology = utils.getPrimitiveTopology( object, material ); + + if ( geometry.index !== null && object.isLine === true && object.isLineSegments !== true ) { + + descriptor.stripIndexFormat = ( geometry.index.array instanceof Uint16Array ) ? GPUIndexFormat.Uint16 : GPUIndexFormat.Uint32; + + } + + switch ( material.side ) { + + case FrontSide: + descriptor.frontFace = GPUFrontFace.CCW; + descriptor.cullMode = GPUCullMode.Back; + break; + + case BackSide: + descriptor.frontFace = GPUFrontFace.CCW; + descriptor.cullMode = GPUCullMode.Front; + break; + + case DoubleSide: + descriptor.frontFace = GPUFrontFace.CCW; + descriptor.cullMode = GPUCullMode.None; + break; + + default: + console.error( 'THREE.WebGPUPipelineUtils: Unknown material.side value.', material.side ); + break; + + } + + return descriptor; + + } + + _getColorWriteMask( material ) { + + return ( material.colorWrite === true ) ? GPUColorWriteFlags.All : GPUColorWriteFlags.None; + + } + + _getDepthCompare( material ) { + + let depthCompare; + + if ( material.depthTest === false ) { + + depthCompare = GPUCompareFunction.Always; + + } else { + + const depthFunc = material.depthFunc; + + switch ( depthFunc ) { + + case NeverDepth: + depthCompare = GPUCompareFunction.Never; + break; + + case AlwaysDepth: + depthCompare = GPUCompareFunction.Always; + break; + + case LessDepth: + depthCompare = GPUCompareFunction.Less; + break; + + case LessEqualDepth: + depthCompare = GPUCompareFunction.LessEqual; + break; + + case EqualDepth: + depthCompare = GPUCompareFunction.Equal; + break; + + case GreaterEqualDepth: + depthCompare = GPUCompareFunction.GreaterEqual; + break; + + case GreaterDepth: + depthCompare = GPUCompareFunction.Greater; + break; + + case NotEqualDepth: + depthCompare = GPUCompareFunction.NotEqual; + break; + + default: + console.error( 'THREE.WebGPUPipelineUtils: Invalid depth function.', depthFunc ); + + } + + } + + return depthCompare; + + } + +} + +/*// debugger tools +import 'https://greggman.github.io/webgpu-avoid-redundant-state-setting/webgpu-check-redundant-state-setting.js'; +//*/ + + +// + +class WebGPUBackend extends Backend { + + constructor( parameters = {} ) { + + super( parameters ); + + this.isWebGPUBackend = true; + + // some parameters require default values other than "undefined" + this.parameters.alpha = ( parameters.alpha === undefined ) ? true : parameters.alpha; + + this.parameters.requiredLimits = ( parameters.requiredLimits === undefined ) ? {} : parameters.requiredLimits; + + this.trackTimestamp = ( parameters.trackTimestamp === true ); + + this.device = null; + this.context = null; + this.colorBuffer = null; + this.defaultRenderPassdescriptor = null; + + this.utils = new WebGPUUtils( this ); + this.attributeUtils = new WebGPUAttributeUtils( this ); + this.bindingUtils = new WebGPUBindingUtils( this ); + this.pipelineUtils = new WebGPUPipelineUtils( this ); + this.textureUtils = new WebGPUTextureUtils( this ); + this.occludedResolveCache = new Map(); + + } + + async init( renderer ) { + + await super.init( renderer ); + + // + + const parameters = this.parameters; + + // create the device if it is not passed with parameters + + let device; + + if ( parameters.device === undefined ) { + + const adapterOptions = { + powerPreference: parameters.powerPreference + }; + + const adapter = await navigator.gpu.requestAdapter( adapterOptions ); + + if ( adapter === null ) { + + throw new Error( 'WebGPUBackend: Unable to create WebGPU adapter.' ); + + } + + // feature support + + const features = Object.values( GPUFeatureName ); + + const supportedFeatures = []; + + for ( const name of features ) { + + if ( adapter.features.has( name ) ) { + + supportedFeatures.push( name ); + + } + + } + + const deviceDescriptor = { + requiredFeatures: supportedFeatures, + requiredLimits: parameters.requiredLimits + }; + + device = await adapter.requestDevice( deviceDescriptor ); + + } else { + + device = parameters.device; + + } + + const context = ( parameters.context !== undefined ) ? parameters.context : renderer.domElement.getContext( 'webgpu' ); + + this.device = device; + this.context = context; + + const alphaMode = parameters.alpha ? 'premultiplied' : 'opaque'; + + this.trackTimestamp = this.trackTimestamp && this.hasFeature( GPUFeatureName.TimestampQuery ); + + this.context.configure( { + device: this.device, + format: this.utils.getPreferredCanvasFormat(), + usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, + alphaMode: alphaMode + } ); + + this.updateSize(); + + } + + get coordinateSystem() { + + return WebGPUCoordinateSystem; + + } + + async getArrayBufferAsync( attribute ) { + + return await this.attributeUtils.getArrayBufferAsync( attribute ); + + } + + getContext() { + + return this.context; + + } + + _getDefaultRenderPassDescriptor() { + + let descriptor = this.defaultRenderPassdescriptor; + + if ( descriptor === null ) { + + const renderer = this.renderer; + + descriptor = { + colorAttachments: [ { + view: null + } ], + depthStencilAttachment: { + view: this.textureUtils.getDepthBuffer( renderer.depth, renderer.stencil ).createView() + } + }; + + const colorAttachment = descriptor.colorAttachments[ 0 ]; + + if ( this.renderer.samples > 0 ) { + + colorAttachment.view = this.colorBuffer.createView(); + + } else { + + colorAttachment.resolveTarget = undefined; + + } + + this.defaultRenderPassdescriptor = descriptor; + + } + + const colorAttachment = descriptor.colorAttachments[ 0 ]; + + if ( this.renderer.samples > 0 ) { + + colorAttachment.resolveTarget = this.context.getCurrentTexture().createView(); + + } else { + + colorAttachment.view = this.context.getCurrentTexture().createView(); + + } + + return descriptor; + + } + + _getRenderPassDescriptor( renderContext ) { + + const renderTarget = renderContext.renderTarget; + const renderTargetData = this.get( renderTarget ); + + let descriptors = renderTargetData.descriptors; + + if ( descriptors === undefined || + renderTargetData.width !== renderTarget.width || + renderTargetData.height !== renderTarget.height || + renderTargetData.activeMipmapLevel !== renderTarget.activeMipmapLevel || + renderTargetData.samples !== renderTarget.samples + ) { + + descriptors = {}; + + renderTargetData.descriptors = descriptors; + + // dispose + + const onDispose = () => { + + renderTarget.removeEventListener( 'dispose', onDispose ); + + this.delete( renderTarget ); + + }; + + renderTarget.addEventListener( 'dispose', onDispose ); + + } + + const cacheKey = renderContext.getCacheKey(); + + let descriptor = descriptors[ cacheKey ]; + + if ( descriptor === undefined ) { + + const textures = renderContext.textures; + const colorAttachments = []; + + for ( let i = 0; i < textures.length; i ++ ) { + + const textureData = this.get( textures[ i ] ); + + const textureView = textureData.texture.createView( { + baseMipLevel: renderContext.activeMipmapLevel, + mipLevelCount: 1, + baseArrayLayer: renderContext.activeCubeFace, + dimension: GPUTextureViewDimension.TwoD + } ); + + let view, resolveTarget; + + if ( textureData.msaaTexture !== undefined ) { + + view = textureData.msaaTexture.createView(); + resolveTarget = textureView; + + } else { + + view = textureView; + resolveTarget = undefined; + + } + + colorAttachments.push( { + view, + resolveTarget, + loadOp: GPULoadOp.Load, + storeOp: GPUStoreOp.Store + } ); + + } + + const depthTextureData = this.get( renderContext.depthTexture ); + + const depthStencilAttachment = { + view: depthTextureData.texture.createView() + }; + + descriptor = { + colorAttachments, + depthStencilAttachment + }; + + descriptors[ cacheKey ] = descriptor; + + renderTargetData.width = renderTarget.width; + renderTargetData.height = renderTarget.height; + renderTargetData.samples = renderTarget.samples; + renderTargetData.activeMipmapLevel = renderTarget.activeMipmapLevel; + + } + + return descriptor; + + } + + beginRender( renderContext ) { + + const renderContextData = this.get( renderContext ); + + const device = this.device; + const occlusionQueryCount = renderContext.occlusionQueryCount; + + let occlusionQuerySet; + + if ( occlusionQueryCount > 0 ) { + + if ( renderContextData.currentOcclusionQuerySet ) renderContextData.currentOcclusionQuerySet.destroy(); + if ( renderContextData.currentOcclusionQueryBuffer ) renderContextData.currentOcclusionQueryBuffer.destroy(); + + // Get a reference to the array of objects with queries. The renderContextData property + // can be changed by another render pass before the buffer.mapAsyc() completes. + renderContextData.currentOcclusionQuerySet = renderContextData.occlusionQuerySet; + renderContextData.currentOcclusionQueryBuffer = renderContextData.occlusionQueryBuffer; + renderContextData.currentOcclusionQueryObjects = renderContextData.occlusionQueryObjects; + + // + + occlusionQuerySet = device.createQuerySet( { type: 'occlusion', count: occlusionQueryCount } ); + + renderContextData.occlusionQuerySet = occlusionQuerySet; + renderContextData.occlusionQueryIndex = 0; + renderContextData.occlusionQueryObjects = new Array( occlusionQueryCount ); + + renderContextData.lastOcclusionObject = null; + + } + + let descriptor; + + if ( renderContext.textures === null ) { + + descriptor = this._getDefaultRenderPassDescriptor(); + + } else { + + descriptor = this._getRenderPassDescriptor( renderContext ); + + } + + this.initTimestampQuery( renderContext, descriptor ); + + descriptor.occlusionQuerySet = occlusionQuerySet; + + const depthStencilAttachment = descriptor.depthStencilAttachment; + + if ( renderContext.textures !== null ) { + + const colorAttachments = descriptor.colorAttachments; + + for ( let i = 0; i < colorAttachments.length; i ++ ) { + + const colorAttachment = colorAttachments[ i ]; + + if ( renderContext.clearColor ) { + + colorAttachment.clearValue = i === 0 ? renderContext.clearColorValue : { r: 0, g: 0, b: 0, a: 1 }; + colorAttachment.loadOp = GPULoadOp.Clear; + colorAttachment.storeOp = GPUStoreOp.Store; + + } else { + + colorAttachment.loadOp = GPULoadOp.Load; + colorAttachment.storeOp = GPUStoreOp.Store; + + } + + } + + } else { + + const colorAttachment = descriptor.colorAttachments[ 0 ]; + + if ( renderContext.clearColor ) { + + colorAttachment.clearValue = renderContext.clearColorValue; + colorAttachment.loadOp = GPULoadOp.Clear; + colorAttachment.storeOp = GPUStoreOp.Store; + + } else { + + colorAttachment.loadOp = GPULoadOp.Load; + colorAttachment.storeOp = GPUStoreOp.Store; + + } + + } + + // + + if ( renderContext.depth ) { + + if ( renderContext.clearDepth ) { + + depthStencilAttachment.depthClearValue = renderContext.clearDepthValue; + depthStencilAttachment.depthLoadOp = GPULoadOp.Clear; + depthStencilAttachment.depthStoreOp = GPUStoreOp.Store; + + } else { + + depthStencilAttachment.depthLoadOp = GPULoadOp.Load; + depthStencilAttachment.depthStoreOp = GPUStoreOp.Store; + + } + + } + + if ( renderContext.stencil ) { + + if ( renderContext.clearStencil ) { + + depthStencilAttachment.stencilClearValue = renderContext.clearStencilValue; + depthStencilAttachment.stencilLoadOp = GPULoadOp.Clear; + depthStencilAttachment.stencilStoreOp = GPUStoreOp.Store; + + } else { + + depthStencilAttachment.stencilLoadOp = GPULoadOp.Load; + depthStencilAttachment.stencilStoreOp = GPUStoreOp.Store; + + } + + } + + // + + const encoder = device.createCommandEncoder( { label: 'renderContext_' + renderContext.id } ); + const currentPass = encoder.beginRenderPass( descriptor ); + + // + + renderContextData.descriptor = descriptor; + renderContextData.encoder = encoder; + renderContextData.currentPass = currentPass; + renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; + renderContextData.renderBundles = []; + + // + + if ( renderContext.viewport ) { + + this.updateViewport( renderContext ); + + } + + if ( renderContext.scissor ) { + + const { x, y, width, height } = renderContext.scissorValue; + + currentPass.setScissorRect( x, y, width, height ); + + } + + } + + finishRender( renderContext ) { + + const renderContextData = this.get( renderContext ); + const occlusionQueryCount = renderContext.occlusionQueryCount; + + if ( renderContextData.renderBundles.length > 0 ) { + + renderContextData.currentPass.executeBundles( renderContextData.renderBundles ); + + } + + if ( occlusionQueryCount > renderContextData.occlusionQueryIndex ) { + + renderContextData.currentPass.endOcclusionQuery(); + + } + + renderContextData.currentPass.end(); + + if ( occlusionQueryCount > 0 ) { + + const bufferSize = occlusionQueryCount * 8; // 8 byte entries for query results + + // + + let queryResolveBuffer = this.occludedResolveCache.get( bufferSize ); + + if ( queryResolveBuffer === undefined ) { + + queryResolveBuffer = this.device.createBuffer( + { + size: bufferSize, + usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC + } + ); + + this.occludedResolveCache.set( bufferSize, queryResolveBuffer ); + + } + + // + + const readBuffer = this.device.createBuffer( + { + size: bufferSize, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ + } + ); + + // two buffers required here - WebGPU doesn't allow usage of QUERY_RESOLVE & MAP_READ to be combined + renderContextData.encoder.resolveQuerySet( renderContextData.occlusionQuerySet, 0, occlusionQueryCount, queryResolveBuffer, 0 ); + renderContextData.encoder.copyBufferToBuffer( queryResolveBuffer, 0, readBuffer, 0, bufferSize ); + + renderContextData.occlusionQueryBuffer = readBuffer; + + // + + this.resolveOccludedAsync( renderContext ); + + } + + this.prepareTimestampBuffer( renderContext, renderContextData.encoder ); + + this.device.queue.submit( [ renderContextData.encoder.finish() ] ); + + + // + + if ( renderContext.textures !== null ) { + + const textures = renderContext.textures; + + for ( let i = 0; i < textures.length; i ++ ) { + + const texture = textures[ i ]; + + if ( texture.generateMipmaps === true ) { + + this.textureUtils.generateMipmaps( texture ); + + } + + } + + } + + } + + isOccluded( renderContext, object ) { + + const renderContextData = this.get( renderContext ); + + return renderContextData.occluded && renderContextData.occluded.has( object ); + + } + + async resolveOccludedAsync( renderContext ) { + + const renderContextData = this.get( renderContext ); + + // handle occlusion query results + + const { currentOcclusionQueryBuffer, currentOcclusionQueryObjects } = renderContextData; + + if ( currentOcclusionQueryBuffer && currentOcclusionQueryObjects ) { + + const occluded = new WeakSet(); + + renderContextData.currentOcclusionQueryObjects = null; + renderContextData.currentOcclusionQueryBuffer = null; + + await currentOcclusionQueryBuffer.mapAsync( GPUMapMode.READ ); + + const buffer = currentOcclusionQueryBuffer.getMappedRange(); + const results = new BigUint64Array( buffer ); + + for ( let i = 0; i < currentOcclusionQueryObjects.length; i ++ ) { + + if ( results[ i ] !== BigInt( 0 ) ) { + + occluded.add( currentOcclusionQueryObjects[ i ] ); + + } + + } + + currentOcclusionQueryBuffer.destroy(); + + renderContextData.occluded = occluded; + + } + + } + + updateViewport( renderContext ) { + + const { currentPass } = this.get( renderContext ); + const { x, y, width, height, minDepth, maxDepth } = renderContext.viewportValue; + + currentPass.setViewport( x, y, width, height, minDepth, maxDepth ); + + } + + clear( color, depth, stencil, renderTargetData = null ) { + + const device = this.device; + const renderer = this.renderer; + + let colorAttachments = []; + + let depthStencilAttachment; + let clearValue; + + let supportsDepth; + let supportsStencil; + + if ( color ) { + + const clearColor = this.getClearColor(); + + if ( this.renderer.alpha === true ) { + + // premultiply alpha + + const a = clearColor.a; + + clearValue = { r: clearColor.r * a, g: clearColor.g * a, b: clearColor.b * a, a: a }; + + } else { + + clearValue = { r: clearColor.r, g: clearColor.g, b: clearColor.b, a: clearColor.a }; + + } + + } + + if ( renderTargetData === null ) { + + supportsDepth = renderer.depth; + supportsStencil = renderer.stencil; + + const descriptor = this._getDefaultRenderPassDescriptor(); + + if ( color ) { + + colorAttachments = descriptor.colorAttachments; + + const colorAttachment = colorAttachments[ 0 ]; + + colorAttachment.clearValue = clearValue; + colorAttachment.loadOp = GPULoadOp.Clear; + colorAttachment.storeOp = GPUStoreOp.Store; + + } + + if ( supportsDepth || supportsStencil ) { + + depthStencilAttachment = descriptor.depthStencilAttachment; + + } + + } else { + + supportsDepth = renderTargetData.depth; + supportsStencil = renderTargetData.stencil; + + if ( color ) { + + for ( const texture of renderTargetData.textures ) { + + const textureData = this.get( texture ); + const textureView = textureData.texture.createView(); + + let view, resolveTarget; + + if ( textureData.msaaTexture !== undefined ) { + + view = textureData.msaaTexture.createView(); + resolveTarget = textureView; + + } else { + + view = textureView; + resolveTarget = undefined; + + } + + colorAttachments.push( { + view, + resolveTarget, + clearValue, + loadOp: GPULoadOp.Clear, + storeOp: GPUStoreOp.Store + } ); + + } + + } + + if ( supportsDepth || supportsStencil ) { + + const depthTextureData = this.get( renderTargetData.depthTexture ); + + depthStencilAttachment = { + view: depthTextureData.texture.createView() + }; + + } + + } + + // + + if ( supportsDepth ) { + + if ( depth ) { + + depthStencilAttachment.depthLoadOp = GPULoadOp.Clear; + depthStencilAttachment.depthClearValue = renderer.getClearDepth(); + depthStencilAttachment.depthStoreOp = GPUStoreOp.Store; + + } else { + + depthStencilAttachment.depthLoadOp = GPULoadOp.Load; + depthStencilAttachment.depthStoreOp = GPUStoreOp.Store; + + } + + } + + // + + if ( supportsStencil ) { + + if ( stencil ) { + + depthStencilAttachment.stencilLoadOp = GPULoadOp.Clear; + depthStencilAttachment.stencilClearValue = renderer.getClearStencil(); + depthStencilAttachment.stencilStoreOp = GPUStoreOp.Store; + + } else { + + depthStencilAttachment.stencilLoadOp = GPULoadOp.Load; + depthStencilAttachment.stencilStoreOp = GPUStoreOp.Store; + + } + + } + + // + + const encoder = device.createCommandEncoder( {} ); + const currentPass = encoder.beginRenderPass( { + colorAttachments, + depthStencilAttachment + } ); + + currentPass.end(); + + device.queue.submit( [ encoder.finish() ] ); + + } + + // compute + + beginCompute( computeGroup ) { + + const groupGPU = this.get( computeGroup ); + + + const descriptor = {}; + + this.initTimestampQuery( computeGroup, descriptor ); + + groupGPU.cmdEncoderGPU = this.device.createCommandEncoder(); + + groupGPU.passEncoderGPU = groupGPU.cmdEncoderGPU.beginComputePass( descriptor ); + + } + + compute( computeGroup, computeNode, bindings, pipeline ) { + + const { passEncoderGPU } = this.get( computeGroup ); + + // pipeline + + const pipelineGPU = this.get( pipeline ).pipeline; + passEncoderGPU.setPipeline( pipelineGPU ); + + // bind groups + + for ( let i = 0, l = bindings.length; i < l; i ++ ) { + + const bindGroup = bindings[ i ]; + const bindingsData = this.get( bindGroup ); + + passEncoderGPU.setBindGroup( i, bindingsData.group ); + + } + + const maxComputeWorkgroupsPerDimension = this.device.limits.maxComputeWorkgroupsPerDimension; + + const computeNodeData = this.get( computeNode ); + + if ( computeNodeData.dispatchSize === undefined ) computeNodeData.dispatchSize = { x: 0, y: 1, z: 1 }; + + const { dispatchSize } = computeNodeData; + + if ( computeNode.dispatchCount > maxComputeWorkgroupsPerDimension ) { + + dispatchSize.x = Math.min( computeNode.dispatchCount, maxComputeWorkgroupsPerDimension ); + dispatchSize.y = Math.ceil( computeNode.dispatchCount / maxComputeWorkgroupsPerDimension ); + + } else { + + dispatchSize.x = computeNode.dispatchCount; + + } + + passEncoderGPU.dispatchWorkgroups( + dispatchSize.x, + dispatchSize.y, + dispatchSize.z + ); + + } + + finishCompute( computeGroup ) { + + const groupData = this.get( computeGroup ); + + groupData.passEncoderGPU.end(); + + this.prepareTimestampBuffer( computeGroup, groupData.cmdEncoderGPU ); + + this.device.queue.submit( [ groupData.cmdEncoderGPU.finish() ] ); + + } + + // render object + + draw( renderObject, info ) { + + const { object, context, pipeline } = renderObject; + const bindings = renderObject.getBindings(); + const renderContextData = this.get( context ); + const pipelineGPU = this.get( pipeline ).pipeline; + const currentSets = renderContextData.currentSets; + const passEncoderGPU = renderContextData.currentPass; + + const drawParms = renderObject.getDrawParameters(); + + if ( drawParms === null ) return; + + // pipeline + + if ( currentSets.pipeline !== pipelineGPU ) { + + passEncoderGPU.setPipeline( pipelineGPU ); + + currentSets.pipeline = pipelineGPU; + + } + + // bind groups + + const currentBindingGroups = currentSets.bindingGroups; + + for ( let i = 0, l = bindings.length; i < l; i ++ ) { + + const bindGroup = bindings[ i ]; + const bindingsData = this.get( bindGroup ); + + if ( currentBindingGroups[ bindGroup.index ] !== bindGroup.id ) { + + passEncoderGPU.setBindGroup( bindGroup.index, bindingsData.group ); + currentBindingGroups[ bindGroup.index ] = bindGroup.id; + + } + + } + + // attributes + + const index = renderObject.getIndex(); + + const hasIndex = ( index !== null ); + + // index + + if ( hasIndex === true ) { + + if ( currentSets.index !== index ) { + + const buffer = this.get( index ).buffer; + const indexFormat = ( index.array instanceof Uint16Array ) ? GPUIndexFormat.Uint16 : GPUIndexFormat.Uint32; + + passEncoderGPU.setIndexBuffer( buffer, indexFormat ); + + currentSets.index = index; + + } + + } + + // vertex buffers + + const vertexBuffers = renderObject.getVertexBuffers(); + + for ( let i = 0, l = vertexBuffers.length; i < l; i ++ ) { + + const vertexBuffer = vertexBuffers[ i ]; + + if ( currentSets.attributes[ i ] !== vertexBuffer ) { + + const buffer = this.get( vertexBuffer ).buffer; + passEncoderGPU.setVertexBuffer( i, buffer ); + + currentSets.attributes[ i ] = vertexBuffer; + + } + + } + + // occlusion queries - handle multiple consecutive draw calls for an object + + if ( renderContextData.occlusionQuerySet !== undefined ) { + + const lastObject = renderContextData.lastOcclusionObject; + + if ( lastObject !== object ) { + + if ( lastObject !== null && lastObject.occlusionTest === true ) { + + passEncoderGPU.endOcclusionQuery(); + renderContextData.occlusionQueryIndex ++; + + } + + if ( object.occlusionTest === true ) { + + passEncoderGPU.beginOcclusionQuery( renderContextData.occlusionQueryIndex ); + renderContextData.occlusionQueryObjects[ renderContextData.occlusionQueryIndex ] = object; + + } + + renderContextData.lastOcclusionObject = object; + + } + + } + + // draw + + if ( object.isBatchedMesh === true ) { + + const starts = object._multiDrawStarts; + const counts = object._multiDrawCounts; + const drawCount = object._multiDrawCount; + const drawInstances = object._multiDrawInstances; + + const bytesPerElement = hasIndex ? index.array.BYTES_PER_ELEMENT : 1; + + for ( let i = 0; i < drawCount; i ++ ) { + + const count = drawInstances ? drawInstances[ i ] : 1; + const firstInstance = count > 1 ? 0 : i; + + passEncoderGPU.drawIndexed( counts[ i ], count, starts[ i ] / bytesPerElement, 0, firstInstance ); + + } + + } else if ( hasIndex === true ) { + + const { vertexCount: indexCount, instanceCount, firstVertex: firstIndex } = drawParms; + + passEncoderGPU.drawIndexed( indexCount, instanceCount, firstIndex, 0, 0 ); + + info.update( object, indexCount, instanceCount ); + + } else { + + const { vertexCount, instanceCount, firstVertex } = drawParms; + + passEncoderGPU.draw( vertexCount, instanceCount, firstVertex, 0 ); + + info.update( object, vertexCount, instanceCount ); + + } + + } + + // cache key + + needsRenderUpdate( renderObject ) { + + const data = this.get( renderObject ); + + const { object, material } = renderObject; + + const utils = this.utils; + + const sampleCount = utils.getSampleCountRenderContext( renderObject.context ); + const colorSpace = utils.getCurrentColorSpace( renderObject.context ); + const colorFormat = utils.getCurrentColorFormat( renderObject.context ); + const depthStencilFormat = utils.getCurrentDepthStencilFormat( renderObject.context ); + const primitiveTopology = utils.getPrimitiveTopology( object, material ); + + let needsUpdate = false; + + if ( data.material !== material || data.materialVersion !== material.version || + data.transparent !== material.transparent || data.blending !== material.blending || data.premultipliedAlpha !== material.premultipliedAlpha || + data.blendSrc !== material.blendSrc || data.blendDst !== material.blendDst || data.blendEquation !== material.blendEquation || + data.blendSrcAlpha !== material.blendSrcAlpha || data.blendDstAlpha !== material.blendDstAlpha || data.blendEquationAlpha !== material.blendEquationAlpha || + data.colorWrite !== material.colorWrite || data.depthWrite !== material.depthWrite || data.depthTest !== material.depthTest || data.depthFunc !== material.depthFunc || + data.stencilWrite !== material.stencilWrite || data.stencilFunc !== material.stencilFunc || + data.stencilFail !== material.stencilFail || data.stencilZFail !== material.stencilZFail || data.stencilZPass !== material.stencilZPass || + data.stencilFuncMask !== material.stencilFuncMask || data.stencilWriteMask !== material.stencilWriteMask || + data.side !== material.side || data.alphaToCoverage !== material.alphaToCoverage || + data.sampleCount !== sampleCount || data.colorSpace !== colorSpace || + data.colorFormat !== colorFormat || data.depthStencilFormat !== depthStencilFormat || + data.primitiveTopology !== primitiveTopology || + data.clippingContextCacheKey !== renderObject.clippingContext.cacheKey + ) { + + data.material = material; data.materialVersion = material.version; + data.transparent = material.transparent; data.blending = material.blending; data.premultipliedAlpha = material.premultipliedAlpha; + data.blendSrc = material.blendSrc; data.blendDst = material.blendDst; data.blendEquation = material.blendEquation; + data.blendSrcAlpha = material.blendSrcAlpha; data.blendDstAlpha = material.blendDstAlpha; data.blendEquationAlpha = material.blendEquationAlpha; + data.colorWrite = material.colorWrite; + data.depthWrite = material.depthWrite; data.depthTest = material.depthTest; data.depthFunc = material.depthFunc; + data.stencilWrite = material.stencilWrite; data.stencilFunc = material.stencilFunc; + data.stencilFail = material.stencilFail; data.stencilZFail = material.stencilZFail; data.stencilZPass = material.stencilZPass; + data.stencilFuncMask = material.stencilFuncMask; data.stencilWriteMask = material.stencilWriteMask; + data.side = material.side; data.alphaToCoverage = material.alphaToCoverage; + data.sampleCount = sampleCount; + data.colorSpace = colorSpace; + data.colorFormat = colorFormat; + data.depthStencilFormat = depthStencilFormat; + data.primitiveTopology = primitiveTopology; + data.clippingContextCacheKey = renderObject.clippingContext.cacheKey; + + needsUpdate = true; + + } + + return needsUpdate; + + } + + getRenderCacheKey( renderObject ) { + + const { object, material } = renderObject; + + const utils = this.utils; + const renderContext = renderObject.context; + + return [ + material.transparent, material.blending, material.premultipliedAlpha, + material.blendSrc, material.blendDst, material.blendEquation, + material.blendSrcAlpha, material.blendDstAlpha, material.blendEquationAlpha, + material.colorWrite, + material.depthWrite, material.depthTest, material.depthFunc, + material.stencilWrite, material.stencilFunc, + material.stencilFail, material.stencilZFail, material.stencilZPass, + material.stencilFuncMask, material.stencilWriteMask, + material.side, + utils.getSampleCountRenderContext( renderContext ), + utils.getCurrentColorSpace( renderContext ), utils.getCurrentColorFormat( renderContext ), utils.getCurrentDepthStencilFormat( renderContext ), + utils.getPrimitiveTopology( object, material ), + renderObject.clippingContext.cacheKey + ].join(); + + } + + // textures + + createSampler( texture ) { + + this.textureUtils.createSampler( texture ); + + } + + destroySampler( texture ) { + + this.textureUtils.destroySampler( texture ); + + } + + createDefaultTexture( texture ) { + + this.textureUtils.createDefaultTexture( texture ); + + } + + createTexture( texture, options ) { + + this.textureUtils.createTexture( texture, options ); + + } + + updateTexture( texture, options ) { + + this.textureUtils.updateTexture( texture, options ); + + } + + generateMipmaps( texture ) { + + this.textureUtils.generateMipmaps( texture ); + + } + + destroyTexture( texture ) { + + this.textureUtils.destroyTexture( texture ); + + } + + copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { + + return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height, faceIndex ); + + } + + + initTimestampQuery( renderContext, descriptor ) { + + if ( ! this.trackTimestamp ) return; + + const renderContextData = this.get( renderContext ); + + if ( ! renderContextData.timeStampQuerySet ) { + + // Create a GPUQuerySet which holds 2 timestamp query results: one for the + // beginning and one for the end of compute pass execution. + const timeStampQuerySet = this.device.createQuerySet( { type: 'timestamp', count: 2 } ); + + const timestampWrites = { + querySet: timeStampQuerySet, + beginningOfPassWriteIndex: 0, // Write timestamp in index 0 when pass begins. + endOfPassWriteIndex: 1, // Write timestamp in index 1 when pass ends. + }; + + Object.assign( descriptor, { + timestampWrites, + } ); + + renderContextData.timeStampQuerySet = timeStampQuerySet; + + } + + } + + // timestamp utils + + prepareTimestampBuffer( renderContext, encoder ) { + + if ( ! this.trackTimestamp ) return; + + const renderContextData = this.get( renderContext ); + + + const size = 2 * BigInt64Array.BYTES_PER_ELEMENT; + + if ( renderContextData.currentTimestampQueryBuffers === undefined ) { + + renderContextData.currentTimestampQueryBuffers = { + resolveBuffer: this.device.createBuffer( { + label: 'timestamp resolve buffer', + size: size, + usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC, + } ), + resultBuffer: this.device.createBuffer( { + label: 'timestamp result buffer', + size: size, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, + } ), + isMappingPending: false, + }; + + } + + const { resolveBuffer, resultBuffer, isMappingPending } = renderContextData.currentTimestampQueryBuffers; + + if ( isMappingPending === true ) return; + + encoder.resolveQuerySet( renderContextData.timeStampQuerySet, 0, 2, resolveBuffer, 0 ); + encoder.copyBufferToBuffer( resolveBuffer, 0, resultBuffer, 0, size ); + + } + + async resolveTimestampAsync( renderContext, type = 'render' ) { + + if ( ! this.trackTimestamp ) return; + + const renderContextData = this.get( renderContext ); + + if ( renderContextData.currentTimestampQueryBuffers === undefined ) return; + + const { resultBuffer, isMappingPending } = renderContextData.currentTimestampQueryBuffers; + + if ( isMappingPending === true ) return; + + renderContextData.currentTimestampQueryBuffers.isMappingPending = true; + + resultBuffer.mapAsync( GPUMapMode.READ ).then( () => { + + const times = new BigUint64Array( resultBuffer.getMappedRange() ); + const duration = Number( times[ 1 ] - times[ 0 ] ) / 1000000; + + + this.renderer.info.updateTimestamp( type, duration ); + + resultBuffer.unmap(); + + renderContextData.currentTimestampQueryBuffers.isMappingPending = false; + + } ); + + } + + // node builder + + createNodeBuilder( object, renderer ) { + + return new WGSLNodeBuilder( object, renderer ); + + } + + // program + + createProgram( program ) { + + const programGPU = this.get( program ); + + programGPU.module = { + module: this.device.createShaderModule( { code: program.code, label: program.stage } ), + entryPoint: 'main' + }; + + } + + destroyProgram( program ) { + + this.delete( program ); + + } + + // pipelines + + createRenderPipeline( renderObject, promises ) { + + this.pipelineUtils.createRenderPipeline( renderObject, promises ); + + } + + createComputePipeline( computePipeline, bindings ) { + + this.pipelineUtils.createComputePipeline( computePipeline, bindings ); + + } + + beginBundle( renderContext ) { + + const renderContextData = this.get( renderContext ); + + renderContextData._currentPass = renderContextData.currentPass; + renderContextData._currentSets = renderContextData.currentSets; + + renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; + renderContextData.currentPass = this.pipelineUtils.createBundleEncoder( renderContext ); + + } + + finishBundle( renderContext, bundle ) { + + const renderContextData = this.get( renderContext ); + + const bundleEncoder = renderContextData.currentPass; + const bundleGPU = bundleEncoder.finish(); + + this.get( bundle ).bundleGPU = bundleGPU; + + // restore render pass state + + renderContextData.currentSets = renderContextData._currentSets; + renderContextData.currentPass = renderContextData._currentPass; + + } + + addBundle( renderContext, bundle ) { + + const renderContextData = this.get( renderContext ); + + renderContextData.renderBundles.push( this.get( bundle ).bundleGPU ); + + } + + // bindings + + createBindings( bindGroup ) { + + this.bindingUtils.createBindings( bindGroup ); + + } + + updateBindings( bindGroup ) { + + this.bindingUtils.createBindings( bindGroup ); + + } + + updateBinding( binding ) { + + this.bindingUtils.updateBinding( binding ); + + } + + // attributes + + createIndexAttribute( attribute ) { + + this.attributeUtils.createAttribute( attribute, GPUBufferUsage.INDEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); + + } + + createAttribute( attribute ) { + + this.attributeUtils.createAttribute( attribute, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); + + } + + createStorageAttribute( attribute ) { + + this.attributeUtils.createAttribute( attribute, GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); + + } + + updateAttribute( attribute ) { + + this.attributeUtils.updateAttribute( attribute ); + + } + + destroyAttribute( attribute ) { + + this.attributeUtils.destroyAttribute( attribute ); + + } + + // canvas + + updateSize() { + + this.colorBuffer = this.textureUtils.getColorBuffer(); + this.defaultRenderPassdescriptor = null; + + } + + // utils public + + getMaxAnisotropy() { + + return 16; + + } + + hasFeature( name ) { + + return this.device.features.has( name ); + + } + + copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { + + let dstX = 0; + let dstY = 0; + let dstLayer = 0; + + let srcX = 0; + let srcY = 0; + let srcLayer = 0; + + let srcWidth = srcTexture.image.width; + let srcHeight = srcTexture.image.height; + + if ( srcRegion !== null ) { + + srcX = srcRegion.x; + srcY = srcRegion.y; + srcLayer = srcRegion.z || 0; + srcWidth = srcRegion.width; + srcHeight = srcRegion.height; + + } + + if ( dstPosition !== null ) { + + dstX = dstPosition.x; + dstY = dstPosition.y; + dstLayer = dstPosition.z || 0; + + } + + const encoder = this.device.createCommandEncoder( { label: 'copyTextureToTexture_' + srcTexture.id + '_' + dstTexture.id } ); + + const sourceGPU = this.get( srcTexture ).texture; + const destinationGPU = this.get( dstTexture ).texture; + + encoder.copyTextureToTexture( + { + texture: sourceGPU, + mipLevel: level, + origin: { x: srcX, y: srcY, z: srcLayer } + }, + { + texture: destinationGPU, + mipLevel: level, + origin: { x: dstX, y: dstY, z: dstLayer } + }, + [ + srcWidth, + srcHeight, + 1 + ] + ); + + this.device.queue.submit( [ encoder.finish() ] ); + + } + + copyFramebufferToTexture( texture, renderContext, rectangle ) { + + const renderContextData = this.get( renderContext ); + + const { encoder, descriptor } = renderContextData; + + let sourceGPU = null; + + if ( renderContext.renderTarget ) { + + if ( texture.isDepthTexture ) { + + sourceGPU = this.get( renderContext.depthTexture ).texture; + + } else { + + sourceGPU = this.get( renderContext.textures[ 0 ] ).texture; + + } + + } else { + + if ( texture.isDepthTexture ) { + + sourceGPU = this.textureUtils.getDepthBuffer( renderContext.depth, renderContext.stencil ); + + } else { + + sourceGPU = this.context.getCurrentTexture(); + + } + + } + + const destinationGPU = this.get( texture ).texture; + + if ( sourceGPU.format !== destinationGPU.format ) { + + console.error( 'WebGPUBackend: copyFramebufferToTexture: Source and destination formats do not match.', sourceGPU.format, destinationGPU.format ); + + return; + + } + + renderContextData.currentPass.end(); + + encoder.copyTextureToTexture( + { + texture: sourceGPU, + origin: { x: rectangle.x, y: rectangle.y, z: 0 } + }, + { + texture: destinationGPU + }, + [ + rectangle.z, + rectangle.w + ] + ); + + if ( texture.generateMipmaps ) this.textureUtils.generateMipmaps( texture ); + + for ( let i = 0; i < descriptor.colorAttachments.length; i ++ ) { + + descriptor.colorAttachments[ i ].loadOp = GPULoadOp.Load; + + } + + if ( renderContext.depth ) descriptor.depthStencilAttachment.depthLoadOp = GPULoadOp.Load; + if ( renderContext.stencil ) descriptor.depthStencilAttachment.stencilLoadOp = GPULoadOp.Load; + + renderContextData.currentPass = encoder.beginRenderPass( descriptor ); + renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; + + } + +} + +class IESSpotLight extends SpotLight { + + constructor( color, intensity, distance, angle, penumbra, decay ) { + + super( color, intensity, distance, angle, penumbra, decay ); + + this.iesMap = null; + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.iesMap = source.iesMap; + + return this; + + } + +} + +class BasicNodeLibrary extends NodeLibrary { + + constructor() { + + super(); + + this.addLight( PointLightNode, PointLight ); + this.addLight( DirectionalLightNode, DirectionalLight ); + this.addLight( RectAreaLightNode, RectAreaLight ); + this.addLight( SpotLightNode, SpotLight ); + this.addLight( AmbientLightNode, AmbientLight ); + this.addLight( HemisphereLightNode, HemisphereLight ); + this.addLight( LightProbeNode, LightProbe ); + this.addLight( IESSpotLightNode, IESSpotLight ); + + this.addToneMapping( linearToneMapping, LinearToneMapping ); + this.addToneMapping( reinhardToneMapping, ReinhardToneMapping ); + this.addToneMapping( cineonToneMapping, CineonToneMapping ); + this.addToneMapping( acesFilmicToneMapping, ACESFilmicToneMapping ); + this.addToneMapping( agxToneMapping, AgXToneMapping ); + this.addToneMapping( neutralToneMapping, NeutralToneMapping ); + + this.addColorSpace( linearSRGBTosRGB, getColorSpaceMethod( LinearSRGBColorSpace, SRGBColorSpace ) ); + this.addColorSpace( sRGBToLinearSRGB, getColorSpaceMethod( SRGBColorSpace, LinearSRGBColorSpace ) ); + + } + +} + +class WebGPURenderer extends Renderer { + + constructor( parameters = {} ) { + + let BackendClass; + + if ( parameters.forceWebGL ) { + + BackendClass = WebGLBackend; + + } else { + + BackendClass = WebGPUBackend; + + parameters.getFallback = () => { + + console.warn( 'THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend.' ); + + return new WebGLBackend( parameters ); + + }; + + } + + const backend = new BackendClass( parameters ); + + super( backend, parameters ); + + this.nodes.library = new BasicNodeLibrary(); + + this.isWebGPURenderer = true; + + } + +} + +const _material = /*@__PURE__*/ new NodeMaterial(); +const _quadMesh = /*@__PURE__*/ new QuadMesh( _material ); + +class PostProcessing { + + constructor( renderer, outputNode = vec4( 0, 0, 1, 1 ) ) { + + this.renderer = renderer; + this.outputNode = outputNode; + + this.outputColorTransform = true; + + this.needsUpdate = true; + + _material.name = 'PostProcessing'; + + } + + render() { + + this.update(); + + const renderer = this.renderer; + + const toneMapping = renderer.toneMapping; + const outputColorSpace = renderer.outputColorSpace; + + renderer.toneMapping = NoToneMapping; + renderer.outputColorSpace = LinearSRGBColorSpace; + + // + + _quadMesh.render( renderer ); + + // + + renderer.toneMapping = toneMapping; + renderer.outputColorSpace = outputColorSpace; + + } + + update() { + + if ( this.needsUpdate === true ) { + + const renderer = this.renderer; + + const toneMapping = renderer.toneMapping; + const outputColorSpace = renderer.outputColorSpace; + + _quadMesh.material.fragmentNode = this.outputColorTransform === true ? renderOutput( this.outputNode, toneMapping, outputColorSpace ) : this.outputNode.context( { toneMapping, outputColorSpace } ); + _quadMesh.material.needsUpdate = true; + + this.needsUpdate = false; + + } + + } + + async renderAsync() { + + this.update(); + + const renderer = this.renderer; + + const toneMapping = renderer.toneMapping; + const outputColorSpace = renderer.outputColorSpace; + + renderer.toneMapping = NoToneMapping; + renderer.outputColorSpace = LinearSRGBColorSpace; + + // + + await _quadMesh.renderAsync( renderer ); + + // + + renderer.toneMapping = toneMapping; + renderer.outputColorSpace = outputColorSpace; + + } + +} + +class StorageTexture extends Texture { + + constructor( width = 1, height = 1 ) { + + super(); + + this.image = { width, height }; + + this.magFilter = LinearFilter; + this.minFilter = LinearFilter; + + this.isStorageTexture = true; + + } + +} + +class StorageBufferAttribute extends BufferAttribute { + + constructor( array, itemSize, typeClass = Float32Array ) { + + if ( ArrayBuffer.isView( array ) === false ) array = new typeClass( array * itemSize ); + + super( array, itemSize ); + + this.isStorageBufferAttribute = true; + + } + +} + +class StorageInstancedBufferAttribute extends InstancedBufferAttribute { + + constructor( array, itemSize, typeClass = Float32Array ) { + + if ( ArrayBuffer.isView( array ) === false ) array = new typeClass( array * itemSize ); + + super( array, itemSize ); + + this.isStorageInstancedBufferAttribute = true; + + } + +} + +class NodeLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + this.textures = {}; + this.nodes = {}; + + } + + load( url, onLoad, onProgress, onError ) { + + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, ( text ) => { + + try { + + onLoad( this.parse( JSON.parse( text ) ) ); + + } catch ( e ) { + + if ( onError ) { + + onError( e ); + + } else { + + console.error( e ); + + } + + this.manager.itemError( url ); + + } + + }, onProgress, onError ); + + } + + parseNodes( json ) { + + const nodes = {}; + + if ( json !== undefined ) { + + for ( const nodeJSON of json ) { + + const { uuid, type } = nodeJSON; + + nodes[ uuid ] = this.createNodeFromType( type ); + nodes[ uuid ].uuid = uuid; + + } + + const meta = { nodes, textures: this.textures }; + + for ( const nodeJSON of json ) { + + nodeJSON.meta = meta; + + const node = nodes[ nodeJSON.uuid ]; + node.deserialize( nodeJSON ); + + delete nodeJSON.meta; + + } + + } + + return nodes; + + } + + parse( json ) { + + const node = this.createNodeFromType( json.type ); + node.uuid = json.uuid; + + const nodes = this.parseNodes( json.nodes ); + const meta = { nodes, textures: this.textures }; + + json.meta = meta; + + node.deserialize( json ); + + delete json.meta; + + return node; + + } + + setTextures( value ) { + + this.textures = value; + return this; + + } + + setNodes( value ) { + + this.nodes = value; + return this; + + } + + createNodeFromType( type ) { + + if ( this.nodes[ type ] === undefined ) { + + console.error( 'THREE.NodeLoader: Node type not found:', type ); + return float(); + + } + + return nodeObject( new this.nodes[ type ]() ); + + } + +} + +class NodeMaterialLoader extends MaterialLoader { + + constructor( manager ) { + + super( manager ); + + this.nodes = {}; + this.nodeMaterials = {}; + + } + + parse( json ) { + + const material = super.parse( json ); + + const nodes = this.nodes; + const inputNodes = json.inputNodes; + + for ( const property in inputNodes ) { + + const uuid = inputNodes[ property ]; + + material[ property ] = nodes[ uuid ]; + + } + + return material; + + } + + setNodes( value ) { + + this.nodes = value; + return this; + + } + + setNodeMaterials( value ) { + + this.nodeMaterials = value; + return this; + + } + + createMaterialFromType( type ) { + + const materialClass = this.nodeMaterials[ type ]; + + if ( materialClass !== undefined ) { + + return new materialClass(); + + } + + return super.createMaterialFromType( type ); + + } + +} + +class NodeObjectLoader extends ObjectLoader { + + constructor( manager ) { + + super( manager ); + + this.nodes = {}; + this.nodeMaterials = {}; + + this._nodesJSON = null; + + } + + setNodes( value ) { + + this.nodes = value; + return this; + + } + + setNodeMaterials( value ) { + + this.nodeMaterials = value; + return this; + + } + + parse( json, onLoad ) { + + this._nodesJSON = json.nodes; + + const data = super.parse( json, onLoad ); + + this._nodesJSON = null; // dispose + + return data; + + } + + parseNodes( json, textures ) { + + if ( json !== undefined ) { + + const loader = new NodeLoader(); + loader.setNodes( this.nodes ); + loader.setTextures( textures ); + + return loader.parseNodes( json ); + + } + + return {}; + + } + + parseMaterials( json, textures ) { + + const materials = {}; + + if ( json !== undefined ) { + + const nodes = this.parseNodes( this._nodesJSON, textures ); + + const loader = new NodeMaterialLoader(); + loader.setTextures( textures ); + loader.setNodes( nodes ); + loader.setNodeMaterials( this.nodeMaterials ); + + for ( let i = 0, l = json.length; i < l; i ++ ) { + + const data = json[ i ]; + + materials[ data.uuid ] = loader.parse( data ); + + } + + } + + return materials; + + } + +} + +if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { + + __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: { + revision: REVISION, + } } ) ); + +} + +if ( typeof window !== 'undefined' ) { + + if ( window.__THREE__ ) { + + console.warn( 'WARNING: Multiple instances of Three.js being imported.' ); + + } else { + + window.__THREE__ = REVISION; + + } + +} + +export { ACESFilmicToneMapping, AONode, AddEquation, AddOperation, AdditiveAnimationBlendMode, AdditiveBlending, AfterImageNode, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AmbientLightNode, AnaglyphPassNode, AnalyticLightNode, AnamorphicNode, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrayCamera, ArrayElementNode, ArrowHelper, AssignNode, AttachedBindMode, AttributeNode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BRDF_GGX, BRDF_Lambert, BackSide, BasicDepthPacking, BasicEnvironmentNode, BasicShadowMap$1 as BasicShadowMap, BatchNode, BatchedMesh, BloomNode, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxGeometry, BoxHelper, Break, BufferAttribute, BufferAttributeNode, BufferGeometry, BufferGeometryLoader, BufferNode, BumpMapNode, BypassNode, ByteType, Cache, CacheNode, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CineonToneMapping, CircleGeometry, ClampToEdgeWrapping, Clock, CodeNode, Color, ColorKeyframeTrack, ColorManagement, ColorSpaceNode, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ComputeNode, ConeGeometry, ConstNode, ConstantAlphaFactor, ConstantColorFactor, ContextNode, Continue, Controls, ConvertNode, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureLoader, CubeTextureNode, CubeUVReflectionMapping, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceBack, CullFaceFront, CullFaceFrontBack, CullFaceNone, Curve, CurvePath, CustomBlending, CustomToneMapping, CylinderGeometry, Cylindrical, DFGApprox, D_GGX, Data3DTexture, DataArrayTexture, DataTexture, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DenoiseNode, DepthFormat, DepthOfFieldNode, DepthStencilFormat, DepthTexture, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DirectionalLightNode, Discard, DiscreteInterpolant, DisplayP3ColorSpace, DodecahedronGeometry, DotScreenNode, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EPSILON, EdgesGeometry, EllipseCurve, EnvironmentNode, EqualCompare, EqualDepth, EqualStencilFunc, EquirectUVNode, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExpressionNode, ExtrudeGeometry, FXAANode, F_Schlick, FileLoader, FilmNode, Float16BufferAttribute, Float32BufferAttribute, FloatType, Fn, Fog, FogExp2, FogExp2Node, FogNode, FogRangeNode, FramebufferTexture, FrontFacingNode, FrontSide, Frustum, FunctionCallNode, FunctionNode, FunctionOverloadingNode, GLBufferAttribute, GLSL1, GLSL3, GLSLNodeParser, GTAONode, GaussianBlurNode, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HalfFloatType, HemisphereLight, HemisphereLightHelper, HemisphereLightNode, IESSpotLight, IESSpotLightNode, INFINITY, IcosahedronGeometry, If, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, IndexNode, InstanceNode, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, InstancedPointsNodeMaterial, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, IntType, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InvertStencilOp, IrradianceNode, JoinNode, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, Layers, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, LightProbeNode, LightingContextNode, LightingModel, LightingNode, LightsNode, Line, Line2NodeMaterial, Line3, LineBasicMaterial, LineBasicNodeMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineDashedNodeMaterial, LineLoop, LineSegments, LinearDisplayP3ColorSpace, LinearFilter, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Loader, LoaderUtils, LoadingManager, Loop, LoopNode, LoopOnce, LoopPingPong, LoopRepeat, LuminanceAlphaFormat, LuminanceFormat, Lut3DNode, MOUSE, MRTNode, MatcapUVNode, Material, MaterialLoader, MaterialNode, MaterialReferenceNode, MathUtils, Matrix2, Matrix3, Matrix4, MaxEquation, MaxMipLevelNode, Mesh, MeshBasicMaterial, MeshBasicNodeMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshLambertMaterial, MeshLambertNodeMaterial, MeshMatcapMaterial, MeshMatcapNodeMaterial, MeshNormalMaterial, MeshNormalNodeMaterial, MeshPhongMaterial, MeshPhongNodeMaterial, MeshPhysicalMaterial, MeshPhysicalNodeMaterial, MeshSSSNodeMaterial, MeshStandardMaterial, MeshStandardNodeMaterial, MeshToonMaterial, MeshToonNodeMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, ModelNode, ModelViewProjectionNode, MorphNode, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoToneMapping, Node, NodeAttribute, NodeBuilder, NodeCache, NodeCode, NodeFrame, NodeFunctionInput, NodeLoader, NodeMaterial, NodeMaterialLoader, NodeMaterialObserver, NodeObjectLoader, NodeShaderStage, NodeType, NodeUniform, NodeUpdateType, NodeUtils, NodeVar, NodeVarying, NormalAnimationBlendMode, NormalBlending, NormalMapNode, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, Object3DNode, ObjectLoader, ObjectSpaceNormalMap, OctahedronGeometry, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, OscNode, OutputStructNode, P3Primaries, PCFShadowMap$1 as PCFShadowMap, PCFSoftShadowMap$1 as PCFSoftShadowMap, PI, PI2, PMREMGenerator, PMREMNode, ParallaxBarrierPassNode, ParameterNode, PassNode, Path, PerspectiveCamera, PhongLightingModel, PhysicalLightingModel, PixelationPassNode, Plane, PlaneGeometry, PlaneHelper, PointLight, PointLightHelper, PointLightNode, PointUVNode, Points, PointsMaterial, PointsNodeMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PostProcessing, PosterizeNode, PropertyBinding, PropertyMixer, PropertyNode, QuadMesh, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RGBADepthPacking, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBDepthPacking, RGBFormat, RGBIntegerFormat, RGBShiftNode, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGDepthPacking, RGFormat, RGIntegerFormat, RTTNode, RangeNode, RawShaderMaterial, Ray, Raycaster, Rec709Primaries, RectAreaLight, RectAreaLightNode, RedFormat, RedIntegerFormat, ReferenceNode, ReflectorNode, ReinhardToneMapping, RemapNode, RenderOutputNode, RenderTarget, RendererReferenceNode, RepeatWrapping, ReplaceStencilOp, Return, ReverseSubtractEquation, RingGeometry, RotateNode, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, SRGBTransfer, SSAAPassNode, Scene, SceneNode, Schlick_to_F0, ScreenNode, ScriptableNode, ScriptableValueNode, SetNode, ShaderMaterial, ShaderNode, ShadowMaterial, ShadowNodeMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, SkinningNode, SobelOperatorNode, Source, Sphere, SphereGeometry, Spherical, SphericalHarmonics3, SplineCurve, SplitNode, SpotLight, SpotLightHelper, SpotLightNode, Sprite, SpriteMaterial, SpriteNodeMaterial, SpriteSheetUVNode, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StackNode, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StereoPassNode, StorageArrayElementNode, StorageBufferAttribute, StorageBufferNode, StorageInstancedBufferAttribute, StorageTexture, StorageTextureNode, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SubtractEquation, SubtractiveBlending, TBNViewMatrix, TOUCH, TangentSpaceNormalMap, TempNode, TetrahedronGeometry, Texture, Texture3DNode, TextureLoader, TextureNode, TextureSizeNode, TimerNode, ToneMappingNode, ToonOutlinePassNode, TorusGeometry, TorusKnotGeometry, TransitionNode, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TriplanarTexturesNode, TubeGeometry, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform$1 as Uniform, UniformArrayNode, UniformGroupNode, UniformNode, UniformsGroup$1 as UniformsGroup, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, UserDataNode, VSMShadowMap, V_GGX_SmithCorrelated, VarNode, VaryingNode, Vector2, Vector3, Vector4, VectorKeyframeTrack, VertexColorNode, VideoTexture, ViewportDepthNode, ViewportDepthTextureNode, ViewportSharedTextureNode, ViewportTextureNode, VolumeNodeMaterial, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGLMultipleRenderTargets, WebGLRenderTarget, WebGPUCoordinateSystem, WebGPURenderer, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, abs, acesFilmicToneMapping, acos, add, addMethodChaining, addNodeElement, afterImage, agxToneMapping, all, alphaT, anaglyphPass, anamorphic, and, anisotropy, anisotropyB, anisotropyT, any, ao, append, arrayBuffer, asin, assign, atan, atan2, atomicAdd, atomicAnd, atomicFunc, atomicMax, atomicMin, atomicOr, atomicStore, atomicSub, atomicXor, attenuationColor, attenuationDistance, attribute, backgroundBlurriness, backgroundIntensity, batch, billboarding, bitAnd, bitNot, bitOr, bitXor, bitangentGeometry, bitangentLocal, bitangentView, bitangentWorld, bitcast, bleach, bloom, blur, bool, buffer, bufferAttribute, bumpMap, burn, bvec2, bvec3, bvec4, bypass, cache, call, cameraFar, cameraLogDepth, cameraNear, cameraNormalMatrix, cameraPosition, cameraProjectionMatrix, cameraProjectionMatrixInverse, cameraViewMatrix, cameraWorldMatrix, cbrt, ceil, checker, cineonToneMapping, clamp, clearcoat, clearcoatRoughness, code, color, colorSpaceToWorking, colorToDirection, compute, cond, context, convert, convertToTexture, cos, createCanvasElement, cross, cubeTexture, dFdx, dFdy, dashSize, defaultBuildStages, defaultShaderStages, defined, degrees, denoise, densityFog, depth, depthPass, difference, diffuseColor, directionToColor, dispersion, distance, div, dodge, dof, dot, dotScreen, drawIndex, dynamicBufferAttribute, element, emissive, equal, equals, equirectUV, exp, exp2, expression, faceDirection, faceForward, film, float, floor, fog, fract, frameGroup, frameId, frontFacing, fwidth, fxaa, gain, gapSize, gaussianBlur, getColorSpaceMethod, getConstNodeType, getCurrentStack, getDirection, getDistanceAttenuation, getGeometryRoughness, getRoughness, getShIrradianceAt, getTextureIndex, global, glsl, glslFn, grayscale, greaterThan, greaterThanEqual, hash, highPrecisionModelNormalViewMatrix, highPrecisionModelViewMatrix, hue, instance, instanceIndex, instancedBufferAttribute, instancedDynamicBufferAttribute, int, inverseSqrt, invocationLocalIndex, invocationSubgroupIndex, ior, iridescence, iridescenceIOR, iridescenceThickness, ivec2, ivec3, ivec4, js, label, length, lengthSq, lessThan, lessThanEqual, lightPosition, lightTargetDirection, lightTargetPosition, lightViewPosition, lightingContext, lights, linearDepth, linearSRGBTosRGB, linearToneMapping, localId, log, log2, loop, luminance, lut3D, mat2, mat3, mat4, matcapUV, materialAOMap, materialAlphaTest, materialAnisotropy, materialAnisotropyVector, materialAttenuationColor, materialAttenuationDistance, materialClearcoat, materialClearcoatNormal, materialClearcoatRoughness, materialColor, materialDispersion, materialEmissive, materialIOR, materialIridescence, materialIridescenceIOR, materialIridescenceThickness, materialLightMap, materialLineDashOffset, materialLineDashSize, materialLineGapSize, materialLineScale, materialLineWidth, materialMetalness, materialNormal, materialOpacity, materialPointWidth, materialReference, materialReflectivity, materialRefractionRatio, materialRotation, materialRoughness, materialSheen, materialSheenRoughness, materialShininess, materialSpecular, materialSpecularColor, materialSpecularIntensity, materialSpecularStrength, materialThickness, materialTransmission, max$1 as max, maxMipLevel, metalness, min$1 as min, mix, mixElement, mod, modInt, modelDirection, modelNormalMatrix, modelPosition, modelScale, modelViewMatrix, modelViewPosition, modelViewProjection, modelWorldMatrix, modelWorldMatrixInverse, morphReference, motionBlur, mrt, mul, mx_aastep, mx_cell_noise_float, mx_contrast, mx_fractal_noise_float, mx_fractal_noise_vec2, mx_fractal_noise_vec3, mx_fractal_noise_vec4, mx_hsvtorgb, mx_noise_float, mx_noise_vec3, mx_noise_vec4, mx_ramplr, mx_ramptb, mx_rgbtohsv, mx_safepower, mx_splitlr, mx_splittb, mx_srgb_texture_to_lin_rec709, mx_transform_uv, mx_worley_noise_float, mx_worley_noise_vec2, mx_worley_noise_vec3, negate, neutralToneMapping, nodeArray, nodeImmutable, nodeObject, nodeObjects, nodeProxy, normalFlat, normalGeometry, normalLocal, normalMap, normalView, normalWorld, normalize, not, notEqual, numWorkgroups, objectDirection, objectGroup, objectPosition, objectScale, objectViewPosition, objectWorldMatrix, oneMinus, or, orthographicDepthToViewZ, oscSawtooth, oscSine, oscSquare, oscTriangle, output, outputStruct, overlay, overloadingFn, parabola, parallaxBarrierPass, parallaxDirection, parallaxUV, parameter, pass, passTexture, pcurve, perspectiveDepthToViewZ, pixelationPass, pmremTexture, pointUV, pointWidth, positionGeometry, positionLocal, positionPrevious, positionView, positionViewDirection, positionWorld, positionWorldDirection, posterize, pow, pow2, pow3, pow4, property, radians, rand, range, rangeFog, reciprocal, reference, referenceBuffer, reflect, reflectVector, reflectView, reflector, refract, refractVector, refractView, reinhardToneMapping, remainder, remap, remapClamp, renderGroup, renderOutput, rendererReference, rgbShift, rotate, rotateUV, roughness, round, rtt, sRGBToLinearSRGB, sampler, saturate, saturation, screen, screenCoordinate, screenSize, screenUV, scriptable, scriptableValue, select, sepia, setCurrentStack, shaderStages, sharedUniformGroup, sheen, sheenRoughness, shiftLeft, shiftRight, shininess, sign, sin, sinc, skinning, skinningReference, smoothstep, smoothstepElement, sobel, specularColor, specularF90, spherizeUV, split, spritesheetUV, sqrt, ssaaPass, stack, step, stereoPass, storage, storageBarrier, storageObject, storageTexture, string, sub, subgroupIndex, subgroupSize, tan, tangentGeometry, tangentLocal, tangentView, tangentWorld, temp, texture, texture3D, textureBarrier, textureBicubic, textureCubeUV, textureLoad, textureSize, textureStore, thickness, threshold, timerDelta, timerGlobal, timerLocal, toOutputColorSpace, toWorkingColorSpace, toneMapping, toneMappingExposure, toonOutlinePass, transformDirection, transformNormal, transformNormalToView, transformedBentNormalView, transformedBitangentView, transformedBitangentWorld, transformedClearcoatNormalView, transformedNormalView, transformedNormalWorld, transformedTangentView, transformedTangentWorld, transition, transmission, transpose, tri, tri3, triNoise3D, triplanarTexture, triplanarTextures, trunc, tslFn, uint, uniform, uniformArray, uniformGroup, uniforms, userData, uv, uvec2, uvec3, uvec4, varying, varyingProperty, vec2, vec3, vec4, vectorComponents, velocity, vertexColor, vertexIndex, vibrance, viewZToOrthographicDepth, viewZToPerspectiveDepth, viewport, viewportBottomLeft, viewportCoordinate, viewportDepthTexture, viewportLinearDepth, viewportMipTexture, viewportResolution, viewportSafeUV, viewportSharedTexture, viewportSize, viewportTexture, viewportTopLeft, viewportUV, wgsl, wgslFn, workgroupArray, workgroupBarrier, workgroupId, workingToColorSpace, xor }; diff --git a/build/three.webgpu.nodes.min.js b/build/three.webgpu.nodes.min.js new file mode 100644 index 00000000000000..17808bc51fbd44 --- /dev/null +++ b/build/three.webgpu.nodes.min.js @@ -0,0 +1,6 @@ +/** + * @license + * Copyright 2010-2024 Three.js Authors + * SPDX-License-Identifier: MIT + */ +const e="169",t={LEFT:0,MIDDLE:1,RIGHT:2,ROTATE:0,DOLLY:1,PAN:2},s={ROTATE:0,PAN:1,DOLLY_PAN:2,DOLLY_ROTATE:3},i=0,r=1,n=2,o=3,a=0,h=1,u=2,l=3,c=0,d=1,p=2,m=0,g=1,f=2,y=3,x=4,b=5,v=100,T=101,_=102,w=103,S=104,M=200,N=201,A=202,C=203,R=204,E=205,B=206,I=207,P=208,F=209,z=210,U=211,O=212,L=213,V=214,D=0,k=1,G=2,W=3,j=4,H=5,q=6,$=7,X=0,Y=1,Z=2,J=0,K=1,Q=2,ee=3,te=4,se=5,ie=6,re=7,ne="attached",oe="detached",ae=300,he=301,ue=302,le=303,ce=304,de=306,pe=1e3,me=1001,ge=1002,fe=1003,ye=1004,xe=1004,be=1005,ve=1005,Te=1006,_e=1007,we=1007,Se=1008,Me=1008,Ne=1009,Ae=1010,Ce=1011,Re=1012,Ee=1013,Be=1014,Ie=1015,Pe=1016,Fe=1017,ze=1018,Ue=1020,Oe=35902,Le=1021,Ve=1022,De=1023,ke=1024,Ge=1025,We=1026,je=1027,He=1028,qe=1029,$e=1030,Xe=1031,Ye=1032,Ze=1033,Je=33776,Ke=33777,Qe=33778,et=33779,tt=35840,st=35841,it=35842,rt=35843,nt=36196,ot=37492,at=37496,ht=37808,ut=37809,lt=37810,ct=37811,dt=37812,pt=37813,mt=37814,gt=37815,ft=37816,yt=37817,xt=37818,bt=37819,vt=37820,Tt=37821,_t=36492,wt=36494,St=36495,Mt=36283,Nt=36284,At=36285,Ct=36286,Rt=2200,Et=2201,Bt=2202,It=2300,Pt=2301,Ft=2302,zt=2400,Ut=2401,Ot=2402,Lt=2500,Vt=2501,Dt=0,kt=1,Gt=2,Wt=3200,jt=3201,Ht=3202,qt=3203,$t=0,Xt=1,Yt="",Zt="srgb",Jt="srgb-linear",Kt="display-p3",Qt="display-p3-linear",es="linear",ts="srgb",ss="rec709",is="p3",rs=0,ns=7680,os=7681,as=7682,hs=7683,us=34055,ls=34056,cs=5386,ds=512,ps=513,ms=514,gs=515,fs=516,ys=517,xs=518,bs=519,vs=512,Ts=513,_s=514,ws=515,Ss=516,Ms=517,Ns=518,As=519,Cs=35044,Rs=35048,Es=35040,Bs=35045,Is=35049,Ps=35041,Fs=35046,zs=35050,Us=35042,Os="100",Ls="300 es",Vs=2e3,Ds=2001;class ks{addEventListener(e,t){void 0===this._listeners&&(this._listeners={});const s=this._listeners;void 0===s[e]&&(s[e]=[]),-1===s[e].indexOf(t)&&s[e].push(t)}hasEventListener(e,t){if(void 0===this._listeners)return!1;const s=this._listeners;return void 0!==s[e]&&-1!==s[e].indexOf(t)}removeEventListener(e,t){if(void 0===this._listeners)return;const s=this._listeners[e];if(void 0!==s){const e=s.indexOf(t);-1!==e&&s.splice(e,1)}}dispatchEvent(e){if(void 0===this._listeners)return;const t=this._listeners[e.type];if(void 0!==t){e.target=this;const s=t.slice(0);for(let t=0,i=s.length;t>8&255]+Gs[e>>16&255]+Gs[e>>24&255]+"-"+Gs[255&t]+Gs[t>>8&255]+"-"+Gs[t>>16&15|64]+Gs[t>>24&255]+"-"+Gs[63&s|128]+Gs[s>>8&255]+"-"+Gs[s>>16&255]+Gs[s>>24&255]+Gs[255&i]+Gs[i>>8&255]+Gs[i>>16&255]+Gs[i>>24&255]).toLowerCase()}function $s(e,t,s){return Math.max(t,Math.min(s,e))}function Xs(e,t){return(e%t+t)%t}function Ys(e,t,s){return(1-s)*e+s*t}function Zs(e,t){switch(t.constructor){case Float32Array:return e;case Uint32Array:return e/4294967295;case Uint16Array:return e/65535;case Uint8Array:return e/255;case Int32Array:return Math.max(e/2147483647,-1);case Int16Array:return Math.max(e/32767,-1);case Int8Array:return Math.max(e/127,-1);default:throw new Error("Invalid component type.")}}function Js(e,t){switch(t.constructor){case Float32Array:return e;case Uint32Array:return Math.round(4294967295*e);case Uint16Array:return Math.round(65535*e);case Uint8Array:return Math.round(255*e);case Int32Array:return Math.round(2147483647*e);case Int16Array:return Math.round(32767*e);case Int8Array:return Math.round(127*e);default:throw new Error("Invalid component type.")}}const Ks={DEG2RAD:js,RAD2DEG:Hs,generateUUID:qs,clamp:$s,euclideanModulo:Xs,mapLinear:function(e,t,s,i,r){return i+(e-t)*(r-i)/(s-t)},inverseLerp:function(e,t,s){return e!==t?(s-e)/(t-e):0},lerp:Ys,damp:function(e,t,s,i){return Ys(e,t,1-Math.exp(-s*i))},pingpong:function(e,t=1){return t-Math.abs(Xs(e,2*t)-t)},smoothstep:function(e,t,s){return e<=t?0:e>=s?1:(e=(e-t)/(s-t))*e*(3-2*e)},smootherstep:function(e,t,s){return e<=t?0:e>=s?1:(e=(e-t)/(s-t))*e*e*(e*(6*e-15)+10)},randInt:function(e,t){return e+Math.floor(Math.random()*(t-e+1))},randFloat:function(e,t){return e+Math.random()*(t-e)},randFloatSpread:function(e){return e*(.5-Math.random())},seededRandom:function(e){void 0!==e&&(Ws=e);let t=Ws+=1831565813;return t=Math.imul(t^t>>>15,1|t),t^=t+Math.imul(t^t>>>7,61|t),((t^t>>>14)>>>0)/4294967296},degToRad:function(e){return e*js},radToDeg:function(e){return e*Hs},isPowerOfTwo:function(e){return 0==(e&e-1)&&0!==e},ceilPowerOfTwo:function(e){return Math.pow(2,Math.ceil(Math.log(e)/Math.LN2))},floorPowerOfTwo:function(e){return Math.pow(2,Math.floor(Math.log(e)/Math.LN2))},setQuaternionFromProperEuler:function(e,t,s,i,r){const n=Math.cos,o=Math.sin,a=n(s/2),h=o(s/2),u=n((t+i)/2),l=o((t+i)/2),c=n((t-i)/2),d=o((t-i)/2),p=n((i-t)/2),m=o((i-t)/2);switch(r){case"XYX":e.set(a*l,h*c,h*d,a*u);break;case"YZY":e.set(h*d,a*l,h*c,a*u);break;case"ZXZ":e.set(h*c,h*d,a*l,a*u);break;case"XZX":e.set(a*l,h*m,h*p,a*u);break;case"YXY":e.set(h*p,a*l,h*m,a*u);break;case"ZYZ":e.set(h*m,h*p,a*l,a*u);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+r)}},normalize:Js,denormalize:Zs};class Qs{constructor(e=0,t=0){Qs.prototype.isVector2=!0,this.x=e,this.y=t}get width(){return this.x}set width(e){this.x=e}get height(){return this.y}set height(e){this.y=e}set(e,t){return this.x=e,this.y=t,this}setScalar(e){return this.x=e,this.y=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}addScalar(e){return this.x+=e,this.y+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this}subScalar(e){return this.x-=e,this.y-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this}multiply(e){return this.x*=e.x,this.y*=e.y,this}multiplyScalar(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e.x,this.y/=e.y,this}divideScalar(e){return this.multiplyScalar(1/e)}applyMatrix3(e){const t=this.x,s=this.y,i=e.elements;return this.x=i[0]*t+i[3]*s+i[6],this.y=i[1]*t+i[4]*s+i[7],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this}clampLength(e,t){const s=this.length();return this.divideScalar(s||1).multiplyScalar(Math.max(e,Math.min(t,s)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(e){return this.x*e.x+this.y*e.y}cross(e){return this.x*e.y-this.y*e.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(0===t)return Math.PI/2;const s=this.dot(e)/t;return Math.acos($s(s,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,s=this.y-e.y;return t*t+s*s}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this}lerpVectors(e,t,s){return this.x=e.x+(t.x-e.x)*s,this.y=e.y+(t.y-e.y)*s,this}equals(e){return e.x===this.x&&e.y===this.y}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this}rotateAround(e,t){const s=Math.cos(t),i=Math.sin(t),r=this.x-e.x,n=this.y-e.y;return this.x=r*s-n*i+e.x,this.y=r*i+n*s+e.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class ei{constructor(e,t,s,i,r,n,o,a,h){ei.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],void 0!==e&&this.set(e,t,s,i,r,n,o,a,h)}set(e,t,s,i,r,n,o,a,h){const u=this.elements;return u[0]=e,u[1]=i,u[2]=o,u[3]=t,u[4]=r,u[5]=a,u[6]=s,u[7]=n,u[8]=h,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(e){const t=this.elements,s=e.elements;return t[0]=s[0],t[1]=s[1],t[2]=s[2],t[3]=s[3],t[4]=s[4],t[5]=s[5],t[6]=s[6],t[7]=s[7],t[8]=s[8],this}extractBasis(e,t,s){return e.setFromMatrix3Column(this,0),t.setFromMatrix3Column(this,1),s.setFromMatrix3Column(this,2),this}setFromMatrix4(e){const t=e.elements;return this.set(t[0],t[4],t[8],t[1],t[5],t[9],t[2],t[6],t[10]),this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const s=e.elements,i=t.elements,r=this.elements,n=s[0],o=s[3],a=s[6],h=s[1],u=s[4],l=s[7],c=s[2],d=s[5],p=s[8],m=i[0],g=i[3],f=i[6],y=i[1],x=i[4],b=i[7],v=i[2],T=i[5],_=i[8];return r[0]=n*m+o*y+a*v,r[3]=n*g+o*x+a*T,r[6]=n*f+o*b+a*_,r[1]=h*m+u*y+l*v,r[4]=h*g+u*x+l*T,r[7]=h*f+u*b+l*_,r[2]=c*m+d*y+p*v,r[5]=c*g+d*x+p*T,r[8]=c*f+d*b+p*_,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[3]*=e,t[6]*=e,t[1]*=e,t[4]*=e,t[7]*=e,t[2]*=e,t[5]*=e,t[8]*=e,this}determinant(){const e=this.elements,t=e[0],s=e[1],i=e[2],r=e[3],n=e[4],o=e[5],a=e[6],h=e[7],u=e[8];return t*n*u-t*o*h-s*r*u+s*o*a+i*r*h-i*n*a}invert(){const e=this.elements,t=e[0],s=e[1],i=e[2],r=e[3],n=e[4],o=e[5],a=e[6],h=e[7],u=e[8],l=u*n-o*h,c=o*a-u*r,d=h*r-n*a,p=t*l+s*c+i*d;if(0===p)return this.set(0,0,0,0,0,0,0,0,0);const m=1/p;return e[0]=l*m,e[1]=(i*h-u*s)*m,e[2]=(o*s-i*n)*m,e[3]=c*m,e[4]=(u*t-i*a)*m,e[5]=(i*r-o*t)*m,e[6]=d*m,e[7]=(s*a-h*t)*m,e[8]=(n*t-s*r)*m,this}transpose(){let e;const t=this.elements;return e=t[1],t[1]=t[3],t[3]=e,e=t[2],t[2]=t[6],t[6]=e,e=t[5],t[5]=t[7],t[7]=e,this}getNormalMatrix(e){return this.setFromMatrix4(e).invert().transpose()}transposeIntoArray(e){const t=this.elements;return e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8],this}setUvTransform(e,t,s,i,r,n,o){const a=Math.cos(r),h=Math.sin(r);return this.set(s*a,s*h,-s*(a*n+h*o)+n+e,-i*h,i*a,-i*(-h*n+a*o)+o+t,0,0,1),this}scale(e,t){return this.premultiply(ti.makeScale(e,t)),this}rotate(e){return this.premultiply(ti.makeRotation(-e)),this}translate(e,t){return this.premultiply(ti.makeTranslation(e,t)),this}makeTranslation(e,t){return e.isVector2?this.set(1,0,e.x,0,1,e.y,0,0,1):this.set(1,0,e,0,1,t,0,0,1),this}makeRotation(e){const t=Math.cos(e),s=Math.sin(e);return this.set(t,-s,0,s,t,0,0,0,1),this}makeScale(e,t){return this.set(e,0,0,0,t,0,0,0,1),this}equals(e){const t=this.elements,s=e.elements;for(let e=0;e<9;e++)if(t[e]!==s[e])return!1;return!0}fromArray(e,t=0){for(let s=0;s<9;s++)this.elements[s]=e[s+t];return this}toArray(e=[],t=0){const s=this.elements;return e[t]=s[0],e[t+1]=s[1],e[t+2]=s[2],e[t+3]=s[3],e[t+4]=s[4],e[t+5]=s[5],e[t+6]=s[6],e[t+7]=s[7],e[t+8]=s[8],e}clone(){return(new this.constructor).fromArray(this.elements)}}const ti=new ei;const si={Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:Uint8ClampedArray,Int16Array:Int16Array,Uint16Array:Uint16Array,Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array};function ii(e,t){return new si[e](t)}function ri(e){return document.createElementNS("http://www.w3.org/1999/xhtml",e)}function ni(){const e=ri("canvas");return e.style.display="block",e}const oi={};const ai=(new ei).set(.8224621,.177538,0,.0331941,.9668058,0,.0170827,.0723974,.9105199),hi=(new ei).set(1.2249401,-.2249404,0,-.0420569,1.0420571,0,-.0196376,-.0786361,1.0982735),ui={[Jt]:{transfer:es,primaries:ss,luminanceCoefficients:[.2126,.7152,.0722],toReference:e=>e,fromReference:e=>e},[Zt]:{transfer:ts,primaries:ss,luminanceCoefficients:[.2126,.7152,.0722],toReference:e=>e.convertSRGBToLinear(),fromReference:e=>e.convertLinearToSRGB()},[Qt]:{transfer:es,primaries:is,luminanceCoefficients:[.2289,.6917,.0793],toReference:e=>e.applyMatrix3(hi),fromReference:e=>e.applyMatrix3(ai)},[Kt]:{transfer:ts,primaries:is,luminanceCoefficients:[.2289,.6917,.0793],toReference:e=>e.convertSRGBToLinear().applyMatrix3(hi),fromReference:e=>e.applyMatrix3(ai).convertLinearToSRGB()}},li=new Set([Jt,Qt]),ci={enabled:!0,_workingColorSpace:Jt,get workingColorSpace(){return this._workingColorSpace},set workingColorSpace(e){if(!li.has(e))throw new Error(`Unsupported working color space, "${e}".`);this._workingColorSpace=e},convert:function(e,t,s){if(!1===this.enabled||t===s||!t||!s)return e;const i=ui[t].toReference;return(0,ui[s].fromReference)(i(e))},fromWorkingColorSpace:function(e,t){return this.convert(e,this._workingColorSpace,t)},toWorkingColorSpace:function(e,t){return this.convert(e,t,this._workingColorSpace)},getPrimaries:function(e){return ui[e].primaries},getTransfer:function(e){return e===Yt?es:ui[e].transfer},getLuminanceCoefficients:function(e,t=this._workingColorSpace){return e.fromArray(ui[t].luminanceCoefficients)}};function di(e){return e<.04045?.0773993808*e:Math.pow(.9478672986*e+.0521327014,2.4)}function pi(e){return e<.0031308?12.92*e:1.055*Math.pow(e,.41666)-.055}let mi;class gi{static getDataURL(e){if(/^data:/i.test(e.src))return e.src;if("undefined"==typeof HTMLCanvasElement)return e.src;let t;if(e instanceof HTMLCanvasElement)t=e;else{void 0===mi&&(mi=ri("canvas")),mi.width=e.width,mi.height=e.height;const s=mi.getContext("2d");e instanceof ImageData?s.putImageData(e,0,0):s.drawImage(e,0,0,e.width,e.height),t=mi}return t.width>2048||t.height>2048?(console.warn("THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons",e),t.toDataURL("image/jpeg",.6)):t.toDataURL("image/png")}static sRGBToLinear(e){if("undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap){const t=ri("canvas");t.width=e.width,t.height=e.height;const s=t.getContext("2d");s.drawImage(e,0,0,e.width,e.height);const i=s.getImageData(0,0,e.width,e.height),r=i.data;for(let e=0;e0&&(s.userData=this.userData),t||(e.textures[this.uuid]=s),s}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(e){if(this.mapping!==ae)return e;if(e.applyMatrix3(this.matrix),e.x<0||e.x>1)switch(this.wrapS){case pe:e.x=e.x-Math.floor(e.x);break;case me:e.x=e.x<0?0:1;break;case ge:1===Math.abs(Math.floor(e.x)%2)?e.x=Math.ceil(e.x)-e.x:e.x=e.x-Math.floor(e.x)}if(e.y<0||e.y>1)switch(this.wrapT){case pe:e.y=e.y-Math.floor(e.y);break;case me:e.y=e.y<0?0:1;break;case ge:1===Math.abs(Math.floor(e.y)%2)?e.y=Math.ceil(e.y)-e.y:e.y=e.y-Math.floor(e.y)}return this.flipY&&(e.y=1-e.y),e}set needsUpdate(e){!0===e&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(e){!0===e&&this.pmremVersion++}}vi.DEFAULT_IMAGE=null,vi.DEFAULT_MAPPING=ae,vi.DEFAULT_ANISOTROPY=1;class Ti{constructor(e=0,t=0,s=0,i=1){Ti.prototype.isVector4=!0,this.x=e,this.y=t,this.z=s,this.w=i}get width(){return this.z}set width(e){this.z=e}get height(){return this.w}set height(e){this.w=e}set(e,t,s,i){return this.x=e,this.y=t,this.z=s,this.w=i,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this.w=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setW(e){return this.w=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;case 3:this.w=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=void 0!==e.w?e.w:1,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this.w+=e.w,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this.w+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this.w=e.w+t.w,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this.w+=e.w*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this.w-=e.w,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this.w-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this.w=e.w-t.w,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this.w*=e.w,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this.w*=e,this}applyMatrix4(e){const t=this.x,s=this.y,i=this.z,r=this.w,n=e.elements;return this.x=n[0]*t+n[4]*s+n[8]*i+n[12]*r,this.y=n[1]*t+n[5]*s+n[9]*i+n[13]*r,this.z=n[2]*t+n[6]*s+n[10]*i+n[14]*r,this.w=n[3]*t+n[7]*s+n[11]*i+n[15]*r,this}divideScalar(e){return this.multiplyScalar(1/e)}setAxisAngleFromQuaternion(e){this.w=2*Math.acos(e.w);const t=Math.sqrt(1-e.w*e.w);return t<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=e.x/t,this.y=e.y/t,this.z=e.z/t),this}setAxisAngleFromRotationMatrix(e){let t,s,i,r;const n=.01,o=.1,a=e.elements,h=a[0],u=a[4],l=a[8],c=a[1],d=a[5],p=a[9],m=a[2],g=a[6],f=a[10];if(Math.abs(u-c)a&&e>y?ey?a=0?1:-1,i=1-t*t;if(i>Number.EPSILON){const r=Math.sqrt(i),n=Math.atan2(r,t*s);e=Math.sin(e*n)/r,o=Math.sin(o*n)/r}const r=o*s;if(a=a*e+c*r,h=h*e+d*r,u=u*e+p*r,l=l*e+m*r,e===1-o){const e=1/Math.sqrt(a*a+h*h+u*u+l*l);a*=e,h*=e,u*=e,l*=e}}e[t]=a,e[t+1]=h,e[t+2]=u,e[t+3]=l}static multiplyQuaternionsFlat(e,t,s,i,r,n){const o=s[i],a=s[i+1],h=s[i+2],u=s[i+3],l=r[n],c=r[n+1],d=r[n+2],p=r[n+3];return e[t]=o*p+u*l+a*d-h*c,e[t+1]=a*p+u*c+h*l-o*d,e[t+2]=h*p+u*d+o*c-a*l,e[t+3]=u*p-o*l-a*c-h*d,e}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get w(){return this._w}set w(e){this._w=e,this._onChangeCallback()}set(e,t,s,i){return this._x=e,this._y=t,this._z=s,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(e){return this._x=e.x,this._y=e.y,this._z=e.z,this._w=e.w,this._onChangeCallback(),this}setFromEuler(e,t=!0){const s=e._x,i=e._y,r=e._z,n=e._order,o=Math.cos,a=Math.sin,h=o(s/2),u=o(i/2),l=o(r/2),c=a(s/2),d=a(i/2),p=a(r/2);switch(n){case"XYZ":this._x=c*u*l+h*d*p,this._y=h*d*l-c*u*p,this._z=h*u*p+c*d*l,this._w=h*u*l-c*d*p;break;case"YXZ":this._x=c*u*l+h*d*p,this._y=h*d*l-c*u*p,this._z=h*u*p-c*d*l,this._w=h*u*l+c*d*p;break;case"ZXY":this._x=c*u*l-h*d*p,this._y=h*d*l+c*u*p,this._z=h*u*p+c*d*l,this._w=h*u*l-c*d*p;break;case"ZYX":this._x=c*u*l-h*d*p,this._y=h*d*l+c*u*p,this._z=h*u*p-c*d*l,this._w=h*u*l+c*d*p;break;case"YZX":this._x=c*u*l+h*d*p,this._y=h*d*l+c*u*p,this._z=h*u*p-c*d*l,this._w=h*u*l-c*d*p;break;case"XZY":this._x=c*u*l-h*d*p,this._y=h*d*l-c*u*p,this._z=h*u*p+c*d*l,this._w=h*u*l+c*d*p;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+n)}return!0===t&&this._onChangeCallback(),this}setFromAxisAngle(e,t){const s=t/2,i=Math.sin(s);return this._x=e.x*i,this._y=e.y*i,this._z=e.z*i,this._w=Math.cos(s),this._onChangeCallback(),this}setFromRotationMatrix(e){const t=e.elements,s=t[0],i=t[4],r=t[8],n=t[1],o=t[5],a=t[9],h=t[2],u=t[6],l=t[10],c=s+o+l;if(c>0){const e=.5/Math.sqrt(c+1);this._w=.25/e,this._x=(u-a)*e,this._y=(r-h)*e,this._z=(n-i)*e}else if(s>o&&s>l){const e=2*Math.sqrt(1+s-o-l);this._w=(u-a)/e,this._x=.25*e,this._y=(i+n)/e,this._z=(r+h)/e}else if(o>l){const e=2*Math.sqrt(1+o-s-l);this._w=(r-h)/e,this._x=(i+n)/e,this._y=.25*e,this._z=(a+u)/e}else{const e=2*Math.sqrt(1+l-s-o);this._w=(n-i)/e,this._x=(r+h)/e,this._y=(a+u)/e,this._z=.25*e}return this._onChangeCallback(),this}setFromUnitVectors(e,t){let s=e.dot(t)+1;return sMath.abs(e.z)?(this._x=-e.y,this._y=e.x,this._z=0,this._w=s):(this._x=0,this._y=-e.z,this._z=e.y,this._w=s)):(this._x=e.y*t.z-e.z*t.y,this._y=e.z*t.x-e.x*t.z,this._z=e.x*t.y-e.y*t.x,this._w=s),this.normalize()}angleTo(e){return 2*Math.acos(Math.abs($s(this.dot(e),-1,1)))}rotateTowards(e,t){const s=this.angleTo(e);if(0===s)return this;const i=Math.min(1,t/s);return this.slerp(e,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(e){return this._x*e._x+this._y*e._y+this._z*e._z+this._w*e._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let e=this.length();return 0===e?(this._x=0,this._y=0,this._z=0,this._w=1):(e=1/e,this._x=this._x*e,this._y=this._y*e,this._z=this._z*e,this._w=this._w*e),this._onChangeCallback(),this}multiply(e){return this.multiplyQuaternions(this,e)}premultiply(e){return this.multiplyQuaternions(e,this)}multiplyQuaternions(e,t){const s=e._x,i=e._y,r=e._z,n=e._w,o=t._x,a=t._y,h=t._z,u=t._w;return this._x=s*u+n*o+i*h-r*a,this._y=i*u+n*a+r*o-s*h,this._z=r*u+n*h+s*a-i*o,this._w=n*u-s*o-i*a-r*h,this._onChangeCallback(),this}slerp(e,t){if(0===t)return this;if(1===t)return this.copy(e);const s=this._x,i=this._y,r=this._z,n=this._w;let o=n*e._w+s*e._x+i*e._y+r*e._z;if(o<0?(this._w=-e._w,this._x=-e._x,this._y=-e._y,this._z=-e._z,o=-o):this.copy(e),o>=1)return this._w=n,this._x=s,this._y=i,this._z=r,this;const a=1-o*o;if(a<=Number.EPSILON){const e=1-t;return this._w=e*n+t*this._w,this._x=e*s+t*this._x,this._y=e*i+t*this._y,this._z=e*r+t*this._z,this.normalize(),this}const h=Math.sqrt(a),u=Math.atan2(h,o),l=Math.sin((1-t)*u)/h,c=Math.sin(t*u)/h;return this._w=n*l+this._w*c,this._x=s*l+this._x*c,this._y=i*l+this._y*c,this._z=r*l+this._z*c,this._onChangeCallback(),this}slerpQuaternions(e,t,s){return this.copy(e).slerp(t,s)}random(){const e=2*Math.PI*Math.random(),t=2*Math.PI*Math.random(),s=Math.random(),i=Math.sqrt(1-s),r=Math.sqrt(s);return this.set(i*Math.sin(e),i*Math.cos(e),r*Math.sin(t),r*Math.cos(t))}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._w===this._w}fromArray(e,t=0){return this._x=e[t],this._y=e[t+1],this._z=e[t+2],this._w=e[t+3],this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._w,e}fromBufferAttribute(e,t){return this._x=e.getX(t),this._y=e.getY(t),this._z=e.getZ(t),this._w=e.getW(t),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}class Ri{constructor(e=0,t=0,s=0){Ri.prototype.isVector3=!0,this.x=e,this.y=t,this.z=s}set(e,t,s){return void 0===s&&(s=this.z),this.x=e,this.y=t,this.z=s,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this}multiplyVectors(e,t){return this.x=e.x*t.x,this.y=e.y*t.y,this.z=e.z*t.z,this}applyEuler(e){return this.applyQuaternion(Bi.setFromEuler(e))}applyAxisAngle(e,t){return this.applyQuaternion(Bi.setFromAxisAngle(e,t))}applyMatrix3(e){const t=this.x,s=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[3]*s+r[6]*i,this.y=r[1]*t+r[4]*s+r[7]*i,this.z=r[2]*t+r[5]*s+r[8]*i,this}applyNormalMatrix(e){return this.applyMatrix3(e).normalize()}applyMatrix4(e){const t=this.x,s=this.y,i=this.z,r=e.elements,n=1/(r[3]*t+r[7]*s+r[11]*i+r[15]);return this.x=(r[0]*t+r[4]*s+r[8]*i+r[12])*n,this.y=(r[1]*t+r[5]*s+r[9]*i+r[13])*n,this.z=(r[2]*t+r[6]*s+r[10]*i+r[14])*n,this}applyQuaternion(e){const t=this.x,s=this.y,i=this.z,r=e.x,n=e.y,o=e.z,a=e.w,h=2*(n*i-o*s),u=2*(o*t-r*i),l=2*(r*s-n*t);return this.x=t+a*h+n*l-o*u,this.y=s+a*u+o*h-r*l,this.z=i+a*l+r*u-n*h,this}project(e){return this.applyMatrix4(e.matrixWorldInverse).applyMatrix4(e.projectionMatrix)}unproject(e){return this.applyMatrix4(e.projectionMatrixInverse).applyMatrix4(e.matrixWorld)}transformDirection(e){const t=this.x,s=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[4]*s+r[8]*i,this.y=r[1]*t+r[5]*s+r[9]*i,this.z=r[2]*t+r[6]*s+r[10]*i,this.normalize()}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this}divideScalar(e){return this.multiplyScalar(1/e)}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this.z=Math.max(e,Math.min(t,this.z)),this}clampLength(e,t){const s=this.length();return this.divideScalar(s||1).multiplyScalar(Math.max(e,Math.min(t,s)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this}lerpVectors(e,t,s){return this.x=e.x+(t.x-e.x)*s,this.y=e.y+(t.y-e.y)*s,this.z=e.z+(t.z-e.z)*s,this}cross(e){return this.crossVectors(this,e)}crossVectors(e,t){const s=e.x,i=e.y,r=e.z,n=t.x,o=t.y,a=t.z;return this.x=i*a-r*o,this.y=r*n-s*a,this.z=s*o-i*n,this}projectOnVector(e){const t=e.lengthSq();if(0===t)return this.set(0,0,0);const s=e.dot(this)/t;return this.copy(e).multiplyScalar(s)}projectOnPlane(e){return Ei.copy(this).projectOnVector(e),this.sub(Ei)}reflect(e){return this.sub(Ei.copy(e).multiplyScalar(2*this.dot(e)))}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(0===t)return Math.PI/2;const s=this.dot(e)/t;return Math.acos($s(s,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,s=this.y-e.y,i=this.z-e.z;return t*t+s*s+i*i}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)+Math.abs(this.z-e.z)}setFromSpherical(e){return this.setFromSphericalCoords(e.radius,e.phi,e.theta)}setFromSphericalCoords(e,t,s){const i=Math.sin(t)*e;return this.x=i*Math.sin(s),this.y=Math.cos(t)*e,this.z=i*Math.cos(s),this}setFromCylindrical(e){return this.setFromCylindricalCoords(e.radius,e.theta,e.y)}setFromCylindricalCoords(e,t,s){return this.x=e*Math.sin(t),this.y=s,this.z=e*Math.cos(t),this}setFromMatrixPosition(e){const t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this}setFromMatrixScale(e){const t=this.setFromMatrixColumn(e,0).length(),s=this.setFromMatrixColumn(e,1).length(),i=this.setFromMatrixColumn(e,2).length();return this.x=t,this.y=s,this.z=i,this}setFromMatrixColumn(e,t){return this.fromArray(e.elements,4*t)}setFromMatrix3Column(e,t){return this.fromArray(e.elements,3*t)}setFromEuler(e){return this.x=e._x,this.y=e._y,this.z=e._z,this}setFromColor(e){return this.x=e.r,this.y=e.g,this.z=e.b,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const e=Math.random()*Math.PI*2,t=2*Math.random()-1,s=Math.sqrt(1-t*t);return this.x=s*Math.cos(e),this.y=t,this.z=s*Math.sin(e),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const Ei=new Ri,Bi=new Ci;class Ii{constructor(e=new Ri(1/0,1/0,1/0),t=new Ri(-1/0,-1/0,-1/0)){this.isBox3=!0,this.min=e,this.max=t}set(e,t){return this.min.copy(e),this.max.copy(t),this}setFromArray(e){this.makeEmpty();for(let t=0,s=e.length;t=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y&&e.z>=this.min.z&&e.z<=this.max.z}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y),(e.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y&&e.max.z>=this.min.z&&e.min.z<=this.max.z}intersectsSphere(e){return this.clampPoint(e.center,Fi),Fi.distanceToSquared(e.center)<=e.radius*e.radius}intersectsPlane(e){let t,s;return e.normal.x>0?(t=e.normal.x*this.min.x,s=e.normal.x*this.max.x):(t=e.normal.x*this.max.x,s=e.normal.x*this.min.x),e.normal.y>0?(t+=e.normal.y*this.min.y,s+=e.normal.y*this.max.y):(t+=e.normal.y*this.max.y,s+=e.normal.y*this.min.y),e.normal.z>0?(t+=e.normal.z*this.min.z,s+=e.normal.z*this.max.z):(t+=e.normal.z*this.max.z,s+=e.normal.z*this.min.z),t<=-e.constant&&s>=-e.constant}intersectsTriangle(e){if(this.isEmpty())return!1;this.getCenter(Gi),Wi.subVectors(this.max,Gi),Ui.subVectors(e.a,Gi),Oi.subVectors(e.b,Gi),Li.subVectors(e.c,Gi),Vi.subVectors(Oi,Ui),Di.subVectors(Li,Oi),ki.subVectors(Ui,Li);let t=[0,-Vi.z,Vi.y,0,-Di.z,Di.y,0,-ki.z,ki.y,Vi.z,0,-Vi.x,Di.z,0,-Di.x,ki.z,0,-ki.x,-Vi.y,Vi.x,0,-Di.y,Di.x,0,-ki.y,ki.x,0];return!!qi(t,Ui,Oi,Li,Wi)&&(t=[1,0,0,0,1,0,0,0,1],!!qi(t,Ui,Oi,Li,Wi)&&(ji.crossVectors(Vi,Di),t=[ji.x,ji.y,ji.z],qi(t,Ui,Oi,Li,Wi)))}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,Fi).distanceTo(e)}getBoundingSphere(e){return this.isEmpty()?e.makeEmpty():(this.getCenter(e.center),e.radius=.5*this.getSize(Fi).length()),e}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}applyMatrix4(e){return this.isEmpty()||(Pi[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(e),Pi[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(e),Pi[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(e),Pi[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(e),Pi[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(e),Pi[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(e),Pi[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(e),Pi[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(e),this.setFromPoints(Pi)),this}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}const Pi=[new Ri,new Ri,new Ri,new Ri,new Ri,new Ri,new Ri,new Ri],Fi=new Ri,zi=new Ii,Ui=new Ri,Oi=new Ri,Li=new Ri,Vi=new Ri,Di=new Ri,ki=new Ri,Gi=new Ri,Wi=new Ri,ji=new Ri,Hi=new Ri;function qi(e,t,s,i,r){for(let n=0,o=e.length-3;n<=o;n+=3){Hi.fromArray(e,n);const o=r.x*Math.abs(Hi.x)+r.y*Math.abs(Hi.y)+r.z*Math.abs(Hi.z),a=t.dot(Hi),h=s.dot(Hi),u=i.dot(Hi);if(Math.max(-Math.max(a,h,u),Math.min(a,h,u))>o)return!1}return!0}const $i=new Ii,Xi=new Ri,Yi=new Ri;class Zi{constructor(e=new Ri,t=-1){this.isSphere=!0,this.center=e,this.radius=t}set(e,t){return this.center.copy(e),this.radius=t,this}setFromPoints(e,t){const s=this.center;void 0!==t?s.copy(t):$i.setFromPoints(e).getCenter(s);let i=0;for(let t=0,r=e.length;tthis.radius*this.radius&&(t.sub(this.center).normalize(),t.multiplyScalar(this.radius).add(this.center)),t}getBoundingBox(e){return this.isEmpty()?(e.makeEmpty(),e):(e.set(this.center,this.center),e.expandByScalar(this.radius),e)}applyMatrix4(e){return this.center.applyMatrix4(e),this.radius=this.radius*e.getMaxScaleOnAxis(),this}translate(e){return this.center.add(e),this}expandByPoint(e){if(this.isEmpty())return this.center.copy(e),this.radius=0,this;Xi.subVectors(e,this.center);const t=Xi.lengthSq();if(t>this.radius*this.radius){const e=Math.sqrt(t),s=.5*(e-this.radius);this.center.addScaledVector(Xi,s/e),this.radius+=s}return this}union(e){return e.isEmpty()?this:this.isEmpty()?(this.copy(e),this):(!0===this.center.equals(e.center)?this.radius=Math.max(this.radius,e.radius):(Yi.subVectors(e.center,this.center).setLength(e.radius),this.expandByPoint(Xi.copy(e.center).add(Yi)),this.expandByPoint(Xi.copy(e.center).sub(Yi))),this)}equals(e){return e.center.equals(this.center)&&e.radius===this.radius}clone(){return(new this.constructor).copy(this)}}const Ji=new Ri,Ki=new Ri,Qi=new Ri,er=new Ri,tr=new Ri,sr=new Ri,ir=new Ri;class rr{constructor(e=new Ri,t=new Ri(0,0,-1)){this.origin=e,this.direction=t}set(e,t){return this.origin.copy(e),this.direction.copy(t),this}copy(e){return this.origin.copy(e.origin),this.direction.copy(e.direction),this}at(e,t){return t.copy(this.origin).addScaledVector(this.direction,e)}lookAt(e){return this.direction.copy(e).sub(this.origin).normalize(),this}recast(e){return this.origin.copy(this.at(e,Ji)),this}closestPointToPoint(e,t){t.subVectors(e,this.origin);const s=t.dot(this.direction);return s<0?t.copy(this.origin):t.copy(this.origin).addScaledVector(this.direction,s)}distanceToPoint(e){return Math.sqrt(this.distanceSqToPoint(e))}distanceSqToPoint(e){const t=Ji.subVectors(e,this.origin).dot(this.direction);return t<0?this.origin.distanceToSquared(e):(Ji.copy(this.origin).addScaledVector(this.direction,t),Ji.distanceToSquared(e))}distanceSqToSegment(e,t,s,i){Ki.copy(e).add(t).multiplyScalar(.5),Qi.copy(t).sub(e).normalize(),er.copy(this.origin).sub(Ki);const r=.5*e.distanceTo(t),n=-this.direction.dot(Qi),o=er.dot(this.direction),a=-er.dot(Qi),h=er.lengthSq(),u=Math.abs(1-n*n);let l,c,d,p;if(u>0)if(l=n*a-o,c=n*o-a,p=r*u,l>=0)if(c>=-p)if(c<=p){const e=1/u;l*=e,c*=e,d=l*(l+n*c+2*o)+c*(n*l+c+2*a)+h}else c=r,l=Math.max(0,-(n*c+o)),d=-l*l+c*(c+2*a)+h;else c=-r,l=Math.max(0,-(n*c+o)),d=-l*l+c*(c+2*a)+h;else c<=-p?(l=Math.max(0,-(-n*r+o)),c=l>0?-r:Math.min(Math.max(-r,-a),r),d=-l*l+c*(c+2*a)+h):c<=p?(l=0,c=Math.min(Math.max(-r,-a),r),d=c*(c+2*a)+h):(l=Math.max(0,-(n*r+o)),c=l>0?r:Math.min(Math.max(-r,-a),r),d=-l*l+c*(c+2*a)+h);else c=n>0?-r:r,l=Math.max(0,-(n*c+o)),d=-l*l+c*(c+2*a)+h;return s&&s.copy(this.origin).addScaledVector(this.direction,l),i&&i.copy(Ki).addScaledVector(Qi,c),d}intersectSphere(e,t){Ji.subVectors(e.center,this.origin);const s=Ji.dot(this.direction),i=Ji.dot(Ji)-s*s,r=e.radius*e.radius;if(i>r)return null;const n=Math.sqrt(r-i),o=s-n,a=s+n;return a<0?null:o<0?this.at(a,t):this.at(o,t)}intersectsSphere(e){return this.distanceSqToPoint(e.center)<=e.radius*e.radius}distanceToPlane(e){const t=e.normal.dot(this.direction);if(0===t)return 0===e.distanceToPoint(this.origin)?0:null;const s=-(this.origin.dot(e.normal)+e.constant)/t;return s>=0?s:null}intersectPlane(e,t){const s=this.distanceToPlane(e);return null===s?null:this.at(s,t)}intersectsPlane(e){const t=e.distanceToPoint(this.origin);if(0===t)return!0;return e.normal.dot(this.direction)*t<0}intersectBox(e,t){let s,i,r,n,o,a;const h=1/this.direction.x,u=1/this.direction.y,l=1/this.direction.z,c=this.origin;return h>=0?(s=(e.min.x-c.x)*h,i=(e.max.x-c.x)*h):(s=(e.max.x-c.x)*h,i=(e.min.x-c.x)*h),u>=0?(r=(e.min.y-c.y)*u,n=(e.max.y-c.y)*u):(r=(e.max.y-c.y)*u,n=(e.min.y-c.y)*u),s>n||r>i?null:((r>s||isNaN(s))&&(s=r),(n=0?(o=(e.min.z-c.z)*l,a=(e.max.z-c.z)*l):(o=(e.max.z-c.z)*l,a=(e.min.z-c.z)*l),s>a||o>i?null:((o>s||s!=s)&&(s=o),(a=0?s:i,t)))}intersectsBox(e){return null!==this.intersectBox(e,Ji)}intersectTriangle(e,t,s,i,r){tr.subVectors(t,e),sr.subVectors(s,e),ir.crossVectors(tr,sr);let n,o=this.direction.dot(ir);if(o>0){if(i)return null;n=1}else{if(!(o<0))return null;n=-1,o=-o}er.subVectors(this.origin,e);const a=n*this.direction.dot(sr.crossVectors(er,sr));if(a<0)return null;const h=n*this.direction.dot(tr.cross(er));if(h<0)return null;if(a+h>o)return null;const u=-n*er.dot(ir);return u<0?null:this.at(u/o,r)}applyMatrix4(e){return this.origin.applyMatrix4(e),this.direction.transformDirection(e),this}equals(e){return e.origin.equals(this.origin)&&e.direction.equals(this.direction)}clone(){return(new this.constructor).copy(this)}}class nr{constructor(e,t,s,i,r,n,o,a,h,u,l,c,d,p,m,g){nr.prototype.isMatrix4=!0,this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],void 0!==e&&this.set(e,t,s,i,r,n,o,a,h,u,l,c,d,p,m,g)}set(e,t,s,i,r,n,o,a,h,u,l,c,d,p,m,g){const f=this.elements;return f[0]=e,f[4]=t,f[8]=s,f[12]=i,f[1]=r,f[5]=n,f[9]=o,f[13]=a,f[2]=h,f[6]=u,f[10]=l,f[14]=c,f[3]=d,f[7]=p,f[11]=m,f[15]=g,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return(new nr).fromArray(this.elements)}copy(e){const t=this.elements,s=e.elements;return t[0]=s[0],t[1]=s[1],t[2]=s[2],t[3]=s[3],t[4]=s[4],t[5]=s[5],t[6]=s[6],t[7]=s[7],t[8]=s[8],t[9]=s[9],t[10]=s[10],t[11]=s[11],t[12]=s[12],t[13]=s[13],t[14]=s[14],t[15]=s[15],this}copyPosition(e){const t=this.elements,s=e.elements;return t[12]=s[12],t[13]=s[13],t[14]=s[14],this}setFromMatrix3(e){const t=e.elements;return this.set(t[0],t[3],t[6],0,t[1],t[4],t[7],0,t[2],t[5],t[8],0,0,0,0,1),this}extractBasis(e,t,s){return e.setFromMatrixColumn(this,0),t.setFromMatrixColumn(this,1),s.setFromMatrixColumn(this,2),this}makeBasis(e,t,s){return this.set(e.x,t.x,s.x,0,e.y,t.y,s.y,0,e.z,t.z,s.z,0,0,0,0,1),this}extractRotation(e){const t=this.elements,s=e.elements,i=1/or.setFromMatrixColumn(e,0).length(),r=1/or.setFromMatrixColumn(e,1).length(),n=1/or.setFromMatrixColumn(e,2).length();return t[0]=s[0]*i,t[1]=s[1]*i,t[2]=s[2]*i,t[3]=0,t[4]=s[4]*r,t[5]=s[5]*r,t[6]=s[6]*r,t[7]=0,t[8]=s[8]*n,t[9]=s[9]*n,t[10]=s[10]*n,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromEuler(e){const t=this.elements,s=e.x,i=e.y,r=e.z,n=Math.cos(s),o=Math.sin(s),a=Math.cos(i),h=Math.sin(i),u=Math.cos(r),l=Math.sin(r);if("XYZ"===e.order){const e=n*u,s=n*l,i=o*u,r=o*l;t[0]=a*u,t[4]=-a*l,t[8]=h,t[1]=s+i*h,t[5]=e-r*h,t[9]=-o*a,t[2]=r-e*h,t[6]=i+s*h,t[10]=n*a}else if("YXZ"===e.order){const e=a*u,s=a*l,i=h*u,r=h*l;t[0]=e+r*o,t[4]=i*o-s,t[8]=n*h,t[1]=n*l,t[5]=n*u,t[9]=-o,t[2]=s*o-i,t[6]=r+e*o,t[10]=n*a}else if("ZXY"===e.order){const e=a*u,s=a*l,i=h*u,r=h*l;t[0]=e-r*o,t[4]=-n*l,t[8]=i+s*o,t[1]=s+i*o,t[5]=n*u,t[9]=r-e*o,t[2]=-n*h,t[6]=o,t[10]=n*a}else if("ZYX"===e.order){const e=n*u,s=n*l,i=o*u,r=o*l;t[0]=a*u,t[4]=i*h-s,t[8]=e*h+r,t[1]=a*l,t[5]=r*h+e,t[9]=s*h-i,t[2]=-h,t[6]=o*a,t[10]=n*a}else if("YZX"===e.order){const e=n*a,s=n*h,i=o*a,r=o*h;t[0]=a*u,t[4]=r-e*l,t[8]=i*l+s,t[1]=l,t[5]=n*u,t[9]=-o*u,t[2]=-h*u,t[6]=s*l+i,t[10]=e-r*l}else if("XZY"===e.order){const e=n*a,s=n*h,i=o*a,r=o*h;t[0]=a*u,t[4]=-l,t[8]=h*u,t[1]=e*l+r,t[5]=n*u,t[9]=s*l-i,t[2]=i*l-s,t[6]=o*u,t[10]=r*l+e}return t[3]=0,t[7]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromQuaternion(e){return this.compose(hr,e,ur)}lookAt(e,t,s){const i=this.elements;return dr.subVectors(e,t),0===dr.lengthSq()&&(dr.z=1),dr.normalize(),lr.crossVectors(s,dr),0===lr.lengthSq()&&(1===Math.abs(s.z)?dr.x+=1e-4:dr.z+=1e-4,dr.normalize(),lr.crossVectors(s,dr)),lr.normalize(),cr.crossVectors(dr,lr),i[0]=lr.x,i[4]=cr.x,i[8]=dr.x,i[1]=lr.y,i[5]=cr.y,i[9]=dr.y,i[2]=lr.z,i[6]=cr.z,i[10]=dr.z,this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const s=e.elements,i=t.elements,r=this.elements,n=s[0],o=s[4],a=s[8],h=s[12],u=s[1],l=s[5],c=s[9],d=s[13],p=s[2],m=s[6],g=s[10],f=s[14],y=s[3],x=s[7],b=s[11],v=s[15],T=i[0],_=i[4],w=i[8],S=i[12],M=i[1],N=i[5],A=i[9],C=i[13],R=i[2],E=i[6],B=i[10],I=i[14],P=i[3],F=i[7],z=i[11],U=i[15];return r[0]=n*T+o*M+a*R+h*P,r[4]=n*_+o*N+a*E+h*F,r[8]=n*w+o*A+a*B+h*z,r[12]=n*S+o*C+a*I+h*U,r[1]=u*T+l*M+c*R+d*P,r[5]=u*_+l*N+c*E+d*F,r[9]=u*w+l*A+c*B+d*z,r[13]=u*S+l*C+c*I+d*U,r[2]=p*T+m*M+g*R+f*P,r[6]=p*_+m*N+g*E+f*F,r[10]=p*w+m*A+g*B+f*z,r[14]=p*S+m*C+g*I+f*U,r[3]=y*T+x*M+b*R+v*P,r[7]=y*_+x*N+b*E+v*F,r[11]=y*w+x*A+b*B+v*z,r[15]=y*S+x*C+b*I+v*U,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[4]*=e,t[8]*=e,t[12]*=e,t[1]*=e,t[5]*=e,t[9]*=e,t[13]*=e,t[2]*=e,t[6]*=e,t[10]*=e,t[14]*=e,t[3]*=e,t[7]*=e,t[11]*=e,t[15]*=e,this}determinant(){const e=this.elements,t=e[0],s=e[4],i=e[8],r=e[12],n=e[1],o=e[5],a=e[9],h=e[13],u=e[2],l=e[6],c=e[10],d=e[14];return e[3]*(+r*a*l-i*h*l-r*o*c+s*h*c+i*o*d-s*a*d)+e[7]*(+t*a*d-t*h*c+r*n*c-i*n*d+i*h*u-r*a*u)+e[11]*(+t*h*l-t*o*d-r*n*l+s*n*d+r*o*u-s*h*u)+e[15]*(-i*o*u-t*a*l+t*o*c+i*n*l-s*n*c+s*a*u)}transpose(){const e=this.elements;let t;return t=e[1],e[1]=e[4],e[4]=t,t=e[2],e[2]=e[8],e[8]=t,t=e[6],e[6]=e[9],e[9]=t,t=e[3],e[3]=e[12],e[12]=t,t=e[7],e[7]=e[13],e[13]=t,t=e[11],e[11]=e[14],e[14]=t,this}setPosition(e,t,s){const i=this.elements;return e.isVector3?(i[12]=e.x,i[13]=e.y,i[14]=e.z):(i[12]=e,i[13]=t,i[14]=s),this}invert(){const e=this.elements,t=e[0],s=e[1],i=e[2],r=e[3],n=e[4],o=e[5],a=e[6],h=e[7],u=e[8],l=e[9],c=e[10],d=e[11],p=e[12],m=e[13],g=e[14],f=e[15],y=l*g*h-m*c*h+m*a*d-o*g*d-l*a*f+o*c*f,x=p*c*h-u*g*h-p*a*d+n*g*d+u*a*f-n*c*f,b=u*m*h-p*l*h+p*o*d-n*m*d-u*o*f+n*l*f,v=p*l*a-u*m*a-p*o*c+n*m*c+u*o*g-n*l*g,T=t*y+s*x+i*b+r*v;if(0===T)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const _=1/T;return e[0]=y*_,e[1]=(m*c*r-l*g*r-m*i*d+s*g*d+l*i*f-s*c*f)*_,e[2]=(o*g*r-m*a*r+m*i*h-s*g*h-o*i*f+s*a*f)*_,e[3]=(l*a*r-o*c*r-l*i*h+s*c*h+o*i*d-s*a*d)*_,e[4]=x*_,e[5]=(u*g*r-p*c*r+p*i*d-t*g*d-u*i*f+t*c*f)*_,e[6]=(p*a*r-n*g*r-p*i*h+t*g*h+n*i*f-t*a*f)*_,e[7]=(n*c*r-u*a*r+u*i*h-t*c*h-n*i*d+t*a*d)*_,e[8]=b*_,e[9]=(p*l*r-u*m*r-p*s*d+t*m*d+u*s*f-t*l*f)*_,e[10]=(n*m*r-p*o*r+p*s*h-t*m*h-n*s*f+t*o*f)*_,e[11]=(u*o*r-n*l*r-u*s*h+t*l*h+n*s*d-t*o*d)*_,e[12]=v*_,e[13]=(u*m*i-p*l*i+p*s*c-t*m*c-u*s*g+t*l*g)*_,e[14]=(p*o*i-n*m*i-p*s*a+t*m*a+n*s*g-t*o*g)*_,e[15]=(n*l*i-u*o*i+u*s*a-t*l*a-n*s*c+t*o*c)*_,this}scale(e){const t=this.elements,s=e.x,i=e.y,r=e.z;return t[0]*=s,t[4]*=i,t[8]*=r,t[1]*=s,t[5]*=i,t[9]*=r,t[2]*=s,t[6]*=i,t[10]*=r,t[3]*=s,t[7]*=i,t[11]*=r,this}getMaxScaleOnAxis(){const e=this.elements,t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2],s=e[4]*e[4]+e[5]*e[5]+e[6]*e[6],i=e[8]*e[8]+e[9]*e[9]+e[10]*e[10];return Math.sqrt(Math.max(t,s,i))}makeTranslation(e,t,s){return e.isVector3?this.set(1,0,0,e.x,0,1,0,e.y,0,0,1,e.z,0,0,0,1):this.set(1,0,0,e,0,1,0,t,0,0,1,s,0,0,0,1),this}makeRotationX(e){const t=Math.cos(e),s=Math.sin(e);return this.set(1,0,0,0,0,t,-s,0,0,s,t,0,0,0,0,1),this}makeRotationY(e){const t=Math.cos(e),s=Math.sin(e);return this.set(t,0,s,0,0,1,0,0,-s,0,t,0,0,0,0,1),this}makeRotationZ(e){const t=Math.cos(e),s=Math.sin(e);return this.set(t,-s,0,0,s,t,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(e,t){const s=Math.cos(t),i=Math.sin(t),r=1-s,n=e.x,o=e.y,a=e.z,h=r*n,u=r*o;return this.set(h*n+s,h*o-i*a,h*a+i*o,0,h*o+i*a,u*o+s,u*a-i*n,0,h*a-i*o,u*a+i*n,r*a*a+s,0,0,0,0,1),this}makeScale(e,t,s){return this.set(e,0,0,0,0,t,0,0,0,0,s,0,0,0,0,1),this}makeShear(e,t,s,i,r,n){return this.set(1,s,r,0,e,1,n,0,t,i,1,0,0,0,0,1),this}compose(e,t,s){const i=this.elements,r=t._x,n=t._y,o=t._z,a=t._w,h=r+r,u=n+n,l=o+o,c=r*h,d=r*u,p=r*l,m=n*u,g=n*l,f=o*l,y=a*h,x=a*u,b=a*l,v=s.x,T=s.y,_=s.z;return i[0]=(1-(m+f))*v,i[1]=(d+b)*v,i[2]=(p-x)*v,i[3]=0,i[4]=(d-b)*T,i[5]=(1-(c+f))*T,i[6]=(g+y)*T,i[7]=0,i[8]=(p+x)*_,i[9]=(g-y)*_,i[10]=(1-(c+m))*_,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,this}decompose(e,t,s){const i=this.elements;let r=or.set(i[0],i[1],i[2]).length();const n=or.set(i[4],i[5],i[6]).length(),o=or.set(i[8],i[9],i[10]).length();this.determinant()<0&&(r=-r),e.x=i[12],e.y=i[13],e.z=i[14],ar.copy(this);const a=1/r,h=1/n,u=1/o;return ar.elements[0]*=a,ar.elements[1]*=a,ar.elements[2]*=a,ar.elements[4]*=h,ar.elements[5]*=h,ar.elements[6]*=h,ar.elements[8]*=u,ar.elements[9]*=u,ar.elements[10]*=u,t.setFromRotationMatrix(ar),s.x=r,s.y=n,s.z=o,this}makePerspective(e,t,s,i,r,n,o=2e3){const a=this.elements,h=2*r/(t-e),u=2*r/(s-i),l=(t+e)/(t-e),c=(s+i)/(s-i);let d,p;if(o===Vs)d=-(n+r)/(n-r),p=-2*n*r/(n-r);else{if(o!==Ds)throw new Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: "+o);d=-n/(n-r),p=-n*r/(n-r)}return a[0]=h,a[4]=0,a[8]=l,a[12]=0,a[1]=0,a[5]=u,a[9]=c,a[13]=0,a[2]=0,a[6]=0,a[10]=d,a[14]=p,a[3]=0,a[7]=0,a[11]=-1,a[15]=0,this}makeOrthographic(e,t,s,i,r,n,o=2e3){const a=this.elements,h=1/(t-e),u=1/(s-i),l=1/(n-r),c=(t+e)*h,d=(s+i)*u;let p,m;if(o===Vs)p=(n+r)*l,m=-2*l;else{if(o!==Ds)throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+o);p=r*l,m=-1*l}return a[0]=2*h,a[4]=0,a[8]=0,a[12]=-c,a[1]=0,a[5]=2*u,a[9]=0,a[13]=-d,a[2]=0,a[6]=0,a[10]=m,a[14]=-p,a[3]=0,a[7]=0,a[11]=0,a[15]=1,this}equals(e){const t=this.elements,s=e.elements;for(let e=0;e<16;e++)if(t[e]!==s[e])return!1;return!0}fromArray(e,t=0){for(let s=0;s<16;s++)this.elements[s]=e[s+t];return this}toArray(e=[],t=0){const s=this.elements;return e[t]=s[0],e[t+1]=s[1],e[t+2]=s[2],e[t+3]=s[3],e[t+4]=s[4],e[t+5]=s[5],e[t+6]=s[6],e[t+7]=s[7],e[t+8]=s[8],e[t+9]=s[9],e[t+10]=s[10],e[t+11]=s[11],e[t+12]=s[12],e[t+13]=s[13],e[t+14]=s[14],e[t+15]=s[15],e}}const or=new Ri,ar=new nr,hr=new Ri(0,0,0),ur=new Ri(1,1,1),lr=new Ri,cr=new Ri,dr=new Ri,pr=new nr,mr=new Ci;class gr{constructor(e=0,t=0,s=0,i=gr.DEFAULT_ORDER){this.isEuler=!0,this._x=e,this._y=t,this._z=s,this._order=i}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get order(){return this._order}set order(e){this._order=e,this._onChangeCallback()}set(e,t,s,i=this._order){return this._x=e,this._y=t,this._z=s,this._order=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(e){return this._x=e._x,this._y=e._y,this._z=e._z,this._order=e._order,this._onChangeCallback(),this}setFromRotationMatrix(e,t=this._order,s=!0){const i=e.elements,r=i[0],n=i[4],o=i[8],a=i[1],h=i[5],u=i[9],l=i[2],c=i[6],d=i[10];switch(t){case"XYZ":this._y=Math.asin($s(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-u,d),this._z=Math.atan2(-n,r)):(this._x=Math.atan2(c,h),this._z=0);break;case"YXZ":this._x=Math.asin(-$s(u,-1,1)),Math.abs(u)<.9999999?(this._y=Math.atan2(o,d),this._z=Math.atan2(a,h)):(this._y=Math.atan2(-l,r),this._z=0);break;case"ZXY":this._x=Math.asin($s(c,-1,1)),Math.abs(c)<.9999999?(this._y=Math.atan2(-l,d),this._z=Math.atan2(-n,h)):(this._y=0,this._z=Math.atan2(a,r));break;case"ZYX":this._y=Math.asin(-$s(l,-1,1)),Math.abs(l)<.9999999?(this._x=Math.atan2(c,d),this._z=Math.atan2(a,r)):(this._x=0,this._z=Math.atan2(-n,h));break;case"YZX":this._z=Math.asin($s(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(-u,h),this._y=Math.atan2(-l,r)):(this._x=0,this._y=Math.atan2(o,d));break;case"XZY":this._z=Math.asin(-$s(n,-1,1)),Math.abs(n)<.9999999?(this._x=Math.atan2(c,h),this._y=Math.atan2(o,r)):(this._x=Math.atan2(-u,d),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+t)}return this._order=t,!0===s&&this._onChangeCallback(),this}setFromQuaternion(e,t,s){return pr.makeRotationFromQuaternion(e),this.setFromRotationMatrix(pr,t,s)}setFromVector3(e,t=this._order){return this.set(e.x,e.y,e.z,t)}reorder(e){return mr.setFromEuler(this),this.setFromQuaternion(mr,e)}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._order===this._order}fromArray(e){return this._x=e[0],this._y=e[1],this._z=e[2],void 0!==e[3]&&(this._order=e[3]),this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._order,e}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._order}}gr.DEFAULT_ORDER="XYZ";class fr{constructor(){this.mask=1}set(e){this.mask=(1<>>0}enable(e){this.mask|=1<1){for(let e=0;e1){for(let e=0;e0&&(i.userData=this.userData),i.layers=this.layers.mask,i.matrix=this.matrix.toArray(),i.up=this.up.toArray(),!1===this.matrixAutoUpdate&&(i.matrixAutoUpdate=!1),this.isInstancedMesh&&(i.type="InstancedMesh",i.count=this.count,i.instanceMatrix=this.instanceMatrix.toJSON(),null!==this.instanceColor&&(i.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(i.type="BatchedMesh",i.perObjectFrustumCulled=this.perObjectFrustumCulled,i.sortObjects=this.sortObjects,i.drawRanges=this._drawRanges,i.reservedRanges=this._reservedRanges,i.visibility=this._visibility,i.active=this._active,i.bounds=this._bounds.map((e=>({boxInitialized:e.boxInitialized,boxMin:e.box.min.toArray(),boxMax:e.box.max.toArray(),sphereInitialized:e.sphereInitialized,sphereRadius:e.sphere.radius,sphereCenter:e.sphere.center.toArray()}))),i.maxInstanceCount=this._maxInstanceCount,i.maxVertexCount=this._maxVertexCount,i.maxIndexCount=this._maxIndexCount,i.geometryInitialized=this._geometryInitialized,i.geometryCount=this._geometryCount,i.matricesTexture=this._matricesTexture.toJSON(e),null!==this._colorsTexture&&(i.colorsTexture=this._colorsTexture.toJSON(e)),null!==this.boundingSphere&&(i.boundingSphere={center:i.boundingSphere.center.toArray(),radius:i.boundingSphere.radius}),null!==this.boundingBox&&(i.boundingBox={min:i.boundingBox.min.toArray(),max:i.boundingBox.max.toArray()})),this.isScene)this.background&&(this.background.isColor?i.background=this.background.toJSON():this.background.isTexture&&(i.background=this.background.toJSON(e).uuid)),this.environment&&this.environment.isTexture&&!0!==this.environment.isRenderTargetTexture&&(i.environment=this.environment.toJSON(e).uuid);else if(this.isMesh||this.isLine||this.isPoints){i.geometry=r(e.geometries,this.geometry);const t=this.geometry.parameters;if(void 0!==t&&void 0!==t.shapes){const s=t.shapes;if(Array.isArray(s))for(let t=0,i=s.length;t0){i.children=[];for(let t=0;t0){i.animations=[];for(let t=0;t0&&(s.geometries=t),i.length>0&&(s.materials=i),r.length>0&&(s.textures=r),o.length>0&&(s.images=o),a.length>0&&(s.shapes=a),h.length>0&&(s.skeletons=h),u.length>0&&(s.animations=u),l.length>0&&(s.nodes=l)}return s.object=i,s;function n(e){const t=[];for(const s in e){const i=e[s];delete i.metadata,t.push(i)}return t}}clone(e){return(new this.constructor).copy(this,e)}copy(e,t=!0){if(this.name=e.name,this.up.copy(e.up),this.position.copy(e.position),this.rotation.order=e.rotation.order,this.quaternion.copy(e.quaternion),this.scale.copy(e.scale),this.matrix.copy(e.matrix),this.matrixWorld.copy(e.matrixWorld),this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrixWorldAutoUpdate=e.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=e.matrixWorldNeedsUpdate,this.layers.mask=e.layers.mask,this.visible=e.visible,this.castShadow=e.castShadow,this.receiveShadow=e.receiveShadow,this.frustumCulled=e.frustumCulled,this.renderOrder=e.renderOrder,this.animations=e.animations.slice(),this.userData=JSON.parse(JSON.stringify(e.userData)),!0===t)for(let t=0;t0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(e,t,s,i,r){Pr.subVectors(i,t),Fr.subVectors(s,t),zr.subVectors(e,t);const n=Pr.dot(Pr),o=Pr.dot(Fr),a=Pr.dot(zr),h=Fr.dot(Fr),u=Fr.dot(zr),l=n*h-o*o;if(0===l)return r.set(0,0,0),null;const c=1/l,d=(h*a-o*u)*c,p=(n*u-o*a)*c;return r.set(1-d-p,p,d)}static containsPoint(e,t,s,i){return null!==this.getBarycoord(e,t,s,i,Ur)&&(Ur.x>=0&&Ur.y>=0&&Ur.x+Ur.y<=1)}static getInterpolation(e,t,s,i,r,n,o,a){return null===this.getBarycoord(e,t,s,i,Ur)?(a.x=0,a.y=0,"z"in a&&(a.z=0),"w"in a&&(a.w=0),null):(a.setScalar(0),a.addScaledVector(r,Ur.x),a.addScaledVector(n,Ur.y),a.addScaledVector(o,Ur.z),a)}static getInterpolatedAttribute(e,t,s,i,r,n){return Wr.setScalar(0),jr.setScalar(0),Hr.setScalar(0),Wr.fromBufferAttribute(e,t),jr.fromBufferAttribute(e,s),Hr.fromBufferAttribute(e,i),n.setScalar(0),n.addScaledVector(Wr,r.x),n.addScaledVector(jr,r.y),n.addScaledVector(Hr,r.z),n}static isFrontFacing(e,t,s,i){return Pr.subVectors(s,t),Fr.subVectors(e,t),Pr.cross(Fr).dot(i)<0}set(e,t,s){return this.a.copy(e),this.b.copy(t),this.c.copy(s),this}setFromPointsAndIndices(e,t,s,i){return this.a.copy(e[t]),this.b.copy(e[s]),this.c.copy(e[i]),this}setFromAttributeAndIndices(e,t,s,i){return this.a.fromBufferAttribute(e,t),this.b.fromBufferAttribute(e,s),this.c.fromBufferAttribute(e,i),this}clone(){return(new this.constructor).copy(this)}copy(e){return this.a.copy(e.a),this.b.copy(e.b),this.c.copy(e.c),this}getArea(){return Pr.subVectors(this.c,this.b),Fr.subVectors(this.a,this.b),.5*Pr.cross(Fr).length()}getMidpoint(e){return e.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(e){return qr.getNormal(this.a,this.b,this.c,e)}getPlane(e){return e.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(e,t){return qr.getBarycoord(e,this.a,this.b,this.c,t)}getInterpolation(e,t,s,i,r){return qr.getInterpolation(e,this.a,this.b,this.c,t,s,i,r)}containsPoint(e){return qr.containsPoint(e,this.a,this.b,this.c)}isFrontFacing(e){return qr.isFrontFacing(this.a,this.b,this.c,e)}intersectsBox(e){return e.intersectsTriangle(this)}closestPointToPoint(e,t){const s=this.a,i=this.b,r=this.c;let n,o;Or.subVectors(i,s),Lr.subVectors(r,s),Dr.subVectors(e,s);const a=Or.dot(Dr),h=Lr.dot(Dr);if(a<=0&&h<=0)return t.copy(s);kr.subVectors(e,i);const u=Or.dot(kr),l=Lr.dot(kr);if(u>=0&&l<=u)return t.copy(i);const c=a*l-u*h;if(c<=0&&a>=0&&u<=0)return n=a/(a-u),t.copy(s).addScaledVector(Or,n);Gr.subVectors(e,r);const d=Or.dot(Gr),p=Lr.dot(Gr);if(p>=0&&d<=p)return t.copy(r);const m=d*h-a*p;if(m<=0&&h>=0&&p<=0)return o=h/(h-p),t.copy(s).addScaledVector(Lr,o);const g=u*p-d*l;if(g<=0&&l-u>=0&&d-p>=0)return Vr.subVectors(r,i),o=(l-u)/(l-u+(d-p)),t.copy(i).addScaledVector(Vr,o);const f=1/(g+m+c);return n=m*f,o=c*f,t.copy(s).addScaledVector(Or,n).addScaledVector(Lr,o)}equals(e){return e.a.equals(this.a)&&e.b.equals(this.b)&&e.c.equals(this.c)}}const $r={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},Xr={h:0,s:0,l:0},Yr={h:0,s:0,l:0};function Zr(e,t,s){return s<0&&(s+=1),s>1&&(s-=1),s<1/6?e+6*(t-e)*s:s<.5?t:s<2/3?e+6*(t-e)*(2/3-s):e}class Jr{constructor(e,t,s){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(e,t,s)}set(e,t,s){if(void 0===t&&void 0===s){const t=e;t&&t.isColor?this.copy(t):"number"==typeof t?this.setHex(t):"string"==typeof t&&this.setStyle(t)}else this.setRGB(e,t,s);return this}setScalar(e){return this.r=e,this.g=e,this.b=e,this}setHex(e,t=Zt){return e=Math.floor(e),this.r=(e>>16&255)/255,this.g=(e>>8&255)/255,this.b=(255&e)/255,ci.toWorkingColorSpace(this,t),this}setRGB(e,t,s,i=ci.workingColorSpace){return this.r=e,this.g=t,this.b=s,ci.toWorkingColorSpace(this,i),this}setHSL(e,t,s,i=ci.workingColorSpace){if(e=Xs(e,1),t=$s(t,0,1),s=$s(s,0,1),0===t)this.r=this.g=this.b=s;else{const i=s<=.5?s*(1+t):s+t-s*t,r=2*s-i;this.r=Zr(r,i,e+1/3),this.g=Zr(r,i,e),this.b=Zr(r,i,e-1/3)}return ci.toWorkingColorSpace(this,i),this}setStyle(e,t=Zt){function s(t){void 0!==t&&parseFloat(t)<1&&console.warn("THREE.Color: Alpha component of "+e+" will be ignored.")}let i;if(i=/^(\w+)\(([^\)]*)\)/.exec(e)){let r;const n=i[1],o=i[2];switch(n){case"rgb":case"rgba":if(r=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return s(r[4]),this.setRGB(Math.min(255,parseInt(r[1],10))/255,Math.min(255,parseInt(r[2],10))/255,Math.min(255,parseInt(r[3],10))/255,t);if(r=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return s(r[4]),this.setRGB(Math.min(100,parseInt(r[1],10))/100,Math.min(100,parseInt(r[2],10))/100,Math.min(100,parseInt(r[3],10))/100,t);break;case"hsl":case"hsla":if(r=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return s(r[4]),this.setHSL(parseFloat(r[1])/360,parseFloat(r[2])/100,parseFloat(r[3])/100,t);break;default:console.warn("THREE.Color: Unknown color model "+e)}}else if(i=/^\#([A-Fa-f\d]+)$/.exec(e)){const s=i[1],r=s.length;if(3===r)return this.setRGB(parseInt(s.charAt(0),16)/15,parseInt(s.charAt(1),16)/15,parseInt(s.charAt(2),16)/15,t);if(6===r)return this.setHex(parseInt(s,16),t);console.warn("THREE.Color: Invalid hex color "+e)}else if(e&&e.length>0)return this.setColorName(e,t);return this}setColorName(e,t=Zt){const s=$r[e.toLowerCase()];return void 0!==s?this.setHex(s,t):console.warn("THREE.Color: Unknown color "+e),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(e){return this.r=e.r,this.g=e.g,this.b=e.b,this}copySRGBToLinear(e){return this.r=di(e.r),this.g=di(e.g),this.b=di(e.b),this}copyLinearToSRGB(e){return this.r=pi(e.r),this.g=pi(e.g),this.b=pi(e.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(e=Zt){return ci.fromWorkingColorSpace(Kr.copy(this),e),65536*Math.round($s(255*Kr.r,0,255))+256*Math.round($s(255*Kr.g,0,255))+Math.round($s(255*Kr.b,0,255))}getHexString(e=Zt){return("000000"+this.getHex(e).toString(16)).slice(-6)}getHSL(e,t=ci.workingColorSpace){ci.fromWorkingColorSpace(Kr.copy(this),t);const s=Kr.r,i=Kr.g,r=Kr.b,n=Math.max(s,i,r),o=Math.min(s,i,r);let a,h;const u=(o+n)/2;if(o===n)a=0,h=0;else{const e=n-o;switch(h=u<=.5?e/(n+o):e/(2-n-o),n){case s:a=(i-r)/e+(i0!=e>0&&this.version++,this._alphaTest=e}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(e){if(void 0!==e)for(const t in e){const s=e[t];if(void 0===s){console.warn(`THREE.Material: parameter '${t}' has value of undefined.`);continue}const i=this[t];void 0!==i?i&&i.isColor?i.set(s):i&&i.isVector3&&s&&s.isVector3?i.copy(s):this[t]=s:console.warn(`THREE.Material: '${t}' is not a property of THREE.${this.type}.`)}}toJSON(e){const t=void 0===e||"string"==typeof e;t&&(e={textures:{},images:{}});const s={metadata:{version:4.6,type:"Material",generator:"Material.toJSON"}};function i(e){const t=[];for(const s in e){const i=e[s];delete i.metadata,t.push(i)}return t}if(s.uuid=this.uuid,s.type=this.type,""!==this.name&&(s.name=this.name),this.color&&this.color.isColor&&(s.color=this.color.getHex()),void 0!==this.roughness&&(s.roughness=this.roughness),void 0!==this.metalness&&(s.metalness=this.metalness),void 0!==this.sheen&&(s.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(s.sheenColor=this.sheenColor.getHex()),void 0!==this.sheenRoughness&&(s.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(s.emissive=this.emissive.getHex()),void 0!==this.emissiveIntensity&&1!==this.emissiveIntensity&&(s.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(s.specular=this.specular.getHex()),void 0!==this.specularIntensity&&(s.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(s.specularColor=this.specularColor.getHex()),void 0!==this.shininess&&(s.shininess=this.shininess),void 0!==this.clearcoat&&(s.clearcoat=this.clearcoat),void 0!==this.clearcoatRoughness&&(s.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(s.clearcoatMap=this.clearcoatMap.toJSON(e).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(s.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(e).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(s.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(e).uuid,s.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),void 0!==this.dispersion&&(s.dispersion=this.dispersion),void 0!==this.iridescence&&(s.iridescence=this.iridescence),void 0!==this.iridescenceIOR&&(s.iridescenceIOR=this.iridescenceIOR),void 0!==this.iridescenceThicknessRange&&(s.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(s.iridescenceMap=this.iridescenceMap.toJSON(e).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(s.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(e).uuid),void 0!==this.anisotropy&&(s.anisotropy=this.anisotropy),void 0!==this.anisotropyRotation&&(s.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(s.anisotropyMap=this.anisotropyMap.toJSON(e).uuid),this.map&&this.map.isTexture&&(s.map=this.map.toJSON(e).uuid),this.matcap&&this.matcap.isTexture&&(s.matcap=this.matcap.toJSON(e).uuid),this.alphaMap&&this.alphaMap.isTexture&&(s.alphaMap=this.alphaMap.toJSON(e).uuid),this.lightMap&&this.lightMap.isTexture&&(s.lightMap=this.lightMap.toJSON(e).uuid,s.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(s.aoMap=this.aoMap.toJSON(e).uuid,s.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(s.bumpMap=this.bumpMap.toJSON(e).uuid,s.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(s.normalMap=this.normalMap.toJSON(e).uuid,s.normalMapType=this.normalMapType,s.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(s.displacementMap=this.displacementMap.toJSON(e).uuid,s.displacementScale=this.displacementScale,s.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(s.roughnessMap=this.roughnessMap.toJSON(e).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(s.metalnessMap=this.metalnessMap.toJSON(e).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(s.emissiveMap=this.emissiveMap.toJSON(e).uuid),this.specularMap&&this.specularMap.isTexture&&(s.specularMap=this.specularMap.toJSON(e).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(s.specularIntensityMap=this.specularIntensityMap.toJSON(e).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(s.specularColorMap=this.specularColorMap.toJSON(e).uuid),this.envMap&&this.envMap.isTexture&&(s.envMap=this.envMap.toJSON(e).uuid,void 0!==this.combine&&(s.combine=this.combine)),void 0!==this.envMapRotation&&(s.envMapRotation=this.envMapRotation.toArray()),void 0!==this.envMapIntensity&&(s.envMapIntensity=this.envMapIntensity),void 0!==this.reflectivity&&(s.reflectivity=this.reflectivity),void 0!==this.refractionRatio&&(s.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(s.gradientMap=this.gradientMap.toJSON(e).uuid),void 0!==this.transmission&&(s.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(s.transmissionMap=this.transmissionMap.toJSON(e).uuid),void 0!==this.thickness&&(s.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(s.thicknessMap=this.thicknessMap.toJSON(e).uuid),void 0!==this.attenuationDistance&&this.attenuationDistance!==1/0&&(s.attenuationDistance=this.attenuationDistance),void 0!==this.attenuationColor&&(s.attenuationColor=this.attenuationColor.getHex()),void 0!==this.size&&(s.size=this.size),null!==this.shadowSide&&(s.shadowSide=this.shadowSide),void 0!==this.sizeAttenuation&&(s.sizeAttenuation=this.sizeAttenuation),1!==this.blending&&(s.blending=this.blending),this.side!==c&&(s.side=this.side),!0===this.vertexColors&&(s.vertexColors=!0),this.opacity<1&&(s.opacity=this.opacity),!0===this.transparent&&(s.transparent=!0),this.blendSrc!==R&&(s.blendSrc=this.blendSrc),this.blendDst!==E&&(s.blendDst=this.blendDst),this.blendEquation!==v&&(s.blendEquation=this.blendEquation),null!==this.blendSrcAlpha&&(s.blendSrcAlpha=this.blendSrcAlpha),null!==this.blendDstAlpha&&(s.blendDstAlpha=this.blendDstAlpha),null!==this.blendEquationAlpha&&(s.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(s.blendColor=this.blendColor.getHex()),0!==this.blendAlpha&&(s.blendAlpha=this.blendAlpha),3!==this.depthFunc&&(s.depthFunc=this.depthFunc),!1===this.depthTest&&(s.depthTest=this.depthTest),!1===this.depthWrite&&(s.depthWrite=this.depthWrite),!1===this.colorWrite&&(s.colorWrite=this.colorWrite),255!==this.stencilWriteMask&&(s.stencilWriteMask=this.stencilWriteMask),this.stencilFunc!==bs&&(s.stencilFunc=this.stencilFunc),0!==this.stencilRef&&(s.stencilRef=this.stencilRef),255!==this.stencilFuncMask&&(s.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==ns&&(s.stencilFail=this.stencilFail),this.stencilZFail!==ns&&(s.stencilZFail=this.stencilZFail),this.stencilZPass!==ns&&(s.stencilZPass=this.stencilZPass),!0===this.stencilWrite&&(s.stencilWrite=this.stencilWrite),void 0!==this.rotation&&0!==this.rotation&&(s.rotation=this.rotation),!0===this.polygonOffset&&(s.polygonOffset=!0),0!==this.polygonOffsetFactor&&(s.polygonOffsetFactor=this.polygonOffsetFactor),0!==this.polygonOffsetUnits&&(s.polygonOffsetUnits=this.polygonOffsetUnits),void 0!==this.linewidth&&1!==this.linewidth&&(s.linewidth=this.linewidth),void 0!==this.dashSize&&(s.dashSize=this.dashSize),void 0!==this.gapSize&&(s.gapSize=this.gapSize),void 0!==this.scale&&(s.scale=this.scale),!0===this.dithering&&(s.dithering=!0),this.alphaTest>0&&(s.alphaTest=this.alphaTest),!0===this.alphaHash&&(s.alphaHash=!0),!0===this.alphaToCoverage&&(s.alphaToCoverage=!0),!0===this.premultipliedAlpha&&(s.premultipliedAlpha=!0),!0===this.forceSinglePass&&(s.forceSinglePass=!0),!0===this.wireframe&&(s.wireframe=!0),this.wireframeLinewidth>1&&(s.wireframeLinewidth=this.wireframeLinewidth),"round"!==this.wireframeLinecap&&(s.wireframeLinecap=this.wireframeLinecap),"round"!==this.wireframeLinejoin&&(s.wireframeLinejoin=this.wireframeLinejoin),!0===this.flatShading&&(s.flatShading=!0),!1===this.visible&&(s.visible=!1),!1===this.toneMapped&&(s.toneMapped=!1),!1===this.fog&&(s.fog=!1),Object.keys(this.userData).length>0&&(s.userData=this.userData),t){const t=i(e.textures),r=i(e.images);t.length>0&&(s.textures=t),r.length>0&&(s.images=r)}return s}clone(){return(new this.constructor).copy(this)}copy(e){this.name=e.name,this.blending=e.blending,this.side=e.side,this.vertexColors=e.vertexColors,this.opacity=e.opacity,this.transparent=e.transparent,this.blendSrc=e.blendSrc,this.blendDst=e.blendDst,this.blendEquation=e.blendEquation,this.blendSrcAlpha=e.blendSrcAlpha,this.blendDstAlpha=e.blendDstAlpha,this.blendEquationAlpha=e.blendEquationAlpha,this.blendColor.copy(e.blendColor),this.blendAlpha=e.blendAlpha,this.depthFunc=e.depthFunc,this.depthTest=e.depthTest,this.depthWrite=e.depthWrite,this.stencilWriteMask=e.stencilWriteMask,this.stencilFunc=e.stencilFunc,this.stencilRef=e.stencilRef,this.stencilFuncMask=e.stencilFuncMask,this.stencilFail=e.stencilFail,this.stencilZFail=e.stencilZFail,this.stencilZPass=e.stencilZPass,this.stencilWrite=e.stencilWrite;const t=e.clippingPlanes;let s=null;if(null!==t){const e=t.length;s=new Array(e);for(let i=0;i!==e;++i)s[i]=t[i].clone()}return this.clippingPlanes=s,this.clipIntersection=e.clipIntersection,this.clipShadows=e.clipShadows,this.shadowSide=e.shadowSide,this.colorWrite=e.colorWrite,this.precision=e.precision,this.polygonOffset=e.polygonOffset,this.polygonOffsetFactor=e.polygonOffsetFactor,this.polygonOffsetUnits=e.polygonOffsetUnits,this.dithering=e.dithering,this.alphaTest=e.alphaTest,this.alphaHash=e.alphaHash,this.alphaToCoverage=e.alphaToCoverage,this.premultipliedAlpha=e.premultipliedAlpha,this.forceSinglePass=e.forceSinglePass,this.visible=e.visible,this.toneMapped=e.toneMapped,this.userData=JSON.parse(JSON.stringify(e.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){!0===e&&this.version++}onBuild(){console.warn("Material: onBuild() has been removed.")}}class tn extends en{constructor(e){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new Jr(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new gr,this.combine=0,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}}const sn=rn();function rn(){const e=new ArrayBuffer(4),t=new Float32Array(e),s=new Uint32Array(e),i=new Uint32Array(512),r=new Uint32Array(512);for(let e=0;e<256;++e){const t=e-127;t<-27?(i[e]=0,i[256|e]=32768,r[e]=24,r[256|e]=24):t<-14?(i[e]=1024>>-t-14,i[256|e]=1024>>-t-14|32768,r[e]=-t-1,r[256|e]=-t-1):t<=15?(i[e]=t+15<<10,i[256|e]=t+15<<10|32768,r[e]=13,r[256|e]=13):t<128?(i[e]=31744,i[256|e]=64512,r[e]=24,r[256|e]=24):(i[e]=31744,i[256|e]=64512,r[e]=13,r[256|e]=13)}const n=new Uint32Array(2048),o=new Uint32Array(64),a=new Uint32Array(64);for(let e=1;e<1024;++e){let t=e<<13,s=0;for(;0==(8388608&t);)t<<=1,s-=8388608;t&=-8388609,s+=947912704,n[e]=t|s}for(let e=1024;e<2048;++e)n[e]=939524096+(e-1024<<13);for(let e=1;e<31;++e)o[e]=e<<23;o[31]=1199570944,o[32]=2147483648;for(let e=33;e<63;++e)o[e]=2147483648+(e-32<<23);o[63]=3347054592;for(let e=1;e<64;++e)32!==e&&(a[e]=1024);return{floatView:t,uint32View:s,baseTable:i,shiftTable:r,mantissaTable:n,exponentTable:o,offsetTable:a}}function nn(e){Math.abs(e)>65504&&console.warn("THREE.DataUtils.toHalfFloat(): Value out of range."),e=$s(e,-65504,65504),sn.floatView[0]=e;const t=sn.uint32View[0],s=t>>23&511;return sn.baseTable[s]+((8388607&t)>>sn.shiftTable[s])}function on(e){const t=e>>10;return sn.uint32View[0]=sn.mantissaTable[sn.offsetTable[t]+(1023&e)]+sn.exponentTable[t],sn.floatView[0]}const an={toHalfFloat:nn,fromHalfFloat:on},hn=new Ri,un=new Qs;class ln{constructor(e,t,s=!1){if(Array.isArray(e))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,this.name="",this.array=e,this.itemSize=t,this.count=void 0!==e?e.length/t:0,this.normalized=s,this.usage=Cs,this.updateRanges=[],this.gpuType=Ie,this.version=0}onUploadCallback(){}set needsUpdate(e){!0===e&&this.version++}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.name=e.name,this.array=new e.array.constructor(e.array),this.itemSize=e.itemSize,this.count=e.count,this.normalized=e.normalized,this.usage=e.usage,this.gpuType=e.gpuType,this}copyAt(e,t,s){e*=this.itemSize,s*=t.itemSize;for(let i=0,r=this.itemSize;i=0;--t)if(e[t]>=65535)return!0;return!1}(e)?yn:gn)(e,1):this.index=e,this}getAttribute(e){return this.attributes[e]}setAttribute(e,t){return this.attributes[e]=t,this}deleteAttribute(e){return delete this.attributes[e],this}hasAttribute(e){return void 0!==this.attributes[e]}addGroup(e,t,s=0){this.groups.push({start:e,count:t,materialIndex:s})}clearGroups(){this.groups=[]}setDrawRange(e,t){this.drawRange.start=e,this.drawRange.count=t}applyMatrix4(e){const t=this.attributes.position;void 0!==t&&(t.applyMatrix4(e),t.needsUpdate=!0);const s=this.attributes.normal;if(void 0!==s){const t=(new ei).getNormalMatrix(e);s.applyNormalMatrix(t),s.needsUpdate=!0}const i=this.attributes.tangent;return void 0!==i&&(i.transformDirection(e),i.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this}applyQuaternion(e){return Tn.makeRotationFromQuaternion(e),this.applyMatrix4(Tn),this}rotateX(e){return Tn.makeRotationX(e),this.applyMatrix4(Tn),this}rotateY(e){return Tn.makeRotationY(e),this.applyMatrix4(Tn),this}rotateZ(e){return Tn.makeRotationZ(e),this.applyMatrix4(Tn),this}translate(e,t,s){return Tn.makeTranslation(e,t,s),this.applyMatrix4(Tn),this}scale(e,t,s){return Tn.makeScale(e,t,s),this.applyMatrix4(Tn),this}lookAt(e){return _n.lookAt(e),_n.updateMatrix(),this.applyMatrix4(_n.matrix),this}center(){return this.computeBoundingBox(),this.boundingBox.getCenter(wn).negate(),this.translate(wn.x,wn.y,wn.z),this}setFromPoints(e){const t=[];for(let s=0,i=e.length;s0&&(e.userData=this.userData),void 0!==this.parameters){const t=this.parameters;for(const s in t)void 0!==t[s]&&(e[s]=t[s]);return e}e.data={attributes:{}};const t=this.index;null!==t&&(e.data.index={type:t.array.constructor.name,array:Array.prototype.slice.call(t.array)});const s=this.attributes;for(const t in s){const i=s[t];e.data.attributes[t]=i.toJSON(e.data)}const i={};let r=!1;for(const t in this.morphAttributes){const s=this.morphAttributes[t],n=[];for(let t=0,i=s.length;t0&&(i[t]=n,r=!0)}r&&(e.data.morphAttributes=i,e.data.morphTargetsRelative=this.morphTargetsRelative);const n=this.groups;n.length>0&&(e.data.groups=JSON.parse(JSON.stringify(n)));const o=this.boundingSphere;return null!==o&&(e.data.boundingSphere={center:o.center.toArray(),radius:o.radius}),e}clone(){return(new this.constructor).copy(this)}copy(e){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const t={};this.name=e.name;const s=e.index;null!==s&&this.setIndex(s.clone(t));const i=e.attributes;for(const e in i){const s=i[e];this.setAttribute(e,s.clone(t))}const r=e.morphAttributes;for(const e in r){const s=[],i=r[e];for(let e=0,r=i.length;e0){const s=e[t[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,t=s.length;e(e.far-e.near)**2)return}Cn.copy(r).invert(),Rn.copy(e.ray).applyMatrix4(Cn),null!==s.boundingBox&&!1===Rn.intersectsBox(s.boundingBox)||this._computeIntersections(e,t,Rn)}}_computeIntersections(e,t,s){let i;const r=this.geometry,n=this.material,o=r.index,a=r.attributes.position,h=r.attributes.uv,u=r.attributes.uv1,l=r.attributes.normal,c=r.groups,d=r.drawRange;if(null!==o)if(Array.isArray(n))for(let r=0,a=c.length;rs.far?null:{distance:u,point:Ln.clone(),object:e}}(e,t,s,i,In,Pn,Fn,On);if(l){const e=new Ri;qr.getBarycoord(On,In,Pn,Fn,e),r&&(l.uv=qr.getInterpolatedAttribute(r,a,h,u,e,new Qs)),n&&(l.uv1=qr.getInterpolatedAttribute(n,a,h,u,e,new Qs)),o&&(l.normal=qr.getInterpolatedAttribute(o,a,h,u,e,new Ri),l.normal.dot(i.direction)>0&&l.normal.multiplyScalar(-1));const t={a:a,b:h,c:u,normal:new Ri,materialIndex:0};qr.getNormal(In,Pn,Fn,t.normal),l.face=t,l.barycoord=e}return l}class kn extends An{constructor(e=1,t=1,s=1,i=1,r=1,n=1){super(),this.type="BoxGeometry",this.parameters={width:e,height:t,depth:s,widthSegments:i,heightSegments:r,depthSegments:n};const o=this;i=Math.floor(i),r=Math.floor(r),n=Math.floor(n);const a=[],h=[],u=[],l=[];let c=0,d=0;function p(e,t,s,i,r,n,p,m,g,f,y){const x=n/g,b=p/f,v=n/2,T=p/2,_=m/2,w=g+1,S=f+1;let M=0,N=0;const A=new Ri;for(let n=0;n0?1:-1,u.push(A.x,A.y,A.z),l.push(a/g),l.push(1-n/f),M+=1}}for(let e=0;e0&&(t.defines=this.defines),t.vertexShader=this.vertexShader,t.fragmentShader=this.fragmentShader,t.lights=this.lights,t.clipping=this.clipping;const s={};for(const e in this.extensions)!0===this.extensions[e]&&(s[e]=!0);return Object.keys(s).length>0&&(t.extensions=s),t}}class jn extends Ir{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new nr,this.projectionMatrix=new nr,this.projectionMatrixInverse=new nr,this.coordinateSystem=Vs}copy(e,t){return super.copy(e,t),this.matrixWorldInverse.copy(e.matrixWorldInverse),this.projectionMatrix.copy(e.projectionMatrix),this.projectionMatrixInverse.copy(e.projectionMatrixInverse),this.coordinateSystem=e.coordinateSystem,this}getWorldDirection(e){return super.getWorldDirection(e).negate()}updateMatrixWorld(e){super.updateMatrixWorld(e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(e,t){super.updateWorldMatrix(e,t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return(new this.constructor).copy(this)}}const Hn=new Ri,qn=new Qs,$n=new Qs;class Xn extends jn{constructor(e=50,t=1,s=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=e,this.zoom=1,this.near=s,this.far=i,this.focus=10,this.aspect=t,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(e,t){return super.copy(e,t),this.fov=e.fov,this.zoom=e.zoom,this.near=e.near,this.far=e.far,this.focus=e.focus,this.aspect=e.aspect,this.view=null===e.view?null:Object.assign({},e.view),this.filmGauge=e.filmGauge,this.filmOffset=e.filmOffset,this}setFocalLength(e){const t=.5*this.getFilmHeight()/e;this.fov=2*Hs*Math.atan(t),this.updateProjectionMatrix()}getFocalLength(){const e=Math.tan(.5*js*this.fov);return.5*this.getFilmHeight()/e}getEffectiveFOV(){return 2*Hs*Math.atan(Math.tan(.5*js*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(e,t,s){Hn.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),t.set(Hn.x,Hn.y).multiplyScalar(-e/Hn.z),Hn.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),s.set(Hn.x,Hn.y).multiplyScalar(-e/Hn.z)}getViewSize(e,t){return this.getViewBounds(e,qn,$n),t.subVectors($n,qn)}setViewOffset(e,t,s,i,r,n){this.aspect=e/t,null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=s,this.view.offsetY=i,this.view.width=r,this.view.height=n,this.updateProjectionMatrix()}clearViewOffset(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const e=this.near;let t=e*Math.tan(.5*js*this.fov)/this.zoom,s=2*t,i=this.aspect*s,r=-.5*i;const n=this.view;if(null!==this.view&&this.view.enabled){const e=n.fullWidth,o=n.fullHeight;r+=n.offsetX*i/e,t-=n.offsetY*s/o,i*=n.width/e,s*=n.height/o}const o=this.filmOffset;0!==o&&(r+=e*o/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,t,t-s,e,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(e){const t=super.toJSON(e);return t.object.fov=this.fov,t.object.zoom=this.zoom,t.object.near=this.near,t.object.far=this.far,t.object.focus=this.focus,t.object.aspect=this.aspect,null!==this.view&&(t.object.view=Object.assign({},this.view)),t.object.filmGauge=this.filmGauge,t.object.filmOffset=this.filmOffset,t}}const Yn=-90;class Zn extends Ir{constructor(e,t,s){super(),this.type="CubeCamera",this.renderTarget=s,this.coordinateSystem=null,this.activeMipmapLevel=0;const i=new Xn(Yn,1,e,t);i.layers=this.layers,this.add(i);const r=new Xn(Yn,1,e,t);r.layers=this.layers,this.add(r);const n=new Xn(Yn,1,e,t);n.layers=this.layers,this.add(n);const o=new Xn(Yn,1,e,t);o.layers=this.layers,this.add(o);const a=new Xn(Yn,1,e,t);a.layers=this.layers,this.add(a);const h=new Xn(Yn,1,e,t);h.layers=this.layers,this.add(h)}updateCoordinateSystem(){const e=this.coordinateSystem,t=this.children.concat(),[s,i,r,n,o,a]=t;for(const e of t)this.remove(e);if(e===Vs)s.up.set(0,1,0),s.lookAt(1,0,0),i.up.set(0,1,0),i.lookAt(-1,0,0),r.up.set(0,0,-1),r.lookAt(0,1,0),n.up.set(0,0,1),n.lookAt(0,-1,0),o.up.set(0,1,0),o.lookAt(0,0,1),a.up.set(0,1,0),a.lookAt(0,0,-1);else{if(e!==Ds)throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+e);s.up.set(0,-1,0),s.lookAt(-1,0,0),i.up.set(0,-1,0),i.lookAt(1,0,0),r.up.set(0,0,1),r.lookAt(0,1,0),n.up.set(0,0,-1),n.lookAt(0,-1,0),o.up.set(0,-1,0),o.lookAt(0,0,1),a.up.set(0,-1,0),a.lookAt(0,0,-1)}for(const e of t)this.add(e),e.updateMatrixWorld()}update(e,t){null===this.parent&&this.updateMatrixWorld();const{renderTarget:s,activeMipmapLevel:i}=this;this.coordinateSystem!==e.coordinateSystem&&(this.coordinateSystem=e.coordinateSystem,this.updateCoordinateSystem());const[r,n,o,a,h,u]=this.children,l=e.getRenderTarget(),c=e.getActiveCubeFace(),d=e.getActiveMipmapLevel(),p=e.xr.enabled;e.xr.enabled=!1;const m=s.texture.generateMipmaps;s.texture.generateMipmaps=!1,e.setRenderTarget(s,0,i),e.render(t,r),e.setRenderTarget(s,1,i),e.render(t,n),e.setRenderTarget(s,2,i),e.render(t,o),e.setRenderTarget(s,3,i),e.render(t,a),e.setRenderTarget(s,4,i),e.render(t,h),s.texture.generateMipmaps=m,e.setRenderTarget(s,5,i),e.render(t,u),e.setRenderTarget(l,c,d),e.xr.enabled=p,s.texture.needsPMREMUpdate=!0}}class Jn extends vi{constructor(e,t,s,i,r,n,o,a,h,u){super(e=void 0!==e?e:[],t=void 0!==t?t:he,s,i,r,n,o,a,h,u),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(e){this.image=e}}class Kn extends wi{constructor(e=1,t={}){super(e,e,t),this.isWebGLCubeRenderTarget=!0;const s={width:e,height:e,depth:1},i=[s,s,s,s,s,s];this.texture=new Jn(i,t.mapping,t.wrapS,t.wrapT,t.magFilter,t.minFilter,t.format,t.type,t.anisotropy,t.colorSpace),this.texture.isRenderTargetTexture=!0,this.texture.generateMipmaps=void 0!==t.generateMipmaps&&t.generateMipmaps,this.texture.minFilter=void 0!==t.minFilter?t.minFilter:Te}fromEquirectangularTexture(e,t){this.texture.type=t.type,this.texture.colorSpace=t.colorSpace,this.texture.generateMipmaps=t.generateMipmaps,this.texture.minFilter=t.minFilter,this.texture.magFilter=t.magFilter;const s={uniforms:{tEquirect:{value:null}},vertexShader:"\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\tvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\n\t\t\t\t\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvWorldDirection = transformDirection( position, modelMatrix );\n\n\t\t\t\t\t#include \n\t\t\t\t\t#include \n\n\t\t\t\t}\n\t\t\t",fragmentShader:"\n\n\t\t\t\tuniform sampler2D tEquirect;\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\t#include \n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvec3 direction = normalize( vWorldDirection );\n\n\t\t\t\t\tvec2 sampleUV = equirectUv( direction );\n\n\t\t\t\t\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\n\t\t\t\t}\n\t\t\t"},i=new kn(5,5,5),r=new Wn({name:"CubemapFromEquirect",uniforms:Gn(s.uniforms),vertexShader:s.vertexShader,fragmentShader:s.fragmentShader,side:d,blending:m});r.uniforms.tEquirect.value=t;const n=new Vn(i,r),o=t.minFilter;t.minFilter===Se&&(t.minFilter=Te);return new Zn(1,10,this).update(e,n),t.minFilter=o,n.geometry.dispose(),n.material.dispose(),this}clear(e,t,s,i){const r=e.getRenderTarget();for(let r=0;r<6;r++)e.setRenderTarget(this,r),e.clear(t,s,i);e.setRenderTarget(r)}}class Qn{constructor(e,t=25e-5){this.isFogExp2=!0,this.name="",this.color=new Jr(e),this.density=t}clone(){return new Qn(this.color,this.density)}toJSON(){return{type:"FogExp2",name:this.name,color:this.color.getHex(),density:this.density}}}class eo{constructor(e,t=1,s=1e3){this.isFog=!0,this.name="",this.color=new Jr(e),this.near=t,this.far=s}clone(){return new eo(this.color,this.near,this.far)}toJSON(){return{type:"Fog",name:this.name,color:this.color.getHex(),near:this.near,far:this.far}}}class to extends Ir{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.backgroundRotation=new gr,this.environmentIntensity=1,this.environmentRotation=new gr,this.overrideMaterial=null,"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(e,t){return super.copy(e,t),null!==e.background&&(this.background=e.background.clone()),null!==e.environment&&(this.environment=e.environment.clone()),null!==e.fog&&(this.fog=e.fog.clone()),this.backgroundBlurriness=e.backgroundBlurriness,this.backgroundIntensity=e.backgroundIntensity,this.backgroundRotation.copy(e.backgroundRotation),this.environmentIntensity=e.environmentIntensity,this.environmentRotation.copy(e.environmentRotation),null!==e.overrideMaterial&&(this.overrideMaterial=e.overrideMaterial.clone()),this.matrixAutoUpdate=e.matrixAutoUpdate,this}toJSON(e){const t=super.toJSON(e);return null!==this.fog&&(t.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(t.object.backgroundBlurriness=this.backgroundBlurriness),1!==this.backgroundIntensity&&(t.object.backgroundIntensity=this.backgroundIntensity),t.object.backgroundRotation=this.backgroundRotation.toArray(),1!==this.environmentIntensity&&(t.object.environmentIntensity=this.environmentIntensity),t.object.environmentRotation=this.environmentRotation.toArray(),t}}class so{constructor(e,t){this.isInterleavedBuffer=!0,this.array=e,this.stride=t,this.count=void 0!==e?e.length/t:0,this.usage=Cs,this.updateRanges=[],this.version=0,this.uuid=qs()}onUploadCallback(){}set needsUpdate(e){!0===e&&this.version++}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.array=new e.array.constructor(e.array),this.count=e.count,this.stride=e.stride,this.usage=e.usage,this}copyAt(e,t,s){e*=this.stride,s*=t.stride;for(let i=0,r=this.stride;ie.far||t.push({distance:a,point:ao.clone(),uv:qr.getInterpolation(ao,mo,go,fo,yo,xo,bo,new Qs),face:null,object:this})}copy(e,t){return super.copy(e,t),void 0!==e.center&&this.center.copy(e.center),this.material=e.material,this}}function To(e,t,s,i,r,n){lo.subVectors(e,s).addScalar(.5).multiply(i),void 0!==r?(co.x=n*lo.x-r*lo.y,co.y=r*lo.x+n*lo.y):co.copy(lo),e.copy(t),e.x+=co.x,e.y+=co.y,e.applyMatrix4(po)}const _o=new Ri,wo=new Ri;class So extends Ir{constructor(){super(),this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]},isLOD:{value:!0}}),this.autoUpdate=!0}copy(e){super.copy(e,!1);const t=e.levels;for(let e=0,s=t.length;e0){let s,i;for(s=1,i=t.length;s0){_o.setFromMatrixPosition(this.matrixWorld);const s=e.ray.origin.distanceTo(_o);this.getObjectForDistance(s).raycast(e,t)}}update(e){const t=this.levels;if(t.length>1){_o.setFromMatrixPosition(e.matrixWorld),wo.setFromMatrixPosition(this.matrixWorld);const s=_o.distanceTo(wo)/e.zoom;let i,r;for(t[0].object.visible=!0,i=1,r=t.length;i=e))break;t[i-1].object.visible=!1,t[i].object.visible=!0}for(this._currentLevel=i-1;i1?null:t.copy(e.start).addScaledVector(s,r)}intersectsLine(e){const t=this.distanceToPoint(e.start),s=this.distanceToPoint(e.end);return t<0&&s>0||s<0&&t>0}intersectsBox(e){return e.intersectsPlane(this)}intersectsSphere(e){return e.intersectsPlane(this)}coplanarPoint(e){return e.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(e,t){const s=t||Jo.getNormalMatrix(e),i=this.coplanarPoint(Yo).applyMatrix4(e),r=this.normal.applyMatrix3(s).normalize();return this.constant=-i.dot(r),this}translate(e){return this.constant-=e.dot(this.normal),this}equals(e){return e.normal.equals(this.normal)&&e.constant===this.constant}clone(){return(new this.constructor).copy(this)}}const Qo=new Zi,ea=new Ri;class ta{constructor(e=new Ko,t=new Ko,s=new Ko,i=new Ko,r=new Ko,n=new Ko){this.planes=[e,t,s,i,r,n]}set(e,t,s,i,r,n){const o=this.planes;return o[0].copy(e),o[1].copy(t),o[2].copy(s),o[3].copy(i),o[4].copy(r),o[5].copy(n),this}copy(e){const t=this.planes;for(let s=0;s<6;s++)t[s].copy(e.planes[s]);return this}setFromProjectionMatrix(e,t=2e3){const s=this.planes,i=e.elements,r=i[0],n=i[1],o=i[2],a=i[3],h=i[4],u=i[5],l=i[6],c=i[7],d=i[8],p=i[9],m=i[10],g=i[11],f=i[12],y=i[13],x=i[14],b=i[15];if(s[0].setComponents(a-r,c-h,g-d,b-f).normalize(),s[1].setComponents(a+r,c+h,g+d,b+f).normalize(),s[2].setComponents(a+n,c+u,g+p,b+y).normalize(),s[3].setComponents(a-n,c-u,g-p,b-y).normalize(),s[4].setComponents(a-o,c-l,g-m,b-x).normalize(),t===Vs)s[5].setComponents(a+o,c+l,g+m,b+x).normalize();else{if(t!==Ds)throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+t);s[5].setComponents(o,l,m,x).normalize()}return this}intersectsObject(e){if(void 0!==e.boundingSphere)null===e.boundingSphere&&e.computeBoundingSphere(),Qo.copy(e.boundingSphere).applyMatrix4(e.matrixWorld);else{const t=e.geometry;null===t.boundingSphere&&t.computeBoundingSphere(),Qo.copy(t.boundingSphere).applyMatrix4(e.matrixWorld)}return this.intersectsSphere(Qo)}intersectsSprite(e){return Qo.center.set(0,0,0),Qo.radius=.7071067811865476,Qo.applyMatrix4(e.matrixWorld),this.intersectsSphere(Qo)}intersectsSphere(e){const t=this.planes,s=e.center,i=-e.radius;for(let e=0;e<6;e++){if(t[e].distanceToPoint(s)0?e.max.x:e.min.x,ea.y=i.normal.y>0?e.max.y:e.min.y,ea.z=i.normal.z>0?e.max.z:e.min.z,i.distanceToPoint(ea)<0)return!1}return!0}containsPoint(e){const t=this.planes;for(let s=0;s<6;s++)if(t[s].distanceToPoint(e)<0)return!1;return!0}clone(){return(new this.constructor).copy(this)}}function sa(e,t){return e.z-t.z}function ia(e,t){return t.z-e.z}class ra{constructor(){this.index=0,this.pool=[],this.list=[]}push(e,t,s){const i=this.pool,r=this.list;this.index>=i.length&&i.push({start:-1,count:-1,z:-1,index:-1});const n=i[this.index];r.push(n),this.index++,n.start=e.start,n.count=e.count,n.z=t,n.index=s}reset(){this.list.length=0,this.index=0}}const na=new nr,oa=new nr,aa=new nr,ha=new Jr(1,1,1),ua=new nr,la=new ta,ca=new Ii,da=new Zi,pa=new Ri,ma=new Ri,ga=new Ri,fa=new ra,ya=new Vn,xa=[];function ba(e,t,s=0){const i=t.itemSize;if(e.isInterleavedBufferAttribute||e.array.constructor!==t.array.constructor){const r=e.count;for(let n=0;n65535?new Uint32Array(i):new Uint16Array(i);t.setIndex(new ln(e,1))}this._geometryInitialized=!0}}_validateGeometry(e){const t=this.geometry;if(Boolean(e.getIndex())!==Boolean(t.getIndex()))throw new Error('BatchedMesh: All geometries must consistently have "index".');for(const s in t.attributes){if(!e.hasAttribute(s))throw new Error(`BatchedMesh: Added geometry missing "${s}". All geometries must have consistent attributes.`);const i=e.getAttribute(s),r=t.getAttribute(s);if(i.itemSize!==r.itemSize||i.normalized!==r.normalized)throw new Error("BatchedMesh: All attributes must have a consistent itemSize and normalized value.")}}setCustomSort(e){return this.customSort=e,this}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new Ii);const e=this.boundingBox,t=this._drawInfo;e.makeEmpty();for(let s=0,i=t.length;s=this.maxInstanceCount&&0===this._availableInstanceIds.length)throw new Error("BatchedMesh: Maximum item count reached.");const t={visible:!0,active:!0,geometryIndex:e};let s=null;this._availableInstanceIds.length>0?(s=this._availableInstanceIds.pop(),this._drawInfo[s]=t):(s=this._drawInfo.length,this._drawInfo.push(t));const i=this._matricesTexture,r=i.image.data;aa.toArray(r,16*s),i.needsUpdate=!0;const n=this._colorsTexture;return n&&(ha.toArray(n.image.data,4*s),n.needsUpdate=!0),s}addGeometry(e,t=-1,s=-1){if(this._initializeGeometry(e),this._validateGeometry(e),this._drawInfo.length>=this._maxInstanceCount)throw new Error("BatchedMesh: Maximum item count reached.");const i={vertexStart:-1,vertexCount:-1,indexStart:-1,indexCount:-1};let r=null;const n=this._reservedRanges,o=this._drawRanges,a=this._bounds;0!==this._geometryCount&&(r=n[n.length-1]),i.vertexCount=-1===t?e.getAttribute("position").count:t,i.vertexStart=null===r?0:r.vertexStart+r.vertexCount;const h=e.getIndex(),u=null!==h;if(u&&(i.indexCount=-1===s?h.count:s,i.indexStart=null===r?0:r.indexStart+r.indexCount),-1!==i.indexStart&&i.indexStart+i.indexCount>this._maxIndexCount||i.vertexStart+i.vertexCount>this._maxVertexCount)throw new Error("BatchedMesh: Reserved space request exceeds the maximum buffer size.");const l=this._geometryCount;return this._geometryCount++,n.push(i),o.push({start:u?i.indexStart:i.vertexStart,count:-1}),a.push({boxInitialized:!1,box:new Ii,sphereInitialized:!1,sphere:new Zi}),this.setGeometryAt(l,e),l}setGeometryAt(e,t){if(e>=this._geometryCount)throw new Error("BatchedMesh: Maximum geometry count reached.");this._validateGeometry(t);const s=this.geometry,i=null!==s.getIndex(),r=s.getIndex(),n=t.getIndex(),o=this._reservedRanges[e];if(i&&n.count>o.indexCount||t.attributes.position.count>o.vertexCount)throw new Error("BatchedMesh: Reserved space not large enough for provided geometry.");const a=o.vertexStart,h=o.vertexCount;for(const e in s.attributes){const i=t.getAttribute(e),r=s.getAttribute(e);ba(i,r,a);const n=i.itemSize;for(let e=i.count,t=h;e=t.length||!1===t[e].active||(t[e].active=!1,this._availableInstanceIds.push(e),this._visibilityChanged=!0),this}getBoundingBoxAt(e,t){if(e>=this._geometryCount)return null;const s=this._bounds[e],i=s.box,r=this.geometry;if(!1===s.boxInitialized){i.makeEmpty();const t=r.index,n=r.attributes.position,o=this._drawRanges[e];for(let e=o.start,s=o.start+o.count;e=this._geometryCount)return null;const s=this._bounds[e],i=s.sphere,r=this.geometry;if(!1===s.sphereInitialized){i.makeEmpty(),this.getBoundingBoxAt(e,ca),ca.getCenter(i.center);const t=r.index,n=r.attributes.position,o=this._drawRanges[e];let a=0;for(let e=o.start,s=o.start+o.count;e=s.length||!1===s[e].active||(t.toArray(r,16*e),i.needsUpdate=!0),this}getMatrixAt(e,t){const s=this._drawInfo,i=this._matricesTexture.image.data;return e>=s.length||!1===s[e].active?null:t.fromArray(i,16*e)}setColorAt(e,t){null===this._colorsTexture&&this._initColorsTexture();const s=this._colorsTexture,i=this._colorsTexture.image.data,r=this._drawInfo;return e>=r.length||!1===r[e].active||(t.toArray(i,4*e),s.needsUpdate=!0),this}getColorAt(e,t){const s=this._colorsTexture.image.data,i=this._drawInfo;return e>=i.length||!1===i[e].active?null:t.fromArray(s,4*e)}setVisibleAt(e,t){const s=this._drawInfo;return e>=s.length||!1===s[e].active||s[e].visible===t||(s[e].visible=t,this._visibilityChanged=!0),this}getVisibleAt(e){const t=this._drawInfo;return!(e>=t.length||!1===t[e].active)&&t[e].visible}setGeometryIdAt(e,t){const s=this._drawInfo;return e>=s.length||!1===s[e].active||t<0||t>=this._geometryCount?null:(s[e].geometryIndex=t,this)}getGeometryIdAt(e){const t=this._drawInfo;return e>=t.length||!1===t[e].active?-1:t[e].geometryIndex}getGeometryRangeAt(e,t={}){if(e<0||e>=this._geometryCount)return null;const s=this._drawRanges[e];return t.start=s.start,t.count=s.count,t}raycast(e,t){const s=this._drawInfo,i=this._drawRanges,r=this.matrixWorld,n=this.geometry;ya.material=this.material,ya.geometry.index=n.index,ya.geometry.attributes=n.attributes,null===ya.geometry.boundingBox&&(ya.geometry.boundingBox=new Ii),null===ya.geometry.boundingSphere&&(ya.geometry.boundingSphere=new Zi);for(let n=0,o=s.length;n({...e}))),this._reservedRanges=e._reservedRanges.map((e=>({...e}))),this._drawInfo=e._drawInfo.map((e=>({...e}))),this._bounds=e._bounds.map((e=>({boxInitialized:e.boxInitialized,box:e.box.clone(),sphereInitialized:e.sphereInitialized,sphere:e.sphere.clone()}))),this._maxInstanceCount=e._maxInstanceCount,this._maxVertexCount=e._maxVertexCount,this._maxIndexCount=e._maxIndexCount,this._geometryInitialized=e._geometryInitialized,this._geometryCount=e._geometryCount,this._multiDrawCounts=e._multiDrawCounts.slice(),this._multiDrawStarts=e._multiDrawStarts.slice(),this._matricesTexture=e._matricesTexture.clone(),this._matricesTexture.image.data=this._matricesTexture.image.data.slice(),null!==this._colorsTexture&&(this._colorsTexture=e._colorsTexture.clone(),this._colorsTexture.image.data=this._colorsTexture.image.data.slice()),this}dispose(){return this.geometry.dispose(),this._matricesTexture.dispose(),this._matricesTexture=null,this._indirectTexture.dispose(),this._indirectTexture=null,null!==this._colorsTexture&&(this._colorsTexture.dispose(),this._colorsTexture=null),this}onBeforeRender(e,t,s,i,r){if(!this._visibilityChanged&&!this.perObjectFrustumCulled&&!this.sortObjects)return;const n=i.getIndex(),o=null===n?1:n.array.BYTES_PER_ELEMENT,a=this._drawInfo,h=this._multiDrawStarts,u=this._multiDrawCounts,l=this._drawRanges,c=this.perObjectFrustumCulled,d=this._indirectTexture,p=d.image.data;c&&(ua.multiplyMatrices(s.projectionMatrix,s.matrixWorldInverse).multiply(this.matrixWorld),la.setFromProjectionMatrix(ua,e.coordinateSystem));let m=0;if(this.sortObjects){oa.copy(this.matrixWorld).invert(),pa.setFromMatrixPosition(s.matrixWorld).applyMatrix4(oa),ma.set(0,0,-1).transformDirection(s.matrixWorld).transformDirection(oa);for(let e=0,t=a.length;e0){const s=e[t[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,t=s.length;ei)return;Aa.applyMatrix4(e.matrixWorld);const a=t.ray.origin.distanceTo(Aa);return at.far?void 0:{distance:a,point:Ca.clone().applyMatrix4(e.matrixWorld),index:r,face:null,faceIndex:null,barycoord:null,object:e}}const Ba=new Ri,Ia=new Ri;class Pa extends Ra{constructor(e,t){super(e,t),this.isLineSegments=!0,this.type="LineSegments"}computeLineDistances(){const e=this.geometry;if(null===e.index){const t=e.attributes.position,s=[];for(let e=0,i=t.count;e0){const s=e[t[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,t=s.length;er.far)return;n.push({distance:h,distanceToRay:Math.sqrt(a),point:s,index:t,face:null,faceIndex:null,barycoord:null,object:o})}}class Ga extends Ir{constructor(){super(),this.isGroup=!0,this.type="Group"}}class Wa extends vi{constructor(e,t,s,i,r,n,o,a,h){super(e,t,s,i,r,n,o,a,h),this.isVideoTexture=!0,this.minFilter=void 0!==n?n:Te,this.magFilter=void 0!==r?r:Te,this.generateMipmaps=!1;const u=this;"requestVideoFrameCallback"in e&&e.requestVideoFrameCallback((function t(){u.needsUpdate=!0,e.requestVideoFrameCallback(t)}))}clone(){return new this.constructor(this.image).copy(this)}update(){const e=this.image;!1==="requestVideoFrameCallback"in e&&e.readyState>=e.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}}class ja extends vi{constructor(e,t){super({width:e,height:t}),this.isFramebufferTexture=!0,this.magFilter=fe,this.minFilter=fe,this.generateMipmaps=!1,this.needsUpdate=!0}}class Ha extends vi{constructor(e,t,s,i,r,n,o,a,h,u,l,c){super(null,n,o,a,h,u,i,r,l,c),this.isCompressedTexture=!0,this.image={width:t,height:s},this.mipmaps=e,this.flipY=!1,this.generateMipmaps=!1}}class qa extends Ha{constructor(e,t,s,i,r,n){super(e,t,s,r,n),this.isCompressedArrayTexture=!0,this.image.depth=i,this.wrapR=me,this.layerUpdates=new Set}addLayerUpdate(e){this.layerUpdates.add(e)}clearLayerUpdates(){this.layerUpdates.clear()}}class $a extends Ha{constructor(e,t,s){super(void 0,e[0].width,e[0].height,t,s,he),this.isCompressedCubeTexture=!0,this.isCubeTexture=!0,this.image=e}}class Xa extends vi{constructor(e,t,s,i,r,n,o,a,h){super(e,t,s,i,r,n,o,a,h),this.isCanvasTexture=!0,this.needsUpdate=!0}}class Ya extends vi{constructor(e,t,s,i,r,n,o,a,h,u=1026){if(u!==We&&u!==je)throw new Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");void 0===s&&u===We&&(s=Be),void 0===s&&u===je&&(s=Ue),super(null,i,r,n,o,a,u,s,h),this.isDepthTexture=!0,this.image={width:e,height:t},this.magFilter=void 0!==o?o:fe,this.minFilter=void 0!==a?a:fe,this.flipY=!1,this.generateMipmaps=!1,this.compareFunction=null}copy(e){return super.copy(e),this.compareFunction=e.compareFunction,this}toJSON(e){const t=super.toJSON(e);return null!==this.compareFunction&&(t.compareFunction=this.compareFunction),t}}class Za{constructor(){this.type="Curve",this.arcLengthDivisions=200}getPoint(){return console.warn("THREE.Curve: .getPoint() not implemented."),null}getPointAt(e,t){const s=this.getUtoTmapping(e);return this.getPoint(s,t)}getPoints(e=5){const t=[];for(let s=0;s<=e;s++)t.push(this.getPoint(s/e));return t}getSpacedPoints(e=5){const t=[];for(let s=0;s<=e;s++)t.push(this.getPointAt(s/e));return t}getLength(){const e=this.getLengths();return e[e.length-1]}getLengths(e=this.arcLengthDivisions){if(this.cacheArcLengths&&this.cacheArcLengths.length===e+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;const t=[];let s,i=this.getPoint(0),r=0;t.push(0);for(let n=1;n<=e;n++)s=this.getPoint(n/e),r+=s.distanceTo(i),t.push(r),i=s;return this.cacheArcLengths=t,t}updateArcLengths(){this.needsUpdate=!0,this.getLengths()}getUtoTmapping(e,t){const s=this.getLengths();let i=0;const r=s.length;let n;n=t||e*s[r-1];let o,a=0,h=r-1;for(;a<=h;)if(i=Math.floor(a+(h-a)/2),o=s[i]-n,o<0)a=i+1;else{if(!(o>0)){h=i;break}h=i-1}if(i=h,s[i]===n)return i/(r-1);const u=s[i];return(i+(n-u)/(s[i+1]-u))/(r-1)}getTangent(e,t){const s=1e-4;let i=e-s,r=e+s;i<0&&(i=0),r>1&&(r=1);const n=this.getPoint(i),o=this.getPoint(r),a=t||(n.isVector2?new Qs:new Ri);return a.copy(o).sub(n).normalize(),a}getTangentAt(e,t){const s=this.getUtoTmapping(e);return this.getTangent(s,t)}computeFrenetFrames(e,t){const s=new Ri,i=[],r=[],n=[],o=new Ri,a=new nr;for(let t=0;t<=e;t++){const s=t/e;i[t]=this.getTangentAt(s,new Ri)}r[0]=new Ri,n[0]=new Ri;let h=Number.MAX_VALUE;const u=Math.abs(i[0].x),l=Math.abs(i[0].y),c=Math.abs(i[0].z);u<=h&&(h=u,s.set(1,0,0)),l<=h&&(h=l,s.set(0,1,0)),c<=h&&s.set(0,0,1),o.crossVectors(i[0],s).normalize(),r[0].crossVectors(i[0],o),n[0].crossVectors(i[0],r[0]);for(let t=1;t<=e;t++){if(r[t]=r[t-1].clone(),n[t]=n[t-1].clone(),o.crossVectors(i[t-1],i[t]),o.length()>Number.EPSILON){o.normalize();const e=Math.acos($s(i[t-1].dot(i[t]),-1,1));r[t].applyMatrix4(a.makeRotationAxis(o,e))}n[t].crossVectors(i[t],r[t])}if(!0===t){let t=Math.acos($s(r[0].dot(r[e]),-1,1));t/=e,i[0].dot(o.crossVectors(r[0],r[e]))>0&&(t=-t);for(let s=1;s<=e;s++)r[s].applyMatrix4(a.makeRotationAxis(i[s],t*s)),n[s].crossVectors(i[s],r[s])}return{tangents:i,normals:r,binormals:n}}clone(){return(new this.constructor).copy(this)}copy(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}toJSON(){const e={metadata:{version:4.6,type:"Curve",generator:"Curve.toJSON"}};return e.arcLengthDivisions=this.arcLengthDivisions,e.type=this.type,e}fromJSON(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}}class Ja extends Za{constructor(e=0,t=0,s=1,i=1,r=0,n=2*Math.PI,o=!1,a=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=e,this.aY=t,this.xRadius=s,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=n,this.aClockwise=o,this.aRotation=a}getPoint(e,t=new Qs){const s=t,i=2*Math.PI;let r=this.aEndAngle-this.aStartAngle;const n=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(h)/r)+1)*r:0===u&&h===r-1&&(h=r-2,u=1),this.closed||h>0?o=i[(h-1)%r]:(eh.subVectors(i[0],i[1]).add(i[0]),o=eh);const l=i[h%r],c=i[(h+1)%r];if(this.closed||h+2i.length-2?i.length-1:n+1],l=i[n>i.length-3?i.length-1:n+2];return s.set(nh(o,a.x,h.x,u.x,l.x),nh(o,a.y,h.y,u.y,l.y)),s}copy(e){super.copy(e),this.points=[];for(let t=0,s=e.points.length;t=s){const e=i[r]-s,n=this.curves[r],o=n.getLength(),a=0===o?0:1-e/o;return n.getPointAt(a,t)}r++}return null}getLength(){const e=this.getCurveLengths();return e[e.length-1]}updateArcLengths(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()}getCurveLengths(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;const e=[];let t=0;for(let s=0,i=this.curves.length;s1&&!t[t.length-1].equals(t[0])&&t.push(t[0]),t}copy(e){super.copy(e),this.curves=[];for(let t=0,s=e.curves.length;t0){const e=h.getPoint(0);e.equals(this.currentPoint)||this.lineTo(e.x,e.y)}this.curves.push(h);const u=h.getPoint(1);return this.currentPoint.copy(u),this}copy(e){return super.copy(e),this.currentPoint.copy(e.currentPoint),this}toJSON(){const e=super.toJSON();return e.currentPoint=this.currentPoint.toArray(),e}fromJSON(e){return super.fromJSON(e),this.currentPoint.fromArray(e.currentPoint),this}}class xh extends An{constructor(e=[new Qs(0,-.5),new Qs(.5,0),new Qs(0,.5)],t=12,s=0,i=2*Math.PI){super(),this.type="LatheGeometry",this.parameters={points:e,segments:t,phiStart:s,phiLength:i},t=Math.floor(t),i=$s(i,0,2*Math.PI);const r=[],n=[],o=[],a=[],h=[],u=1/t,l=new Ri,c=new Qs,d=new Ri,p=new Ri,m=new Ri;let g=0,f=0;for(let t=0;t<=e.length-1;t++)switch(t){case 0:g=e[t+1].x-e[t].x,f=e[t+1].y-e[t].y,d.x=1*f,d.y=-g,d.z=0*f,m.copy(d),d.normalize(),a.push(d.x,d.y,d.z);break;case e.length-1:a.push(m.x,m.y,m.z);break;default:g=e[t+1].x-e[t].x,f=e[t+1].y-e[t].y,d.x=1*f,d.y=-g,d.z=0*f,p.copy(d),d.x+=m.x,d.y+=m.y,d.z+=m.z,d.normalize(),a.push(d.x,d.y,d.z),m.copy(p)}for(let r=0;r<=t;r++){const d=s+r*u*i,p=Math.sin(d),m=Math.cos(d);for(let s=0;s<=e.length-1;s++){l.x=e[s].x*p,l.y=e[s].y,l.z=e[s].x*m,n.push(l.x,l.y,l.z),c.x=r/t,c.y=s/(e.length-1),o.push(c.x,c.y);const i=a[3*s+0]*p,u=a[3*s+1],d=a[3*s+0]*m;h.push(i,u,d)}}for(let s=0;s0&&(u.push(r,n,a),x+=3),t>0&&(u.push(n,o,a),x+=3)}h.addGroup(f,x,0),f+=x}(),!1===n&&(e>0&&y(!0),t>0&&y(!1)),this.setIndex(u),this.setAttribute("position",new bn(l,3)),this.setAttribute("normal",new bn(c,3)),this.setAttribute("uv",new bn(d,2))}copy(e){return super.copy(e),this.parameters=Object.assign({},e.parameters),this}static fromJSON(e){return new Th(e.radiusTop,e.radiusBottom,e.height,e.radialSegments,e.heightSegments,e.openEnded,e.thetaStart,e.thetaLength)}}class _h extends Th{constructor(e=1,t=1,s=32,i=1,r=!1,n=0,o=2*Math.PI){super(0,e,t,s,i,r,n,o),this.type="ConeGeometry",this.parameters={radius:e,height:t,radialSegments:s,heightSegments:i,openEnded:r,thetaStart:n,thetaLength:o}}static fromJSON(e){return new _h(e.radius,e.height,e.radialSegments,e.heightSegments,e.openEnded,e.thetaStart,e.thetaLength)}}class wh extends An{constructor(e=[],t=[],s=1,i=0){super(),this.type="PolyhedronGeometry",this.parameters={vertices:e,indices:t,radius:s,detail:i};const r=[],n=[];function o(e,t,s,i){const r=i+1,n=[];for(let i=0;i<=r;i++){n[i]=[];const o=e.clone().lerp(s,i/r),a=t.clone().lerp(s,i/r),h=r-i;for(let e=0;e<=h;e++)n[i][e]=0===e&&i===r?o:o.clone().lerp(a,e/h)}for(let e=0;e.9&&o<.1&&(t<.2&&(n[e+0]+=1),s<.2&&(n[e+2]+=1),i<.2&&(n[e+4]+=1))}}()}(),this.setAttribute("position",new bn(r,3)),this.setAttribute("normal",new bn(r.slice(),3)),this.setAttribute("uv",new bn(n,2)),0===i?this.computeVertexNormals():this.normalizeNormals()}copy(e){return super.copy(e),this.parameters=Object.assign({},e.parameters),this}static fromJSON(e){return new wh(e.vertices,e.indices,e.radius,e.details)}}class Sh extends wh{constructor(e=1,t=0){const s=(1+Math.sqrt(5))/2,i=1/s;super([-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-i,-s,0,-i,s,0,i,-s,0,i,s,-i,-s,0,-i,s,0,i,-s,0,i,s,0,-s,0,-i,s,0,-i,-s,0,i,s,0,i],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],e,t),this.type="DodecahedronGeometry",this.parameters={radius:e,detail:t}}static fromJSON(e){return new Sh(e.radius,e.detail)}}const Mh=new Ri,Nh=new Ri,Ah=new Ri,Ch=new qr;class Rh extends An{constructor(e=null,t=1){if(super(),this.type="EdgesGeometry",this.parameters={geometry:e,thresholdAngle:t},null!==e){const s=4,i=Math.pow(10,s),r=Math.cos(js*t),n=e.getIndex(),o=e.getAttribute("position"),a=n?n.count:o.count,h=[0,0,0],u=["a","b","c"],l=new Array(3),c={},d=[];for(let e=0;e80*s){a=u=e[0],h=l=e[1];for(let t=s;tu&&(u=c),d>l&&(l=d);p=Math.max(u-a,l-h),p=0!==p?32767/p:0}return Fh(n,o,s,a,h,p,0),o};function Ih(e,t,s,i,r){let n,o;if(r===function(e,t,s,i){let r=0;for(let n=t,o=s-i;n0)for(n=t;n=t;n-=i)o=Qh(n,e[n],e[n+1],o);return o&&$h(o,o.next)&&(eu(o),o=o.next),o}function Ph(e,t){if(!e)return e;t||(t=e);let s,i=e;do{if(s=!1,i.steiner||!$h(i,i.next)&&0!==qh(i.prev,i,i.next))i=i.next;else{if(eu(i),i=t=i.prev,i===i.next)break;s=!0}}while(s||i!==t);return t}function Fh(e,t,s,i,r,n,o){if(!e)return;!o&&n&&function(e,t,s,i){let r=e;do{0===r.z&&(r.z=Gh(r.x,r.y,t,s,i)),r.prevZ=r.prev,r.nextZ=r.next,r=r.next}while(r!==e);r.prevZ.nextZ=null,r.prevZ=null,function(e){let t,s,i,r,n,o,a,h,u=1;do{for(s=e,e=null,n=null,o=0;s;){for(o++,i=s,a=0,t=0;t0||h>0&&i;)0!==a&&(0===h||!i||s.z<=i.z)?(r=s,s=s.nextZ,a--):(r=i,i=i.nextZ,h--),n?n.nextZ=r:e=r,r.prevZ=n,n=r;s=i}n.nextZ=null,u*=2}while(o>1)}(r)}(e,i,r,n);let a,h,u=e;for(;e.prev!==e.next;)if(a=e.prev,h=e.next,n?Uh(e,i,r,n):zh(e))t.push(a.i/s|0),t.push(e.i/s|0),t.push(h.i/s|0),eu(e),e=h.next,u=h.next;else if((e=h)===u){o?1===o?Fh(e=Oh(Ph(e),t,s),t,s,i,r,n,2):2===o&&Lh(e,t,s,i,r,n):Fh(Ph(e),t,s,i,r,n,1);break}}function zh(e){const t=e.prev,s=e,i=e.next;if(qh(t,s,i)>=0)return!1;const r=t.x,n=s.x,o=i.x,a=t.y,h=s.y,u=i.y,l=rn?r>o?r:o:n>o?n:o,p=a>h?a>u?a:u:h>u?h:u;let m=i.next;for(;m!==t;){if(m.x>=l&&m.x<=d&&m.y>=c&&m.y<=p&&jh(r,a,n,h,o,u,m.x,m.y)&&qh(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function Uh(e,t,s,i){const r=e.prev,n=e,o=e.next;if(qh(r,n,o)>=0)return!1;const a=r.x,h=n.x,u=o.x,l=r.y,c=n.y,d=o.y,p=ah?a>u?a:u:h>u?h:u,f=l>c?l>d?l:d:c>d?c:d,y=Gh(p,m,t,s,i),x=Gh(g,f,t,s,i);let b=e.prevZ,v=e.nextZ;for(;b&&b.z>=y&&v&&v.z<=x;){if(b.x>=p&&b.x<=g&&b.y>=m&&b.y<=f&&b!==r&&b!==o&&jh(a,l,h,c,u,d,b.x,b.y)&&qh(b.prev,b,b.next)>=0)return!1;if(b=b.prevZ,v.x>=p&&v.x<=g&&v.y>=m&&v.y<=f&&v!==r&&v!==o&&jh(a,l,h,c,u,d,v.x,v.y)&&qh(v.prev,v,v.next)>=0)return!1;v=v.nextZ}for(;b&&b.z>=y;){if(b.x>=p&&b.x<=g&&b.y>=m&&b.y<=f&&b!==r&&b!==o&&jh(a,l,h,c,u,d,b.x,b.y)&&qh(b.prev,b,b.next)>=0)return!1;b=b.prevZ}for(;v&&v.z<=x;){if(v.x>=p&&v.x<=g&&v.y>=m&&v.y<=f&&v!==r&&v!==o&&jh(a,l,h,c,u,d,v.x,v.y)&&qh(v.prev,v,v.next)>=0)return!1;v=v.nextZ}return!0}function Oh(e,t,s){let i=e;do{const r=i.prev,n=i.next.next;!$h(r,n)&&Xh(r,i,i.next,n)&&Jh(r,n)&&Jh(n,r)&&(t.push(r.i/s|0),t.push(i.i/s|0),t.push(n.i/s|0),eu(i),eu(i.next),i=e=n),i=i.next}while(i!==e);return Ph(i)}function Lh(e,t,s,i,r,n){let o=e;do{let e=o.next.next;for(;e!==o.prev;){if(o.i!==e.i&&Hh(o,e)){let a=Kh(o,e);return o=Ph(o,o.next),a=Ph(a,a.next),Fh(o,t,s,i,r,n,0),void Fh(a,t,s,i,r,n,0)}e=e.next}o=o.next}while(o!==e)}function Vh(e,t){return e.x-t.x}function Dh(e,t){const s=function(e,t){let s,i=t,r=-1/0;const n=e.x,o=e.y;do{if(o<=i.y&&o>=i.next.y&&i.next.y!==i.y){const e=i.x+(o-i.y)*(i.next.x-i.x)/(i.next.y-i.y);if(e<=n&&e>r&&(r=e,s=i.x=i.x&&i.x>=h&&n!==i.x&&jh(os.x||i.x===s.x&&kh(s,i)))&&(s=i,c=l)),i=i.next}while(i!==a);return s}(e,t);if(!s)return t;const i=Kh(s,e);return Ph(i,i.next),Ph(s,s.next)}function kh(e,t){return qh(e.prev,e,t.prev)<0&&qh(t.next,e,e.next)<0}function Gh(e,t,s,i,r){return(e=1431655765&((e=858993459&((e=252645135&((e=16711935&((e=(e-s)*r|0)|e<<8))|e<<4))|e<<2))|e<<1))|(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=(t-i)*r|0)|t<<8))|t<<4))|t<<2))|t<<1))<<1}function Wh(e){let t=e,s=e;do{(t.x=(e-o)*(n-a)&&(e-o)*(i-a)>=(s-o)*(t-a)&&(s-o)*(n-a)>=(r-o)*(i-a)}function Hh(e,t){return e.next.i!==t.i&&e.prev.i!==t.i&&!function(e,t){let s=e;do{if(s.i!==e.i&&s.next.i!==e.i&&s.i!==t.i&&s.next.i!==t.i&&Xh(s,s.next,e,t))return!0;s=s.next}while(s!==e);return!1}(e,t)&&(Jh(e,t)&&Jh(t,e)&&function(e,t){let s=e,i=!1;const r=(e.x+t.x)/2,n=(e.y+t.y)/2;do{s.y>n!=s.next.y>n&&s.next.y!==s.y&&r<(s.next.x-s.x)*(n-s.y)/(s.next.y-s.y)+s.x&&(i=!i),s=s.next}while(s!==e);return i}(e,t)&&(qh(e.prev,e,t.prev)||qh(e,t.prev,t))||$h(e,t)&&qh(e.prev,e,e.next)>0&&qh(t.prev,t,t.next)>0)}function qh(e,t,s){return(t.y-e.y)*(s.x-t.x)-(t.x-e.x)*(s.y-t.y)}function $h(e,t){return e.x===t.x&&e.y===t.y}function Xh(e,t,s,i){const r=Zh(qh(e,t,s)),n=Zh(qh(e,t,i)),o=Zh(qh(s,i,e)),a=Zh(qh(s,i,t));return r!==n&&o!==a||(!(0!==r||!Yh(e,s,t))||(!(0!==n||!Yh(e,i,t))||(!(0!==o||!Yh(s,e,i))||!(0!==a||!Yh(s,t,i)))))}function Yh(e,t,s){return t.x<=Math.max(e.x,s.x)&&t.x>=Math.min(e.x,s.x)&&t.y<=Math.max(e.y,s.y)&&t.y>=Math.min(e.y,s.y)}function Zh(e){return e>0?1:e<0?-1:0}function Jh(e,t){return qh(e.prev,e,e.next)<0?qh(e,t,e.next)>=0&&qh(e,e.prev,t)>=0:qh(e,t,e.prev)<0||qh(e,e.next,t)<0}function Kh(e,t){const s=new tu(e.i,e.x,e.y),i=new tu(t.i,t.x,t.y),r=e.next,n=t.prev;return e.next=t,t.prev=e,s.next=r,r.prev=s,i.next=s,s.prev=i,n.next=i,i.prev=n,i}function Qh(e,t,s,i){const r=new tu(e,t,s);return i?(r.next=i.next,r.prev=i,i.next.prev=r,i.next=r):(r.prev=r,r.next=r),r}function eu(e){e.next.prev=e.prev,e.prev.next=e.next,e.prevZ&&(e.prevZ.nextZ=e.nextZ),e.nextZ&&(e.nextZ.prevZ=e.prevZ)}function tu(e,t,s){this.i=e,this.x=t,this.y=s,this.prev=null,this.next=null,this.z=0,this.prevZ=null,this.nextZ=null,this.steiner=!1}class su{static area(e){const t=e.length;let s=0;for(let i=t-1,r=0;r2&&e[t-1].equals(e[0])&&e.pop()}function ru(e,t){for(let s=0;sNumber.EPSILON){const c=Math.sqrt(l),d=Math.sqrt(h*h+u*u),p=t.x-a/c,m=t.y+o/c,g=((s.x-u/d-p)*u-(s.y+h/d-m)*h)/(o*u-a*h);i=p+o*g-e.x,r=m+a*g-e.y;const f=i*i+r*r;if(f<=2)return new Qs(i,r);n=Math.sqrt(f/2)}else{let e=!1;o>Number.EPSILON?h>Number.EPSILON&&(e=!0):o<-Number.EPSILON?h<-Number.EPSILON&&(e=!0):Math.sign(a)===Math.sign(u)&&(e=!0),e?(i=-a,r=o,n=Math.sqrt(l)):(i=o,r=a,n=Math.sqrt(l/2))}return new Qs(i/n,r/n)}const B=[];for(let e=0,t=N.length,s=t-1,i=e+1;e=0;e--){const t=e/p,s=l*Math.cos(t*Math.PI/2),i=c*Math.sin(t*Math.PI/2)+d;for(let e=0,t=N.length;e=0;){const i=s;let r=s-1;r<0&&(r=e.length-1);for(let e=0,s=a+2*p;e0)&&d.push(t,r,h),(e!==s-1||a0!=e>0&&this.version++,this._anisotropy=e}get clearcoat(){return this._clearcoat}set clearcoat(e){this._clearcoat>0!=e>0&&this.version++,this._clearcoat=e}get iridescence(){return this._iridescence}set iridescence(e){this._iridescence>0!=e>0&&this.version++,this._iridescence=e}get dispersion(){return this._dispersion}set dispersion(e){this._dispersion>0!=e>0&&this.version++,this._dispersion=e}get sheen(){return this._sheen}set sheen(e){this._sheen>0!=e>0&&this.version++,this._sheen=e}get transmission(){return this._transmission}set transmission(e){this._transmission>0!=e>0&&this.version++,this._transmission=e}copy(e){return super.copy(e),this.defines={STANDARD:"",PHYSICAL:""},this.anisotropy=e.anisotropy,this.anisotropyRotation=e.anisotropyRotation,this.anisotropyMap=e.anisotropyMap,this.clearcoat=e.clearcoat,this.clearcoatMap=e.clearcoatMap,this.clearcoatRoughness=e.clearcoatRoughness,this.clearcoatRoughnessMap=e.clearcoatRoughnessMap,this.clearcoatNormalMap=e.clearcoatNormalMap,this.clearcoatNormalScale.copy(e.clearcoatNormalScale),this.dispersion=e.dispersion,this.ior=e.ior,this.iridescence=e.iridescence,this.iridescenceMap=e.iridescenceMap,this.iridescenceIOR=e.iridescenceIOR,this.iridescenceThicknessRange=[...e.iridescenceThicknessRange],this.iridescenceThicknessMap=e.iridescenceThicknessMap,this.sheen=e.sheen,this.sheenColor.copy(e.sheenColor),this.sheenColorMap=e.sheenColorMap,this.sheenRoughness=e.sheenRoughness,this.sheenRoughnessMap=e.sheenRoughnessMap,this.transmission=e.transmission,this.transmissionMap=e.transmissionMap,this.thickness=e.thickness,this.thicknessMap=e.thicknessMap,this.attenuationDistance=e.attenuationDistance,this.attenuationColor.copy(e.attenuationColor),this.specularIntensity=e.specularIntensity,this.specularIntensityMap=e.specularIntensityMap,this.specularColor.copy(e.specularColor),this.specularColorMap=e.specularColorMap,this}}class Su extends en{constructor(e){super(),this.isMeshPhongMaterial=!0,this.type="MeshPhongMaterial",this.color=new Jr(16777215),this.specular=new Jr(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Jr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new gr,this.combine=0,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.specular.copy(e.specular),this.shininess=e.shininess,this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.flatShading=e.flatShading,this.fog=e.fog,this}}class Mu extends en{constructor(e){super(),this.isMeshToonMaterial=!0,this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new Jr(16777215),this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Jr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.gradientMap=e.gradientMap,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}}class Nu extends en{constructor(e){super(),this.isMeshNormalMaterial=!0,this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.flatShading=!1,this.setValues(e)}copy(e){return super.copy(e),this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.flatShading=e.flatShading,this}}class Au extends en{constructor(e){super(),this.isMeshLambertMaterial=!0,this.type="MeshLambertMaterial",this.color=new Jr(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Jr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new gr,this.combine=0,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.flatShading=e.flatShading,this.fog=e.fog,this}}class Cu extends en{constructor(e){super(),this.isMeshDepthMaterial=!0,this.type="MeshDepthMaterial",this.depthPacking=3200,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.setValues(e)}copy(e){return super.copy(e),this.depthPacking=e.depthPacking,this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this}}class Ru extends en{constructor(e){super(),this.isMeshDistanceMaterial=!0,this.type="MeshDistanceMaterial",this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.setValues(e)}copy(e){return super.copy(e),this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this}}class Eu extends en{constructor(e){super(),this.isMeshMatcapMaterial=!0,this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new Jr(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Qs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.defines={MATCAP:""},this.color.copy(e.color),this.matcap=e.matcap,this.map=e.map,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.flatShading=e.flatShading,this.fog=e.fog,this}}class Bu extends Ta{constructor(e){super(),this.isLineDashedMaterial=!0,this.type="LineDashedMaterial",this.scale=1,this.dashSize=3,this.gapSize=1,this.setValues(e)}copy(e){return super.copy(e),this.scale=e.scale,this.dashSize=e.dashSize,this.gapSize=e.gapSize,this}}function Iu(e,t,s){return!e||!s&&e.constructor===t?e:"number"==typeof t.BYTES_PER_ELEMENT?new t(e):Array.prototype.slice.call(e)}function Pu(e){return ArrayBuffer.isView(e)&&!(e instanceof DataView)}function Fu(e){const t=e.length,s=new Array(t);for(let e=0;e!==t;++e)s[e]=e;return s.sort((function(t,s){return e[t]-e[s]})),s}function zu(e,t,s){const i=e.length,r=new e.constructor(i);for(let n=0,o=0;o!==i;++n){const i=s[n]*t;for(let s=0;s!==t;++s)r[o++]=e[i+s]}return r}function Uu(e,t,s,i){let r=1,n=e[0];for(;void 0!==n&&void 0===n[i];)n=e[r++];if(void 0===n)return;let o=n[i];if(void 0!==o)if(Array.isArray(o))do{o=n[i],void 0!==o&&(t.push(n.time),s.push.apply(s,o)),n=e[r++]}while(void 0!==n);else if(void 0!==o.toArray)do{o=n[i],void 0!==o&&(t.push(n.time),o.toArray(s,s.length)),n=e[r++]}while(void 0!==n);else do{o=n[i],void 0!==o&&(t.push(n.time),s.push(o)),n=e[r++]}while(void 0!==n)}const Ou={convertArray:Iu,isTypedArray:Pu,getKeyframeOrder:Fu,sortedArray:zu,flattenJSON:Uu,subclip:function(e,t,s,i,r=30){const n=e.clone();n.name=t;const o=[];for(let e=0;e=i)){h.push(t.times[e]);for(let s=0;sn.tracks[e].times[0]&&(a=n.tracks[e].times[0]);for(let e=0;e=i.times[c]){const e=c*h+a,t=e+h-a;d=i.values.slice(e,t)}else{const e=i.createInterpolant(),t=a,s=h-a;e.evaluate(n),d=e.resultBuffer.slice(t,s)}if("quaternion"===r){(new Ci).fromArray(d).normalize().conjugate().toArray(d)}const p=o.times.length;for(let e=0;e=r)break e;{const o=t[1];e=r)break t}n=s,s=0}}for(;s>>1;et;)--n;if(++n,0!==r||n!==i){r>=n&&(n=Math.max(n,1),r=n-1);const e=this.getValueSize();this.times=s.slice(r,n),this.values=this.values.slice(r*e,n*e)}return this}validate(){let e=!0;const t=this.getValueSize();t-Math.floor(t)!=0&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),e=!1);const s=this.times,i=this.values,r=s.length;0===r&&(console.error("THREE.KeyframeTrack: Track is empty.",this),e=!1);let n=null;for(let t=0;t!==r;t++){const i=s[t];if("number"==typeof i&&isNaN(i)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,t,i),e=!1;break}if(null!==n&&n>i){console.error("THREE.KeyframeTrack: Out of order keys.",this,t,i,n),e=!1;break}n=i}if(void 0!==i&&Pu(i))for(let t=0,s=i.length;t!==s;++t){const s=i[t];if(isNaN(s)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,t,s),e=!1;break}}return e}optimize(){const e=this.times.slice(),t=this.values.slice(),s=this.getValueSize(),i=this.getInterpolation()===Ft,r=e.length-1;let n=1;for(let o=1;o0){e[n]=e[r];for(let e=r*s,i=n*s,o=0;o!==s;++o)t[i+o]=t[e+o];++n}return n!==e.length?(this.times=e.slice(0,n),this.values=t.slice(0,n*s)):(this.times=e,this.values=t),this}clone(){const e=this.times.slice(),t=this.values.slice(),s=new(0,this.constructor)(this.name,e,t);return s.createInterpolant=this.createInterpolant,s}}Gu.prototype.TimeBufferType=Float32Array,Gu.prototype.ValueBufferType=Float32Array,Gu.prototype.DefaultInterpolation=Pt;class Wu extends Gu{constructor(e,t,s){super(e,t,s)}}Wu.prototype.ValueTypeName="bool",Wu.prototype.ValueBufferType=Array,Wu.prototype.DefaultInterpolation=It,Wu.prototype.InterpolantFactoryMethodLinear=void 0,Wu.prototype.InterpolantFactoryMethodSmooth=void 0;class ju extends Gu{}ju.prototype.ValueTypeName="color";class Hu extends Gu{}Hu.prototype.ValueTypeName="number";class qu extends Lu{constructor(e,t,s,i){super(e,t,s,i)}interpolate_(e,t,s,i){const r=this.resultBuffer,n=this.sampleValues,o=this.valueSize,a=(s-t)/(i-t);let h=e*o;for(let e=h+o;h!==e;h+=4)Ci.slerpFlat(r,0,n,h-o,n,h,a);return r}}class $u extends Gu{InterpolantFactoryMethodLinear(e){return new qu(this.times,this.values,this.getValueSize(),e)}}$u.prototype.ValueTypeName="quaternion",$u.prototype.InterpolantFactoryMethodSmooth=void 0;class Xu extends Gu{constructor(e,t,s){super(e,t,s)}}Xu.prototype.ValueTypeName="string",Xu.prototype.ValueBufferType=Array,Xu.prototype.DefaultInterpolation=It,Xu.prototype.InterpolantFactoryMethodLinear=void 0,Xu.prototype.InterpolantFactoryMethodSmooth=void 0;class Yu extends Gu{}Yu.prototype.ValueTypeName="vector";class Zu{constructor(e="",t=-1,s=[],i=2500){this.name=e,this.tracks=s,this.duration=t,this.blendMode=i,this.uuid=qs(),this.duration<0&&this.resetDuration()}static parse(e){const t=[],s=e.tracks,i=1/(e.fps||1);for(let e=0,r=s.length;e!==r;++e)t.push(Ju(s[e]).scale(i));const r=new this(e.name,e.duration,t,e.blendMode);return r.uuid=e.uuid,r}static toJSON(e){const t=[],s=e.tracks,i={name:e.name,duration:e.duration,tracks:t,uuid:e.uuid,blendMode:e.blendMode};for(let e=0,i=s.length;e!==i;++e)t.push(Gu.toJSON(s[e]));return i}static CreateFromMorphTargetSequence(e,t,s,i){const r=t.length,n=[];for(let e=0;e1){const e=n[1];let t=i[e];t||(i[e]=t=[]),t.push(s)}}const n=[];for(const e in i)n.push(this.CreateFromMorphTargetSequence(e,i[e],t,s));return n}static parseAnimation(e,t){if(!e)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;const s=function(e,t,s,i,r){if(0!==s.length){const n=[],o=[];Uu(s,n,o,i),0!==n.length&&r.push(new e(t,n,o))}},i=[],r=e.name||"default",n=e.fps||30,o=e.blendMode;let a=e.length||-1;const h=e.hierarchy||[];for(let e=0;e{t&&t(r),this.manager.itemEnd(e)}),0),r;if(void 0!==sl[e])return void sl[e].push({onLoad:t,onProgress:s,onError:i});sl[e]=[],sl[e].push({onLoad:t,onProgress:s,onError:i});const n=new Request(e,{headers:new Headers(this.requestHeader),credentials:this.withCredentials?"include":"same-origin"}),o=this.mimeType,a=this.responseType;fetch(n).then((t=>{if(200===t.status||0===t.status){if(0===t.status&&console.warn("THREE.FileLoader: HTTP Status 0 received."),"undefined"==typeof ReadableStream||void 0===t.body||void 0===t.body.getReader)return t;const s=sl[e],i=t.body.getReader(),r=t.headers.get("X-File-Size")||t.headers.get("Content-Length"),n=r?parseInt(r):0,o=0!==n;let a=0;const h=new ReadableStream({start(e){!function t(){i.read().then((({done:i,value:r})=>{if(i)e.close();else{a+=r.byteLength;const i=new ProgressEvent("progress",{lengthComputable:o,loaded:a,total:n});for(let e=0,t=s.length;e{e.error(t)}))}()}});return new Response(h)}throw new il(`fetch for "${t.url}" responded with ${t.status}: ${t.statusText}`,t)})).then((e=>{switch(a){case"arraybuffer":return e.arrayBuffer();case"blob":return e.blob();case"document":return e.text().then((e=>(new DOMParser).parseFromString(e,o)));case"json":return e.json();default:if(void 0===o)return e.text();{const t=/charset="?([^;"\s]*)"?/i.exec(o),s=t&&t[1]?t[1].toLowerCase():void 0,i=new TextDecoder(s);return e.arrayBuffer().then((e=>i.decode(e)))}}})).then((t=>{Ku.add(e,t);const s=sl[e];delete sl[e];for(let e=0,i=s.length;e{const s=sl[e];if(void 0===s)throw this.manager.itemError(e),t;delete sl[e];for(let e=0,i=s.length;e{this.manager.itemEnd(e)})),this.manager.itemStart(e)}setResponseType(e){return this.responseType=e,this}setMimeType(e){return this.mimeType=e,this}}class nl extends tl{constructor(e){super(e)}load(e,t,s,i){const r=this,n=new rl(this.manager);n.setPath(this.path),n.setRequestHeader(this.requestHeader),n.setWithCredentials(this.withCredentials),n.load(e,(function(s){try{t(r.parse(JSON.parse(s)))}catch(t){i?i(t):console.error(t),r.manager.itemError(e)}}),s,i)}parse(e){const t=[];for(let s=0;s0:i.vertexColors=e.vertexColors),void 0!==e.uniforms)for(const t in e.uniforms){const r=e.uniforms[t];switch(i.uniforms[t]={},r.type){case"t":i.uniforms[t].value=s(r.value);break;case"c":i.uniforms[t].value=(new Jr).setHex(r.value);break;case"v2":i.uniforms[t].value=(new Qs).fromArray(r.value);break;case"v3":i.uniforms[t].value=(new Ri).fromArray(r.value);break;case"v4":i.uniforms[t].value=(new Ti).fromArray(r.value);break;case"m3":i.uniforms[t].value=(new ei).fromArray(r.value);break;case"m4":i.uniforms[t].value=(new nr).fromArray(r.value);break;default:i.uniforms[t].value=r.value}}if(void 0!==e.defines&&(i.defines=e.defines),void 0!==e.vertexShader&&(i.vertexShader=e.vertexShader),void 0!==e.fragmentShader&&(i.fragmentShader=e.fragmentShader),void 0!==e.glslVersion&&(i.glslVersion=e.glslVersion),void 0!==e.extensions)for(const t in e.extensions)i.extensions[t]=e.extensions[t];if(void 0!==e.lights&&(i.lights=e.lights),void 0!==e.clipping&&(i.clipping=e.clipping),void 0!==e.size&&(i.size=e.size),void 0!==e.sizeAttenuation&&(i.sizeAttenuation=e.sizeAttenuation),void 0!==e.map&&(i.map=s(e.map)),void 0!==e.matcap&&(i.matcap=s(e.matcap)),void 0!==e.alphaMap&&(i.alphaMap=s(e.alphaMap)),void 0!==e.bumpMap&&(i.bumpMap=s(e.bumpMap)),void 0!==e.bumpScale&&(i.bumpScale=e.bumpScale),void 0!==e.normalMap&&(i.normalMap=s(e.normalMap)),void 0!==e.normalMapType&&(i.normalMapType=e.normalMapType),void 0!==e.normalScale){let t=e.normalScale;!1===Array.isArray(t)&&(t=[t,t]),i.normalScale=(new Qs).fromArray(t)}return void 0!==e.displacementMap&&(i.displacementMap=s(e.displacementMap)),void 0!==e.displacementScale&&(i.displacementScale=e.displacementScale),void 0!==e.displacementBias&&(i.displacementBias=e.displacementBias),void 0!==e.roughnessMap&&(i.roughnessMap=s(e.roughnessMap)),void 0!==e.metalnessMap&&(i.metalnessMap=s(e.metalnessMap)),void 0!==e.emissiveMap&&(i.emissiveMap=s(e.emissiveMap)),void 0!==e.emissiveIntensity&&(i.emissiveIntensity=e.emissiveIntensity),void 0!==e.specularMap&&(i.specularMap=s(e.specularMap)),void 0!==e.specularIntensityMap&&(i.specularIntensityMap=s(e.specularIntensityMap)),void 0!==e.specularColorMap&&(i.specularColorMap=s(e.specularColorMap)),void 0!==e.envMap&&(i.envMap=s(e.envMap)),void 0!==e.envMapRotation&&i.envMapRotation.fromArray(e.envMapRotation),void 0!==e.envMapIntensity&&(i.envMapIntensity=e.envMapIntensity),void 0!==e.reflectivity&&(i.reflectivity=e.reflectivity),void 0!==e.refractionRatio&&(i.refractionRatio=e.refractionRatio),void 0!==e.lightMap&&(i.lightMap=s(e.lightMap)),void 0!==e.lightMapIntensity&&(i.lightMapIntensity=e.lightMapIntensity),void 0!==e.aoMap&&(i.aoMap=s(e.aoMap)),void 0!==e.aoMapIntensity&&(i.aoMapIntensity=e.aoMapIntensity),void 0!==e.gradientMap&&(i.gradientMap=s(e.gradientMap)),void 0!==e.clearcoatMap&&(i.clearcoatMap=s(e.clearcoatMap)),void 0!==e.clearcoatRoughnessMap&&(i.clearcoatRoughnessMap=s(e.clearcoatRoughnessMap)),void 0!==e.clearcoatNormalMap&&(i.clearcoatNormalMap=s(e.clearcoatNormalMap)),void 0!==e.clearcoatNormalScale&&(i.clearcoatNormalScale=(new Qs).fromArray(e.clearcoatNormalScale)),void 0!==e.iridescenceMap&&(i.iridescenceMap=s(e.iridescenceMap)),void 0!==e.iridescenceThicknessMap&&(i.iridescenceThicknessMap=s(e.iridescenceThicknessMap)),void 0!==e.transmissionMap&&(i.transmissionMap=s(e.transmissionMap)),void 0!==e.thicknessMap&&(i.thicknessMap=s(e.thicknessMap)),void 0!==e.anisotropyMap&&(i.anisotropyMap=s(e.anisotropyMap)),void 0!==e.sheenColorMap&&(i.sheenColorMap=s(e.sheenColorMap)),void 0!==e.sheenRoughnessMap&&(i.sheenRoughnessMap=s(e.sheenRoughnessMap)),i}setTextures(e){return this.textures=e,this}createMaterialFromType(e){return Bl.createMaterialFromType(e)}static createMaterialFromType(e){return new{ShadowMaterial:vu,SpriteMaterial:no,RawShaderMaterial:Tu,ShaderMaterial:Wn,PointsMaterial:za,MeshPhysicalMaterial:wu,MeshStandardMaterial:_u,MeshPhongMaterial:Su,MeshToonMaterial:Mu,MeshNormalMaterial:Nu,MeshLambertMaterial:Au,MeshDepthMaterial:Cu,MeshDistanceMaterial:Ru,MeshBasicMaterial:tn,MeshMatcapMaterial:Eu,LineDashedMaterial:Bu,LineBasicMaterial:Ta,Material:en}[e]}}class Il{static decodeText(e){if(console.warn("THREE.LoaderUtils: decodeText() has been deprecated with r165 and will be removed with r175. Use TextDecoder instead."),"undefined"!=typeof TextDecoder)return(new TextDecoder).decode(e);let t="";for(let s=0,i=e.length;s0){const s=new Qu(t);r=new al(s),r.setCrossOrigin(this.crossOrigin);for(let t=0,s=e.length;t0){i=new al(this.manager),i.setCrossOrigin(this.crossOrigin);for(let t=0,i=e.length;t{const t=new Ii;t.min.fromArray(e.boxMin),t.max.fromArray(e.boxMax);const s=new Zi;return s.radius=e.sphereRadius,s.center.fromArray(e.sphereCenter),{boxInitialized:e.boxInitialized,box:t,sphereInitialized:e.sphereInitialized,sphere:s}})),n._maxInstanceCount=e.maxInstanceCount,n._maxVertexCount=e.maxVertexCount,n._maxIndexCount=e.maxIndexCount,n._geometryInitialized=e.geometryInitialized,n._geometryCount=e.geometryCount,n._matricesTexture=l(e.matricesTexture.uuid),void 0!==e.colorsTexture&&(n._colorsTexture=l(e.colorsTexture.uuid));break;case"LOD":n=new So;break;case"Line":n=new Ra(h(e.geometry),u(e.material));break;case"LineLoop":n=new Fa(h(e.geometry),u(e.material));break;case"LineSegments":n=new Pa(h(e.geometry),u(e.material));break;case"PointCloud":case"Points":n=new Da(h(e.geometry),u(e.material));break;case"Sprite":n=new vo(u(e.material));break;case"Group":n=new Ga;break;case"Bone":n=new zo;break;default:n=new Ir}if(n.uuid=e.uuid,void 0!==e.name&&(n.name=e.name),void 0!==e.matrix?(n.matrix.fromArray(e.matrix),void 0!==e.matrixAutoUpdate&&(n.matrixAutoUpdate=e.matrixAutoUpdate),n.matrixAutoUpdate&&n.matrix.decompose(n.position,n.quaternion,n.scale)):(void 0!==e.position&&n.position.fromArray(e.position),void 0!==e.rotation&&n.rotation.fromArray(e.rotation),void 0!==e.quaternion&&n.quaternion.fromArray(e.quaternion),void 0!==e.scale&&n.scale.fromArray(e.scale)),void 0!==e.up&&n.up.fromArray(e.up),void 0!==e.castShadow&&(n.castShadow=e.castShadow),void 0!==e.receiveShadow&&(n.receiveShadow=e.receiveShadow),e.shadow&&(void 0!==e.shadow.intensity&&(n.shadow.intensity=e.shadow.intensity),void 0!==e.shadow.bias&&(n.shadow.bias=e.shadow.bias),void 0!==e.shadow.normalBias&&(n.shadow.normalBias=e.shadow.normalBias),void 0!==e.shadow.radius&&(n.shadow.radius=e.shadow.radius),void 0!==e.shadow.mapSize&&n.shadow.mapSize.fromArray(e.shadow.mapSize),void 0!==e.shadow.camera&&(n.shadow.camera=this.parseObject(e.shadow.camera))),void 0!==e.visible&&(n.visible=e.visible),void 0!==e.frustumCulled&&(n.frustumCulled=e.frustumCulled),void 0!==e.renderOrder&&(n.renderOrder=e.renderOrder),void 0!==e.userData&&(n.userData=e.userData),void 0!==e.layers&&(n.layers.mask=e.layers),void 0!==e.children){const o=e.children;for(let e=0;e{t&&t(s),r.manager.itemEnd(e)})).catch((e=>{i&&i(e)})):(setTimeout((function(){t&&t(n),r.manager.itemEnd(e)}),0),n);const o={};o.credentials="anonymous"===this.crossOrigin?"same-origin":"include",o.headers=this.requestHeader;const a=fetch(e,o).then((function(e){return e.blob()})).then((function(e){return createImageBitmap(e,Object.assign(r.options,{colorSpaceConversion:"none"}))})).then((function(s){return Ku.add(e,s),t&&t(s),r.manager.itemEnd(e),s})).catch((function(t){i&&i(t),Ku.remove(e),r.manager.itemError(e),r.manager.itemEnd(e)}));Ku.add(e,a),r.manager.itemStart(e)}}let Dl;class kl{static getContext(){return void 0===Dl&&(Dl=new(window.AudioContext||window.webkitAudioContext)),Dl}static setContext(e){Dl=e}}class Gl extends tl{constructor(e){super(e)}load(e,t,s,i){const r=this,n=new rl(this.manager);function o(t){i?i(t):console.error(t),r.manager.itemError(e)}n.setResponseType("arraybuffer"),n.setPath(this.path),n.setRequestHeader(this.requestHeader),n.setWithCredentials(this.withCredentials),n.load(e,(function(e){try{const s=e.slice(0);kl.getContext().decodeAudioData(s,(function(e){t(e)})).catch(o)}catch(e){o(e)}}),s,i)}}const Wl=new nr,jl=new nr,Hl=new nr;class ql{constructor(){this.type="StereoCamera",this.aspect=1,this.eyeSep=.064,this.cameraL=new Xn,this.cameraL.layers.enable(1),this.cameraL.matrixAutoUpdate=!1,this.cameraR=new Xn,this.cameraR.layers.enable(2),this.cameraR.matrixAutoUpdate=!1,this._cache={focus:null,fov:null,aspect:null,near:null,far:null,zoom:null,eyeSep:null}}update(e){const t=this._cache;if(t.focus!==e.focus||t.fov!==e.fov||t.aspect!==e.aspect*this.aspect||t.near!==e.near||t.far!==e.far||t.zoom!==e.zoom||t.eyeSep!==this.eyeSep){t.focus=e.focus,t.fov=e.fov,t.aspect=e.aspect*this.aspect,t.near=e.near,t.far=e.far,t.zoom=e.zoom,t.eyeSep=this.eyeSep,Hl.copy(e.projectionMatrix);const s=t.eyeSep/2,i=s*t.near/t.focus,r=t.near*Math.tan(js*t.fov*.5)/t.zoom;let n,o;jl.elements[12]=-s,Wl.elements[12]=s,n=-r*t.aspect+i,o=r*t.aspect+i,Hl.elements[0]=2*t.near/(o-n),Hl.elements[8]=(o+n)/(o-n),this.cameraL.projectionMatrix.copy(Hl),n=-r*t.aspect-i,o=r*t.aspect-i,Hl.elements[0]=2*t.near/(o-n),Hl.elements[8]=(o+n)/(o-n),this.cameraR.projectionMatrix.copy(Hl)}this.cameraL.matrixWorld.copy(e.matrixWorld).multiply(jl),this.cameraR.matrixWorld.copy(e.matrixWorld).multiply(Wl)}}class $l extends Xn{constructor(e=[]){super(),this.isArrayCamera=!0,this.cameras=e}}class Xl{constructor(e=!0){this.autoStart=e,this.startTime=0,this.oldTime=0,this.elapsedTime=0,this.running=!1}start(){this.startTime=Yl(),this.oldTime=this.startTime,this.elapsedTime=0,this.running=!0}stop(){this.getElapsedTime(),this.running=!1,this.autoStart=!1}getElapsedTime(){return this.getDelta(),this.elapsedTime}getDelta(){let e=0;if(this.autoStart&&!this.running)return this.start(),0;if(this.running){const t=Yl();e=(t-this.oldTime)/1e3,this.oldTime=t,this.elapsedTime+=e}return e}}function Yl(){return performance.now()}const Zl=new Ri,Jl=new Ci,Kl=new Ri,Ql=new Ri;class ec extends Ir{constructor(){super(),this.type="AudioListener",this.context=kl.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._clock=new Xl}getInput(){return this.gain}removeFilter(){return null!==this.filter&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null),this}getFilter(){return this.filter}setFilter(e){return null!==this.filter?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination),this.filter=e,this.gain.connect(this.filter),this.filter.connect(this.context.destination),this}getMasterVolume(){return this.gain.gain.value}setMasterVolume(e){return this.gain.gain.setTargetAtTime(e,this.context.currentTime,.01),this}updateMatrixWorld(e){super.updateMatrixWorld(e);const t=this.context.listener,s=this.up;if(this.timeDelta=this._clock.getDelta(),this.matrixWorld.decompose(Zl,Jl,Kl),Ql.set(0,0,-1).applyQuaternion(Jl),t.positionX){const e=this.context.currentTime+this.timeDelta;t.positionX.linearRampToValueAtTime(Zl.x,e),t.positionY.linearRampToValueAtTime(Zl.y,e),t.positionZ.linearRampToValueAtTime(Zl.z,e),t.forwardX.linearRampToValueAtTime(Ql.x,e),t.forwardY.linearRampToValueAtTime(Ql.y,e),t.forwardZ.linearRampToValueAtTime(Ql.z,e),t.upX.linearRampToValueAtTime(s.x,e),t.upY.linearRampToValueAtTime(s.y,e),t.upZ.linearRampToValueAtTime(s.z,e)}else t.setPosition(Zl.x,Zl.y,Zl.z),t.setOrientation(Ql.x,Ql.y,Ql.z,s.x,s.y,s.z)}}class tc extends Ir{constructor(e){super(),this.type="Audio",this.listener=e,this.context=e.context,this.gain=this.context.createGain(),this.gain.connect(e.getInput()),this.autoplay=!1,this.buffer=null,this.detune=0,this.loop=!1,this.loopStart=0,this.loopEnd=0,this.offset=0,this.duration=void 0,this.playbackRate=1,this.isPlaying=!1,this.hasPlaybackControl=!0,this.source=null,this.sourceType="empty",this._startedAt=0,this._progress=0,this._connected=!1,this.filters=[]}getOutput(){return this.gain}setNodeSource(e){return this.hasPlaybackControl=!1,this.sourceType="audioNode",this.source=e,this.connect(),this}setMediaElementSource(e){return this.hasPlaybackControl=!1,this.sourceType="mediaNode",this.source=this.context.createMediaElementSource(e),this.connect(),this}setMediaStreamSource(e){return this.hasPlaybackControl=!1,this.sourceType="mediaStreamNode",this.source=this.context.createMediaStreamSource(e),this.connect(),this}setBuffer(e){return this.buffer=e,this.sourceType="buffer",this.autoplay&&this.play(),this}play(e=0){if(!0===this.isPlaying)return void console.warn("THREE.Audio: Audio is already playing.");if(!1===this.hasPlaybackControl)return void console.warn("THREE.Audio: this Audio has no playback control.");this._startedAt=this.context.currentTime+e;const t=this.context.createBufferSource();return t.buffer=this.buffer,t.loop=this.loop,t.loopStart=this.loopStart,t.loopEnd=this.loopEnd,t.onended=this.onEnded.bind(this),t.start(this._startedAt,this._progress+this.offset,this.duration),this.isPlaying=!0,this.source=t,this.setDetune(this.detune),this.setPlaybackRate(this.playbackRate),this.connect()}pause(){if(!1!==this.hasPlaybackControl)return!0===this.isPlaying&&(this._progress+=Math.max(this.context.currentTime-this._startedAt,0)*this.playbackRate,!0===this.loop&&(this._progress=this._progress%(this.duration||this.buffer.duration)),this.source.stop(),this.source.onended=null,this.isPlaying=!1),this;console.warn("THREE.Audio: this Audio has no playback control.")}stop(e=0){if(!1!==this.hasPlaybackControl)return this._progress=0,null!==this.source&&(this.source.stop(this.context.currentTime+e),this.source.onended=null),this.isPlaying=!1,this;console.warn("THREE.Audio: this Audio has no playback control.")}connect(){if(this.filters.length>0){this.source.connect(this.filters[0]);for(let e=1,t=this.filters.length;e0){this.source.disconnect(this.filters[0]);for(let e=1,t=this.filters.length;e0&&this._mixBufferRegionAdditive(s,i,this._addIndex*t,1,t);for(let e=t,r=t+t;e!==r;++e)if(s[e]!==s[e+t]){o.setValue(s,i);break}}saveOriginalState(){const e=this.binding,t=this.buffer,s=this.valueSize,i=s*this._origIndex;e.getValue(t,i);for(let e=s,r=i;e!==r;++e)t[e]=t[i+e%s];this._setIdentity(),this.cumulativeWeight=0,this.cumulativeWeightAdditive=0}restoreOriginalState(){const e=3*this.valueSize;this.binding.setValue(this.buffer,e)}_setAdditiveIdentityNumeric(){const e=this._addIndex*this.valueSize,t=e+this.valueSize;for(let s=e;s=.5)for(let i=0;i!==r;++i)e[t+i]=e[s+i]}_slerp(e,t,s,i){Ci.slerpFlat(e,t,e,t,e,s,i)}_slerpAdditive(e,t,s,i,r){const n=this._workIndex*r;Ci.multiplyQuaternionsFlat(e,n,e,t,e,s),Ci.slerpFlat(e,t,e,t,e,n,i)}_lerp(e,t,s,i,r){const n=1-i;for(let o=0;o!==r;++o){const r=t+o;e[r]=e[r]*n+e[s+o]*i}}_lerpAdditive(e,t,s,i,r){for(let n=0;n!==r;++n){const r=t+n;e[r]=e[r]+e[s+n]*i}}}const uc="\\[\\]\\.:\\/",lc=new RegExp("["+uc+"]","g"),cc="[^"+uc+"]",dc="[^"+uc.replace("\\.","")+"]",pc=new RegExp("^"+/((?:WC+[\/:])*)/.source.replace("WC",cc)+/(WCOD+)?/.source.replace("WCOD",dc)+/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",cc)+/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",cc)+"$"),mc=["material","materials","bones","map"];class gc{constructor(e,t,s){this.path=t,this.parsedPath=s||gc.parseTrackName(t),this.node=gc.findNode(e,this.parsedPath.nodeName),this.rootNode=e,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(e,t,s){return e&&e.isAnimationObjectGroup?new gc.Composite(e,t,s):new gc(e,t,s)}static sanitizeNodeName(e){return e.replace(/\s/g,"_").replace(lc,"")}static parseTrackName(e){const t=pc.exec(e);if(null===t)throw new Error("PropertyBinding: Cannot parse trackName: "+e);const s={nodeName:t[2],objectName:t[3],objectIndex:t[4],propertyName:t[5],propertyIndex:t[6]},i=s.nodeName&&s.nodeName.lastIndexOf(".");if(void 0!==i&&-1!==i){const e=s.nodeName.substring(i+1);-1!==mc.indexOf(e)&&(s.nodeName=s.nodeName.substring(0,i),s.objectName=e)}if(null===s.propertyName||0===s.propertyName.length)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+e);return s}static findNode(e,t){if(void 0===t||""===t||"."===t||-1===t||t===e.name||t===e.uuid)return e;if(e.skeleton){const s=e.skeleton.getBoneByName(t);if(void 0!==s)return s}if(e.children){const s=function(e){for(let i=0;i=r){const n=r++,u=e[n];t[u.uuid]=h,e[h]=u,t[a]=n,e[n]=o;for(let e=0,t=i;e!==t;++e){const t=s[e],i=t[n],r=t[h];t[h]=i,t[n]=r}}}this.nCachedObjects_=r}uncache(){const e=this._objects,t=this._indicesByUUID,s=this._bindings,i=s.length;let r=this.nCachedObjects_,n=e.length;for(let o=0,a=arguments.length;o!==a;++o){const a=arguments[o].uuid,h=t[a];if(void 0!==h)if(delete t[a],h0&&(t[o.uuid]=h),e[h]=o,e.pop();for(let e=0,t=i;e!==t;++e){const t=s[e];t[h]=t[r],t.pop()}}}this.nCachedObjects_=r}subscribe_(e,t){const s=this._bindingsIndicesByPath;let i=s[e];const r=this._bindings;if(void 0!==i)return r[i];const n=this._paths,o=this._parsedPaths,a=this._objects,h=a.length,u=this.nCachedObjects_,l=new Array(h);i=r.length,s[e]=i,n.push(e),o.push(t),r.push(l);for(let s=u,i=a.length;s!==i;++s){const i=a[s];l[s]=new gc(i,e,t)}return l}unsubscribe_(e){const t=this._bindingsIndicesByPath,s=t[e];if(void 0!==s){const i=this._paths,r=this._parsedPaths,n=this._bindings,o=n.length-1,a=n[o];t[e[o]]=s,n[s]=a,n.pop(),r[s]=r[o],r.pop(),i[s]=i[o],i.pop()}}}class yc{constructor(e,t,s=null,i=t.blendMode){this._mixer=e,this._clip=t,this._localRoot=s,this.blendMode=i;const r=t.tracks,n=r.length,o=new Array(n),a={endingStart:zt,endingEnd:zt};for(let e=0;e!==n;++e){const t=r[e].createInterpolant(null);o[e]=t,t.settings=a}this._interpolantSettings=a,this._interpolants=o,this._propertyBindings=new Array(n),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=2201,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}play(){return this._mixer._activateAction(this),this}stop(){return this._mixer._deactivateAction(this),this.reset()}reset(){return this.paused=!1,this.enabled=!0,this.time=0,this._loopCount=-1,this._startTime=null,this.stopFading().stopWarping()}isRunning(){return this.enabled&&!this.paused&&0!==this.timeScale&&null===this._startTime&&this._mixer._isActiveAction(this)}isScheduled(){return this._mixer._isActiveAction(this)}startAt(e){return this._startTime=e,this}setLoop(e,t){return this.loop=e,this.repetitions=t,this}setEffectiveWeight(e){return this.weight=e,this._effectiveWeight=this.enabled?e:0,this.stopFading()}getEffectiveWeight(){return this._effectiveWeight}fadeIn(e){return this._scheduleFading(e,0,1)}fadeOut(e){return this._scheduleFading(e,1,0)}crossFadeFrom(e,t,s){if(e.fadeOut(t),this.fadeIn(t),s){const s=this._clip.duration,i=e._clip.duration,r=i/s,n=s/i;e.warp(1,r,t),this.warp(n,1,t)}return this}crossFadeTo(e,t,s){return e.crossFadeFrom(this,t,s)}stopFading(){const e=this._weightInterpolant;return null!==e&&(this._weightInterpolant=null,this._mixer._takeBackControlInterpolant(e)),this}setEffectiveTimeScale(e){return this.timeScale=e,this._effectiveTimeScale=this.paused?0:e,this.stopWarping()}getEffectiveTimeScale(){return this._effectiveTimeScale}setDuration(e){return this.timeScale=this._clip.duration/e,this.stopWarping()}syncWith(e){return this.time=e.time,this.timeScale=e.timeScale,this.stopWarping()}halt(e){return this.warp(this._effectiveTimeScale,0,e)}warp(e,t,s){const i=this._mixer,r=i.time,n=this.timeScale;let o=this._timeScaleInterpolant;null===o&&(o=i._lendControlInterpolant(),this._timeScaleInterpolant=o);const a=o.parameterPositions,h=o.sampleValues;return a[0]=r,a[1]=r+s,h[0]=e/n,h[1]=t/n,this}stopWarping(){const e=this._timeScaleInterpolant;return null!==e&&(this._timeScaleInterpolant=null,this._mixer._takeBackControlInterpolant(e)),this}getMixer(){return this._mixer}getClip(){return this._clip}getRoot(){return this._localRoot||this._mixer._root}_update(e,t,s,i){if(!this.enabled)return void this._updateWeight(e);const r=this._startTime;if(null!==r){const i=(e-r)*s;i<0||0===s?t=0:(this._startTime=null,t=s*i)}t*=this._updateTimeScale(e);const n=this._updateTime(t),o=this._updateWeight(e);if(o>0){const e=this._interpolants,t=this._propertyBindings;if(this.blendMode===Vt)for(let s=0,i=e.length;s!==i;++s)e[s].evaluate(n),t[s].accumulateAdditive(o);else for(let s=0,r=e.length;s!==r;++s)e[s].evaluate(n),t[s].accumulate(i,o)}}_updateWeight(e){let t=0;if(this.enabled){t=this.weight;const s=this._weightInterpolant;if(null!==s){const i=s.evaluate(e)[0];t*=i,e>s.parameterPositions[1]&&(this.stopFading(),0===i&&(this.enabled=!1))}}return this._effectiveWeight=t,t}_updateTimeScale(e){let t=0;if(!this.paused){t=this.timeScale;const s=this._timeScaleInterpolant;if(null!==s){t*=s.evaluate(e)[0],e>s.parameterPositions[1]&&(this.stopWarping(),0===t?this.paused=!0:this.timeScale=t)}}return this._effectiveTimeScale=t,t}_updateTime(e){const t=this._clip.duration,s=this.loop;let i=this.time+e,r=this._loopCount;const n=2202===s;if(0===e)return-1===r?i:n&&1==(1&r)?t-i:i;if(2200===s){-1===r&&(this._loopCount=0,this._setEndings(!0,!0,!1));e:{if(i>=t)i=t;else{if(!(i<0)){this.time=i;break e}i=0}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:e<0?-1:1})}}else{if(-1===r&&(e>=0?(r=0,this._setEndings(!0,0===this.repetitions,n)):this._setEndings(0===this.repetitions,!0,n)),i>=t||i<0){const s=Math.floor(i/t);i-=t*s,r+=Math.abs(s);const o=this.repetitions-r;if(o<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,i=e>0?t:0,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:e>0?1:-1});else{if(1===o){const t=e<0;this._setEndings(t,!t,n)}else this._setEndings(!1,!1,n);this._loopCount=r,this.time=i,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:s})}}else this.time=i;if(n&&1==(1&r))return t-i}return i}_setEndings(e,t,s){const i=this._interpolantSettings;s?(i.endingStart=Ut,i.endingEnd=Ut):(i.endingStart=e?this.zeroSlopeAtStart?Ut:zt:Ot,i.endingEnd=t?this.zeroSlopeAtEnd?Ut:zt:Ot)}_scheduleFading(e,t,s){const i=this._mixer,r=i.time;let n=this._weightInterpolant;null===n&&(n=i._lendControlInterpolant(),this._weightInterpolant=n);const o=n.parameterPositions,a=n.sampleValues;return o[0]=r,a[0]=t,o[1]=r+e,a[1]=s,this}}const xc=new Float32Array(1);class bc extends ks{constructor(e){super(),this._root=e,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}_bindAction(e,t){const s=e._localRoot||this._root,i=e._clip.tracks,r=i.length,n=e._propertyBindings,o=e._interpolants,a=s.uuid,h=this._bindingsByRootAndName;let u=h[a];void 0===u&&(u={},h[a]=u);for(let e=0;e!==r;++e){const r=i[e],h=r.name;let l=u[h];if(void 0!==l)++l.referenceCount,n[e]=l;else{if(l=n[e],void 0!==l){null===l._cacheIndex&&(++l.referenceCount,this._addInactiveBinding(l,a,h));continue}const i=t&&t._propertyBindings[e].binding.parsedPath;l=new hc(gc.create(s,h,i),r.ValueTypeName,r.getValueSize()),++l.referenceCount,this._addInactiveBinding(l,a,h),n[e]=l}o[e].resultBuffer=l.buffer}}_activateAction(e){if(!this._isActiveAction(e)){if(null===e._cacheIndex){const t=(e._localRoot||this._root).uuid,s=e._clip.uuid,i=this._actionsByClip[s];this._bindAction(e,i&&i.knownActions[0]),this._addInactiveAction(e,s,t)}const t=e._propertyBindings;for(let e=0,s=t.length;e!==s;++e){const s=t[e];0==s.useCount++&&(this._lendBinding(s),s.saveOriginalState())}this._lendAction(e)}}_deactivateAction(e){if(this._isActiveAction(e)){const t=e._propertyBindings;for(let e=0,s=t.length;e!==s;++e){const s=t[e];0==--s.useCount&&(s.restoreOriginalState(),this._takeBackBinding(s))}this._takeBackAction(e)}}_initMemoryManager(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;const e=this;this.stats={actions:{get total(){return e._actions.length},get inUse(){return e._nActiveActions}},bindings:{get total(){return e._bindings.length},get inUse(){return e._nActiveBindings}},controlInterpolants:{get total(){return e._controlInterpolants.length},get inUse(){return e._nActiveControlInterpolants}}}}_isActiveAction(e){const t=e._cacheIndex;return null!==t&&t=0;--t)e[t].stop();return this}update(e){e*=this.timeScale;const t=this._actions,s=this._nActiveActions,i=this.time+=e,r=Math.sign(e),n=this._accuIndex^=1;for(let o=0;o!==s;++o){t[o]._update(i,e,r,n)}const o=this._bindings,a=this._nActiveBindings;for(let e=0;e!==a;++e)o[e].apply(n);return this}setTime(e){this.time=0;for(let e=0;e=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y))}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,Ic).distanceTo(e)}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}const Fc=new Ri,zc=new Ri;class Uc{constructor(e=new Ri,t=new Ri){this.start=e,this.end=t}set(e,t){return this.start.copy(e),this.end.copy(t),this}copy(e){return this.start.copy(e.start),this.end.copy(e.end),this}getCenter(e){return e.addVectors(this.start,this.end).multiplyScalar(.5)}delta(e){return e.subVectors(this.end,this.start)}distanceSq(){return this.start.distanceToSquared(this.end)}distance(){return this.start.distanceTo(this.end)}at(e,t){return this.delta(t).multiplyScalar(e).add(this.start)}closestPointToPointParameter(e,t){Fc.subVectors(e,this.start),zc.subVectors(this.end,this.start);const s=zc.dot(zc);let i=zc.dot(Fc)/s;return t&&(i=$s(i,0,1)),i}closestPointToPoint(e,t,s){const i=this.closestPointToPointParameter(e,t);return this.delta(s).multiplyScalar(i).add(this.start)}applyMatrix4(e){return this.start.applyMatrix4(e),this.end.applyMatrix4(e),this}equals(e){return e.start.equals(this.start)&&e.end.equals(this.end)}clone(){return(new this.constructor).copy(this)}}const Oc=new Ri;class Lc extends Ir{constructor(e,t){super(),this.light=e,this.matrixAutoUpdate=!1,this.color=t,this.type="SpotLightHelper";const s=new An,i=[0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,-1,0,1,0,0,0,0,1,1,0,0,0,0,-1,1];for(let e=0,t=1,s=32;e1)for(let s=0;s.99999)this.quaternion.set(0,0,0,1);else if(e.y<-.99999)this.quaternion.set(1,0,0,0);else{ud.set(e.z,0,-e.x).normalize();const t=Math.acos(e.y);this.quaternion.setFromAxisAngle(ud,t)}}setLength(e,t=.2*e,s=.2*t){this.line.scale.set(1,Math.max(1e-4,e-t),1),this.line.updateMatrix(),this.cone.scale.set(s,t,s),this.cone.position.y=e,this.cone.updateMatrix()}setColor(e){this.line.material.color.set(e),this.cone.material.color.set(e)}copy(e){return super.copy(e,!1),this.line.copy(e.line),this.cone.copy(e.cone),this}dispose(){this.line.geometry.dispose(),this.line.material.dispose(),this.cone.geometry.dispose(),this.cone.material.dispose()}}class pd extends Pa{constructor(e=1){const t=[0,0,0,e,0,0,0,0,0,0,e,0,0,0,0,0,0,e],s=new An;s.setAttribute("position",new bn(t,3)),s.setAttribute("color",new bn([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1],3));super(s,new Ta({vertexColors:!0,toneMapped:!1})),this.type="AxesHelper"}setColors(e,t,s){const i=new Jr,r=this.geometry.attributes.color.array;return i.set(e),i.toArray(r,0),i.toArray(r,3),i.set(t),i.toArray(r,6),i.toArray(r,9),i.set(s),i.toArray(r,12),i.toArray(r,15),this.geometry.attributes.color.needsUpdate=!0,this}dispose(){this.geometry.dispose(),this.material.dispose()}}class md{constructor(){this.type="ShapePath",this.color=new Jr,this.subPaths=[],this.currentPath=null}moveTo(e,t){return this.currentPath=new yh,this.subPaths.push(this.currentPath),this.currentPath.moveTo(e,t),this}lineTo(e,t){return this.currentPath.lineTo(e,t),this}quadraticCurveTo(e,t,s,i){return this.currentPath.quadraticCurveTo(e,t,s,i),this}bezierCurveTo(e,t,s,i,r,n){return this.currentPath.bezierCurveTo(e,t,s,i,r,n),this}splineThru(e){return this.currentPath.splineThru(e),this}toShapes(e){function t(e,t){const s=t.length;let i=!1;for(let r=s-1,n=0;nNumber.EPSILON){if(h<0&&(s=t[n],a=-a,o=t[r],h=-h),e.yo.y)continue;if(e.y===s.y){if(e.x===s.x)return!0}else{const t=h*(e.x-s.x)-a*(e.y-s.y);if(0===t)return!0;if(t<0)continue;i=!i}}else{if(e.y!==s.y)continue;if(o.x<=e.x&&e.x<=s.x||s.x<=e.x&&e.x<=o.x)return!0}}return i}const s=su.isClockWise,i=this.subPaths;if(0===i.length)return[];let r,n,o;const a=[];if(1===i.length)return n=i[0],o=new Eh,o.curves=n.curves,a.push(o),a;let h=!s(i[0].getPoints());h=e?!h:h;const u=[],l=[];let c,d,p=[],m=0;l[m]=void 0,p[m]=[];for(let t=0,o=i.length;t1){let e=!1,s=0;for(let e=0,t=l.length;e0&&!1===e&&(p=u)}for(let e=0,t=l.length;e>>16,2246822507),s^=Math.imul(i^i>>>13,3266489909),i=Math.imul(i^i>>>16,2246822507),i^=Math.imul(s^s>>>13,3266489909),4294967296*(2097151&i)+(s>>>0)}const vd=e=>bd(e),Td=e=>bd(e),_d=(...e)=>bd(e);function wd(e,t=!1){const s=[];!0===e.isNode&&(s.push(e.id),e=e.getSelf());for(const{property:i,childNode:r}of Sd(e))s.push(s,bd(i.slice(0,-4)),r.getCacheKey(t));return bd(s)}function*Sd(e,t=!1){for(const s in e){if(!0===s.startsWith("_"))continue;const i=e[s];if(!0===Array.isArray(i))for(let e=0;ee.charCodeAt(0))).buffer}var Rd=Object.freeze({__proto__:null,arrayBufferToBase64:Ad,base64ToArrayBuffer:Cd,getCacheKey:wd,getNodeChildren:Sd,getValueFromType:Nd,getValueType:Md,hash:_d,hashArray:Td,hashString:vd});const Ed={VERTEX:"vertex",FRAGMENT:"fragment"},Bd={NONE:"none",FRAME:"frame",RENDER:"render",OBJECT:"object"},Id={BOOLEAN:"bool",INTEGER:"int",FLOAT:"float",VECTOR2:"vec2",VECTOR3:"vec3",VECTOR4:"vec4",MATRIX2:"mat2",MATRIX3:"mat3",MATRIX4:"mat4"},Pd=["fragment","vertex"],Fd=["setup","analyze","generate"],zd=[...Pd,"compute"],Ud=["x","y","z","w"];let Od=0;class Ld extends ks{static get type(){return"Node"}constructor(e=null){super(),this.nodeType=e,this.updateType=Bd.NONE,this.updateBeforeType=Bd.NONE,this.updateAfterType=Bd.NONE,this.uuid=Ks.generateUUID(),this.version=0,this._cacheKey=null,this._cacheKeyVersion=0,this.global=!1,this.isNode=!0,Object.defineProperty(this,"id",{value:Od++})}set needsUpdate(e){!0===e&&this.version++}get type(){return this.constructor.type}onUpdate(e,t){return this.updateType=t,this.update=e.bind(this.getSelf()),this}onFrameUpdate(e){return this.onUpdate(e,Bd.FRAME)}onRenderUpdate(e){return this.onUpdate(e,Bd.RENDER)}onObjectUpdate(e){return this.onUpdate(e,Bd.OBJECT)}onReference(e){return this.updateReference=e.bind(this.getSelf()),this}getSelf(){return this.self||this}updateReference(){return this}isGlobal(){return this.global}*getChildren(){for(const{childNode:e}of Sd(this))yield e}dispose(){this.dispatchEvent({type:"dispose"})}traverse(e){e(this);for(const t of this.getChildren())t.traverse(e)}getCacheKey(e=!1){return!0!==(e=e||this.version!==this._cacheKeyVersion)&&null!==this._cacheKey||(this._cacheKey=wd(this,e),this._cacheKeyVersion=this.version),this._cacheKey}getScope(){return this}getHash(){return this.uuid}getUpdateType(){return this.updateType}getUpdateBeforeType(){return this.updateBeforeType}getUpdateAfterType(){return this.updateAfterType}getElementType(e){const t=this.getNodeType(e);return e.getElementType(t)}getNodeType(e){const t=e.getNodeProperties(this);return t.outputNode?t.outputNode.getNodeType(e):this.nodeType}getShared(e){const t=this.getHash(e);return e.getNodeFromHash(t)||this}setup(e){const t=e.getNodeProperties(this);let s=0;for(const e of this.getChildren())t["node"+s++]=e;return null}analyze(e){if(1===e.increaseUsage(this)){const t=e.getNodeProperties(this);for(const s of Object.values(t))s&&!0===s.isNode&&s.build(e)}}generate(e,t){const{outputNode:s}=e.getNodeProperties(this);if(s&&!0===s.isNode)return s.build(e,t)}updateBefore(){console.warn("Abstract function.")}updateAfter(){console.warn("Abstract function.")}update(){console.warn("Abstract function.")}build(e,t=null){const s=this.getShared(e);if(this!==s)return s.build(e,t);e.addNode(this),e.addChain(this);let i=null;const r=e.getBuildStage();if("setup"===r){this.updateReference(e);const t=e.getNodeProperties(this);if(!0!==t.initialized){e.stack.nodes.length;t.initialized=!0,t.outputNode=this.setup(e),null!==t.outputNode&&e.stack.nodes.length;for(const s of Object.values(t))s&&!0===s.isNode&&s.build(e)}}else if("analyze"===r)this.analyze(e);else if("generate"===r){if(1===this.generate.length){const s=this.getNodeType(e),r=e.getDataFromNode(this);i=r.snippet,void 0===i?(i=this.generate(e)||"",r.snippet=i):void 0!==r.flowCodes&&void 0!==e.context.nodeBlock&&e.addFlowCodeHierarchy(this,e.context.nodeBlock),i=e.format(i,s,t)}else i=this.generate(e,t)||""}return e.removeChain(this),i}getSerializeChildren(){return Sd(this)}serialize(e){const t=this.getSerializeChildren(),s={};for(const{property:i,index:r,childNode:n}of t)void 0!==r?(void 0===s[i]&&(s[i]=Number.isInteger(r)?[]:{}),s[i][r]=n.toJSON(e.meta).uuid):s[i]=n.toJSON(e.meta).uuid;Object.keys(s).length>0&&(e.inputNodes=s)}deserialize(e){if(void 0!==e.inputNodes){const t=e.meta.nodes;for(const s in e.inputNodes)if(Array.isArray(e.inputNodes[s])){const i=[];for(const r of e.inputNodes[s])i.push(t[r]);this[s]=i}else if("object"==typeof e.inputNodes[s]){const i={};for(const r in e.inputNodes[s]){const n=e.inputNodes[s][r];i[r]=t[n]}this[s]=i}else{const i=e.inputNodes[s];this[s]=t[i]}}}toJSON(e){const{uuid:t,type:s}=this,i=void 0===e||"string"==typeof e;i&&(e={textures:{},images:{},nodes:{}});let r=e.nodes[t];function n(e){const t=[];for(const s in e){const i=e[s];delete i.metadata,t.push(i)}return t}if(void 0===r&&(r={uuid:t,type:s,meta:e,metadata:{version:4.6,type:"Node",generator:"Node.toJSON"}},!0!==i&&(e.nodes[r.uuid]=r),this.serialize(r),delete r.meta),i){const t=n(e.textures),s=n(e.images),i=n(e.nodes);t.length>0&&(r.textures=t),s.length>0&&(r.images=s),i.length>0&&(r.nodes=i)}return r}}class Vd extends Ld{static get type(){return"ArrayElementNode"}constructor(e,t){super(),this.node=e,this.indexNode=t,this.isArrayElementNode=!0}getNodeType(e){return this.node.getElementType(e)}generate(e){return`${this.node.build(e)}[ ${this.indexNode.build(e,"uint")} ]`}}class Dd extends Ld{static get type(){return"ConvertNode"}constructor(e,t){super(),this.node=e,this.convertTo=t}getNodeType(e){const t=this.node.getNodeType(e);let s=null;for(const i of this.convertTo.split("|"))null!==s&&e.getTypeLength(t)!==e.getTypeLength(i)||(s=i);return s}serialize(e){super.serialize(e),e.convertTo=this.convertTo}deserialize(e){super.deserialize(e),this.convertTo=e.convertTo}generate(e,t){const s=this.node,i=this.getNodeType(e),r=s.build(e,i);return e.format(r,i,t)}}class kd extends Ld{static get type(){return"TempNode"}constructor(e){super(e),this.isTempNode=!0}hasDependencies(e){return e.getDataFromNode(this).usageCount>1}build(e,t){if("generate"===e.getBuildStage()){const s=e.getVectorType(this.getNodeType(e,t)),i=e.getDataFromNode(this);if(void 0!==i.propertyName)return e.format(i.propertyName,s,t);if("void"!==s&&"void"!==t&&this.hasDependencies(e)){const r=super.build(e,s),n=e.getVarFromNode(this,null,s),o=e.getPropertyName(n);return e.addLineFlowCode(`${o} = ${r}`,this),i.snippet=r,i.propertyName=o,e.format(i.propertyName,s,t)}}return super.build(e,t)}}class Gd extends kd{static get type(){return"JoinNode"}constructor(e=[],t=null){super(t),this.nodes=e}getNodeType(e){return null!==this.nodeType?e.getVectorType(this.nodeType):e.getTypeFromLength(this.nodes.reduce(((t,s)=>t+e.getTypeLength(s.getNodeType(e))),0))}generate(e,t){const s=this.getNodeType(e),i=this.nodes,r=e.getComponentType(s),n=[];for(const t of i){let s=t.build(e);const i=e.getComponentType(t.getNodeType(e));i!==r&&(s=e.format(s,i,r)),n.push(s)}const o=`${e.getType(s)}( ${n.join(", ")} )`;return e.format(o,s,t)}}const Wd=Ud.join("");class jd extends Ld{static get type(){return"SplitNode"}constructor(e,t="x"){super(),this.node=e,this.components=t,this.isSplitNode=!0}getVectorLength(){let e=this.components.length;for(const t of this.components)e=Math.max(Ud.indexOf(t)+1,e);return e}getComponentType(e){return e.getComponentType(this.node.getNodeType(e))}getNodeType(e){return e.getTypeFromLength(this.components.length,this.getComponentType(e))}generate(e,t){const s=this.node,i=e.getTypeLength(s.getNodeType(e));let r=null;if(i>1){let n=null;this.getVectorLength()>=i&&(n=e.getTypeFromLength(this.getVectorLength(),this.getComponentType(e)));const o=s.build(e,n);r=this.components.length===i&&this.components===Wd.slice(0,this.components.length)?e.format(o,n,t):e.format(`${o}.${this.components}`,this.getNodeType(e),t)}else r=s.build(e,t);return r}serialize(e){super.serialize(e),e.components=this.components}deserialize(e){super.deserialize(e),this.components=e.components}}class Hd extends kd{static get type(){return"SetNode"}constructor(e,t,s){super(),this.sourceNode=e,this.components=t,this.targetNode=s}getNodeType(e){return this.sourceNode.getNodeType(e)}generate(e){const{sourceNode:t,components:s,targetNode:i}=this,r=this.getNodeType(e),n=e.getTypeFromLength(s.length,i.getNodeType(e)),o=i.build(e,n),a=t.build(e,r),h=e.getTypeLength(r),u=[];for(let e=0;ee.replace(/r|s/g,"x").replace(/g|t/g,"y").replace(/b|p/g,"z").replace(/a|q/g,"w"),Qd=e=>Kd(e).split("").sort().join(""),ep={setup(e,t){const s=t.shift();return e(Mp(s),...t)},get(e,t,s){if("string"==typeof t&&void 0===e[t]){if(!0!==e.isStackNode&&"assign"===t)return(...e)=>(Yd.assign(s,...e),s);if(Zd.has(t)){const i=Zd.get(t);return e.isStackNode?(...e)=>s.add(i(...e)):(...e)=>i(s,...e)}if("self"===t)return e;if(t.endsWith("Assign")&&Zd.has(t.slice(0,t.length-6))){const i=Zd.get(t.slice(0,t.length-6));return e.isStackNode?(...e)=>s.assign(e[0],i(...e)):(...e)=>s.assign(i(s,...e))}if(!0===/^[xyzwrgbastpq]{1,4}$/.test(t))return t=Kd(t),Sp(new jd(s,t));if(!0===/^set[XYZWRGBASTPQ]{1,4}$/.test(t))return t=Qd(t.slice(3).toLowerCase()),s=>Sp(new Hd(e,t,s));if(!0===/^flip[XYZWRGBASTPQ]{1,4}$/.test(t))return t=Qd(t.slice(4).toLowerCase()),()=>Sp(new qd(Sp(e),t));if("width"===t||"height"===t||"depth"===t)return"width"===t?t="x":"height"===t?t="y":"depth"===t&&(t="z"),Sp(new jd(e,t));if(!0===/^\d+$/.test(t))return Sp(new Vd(s,new Xd(Number(t),"uint")))}return Reflect.get(e,t,s)},set:(e,t,s,i)=>"string"!=typeof t||void 0!==e[t]||!0!==/^[xyzwrgbastpq]{1,4}$/.test(t)&&"width"!==t&&"height"!==t&&"depth"!==t&&!0!==/^\d+$/.test(t)?Reflect.set(e,t,s,i):(i[t].assign(s),!0)},tp=new WeakMap,sp=new WeakMap,ip=function(e,t=null){for(const s in e)e[s]=Sp(e[s],t);return e},rp=function(e,t=null){const s=e.length;for(let i=0;iSp(null!==i?Object.assign(e,i):e);return null===t?(...t)=>r(new e(...Np(t))):null!==s?(s=Sp(s),(...i)=>r(new e(t,...Np(i),s))):(...s)=>r(new e(t,...Np(s)))},op=function(e,...t){return Sp(new e(...Np(t)))};class ap extends Ld{constructor(e,t){super(),this.shaderNode=e,this.inputNodes=t}getNodeType(e){return this.shaderNode.nodeType||this.getOutputNode(e).getNodeType(e)}call(e){const{shaderNode:t,inputNodes:s}=this,i=e.getNodeProperties(t);if(i.onceOutput)return i.onceOutput;let r=null;if(t.layout){let i=sp.get(e.constructor);void 0===i&&(i=new WeakMap,sp.set(e.constructor,i));let n=i.get(t);void 0===n&&(n=Sp(e.buildFunctionNode(t)),i.set(t,n)),null!==e.currentFunctionNode&&e.currentFunctionNode.includes.push(n),r=Sp(n.call(s))}else{const i=t.jsFunc,n=null!==s?i(s,e):i(e);r=Sp(n)}return t.once&&(i.onceOutput=r),r}getOutputNode(e){const t=e.getNodeProperties(this);return null===t.outputNode&&(t.outputNode=this.setupOutput(e)),t.outputNode}setup(e){return this.getOutputNode(e)}setupOutput(e){return e.addStack(),e.stack.outputNode=this.call(e),e.removeStack()}generate(e,t){return this.getOutputNode(e).build(e,t)}}class hp extends Ld{constructor(e,t){super(t),this.jsFunc=e,this.layout=null,this.global=!0,this.once=!1}setLayout(e){return this.layout=e,this}call(e=null){return Mp(e),Sp(new ap(this,e))}setup(){return this.call()}}const up=[!1,!0],lp=[0,1,2,3],cp=[-1,-2],dp=[.5,1.5,1/3,1e-6,1e6,Math.PI,2*Math.PI,1/Math.PI,2/Math.PI,1/(2*Math.PI),Math.PI/2],pp=new Map;for(const e of up)pp.set(e,new Xd(e));const mp=new Map;for(const e of lp)mp.set(e,new Xd(e,"uint"));const gp=new Map([...mp].map((e=>new Xd(e.value,"int"))));for(const e of cp)gp.set(e,new Xd(e,"int"));const fp=new Map([...gp].map((e=>new Xd(e.value))));for(const e of dp)fp.set(e,new Xd(e));for(const e of dp)fp.set(-e,new Xd(-e));const yp={bool:pp,uint:mp,ints:gp,float:fp},xp=new Map([...pp,...fp]),bp=(e,t)=>xp.has(e)?xp.get(e):!0===e.isNode?e:new Xd(e,t),vp=function(e,t=null){return(...s)=>{if((0===s.length||!["bool","float","int","uint"].includes(e)&&s.every((e=>"object"!=typeof e)))&&(s=[Nd(e,...s)]),1===s.length&&null!==t&&t.has(s[0]))return Sp(t.get(s[0]));if(1===s.length){const t=bp(s[0],e);return(e=>{try{return e.getNodeType()}catch(e){return}})(t)===e?Sp(t):Sp(new Dd(t,e))}const i=s.map((e=>bp(e)));return Sp(new Gd(i,e))}},Tp=e=>"object"==typeof e&&null!==e?e.value:e,_p=e=>null!=e?e.nodeType||e.convertTo||("string"==typeof e?e:null):null;function wp(e,t){return new Proxy(new hp(e,t),ep)}const Sp=(e,t=null)=>function(e,t=null){const s=Md(e);if("node"===s){let t=tp.get(e);return void 0===t&&(t=new Proxy(e,ep),tp.set(e,t),tp.set(t,t)),t}return null===t&&("float"===s||"boolean"===s)||s&&"shader"!==s&&"string"!==s?Sp(bp(e,t)):"shader"===s?Rp(e):e}(e,t),Mp=(e,t=null)=>new ip(e,t),Np=(e,t=null)=>new rp(e,t),Ap=(...e)=>new np(...e),Cp=(...e)=>new op(...e),Rp=(e,t)=>{const s=new wp(e,t),i=(...e)=>{let t;return Mp(e),t=e[0]&&e[0].isNode?[...e]:e[0],s.call(t)};return i.shaderNode=s,i.setLayout=e=>(s.setLayout(e),i),i.once=()=>(s.once=!0,i),i},Ep=(...e)=>(console.warn("TSL.ShaderNode: tslFn() has been renamed to Fn()."),Rp(...e));Jd("toGlobal",(e=>(e.global=!0,e)));const Bp=e=>{Yd=e},Ip=()=>Yd,Pp=(...e)=>Yd.If(...e);function Fp(e){return Yd&&Yd.add(e),e}Jd("append",Fp);const zp=new vp("color"),Up=new vp("float",yp.float),Op=new vp("int",yp.ints),Lp=new vp("uint",yp.uint),Vp=new vp("bool",yp.bool),Dp=new vp("vec2"),kp=new vp("ivec2"),Gp=new vp("uvec2"),Wp=new vp("bvec2"),jp=new vp("vec3"),Hp=new vp("ivec3"),qp=new vp("uvec3"),$p=new vp("bvec3"),Xp=new vp("vec4"),Yp=new vp("ivec4"),Zp=new vp("uvec4"),Jp=new vp("bvec4"),Kp=new vp("mat2"),Qp=new vp("mat3"),em=new vp("mat4"),tm=(e="")=>Sp(new Xd(e,"string")),sm=e=>Sp(new Xd(e,"ArrayBuffer"));Jd("toColor",zp),Jd("toFloat",Up),Jd("toInt",Op),Jd("toUint",Lp),Jd("toBool",Vp),Jd("toVec2",Dp),Jd("toIVec2",kp),Jd("toUVec2",Gp),Jd("toBVec2",Wp),Jd("toVec3",jp),Jd("toIVec3",Hp),Jd("toUVec3",qp),Jd("toBVec3",$p),Jd("toVec4",Xp),Jd("toIVec4",Yp),Jd("toUVec4",Zp),Jd("toBVec4",Jp),Jd("toMat2",Kp),Jd("toMat3",Qp),Jd("toMat4",em);const im=Ap(Vd),rm=(e,t)=>Sp(new Dd(Sp(e),t)),nm=(e,t)=>Sp(new jd(Sp(e),t));Jd("element",im),Jd("convert",rm);class om extends Ld{static get type(){return"UniformGroupNode"}constructor(e,t=!1,s=1){super("string"),this.name=e,this.version=0,this.shared=t,this.order=s,this.isUniformGroup=!0}set needsUpdate(e){!0===e&&this.version++}serialize(e){super.serialize(e),e.name=this.name,e.version=this.version,e.shared=this.shared}deserialize(e){super.deserialize(e),this.name=e.name,this.version=e.version,this.shared=e.shared}}const am=e=>new om(e),hm=(e,t=0)=>new om(e,!0,t),um=hm("frame"),lm=hm("render"),cm=am("object");class dm extends $d{static get type(){return"UniformNode"}constructor(e,t=null){super(e,t),this.isUniformNode=!0,this.name="",this.groupNode=cm}label(e){return this.name=e,this}setGroup(e){return this.groupNode=e,this}getGroup(){return this.groupNode}getUniformHash(e){return this.getHash(e)}onUpdate(e,t){const s=this.getSelf();return e=e.bind(s),super.onUpdate((t=>{const i=e(t,s);void 0!==i&&(this.value=i)}),t)}generate(e,t){const s=this.getNodeType(e),i=this.getUniformHash(e);let r=e.getNodeFromHash(i);void 0===r&&(e.setHashNode(this,i),r=this);const n=r.getInputType(e),o=e.getUniformFromNode(r,n,e.shaderStage,this.name||e.context.label),a=e.getPropertyName(o);return void 0!==e.context.label&&delete e.context.label,e.format(a,s,t)}}const pm=(e,t)=>{const s=_p(t||e),i=e&&!0===e.isNode?e.node&&e.node.value||e.value:e;return Sp(new dm(i,s))};class mm extends Ld{static get type(){return"PropertyNode"}constructor(e,t=null,s=!1){super(e),this.name=t,this.varying=s,this.isPropertyNode=!0}getHash(e){return this.name||super.getHash(e)}isGlobal(){return!0}generate(e){let t;return!0===this.varying?(t=e.getVaryingFromNode(this,this.name),t.needsInterpolation=!0):t=e.getVarFromNode(this,this.name),e.getPropertyName(t)}}const gm=(e,t)=>Sp(new mm(e,t)),fm=(e,t)=>Sp(new mm(e,t,!0)),ym=Cp(mm,"vec4","DiffuseColor"),xm=Cp(mm,"vec3","EmissiveColor"),bm=Cp(mm,"float","Roughness"),vm=Cp(mm,"float","Metalness"),Tm=Cp(mm,"float","Clearcoat"),_m=Cp(mm,"float","ClearcoatRoughness"),wm=Cp(mm,"vec3","Sheen"),Sm=Cp(mm,"float","SheenRoughness"),Mm=Cp(mm,"float","Iridescence"),Nm=Cp(mm,"float","IridescenceIOR"),Am=Cp(mm,"float","IridescenceThickness"),Cm=Cp(mm,"float","AlphaT"),Rm=Cp(mm,"float","Anisotropy"),Em=Cp(mm,"vec3","AnisotropyT"),Bm=Cp(mm,"vec3","AnisotropyB"),Im=Cp(mm,"color","SpecularColor"),Pm=Cp(mm,"float","SpecularF90"),Fm=Cp(mm,"float","Shininess"),zm=Cp(mm,"vec4","Output"),Um=Cp(mm,"float","dashSize"),Om=Cp(mm,"float","gapSize"),Lm=Cp(mm,"float","pointWidth"),Vm=Cp(mm,"float","IOR"),Dm=Cp(mm,"float","Transmission"),km=Cp(mm,"float","Thickness"),Gm=Cp(mm,"float","AttenuationDistance"),Wm=Cp(mm,"color","AttenuationColor"),jm=Cp(mm,"float","Dispersion");class Hm extends kd{static get type(){return"AssignNode"}constructor(e,t){super(),this.targetNode=e,this.sourceNode=t}hasDependencies(){return!1}getNodeType(e,t){return"void"!==t?this.targetNode.getNodeType(e):"void"}needsSplitAssign(e){const{targetNode:t}=this;if(!1===e.isAvailable("swizzleAssign")&&t.isSplitNode&&t.components.length>1){const s=e.getTypeLength(t.node.getNodeType(e));return Ud.join("").slice(0,s)!==t.components}return!1}generate(e,t){const{targetNode:s,sourceNode:i}=this,r=this.needsSplitAssign(e),n=s.getNodeType(e),o=s.context({assign:!0}).build(e),a=i.build(e,n),h=i.getNodeType(e),u=e.getDataFromNode(this);let l;if(!0===u.initialized)"void"!==t&&(l=o);else if(r){const i=e.getVarFromNode(this,null,n),r=e.getPropertyName(i);e.addLineFlowCode(`${r} = ${a}`,this);const h=s.node.context({assign:!0}).build(e);for(let t=0;t(t=t.length>1||t[0]&&!0===t[0].isNode?Np(t):Mp(t[0]),Sp(new $m(Sp(e),t)));Jd("call",Xm);class Ym extends kd{static get type(){return"OperatorNode"}constructor(e,t,s,...i){if(super(),i.length>0){let r=new Ym(e,t,s);for(let t=0;t>"===s||"<<"===s)return e.getIntegerType(n);if("!"===s||"=="===s||"&&"===s||"||"===s||"^^"===s)return"bool";if("<"===s||">"===s||"<="===s||">="===s){const s=t?e.getTypeLength(t):Math.max(e.getTypeLength(n),e.getTypeLength(o));return s>1?`bvec${s}`:"bool"}return"float"===n&&e.isMatrix(o)?o:e.isMatrix(n)&&e.isVector(o)?e.getVectorFromMatrix(n):e.isVector(n)&&e.isMatrix(o)?e.getVectorFromMatrix(o):e.getTypeLength(o)>e.getTypeLength(n)?o:n}generate(e,t){const s=this.op,i=this.aNode,r=this.bNode,n=this.getNodeType(e,t);let o=null,a=null;"void"!==n?(o=i.getNodeType(e),a=void 0!==r?r.getNodeType(e):null,"<"===s||">"===s||"<="===s||">="===s||"=="===s?e.isVector(o)?a=o:o!==a&&(o=a="float"):">>"===s||"<<"===s?(o=n,a=e.changeComponentType(a,"uint")):e.isMatrix(o)&&e.isVector(a)?a=e.getVectorFromMatrix(o):o=e.isVector(o)&&e.isMatrix(a)?e.getVectorFromMatrix(a):a=n):o=a=n;const h=i.build(e,o),u=void 0!==r?r.build(e,a):null,l=e.getTypeLength(t),c=e.getFunctionOperator(s);return"void"!==t?"<"===s&&l>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThan",t)}( ${h}, ${u} )`,n,t):e.format(`( ${h} < ${u} )`,n,t):"<="===s&&l>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThanEqual",t)}( ${h}, ${u} )`,n,t):e.format(`( ${h} <= ${u} )`,n,t):">"===s&&l>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThan",t)}( ${h}, ${u} )`,n,t):e.format(`( ${h} > ${u} )`,n,t):">="===s&&l>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThanEqual",t)}( ${h}, ${u} )`,n,t):e.format(`( ${h} >= ${u} )`,n,t):"!"===s||"~"===s?e.format(`(${s}${h})`,o,t):c?e.format(`${c}( ${h}, ${u} )`,n,t):e.format(`( ${h} ${s} ${u} )`,n,t):"void"!==o?c?e.format(`${c}( ${h}, ${u} )`,n,t):e.format(`${h} ${s} ${u}`,n,t):void 0}serialize(e){super.serialize(e),e.op=this.op}deserialize(e){super.deserialize(e),this.op=e.op}}const Zm=Ap(Ym,"+"),Jm=Ap(Ym,"-"),Km=Ap(Ym,"*"),Qm=Ap(Ym,"/"),eg=Ap(Ym,"%"),tg=Ap(Ym,"=="),sg=Ap(Ym,"!="),ig=Ap(Ym,"<"),rg=Ap(Ym,">"),ng=Ap(Ym,"<="),og=Ap(Ym,">="),ag=Ap(Ym,"&&"),hg=Ap(Ym,"||"),ug=Ap(Ym,"!"),lg=Ap(Ym,"^^"),cg=Ap(Ym,"&"),dg=Ap(Ym,"~"),pg=Ap(Ym,"|"),mg=Ap(Ym,"^"),gg=Ap(Ym,"<<"),fg=Ap(Ym,">>");Jd("add",Zm),Jd("sub",Jm),Jd("mul",Km),Jd("div",Qm),Jd("modInt",eg),Jd("equal",tg),Jd("notEqual",sg),Jd("lessThan",ig),Jd("greaterThan",rg),Jd("lessThanEqual",ng),Jd("greaterThanEqual",og),Jd("and",ag),Jd("or",hg),Jd("not",ug),Jd("xor",lg),Jd("bitAnd",cg),Jd("bitNot",dg),Jd("bitOr",pg),Jd("bitXor",mg),Jd("shiftLeft",gg),Jd("shiftRight",fg);const yg=(...e)=>(console.warn("TSL.OperatorNode: .remainder() has been renamed to .modInt()."),eg(...e));Jd("remainder",yg);class xg extends kd{static get type(){return"MathNode"}constructor(e,t,s=null,i=null){super(),this.method=e,this.aNode=t,this.bNode=s,this.cNode=i}getInputType(e){const t=this.aNode.getNodeType(e),s=this.bNode?this.bNode.getNodeType(e):null,i=this.cNode?this.cNode.getNodeType(e):null,r=e.isMatrix(t)?0:e.getTypeLength(t),n=e.isMatrix(s)?0:e.getTypeLength(s),o=e.isMatrix(i)?0:e.getTypeLength(i);return r>n&&r>o?t:n>o?s:o>r?i:t}getNodeType(e){const t=this.method;return t===xg.LENGTH||t===xg.DISTANCE||t===xg.DOT?"float":t===xg.CROSS?"vec3":t===xg.ALL?"bool":t===xg.EQUALS?e.changeComponentType(this.aNode.getNodeType(e),"bool"):t===xg.MOD?this.aNode.getNodeType(e):this.getInputType(e)}generate(e,t){const s=this.method,i=this.getNodeType(e),r=this.getInputType(e),n=this.aNode,o=this.bNode,a=this.cNode,h=!0===e.renderer.isWebGLRenderer;if(s===xg.TRANSFORM_DIRECTION){let s=n,i=o;e.isMatrix(s.getNodeType(e))?i=Xp(jp(i),0):s=Xp(jp(s),0);const r=Km(s,i).xyz;return Ug(r).build(e,t)}if(s===xg.NEGATE)return e.format("( - "+n.build(e,r)+" )",i,t);if(s===xg.ONE_MINUS)return Jm(1,n).build(e,t);if(s===xg.RECIPROCAL)return Qm(1,n).build(e,t);if(s===xg.DIFFERENCE)return jg(Jm(n,o)).build(e,t);{const u=[];return s===xg.CROSS||s===xg.MOD?u.push(n.build(e,i),o.build(e,i)):h&&s===xg.STEP?u.push(n.build(e,1===e.getTypeLength(n.getNodeType(e))?"float":r),o.build(e,r)):h&&(s===xg.MIN||s===xg.MAX)||s===xg.MOD?u.push(n.build(e,r),o.build(e,1===e.getTypeLength(o.getNodeType(e))?"float":r)):s===xg.REFRACT?u.push(n.build(e,r),o.build(e,r),a.build(e,"float")):s===xg.MIX?u.push(n.build(e,r),o.build(e,r),a.build(e,1===e.getTypeLength(a.getNodeType(e))?"float":r)):(u.push(n.build(e,r)),null!==o&&u.push(o.build(e,r)),null!==a&&u.push(a.build(e,r))),e.format(`${e.getMethod(s,i)}( ${u.join(", ")} )`,i,t)}}serialize(e){super.serialize(e),e.method=this.method}deserialize(e){super.deserialize(e),this.method=e.method}}xg.ALL="all",xg.ANY="any",xg.EQUALS="equals",xg.RADIANS="radians",xg.DEGREES="degrees",xg.EXP="exp",xg.EXP2="exp2",xg.LOG="log",xg.LOG2="log2",xg.SQRT="sqrt",xg.INVERSE_SQRT="inversesqrt",xg.FLOOR="floor",xg.CEIL="ceil",xg.NORMALIZE="normalize",xg.FRACT="fract",xg.SIN="sin",xg.COS="cos",xg.TAN="tan",xg.ASIN="asin",xg.ACOS="acos",xg.ATAN="atan",xg.ABS="abs",xg.SIGN="sign",xg.LENGTH="length",xg.NEGATE="negate",xg.ONE_MINUS="oneMinus",xg.DFDX="dFdx",xg.DFDY="dFdy",xg.ROUND="round",xg.RECIPROCAL="reciprocal",xg.TRUNC="trunc",xg.FWIDTH="fwidth",xg.BITCAST="bitcast",xg.TRANSPOSE="transpose",xg.ATAN2="atan2",xg.MIN="min",xg.MAX="max",xg.MOD="mod",xg.STEP="step",xg.REFLECT="reflect",xg.DISTANCE="distance",xg.DIFFERENCE="difference",xg.DOT="dot",xg.CROSS="cross",xg.POW="pow",xg.TRANSFORM_DIRECTION="transformDirection",xg.MIX="mix",xg.CLAMP="clamp",xg.REFRACT="refract",xg.SMOOTHSTEP="smoothstep",xg.FACEFORWARD="faceforward";const bg=Up(1e-6),vg=Up(1e6),Tg=Up(Math.PI),_g=Up(2*Math.PI),wg=Ap(xg,xg.ALL),Sg=Ap(xg,xg.ANY),Mg=Ap(xg,xg.EQUALS),Ng=Ap(xg,xg.RADIANS),Ag=Ap(xg,xg.DEGREES),Cg=Ap(xg,xg.EXP),Rg=Ap(xg,xg.EXP2),Eg=Ap(xg,xg.LOG),Bg=Ap(xg,xg.LOG2),Ig=Ap(xg,xg.SQRT),Pg=Ap(xg,xg.INVERSE_SQRT),Fg=Ap(xg,xg.FLOOR),zg=Ap(xg,xg.CEIL),Ug=Ap(xg,xg.NORMALIZE),Og=Ap(xg,xg.FRACT),Lg=Ap(xg,xg.SIN),Vg=Ap(xg,xg.COS),Dg=Ap(xg,xg.TAN),kg=Ap(xg,xg.ASIN),Gg=Ap(xg,xg.ACOS),Wg=Ap(xg,xg.ATAN),jg=Ap(xg,xg.ABS),Hg=Ap(xg,xg.SIGN),qg=Ap(xg,xg.LENGTH),$g=Ap(xg,xg.NEGATE),Xg=Ap(xg,xg.ONE_MINUS),Yg=Ap(xg,xg.DFDX),Zg=Ap(xg,xg.DFDY),Jg=Ap(xg,xg.ROUND),Kg=Ap(xg,xg.RECIPROCAL),Qg=Ap(xg,xg.TRUNC),ef=Ap(xg,xg.FWIDTH),tf=Ap(xg,xg.BITCAST),sf=Ap(xg,xg.TRANSPOSE),rf=Ap(xg,xg.ATAN2),nf=Ap(xg,xg.MIN),of=Ap(xg,xg.MAX),af=Ap(xg,xg.MOD),hf=Ap(xg,xg.STEP),uf=Ap(xg,xg.REFLECT),lf=Ap(xg,xg.DISTANCE),cf=Ap(xg,xg.DIFFERENCE),df=Ap(xg,xg.DOT),pf=Ap(xg,xg.CROSS),mf=Ap(xg,xg.POW),gf=Ap(xg,xg.POW,2),ff=Ap(xg,xg.POW,3),yf=Ap(xg,xg.POW,4),xf=Ap(xg,xg.TRANSFORM_DIRECTION),bf=e=>Km(Hg(e),mf(jg(e),1/3)),vf=e=>df(e,e),Tf=Ap(xg,xg.MIX),_f=(e,t=0,s=1)=>Sp(new xg(xg.CLAMP,Sp(e),Sp(t),Sp(s))),wf=e=>_f(e),Sf=Ap(xg,xg.REFRACT),Mf=Ap(xg,xg.SMOOTHSTEP),Nf=Ap(xg,xg.FACEFORWARD),Af=Rp((([e])=>{const t=df(e.xy,Dp(12.9898,78.233)),s=af(t,Tg);return Og(Lg(s).mul(43758.5453))})),Cf=(e,t,s)=>Tf(t,s,e),Rf=(e,t,s)=>Mf(t,s,e);Jd("all",wg),Jd("any",Sg),Jd("equals",Mg),Jd("radians",Ng),Jd("degrees",Ag),Jd("exp",Cg),Jd("exp2",Rg),Jd("log",Eg),Jd("log2",Bg),Jd("sqrt",Ig),Jd("inverseSqrt",Pg),Jd("floor",Fg),Jd("ceil",zg),Jd("normalize",Ug),Jd("fract",Og),Jd("sin",Lg),Jd("cos",Vg),Jd("tan",Dg),Jd("asin",kg),Jd("acos",Gg),Jd("atan",Wg),Jd("abs",jg),Jd("sign",Hg),Jd("length",qg),Jd("lengthSq",vf),Jd("negate",$g),Jd("oneMinus",Xg),Jd("dFdx",Yg),Jd("dFdy",Zg),Jd("round",Jg),Jd("reciprocal",Kg),Jd("trunc",Qg),Jd("fwidth",ef),Jd("atan2",rf),Jd("min",nf),Jd("max",of),Jd("mod",af),Jd("step",hf),Jd("reflect",uf),Jd("distance",lf),Jd("dot",df),Jd("cross",pf),Jd("pow",mf),Jd("pow2",gf),Jd("pow3",ff),Jd("pow4",yf),Jd("transformDirection",xf),Jd("mix",Cf),Jd("clamp",_f),Jd("refract",Sf),Jd("smoothstep",Rf),Jd("faceForward",Nf),Jd("difference",cf),Jd("saturate",wf),Jd("cbrt",bf),Jd("transpose",sf),Jd("rand",Af);class Ef extends Ld{static get type(){return"ConditionalNode"}constructor(e,t,s=null){super(),this.condNode=e,this.ifNode=t,this.elseNode=s}getNodeType(e){const t=this.ifNode.getNodeType(e);if(null!==this.elseNode){const s=this.elseNode.getNodeType(e);if(e.getTypeLength(s)>e.getTypeLength(t))return s}return t}setup(e){const t=this.condNode.cache(),s=this.ifNode.cache(),i=this.elseNode?this.elseNode.cache():null,r=e.context.nodeBlock;e.getDataFromNode(s).parentNodeBlock=r,null!==i&&(e.getDataFromNode(i).parentNodeBlock=r);const n=e.getNodeProperties(this);n.condNode=t,n.ifNode=s.context({nodeBlock:s}),n.elseNode=i?i.context({nodeBlock:i}):null}generate(e,t){const s=this.getNodeType(e),i=e.getDataFromNode(this);if(void 0!==i.nodeProperty)return i.nodeProperty;const{condNode:r,ifNode:n,elseNode:o}=e.getNodeProperties(this),a="void"!==t,h=a?gm(s).build(e):"";i.nodeProperty=h;const u=r.build(e,"bool");e.addFlowCode(`\n${e.tab}if ( ${u} ) {\n\n`).addFlowTab();let l=n.build(e,s);if(l&&(l=a?h+" = "+l+";":"return "+l+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+l+"\n\n"+e.tab+"}"),null!==o){e.addFlowCode(" else {\n\n").addFlowTab();let t=o.build(e,s);t&&(t=a?h+" = "+t+";":"return "+t+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+t+"\n\n"+e.tab+"}\n\n")}else e.addFlowCode("\n\n");return e.format(h,s,t)}}const Bf=Ap(Ef);Jd("select",Bf);const If=(...e)=>(console.warn("TSL.ConditionalNode: cond() has been renamed to select()."),Bf(...e));Jd("cond",If);class Pf extends Ld{static get type(){return"ContextNode"}constructor(e,t={}){super(),this.isContextNode=!0,this.node=e,this.value=t}getScope(){return this.node.getScope()}getNodeType(e){return this.node.getNodeType(e)}analyze(e){this.node.build(e)}setup(e){const t=e.getContext();e.setContext({...e.context,...this.value});const s=this.node.build(e);return e.setContext(t),s}generate(e,t){const s=e.getContext();e.setContext({...e.context,...this.value});const i=this.node.build(e,t);return e.setContext(s),i}}const Ff=Ap(Pf),zf=(e,t)=>Ff(e,{label:t});Jd("context",Ff),Jd("label",zf);class Uf extends Ld{static get type(){return"VarNode"}constructor(e,t=null){super(),this.node=e,this.name=t,this.global=!0,this.isVarNode=!0}getHash(e){return this.name||super.getHash(e)}getNodeType(e){return this.node.getNodeType(e)}generate(e){const{node:t,name:s}=this,i=e.getVarFromNode(this,s,e.getVectorType(this.getNodeType(e))),r=e.getPropertyName(i),n=t.build(e,i.type);return e.addLineFlowCode(`${r} = ${n}`,this),r}}const Of=Ap(Uf);Jd("temp",Of),Jd("toVar",((...e)=>Of(...e).append()));class Lf extends Ld{static get type(){return"VaryingNode"}constructor(e,t=null){super(),this.node=e,this.name=t,this.isVaryingNode=!0}isGlobal(){return!0}getHash(e){return this.name||super.getHash(e)}getNodeType(e){return this.node.getNodeType(e)}setupVarying(e){const t=e.getNodeProperties(this);let s=t.varying;if(void 0===s){const i=this.name,r=this.getNodeType(e);t.varying=s=e.getVaryingFromNode(this,i,r),t.node=this.node}return s.needsInterpolation||(s.needsInterpolation="fragment"===e.shaderStage),s}setup(e){this.setupVarying(e)}analyze(e){return this.setupVarying(e),this.node.analyze(e)}generate(e){const t=e.getNodeProperties(this),s=this.setupVarying(e);if(void 0===t.propertyName){const i=this.getNodeType(e),r=e.getPropertyName(s,Ed.VERTEX);e.flowNodeFromShaderStage(Ed.VERTEX,this.node,i,r),t.propertyName=r}return e.getPropertyName(s)}}const Vf=Ap(Lf);Jd("varying",Vf);const Df="WorkingColorSpace",kf="OutputColorSpace";function Gf(e){let t=null;return e===Jt?t="Linear":e===Zt&&(t="sRGB"),t}function Wf(e,t){return Gf(e)+"To"+Gf(t)}class jf extends kd{static get type(){return"ColorSpaceNode"}constructor(e,t,s){super("vec4"),this.colorNode=e,this.source=t,this.target=s}getColorSpace(e,t){return t===Df?ci.workingColorSpace:t===kf?e.context.outputColorSpace||e.renderer.outputColorSpace:t}setup(e){const{renderer:t}=e,{colorNode:s}=this,i=this.getColorSpace(e,this.source),r=this.getColorSpace(e,this.target);if(i===r)return s;const n=Wf(i,r);let o=null;const a=t.nodes.library.getColorSpaceFunction(n);return null!==a?o=Xp(a(s.rgb),s.a):(console.error("ColorSpaceNode: Unsupported Color Space configuration.",n),o=s),o}}const Hf=e=>Sp(new jf(Sp(e),Df,kf)),qf=e=>Sp(new jf(Sp(e),kf,Df)),$f=(e,t)=>Sp(new jf(Sp(e),Df,t)),Xf=(e,t)=>Sp(new jf(Sp(e),t,Df));Jd("toOutputColorSpace",Hf),Jd("toWorkingColorSpace",qf),Jd("workingToColorSpace",$f),Jd("colorSpaceToWorking",Xf);let Yf=class extends Vd{static get type(){return"ReferenceElementNode"}constructor(e,t){super(e,t),this.referenceNode=e,this.isReferenceElementNode=!0}getNodeType(){return this.referenceNode.uniformType}generate(e){const t=super.generate(e),s=this.referenceNode.getNodeType(),i=this.getNodeType();return e.format(t,s,i)}};class Zf extends Ld{static get type(){return"ReferenceBaseNode"}constructor(e,t,s=null,i=null){super(),this.property=e,this.uniformType=t,this.object=s,this.count=i,this.properties=e.split("."),this.reference=s,this.node=null,this.group=null,this.updateType=Bd.OBJECT}setGroup(e){return this.group=e,this}element(e){return Sp(new Yf(this,Sp(e)))}setNodeType(e){const t=pm(null,e).getSelf();null!==this.group&&t.setGroup(this.group),this.node=t}getNodeType(e){return null===this.node&&(this.updateReference(e),this.updateValue()),this.node.getNodeType(e)}getValueFromReference(e=this.reference){const{properties:t}=this;let s=e[t[0]];for(let e=1;eSp(new Jf(e,t,s));class Qf extends kd{static get type(){return"ToneMappingNode"}constructor(e,t=ty,s=null){super("vec3"),this.toneMapping=e,this.exposureNode=t,this.colorNode=s}getCacheKey(){return _d(super.getCacheKey(),this.toneMapping)}setup(e){const t=this.colorNode||e.context.color,s=this.toneMapping;if(0===s)return t;let i=null;const r=e.renderer.nodes.library.getToneMappingFunction(s);return null!==r?i=Xp(r(t.rgb,this.exposureNode),t.a):(console.error("ToneMappingNode: Unsupported Tone Mapping configuration.",s),i=t),i}}const ey=(e,t,s)=>Sp(new Qf(e,Sp(t),Sp(s))),ty=Kf("toneMappingExposure","float");Jd("toneMapping",((e,t,s)=>ey(t,s,e)));class sy extends $d{static get type(){return"BufferAttributeNode"}constructor(e,t=null,s=0,i=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferStride=s,this.bufferOffset=i,this.usage=Cs,this.instanced=!1,this.attribute=null,this.global=!0,e&&!0===e.isBufferAttribute&&(this.attribute=e,this.usage=e.usage,this.instanced=e.isInstancedBufferAttribute)}getHash(e){if(0===this.bufferStride&&0===this.bufferOffset){let t=e.globalCache.getData(this.value);return void 0===t&&(t={node:this},e.globalCache.setData(this.value,t)),t.node.uuid}return this.uuid}getNodeType(e){return null===this.bufferType&&(this.bufferType=e.getTypeFromAttribute(this.attribute)),this.bufferType}setup(e){if(null!==this.attribute)return;const t=this.getNodeType(e),s=this.value,i=e.getTypeLength(t),r=this.bufferStride||i,n=this.bufferOffset,o=!0===s.isInterleavedBuffer?s:new so(s,r),a=new ro(o,i,n);o.setUsage(this.usage),this.attribute=a,this.attribute.isInstancedBufferAttribute=this.instanced}generate(e){const t=this.getNodeType(e),s=e.getBufferAttributeFromNode(this,t),i=e.getPropertyName(s);let r=null;if("vertex"===e.shaderStage||"compute"===e.shaderStage)this.name=i,r=i;else{r=Vf(this).build(e,t)}return r}getInputType(){return"bufferAttribute"}setUsage(e){return this.usage=e,this.attribute&&!0===this.attribute.isBufferAttribute&&(this.attribute.usage=e),this}setInstanced(e){return this.instanced=e,this}}const iy=(e,t,s,i)=>Sp(new sy(e,t,s,i)),ry=(e,t,s,i)=>iy(e,t,s,i).setUsage(Rs),ny=(e,t,s,i)=>iy(e,t,s,i).setInstanced(!0),oy=(e,t,s,i)=>ry(e,t,s,i).setInstanced(!0);Jd("toAttribute",(e=>iy(e.value)));class ay extends Ld{static get type(){return"ComputeNode"}constructor(e,t,s=[64]){super("void"),this.isComputeNode=!0,this.computeNode=e,this.count=t,this.workgroupSize=s,this.dispatchCount=0,this.version=1,this.updateBeforeType=Bd.OBJECT,this.updateDispatchCount()}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){!0===e&&this.version++}updateDispatchCount(){const{count:e,workgroupSize:t}=this;let s=t[0];for(let e=1;eSp(new ay(Sp(e),t,s));Jd("compute",hy);class uy extends Ld{static get type(){return"CacheNode"}constructor(e,t=!0){super(),this.node=e,this.parent=t,this.isCacheNode=!0}getNodeType(e){return this.node.getNodeType(e)}build(e,...t){const s=e.getCache(),i=e.getCacheFromNode(this,this.parent);e.setCache(i);const r=this.node.build(e,...t);return e.setCache(s),r}}const ly=(e,...t)=>Sp(new uy(Sp(e),...t));Jd("cache",ly);class cy extends Ld{static get type(){return"BypassNode"}constructor(e,t){super(),this.isBypassNode=!0,this.outputNode=e,this.callNode=t}getNodeType(e){return this.outputNode.getNodeType(e)}generate(e){const t=this.callNode.build(e,"void");return""!==t&&e.addLineFlowCode(t,this),this.outputNode.build(e)}}const dy=Ap(cy);Jd("bypass",dy);class py extends Ld{static get type(){return"RemapNode"}constructor(e,t,s,i=Up(0),r=Up(1)){super(),this.node=e,this.inLowNode=t,this.inHighNode=s,this.outLowNode=i,this.outHighNode=r,this.doClamp=!0}setup(){const{node:e,inLowNode:t,inHighNode:s,outLowNode:i,outHighNode:r,doClamp:n}=this;let o=e.sub(t).div(s.sub(t));return!0===n&&(o=o.clamp()),o.mul(r.sub(i)).add(i)}}const my=Ap(py,null,null,{doClamp:!1}),gy=Ap(py);Jd("remap",my),Jd("remapClamp",gy);class fy extends Ld{static get type(){return"ExpressionNode"}constructor(e="",t="void"){super(t),this.snippet=e}generate(e,t){const s=this.getNodeType(e),i=this.snippet;if("void"!==s)return e.format(`( ${i} )`,s,t);e.addLineFlowCode(i,this)}}const yy=Ap(fy),xy=e=>(e?Bf(e,yy("discard")):yy("discard")).append(),by=()=>yy("return").append();Jd("discard",xy);class vy extends kd{static get type(){return"RenderOutputNode"}constructor(e,t,s){super("vec4"),this.colorNode=e,this.toneMapping=t,this.outputColorSpace=s,this.isRenderOutput=!0}setup({context:e}){let t=this.colorNode||e.color;const s=(null!==this.toneMapping?this.toneMapping:e.toneMapping)||0,i=(null!==this.outputColorSpace?this.outputColorSpace:e.outputColorSpace)||Yt;return 0!==s&&(t=t.toneMapping(s)),i!==Yt&&i!==ci.workingColorSpace&&(t=t.workingToColorSpace(i)),t}}const Ty=(e,t=null,s=null)=>Sp(new vy(Sp(e),t,s));function _y(e){console.warn("THREE.TSLBase: AddNodeElement has been removed in favor of tree-shaking. Trying add",e)}Jd("renderOutput",Ty);class wy extends Ld{static get type(){return"AttributeNode"}constructor(e,t=null){super(t),this.global=!0,this._attributeName=e}getHash(e){return this.getAttributeName(e)}getNodeType(e){let t=this.nodeType;if(null===t){const s=this.getAttributeName(e);if(e.hasGeometryAttribute(s)){const i=e.geometry.getAttribute(s);t=e.getTypeFromAttribute(i)}else t="float"}return t}setAttributeName(e){return this._attributeName=e,this}getAttributeName(){return this._attributeName}generate(e){const t=this.getAttributeName(e),s=this.getNodeType(e);if(!0===e.hasGeometryAttribute(t)){const i=e.geometry.getAttribute(t),r=e.getTypeFromAttribute(i),n=e.getAttribute(t,r);if("vertex"===e.shaderStage)return e.format(n.name,r,s);return Vf(this).build(e,s)}return console.warn(`AttributeNode: Vertex attribute "${t}" not found on geometry.`),e.generateConst(s)}serialize(e){super.serialize(e),e.global=this.global,e._attributeName=this._attributeName}deserialize(e){super.deserialize(e),this.global=e.global,this._attributeName=e._attributeName}}const Sy=(e,t)=>Sp(new wy(e,t)),My=e=>Sy("uv"+(e>0?e:""),"vec2");class Ny extends Ld{static get type(){return"TextureSizeNode"}constructor(e,t=null){super("uvec2"),this.isTextureSizeNode=!0,this.textureNode=e,this.levelNode=t}generate(e,t){const s=this.textureNode.build(e,"property"),i=null===this.levelNode?"0":this.levelNode.build(e,"int");return e.format(`${e.getMethod("textureDimensions")}( ${s}, ${i} )`,this.getNodeType(e),t)}}const Ay=Ap(Ny);class Cy extends dm{static get type(){return"MaxMipLevelNode"}constructor(e){super(0),this._textureNode=e,this.updateType=Bd.FRAME}get textureNode(){return this._textureNode}get texture(){return this._textureNode.value}update(){const e=this.texture,t=e.images,s=t&&t.length>0?t[0]&&t[0].image||t[0]:e.image;if(s&&void 0!==s.width){const{width:e,height:t}=s;this.value=Math.log2(Math.max(e,t))}}}const Ry=Ap(Cy);class Ey extends dm{static get type(){return"TextureNode"}constructor(e,t=null,s=null,i=null){super(e),this.isTextureNode=!0,this.uvNode=t,this.levelNode=s,this.biasNode=i,this.compareNode=null,this.depthNode=null,this.gradNode=null,this.sampler=!0,this.updateMatrix=!1,this.updateType=Bd.NONE,this.referenceNode=null,this._value=e,this._matrixUniform=null,this.setUpdateMatrix(null===t)}set value(e){this.referenceNode?this.referenceNode.value=e:this._value=e}get value(){return this.referenceNode?this.referenceNode.value:this._value}getUniformHash(){return this.value.uuid}getNodeType(){return!0===this.value.isDepthTexture?"float":this.value.type===Be?"uvec4":this.value.type===Ee?"ivec4":"vec4"}getInputType(){return"texture"}getDefaultUV(){return My(this.value.channel)}updateReference(){return this.value}getTransformedUV(e){return null===this._matrixUniform&&(this._matrixUniform=pm(this.value.matrix)),this._matrixUniform.mul(jp(e,1)).xy}setUpdateMatrix(e){return this.updateMatrix=e,this.updateType=e?Bd.FRAME:Bd.NONE,this}setupUV(e,t){const s=this.value;return!e.isFlipY()||!0!==s.isRenderTargetTexture&&!0!==s.isFramebufferTexture&&!0!==s.isDepthTexture||(t=this.sampler?t.flipY():t.setY(Op(Ay(this,this.levelNode).y).sub(t.y).sub(1))),t}setup(e){const t=e.getNodeProperties(this);t.referenceNode=this.referenceNode;let s=this.uvNode;null!==s&&!0!==e.context.forceUVContext||!e.context.getUV||(s=e.context.getUV(this)),s||(s=this.getDefaultUV()),!0===this.updateMatrix&&(s=this.getTransformedUV(s)),s=this.setupUV(e,s);let i=this.levelNode;null===i&&e.context.getTextureLevel&&(i=e.context.getTextureLevel(this)),t.uvNode=s,t.levelNode=i,t.biasNode=this.biasNode,t.compareNode=this.compareNode,t.gradNode=this.gradNode,t.depthNode=this.depthNode}generateUV(e,t){return t.build(e,!0===this.sampler?"vec2":"ivec2")}generateSnippet(e,t,s,i,r,n,o,a){const h=this.value;let u;return u=i?e.generateTextureLevel(h,t,s,i,n):r?e.generateTextureBias(h,t,s,r,n):a?e.generateTextureGrad(h,t,s,a,n):o?e.generateTextureCompare(h,t,s,o,n):!1===this.sampler?e.generateTextureLoad(h,t,s,n):e.generateTexture(h,t,s,n),u}generate(e,t){const s=e.getNodeProperties(this),i=this.value;if(!i||!0!==i.isTexture)throw new Error("TextureNode: Need a three.js texture.");const r=super.generate(e,"property");if("sampler"===t)return r+"_sampler";if(e.isReference(t))return r;{const n=e.getDataFromNode(this);let o=n.propertyName;if(void 0===o){const{uvNode:t,levelNode:i,biasNode:a,compareNode:h,depthNode:u,gradNode:l}=s,c=this.generateUV(e,t),d=i?i.build(e,"float"):null,p=a?a.build(e,"float"):null,m=u?u.build(e,"int"):null,g=h?h.build(e,"float"):null,f=l?[l[0].build(e,"vec2"),l[1].build(e,"vec2")]:null,y=e.getVarFromNode(this);o=e.getPropertyName(y);const x=this.generateSnippet(e,r,c,d,p,m,g,f);e.addLineFlowCode(`${o} = ${x}`,this),n.snippet=x,n.propertyName=o}let a=o;const h=this.getNodeType(e);return e.needsToWorkingColorSpace(i)&&(a=Xf(yy(a,h),i.colorSpace).setup(e).build(e,h)),e.format(a,h,t)}}setSampler(e){return this.sampler=e,this}getSampler(){return this.sampler}uv(e){const t=this.clone();return t.uvNode=Sp(e),t.referenceNode=this.getSelf(),Sp(t)}blur(e){const t=this.clone();return t.biasNode=Sp(e).mul(Ry(t)),t.referenceNode=this.getSelf(),Sp(t)}level(e){const t=this.clone();return t.levelNode=Sp(e),t.referenceNode=this.getSelf(),Sp(t)}size(e){return Ay(this,e)}bias(e){const t=this.clone();return t.biasNode=Sp(e),t.referenceNode=this.getSelf(),Sp(t)}compare(e){const t=this.clone();return t.compareNode=Sp(e),t.referenceNode=this.getSelf(),Sp(t)}grad(e,t){const s=this.clone();return s.gradNode=[Sp(e),Sp(t)],s.referenceNode=this.getSelf(),Sp(s)}depth(e){const t=this.clone();return t.depthNode=Sp(e),t.referenceNode=this.getSelf(),Sp(t)}serialize(e){super.serialize(e),e.value=this.value.toJSON(e.meta).uuid,e.sampler=this.sampler,e.updateMatrix=this.updateMatrix,e.updateType=this.updateType}deserialize(e){super.deserialize(e),this.value=e.meta.textures[e.value],this.sampler=e.sampler,this.updateMatrix=e.updateMatrix,this.updateType=e.updateType}update(){const e=this.value,t=this._matrixUniform;null!==t&&(t.value=e.matrix),!0===e.matrixAutoUpdate&&e.updateMatrix()}clone(){const e=new this.constructor(this.value,this.uvNode,this.levelNode,this.biasNode);return e.sampler=this.sampler,e}}const By=Ap(Ey),Iy=(...e)=>By(...e).setSampler(!1),Py=e=>(!0===e.isNode?e:By(e)).convert("sampler"),Fy=pm("float").label("cameraNear").setGroup(lm).onRenderUpdate((({camera:e})=>e.near)),zy=pm("float").label("cameraFar").setGroup(lm).onRenderUpdate((({camera:e})=>e.far)),Uy=pm("float").label("cameraLogDepth").setGroup(lm).onRenderUpdate((({camera:e})=>2/(Math.log(e.far+1)/Math.LN2))),Oy=pm("mat4").label("cameraProjectionMatrix").setGroup(lm).onRenderUpdate((({camera:e})=>e.projectionMatrix)),Ly=pm("mat4").label("cameraProjectionMatrixInverse").setGroup(lm).onRenderUpdate((({camera:e})=>e.projectionMatrixInverse)),Vy=pm("mat4").label("cameraViewMatrix").setGroup(lm).onRenderUpdate((({camera:e})=>e.matrixWorldInverse)),Dy=pm("mat4").label("cameraWorldMatrix").setGroup(lm).onRenderUpdate((({camera:e})=>e.matrixWorld)),ky=pm("mat3").label("cameraNormalMatrix").setGroup(lm).onRenderUpdate((({camera:e})=>e.normalMatrix)),Gy=pm(new Ri).label("cameraPosition").setGroup(lm).onRenderUpdate((({camera:e},t)=>t.value.setFromMatrixPosition(e.matrixWorld)));class Wy extends Ld{static get type(){return"Object3DNode"}constructor(e,t=null){super(),this.scope=e,this.object3d=t,this.updateType=Bd.OBJECT,this._uniformNode=new dm(null)}getNodeType(){const e=this.scope;return e===Wy.WORLD_MATRIX?"mat4":e===Wy.POSITION||e===Wy.VIEW_POSITION||e===Wy.DIRECTION||e===Wy.SCALE?"vec3":void 0}update(e){const t=this.object3d,s=this._uniformNode,i=this.scope;if(i===Wy.WORLD_MATRIX)s.value=t.matrixWorld;else if(i===Wy.POSITION)s.value=s.value||new Ri,s.value.setFromMatrixPosition(t.matrixWorld);else if(i===Wy.SCALE)s.value=s.value||new Ri,s.value.setFromMatrixScale(t.matrixWorld);else if(i===Wy.DIRECTION)s.value=s.value||new Ri,t.getWorldDirection(s.value);else if(i===Wy.VIEW_POSITION){const i=e.camera;s.value=s.value||new Ri,s.value.setFromMatrixPosition(t.matrixWorld),s.value.applyMatrix4(i.matrixWorldInverse)}}generate(e){const t=this.scope;return t===Wy.WORLD_MATRIX?this._uniformNode.nodeType="mat4":t!==Wy.POSITION&&t!==Wy.VIEW_POSITION&&t!==Wy.DIRECTION&&t!==Wy.SCALE||(this._uniformNode.nodeType="vec3"),this._uniformNode.build(e)}serialize(e){super.serialize(e),e.scope=this.scope}deserialize(e){super.deserialize(e),this.scope=e.scope}}Wy.WORLD_MATRIX="worldMatrix",Wy.POSITION="position",Wy.SCALE="scale",Wy.VIEW_POSITION="viewPosition",Wy.DIRECTION="direction";const jy=Ap(Wy,Wy.DIRECTION),Hy=Ap(Wy,Wy.WORLD_MATRIX),qy=Ap(Wy,Wy.POSITION),$y=Ap(Wy,Wy.SCALE),Xy=Ap(Wy,Wy.VIEW_POSITION);class Yy extends Wy{static get type(){return"ModelNode"}constructor(e){super(e)}update(e){this.object3d=e.object,super.update(e)}}const Zy=Cp(Yy,Yy.DIRECTION),Jy=Cp(Yy,Yy.WORLD_MATRIX),Ky=Cp(Yy,Yy.POSITION),Qy=Cp(Yy,Yy.SCALE),ex=Cp(Yy,Yy.VIEW_POSITION),tx=pm(new ei).onObjectUpdate((({object:e},t)=>t.value.getNormalMatrix(e.matrixWorld))),sx=pm(new nr).onObjectUpdate((({object:e},t)=>t.value.copy(e.matrixWorld).invert())),ix=Vy.mul(Jy).toVar("modelViewMatrix"),rx=Rp((e=>(e.context.isHighPrecisionModelViewMatrix=!0,pm("mat4").onObjectUpdate((({object:e,camera:t})=>e.modelViewMatrix.multiplyMatrices(t.matrixWorldInverse,e.matrixWorld)))))).once()().toVar("highPrecisionModelViewMatrix"),nx=Rp((e=>{const t=e.context.isHighPrecisionModelViewMatrix;return pm("mat3").onObjectUpdate((({object:e,camera:s})=>(!0!==t&&e.modelViewMatrix.multiplyMatrices(s.matrixWorldInverse,e.matrixWorld),e.normalMatrix.getNormalMatrix(e.modelViewMatrix))))})).once()().toVar("highPrecisionModelNormalMatrix"),ox=Sy("position","vec3"),ax=ox.varying("positionLocal"),hx=ox.varying("positionPrevious"),ux=Jy.mul(ax).xyz.varying("v_positionWorld"),lx=ax.transformDirection(Jy).varying("v_positionWorldDirection").normalize().toVar("positionWorldDirection"),cx=ix.mul(ax).xyz.varying("v_positionView"),dx=cx.negate().varying("v_positionViewDirection").normalize().toVar("positionViewDirection");class px extends Ld{static get type(){return"FrontFacingNode"}constructor(){super("bool"),this.isFrontFacingNode=!0}generate(e){const{renderer:t,material:s}=e;return t.coordinateSystem===Vs&&s.side===d?"false":e.getFrontFacing()}}const mx=Cp(px),gx=Up(mx).mul(2).sub(1),fx=Sy("normal","vec3"),yx=Rp((e=>!1===e.geometry.hasAttribute("normal")?(console.warn('TSL.NormalNode: Vertex attribute "normal" not found on geometry.'),jp(0,1,0)):fx),"vec3").once()().toVar("normalLocal"),xx=cx.dFdx().cross(cx.dFdy()).normalize().toVar("normalFlat"),bx=Rp((e=>{let t;return t=!0===e.material.flatShading?xx:Vf(Mx(yx),"v_normalView").normalize(),t}),"vec3").once()().toVar("normalView"),vx=Vf(bx.transformDirection(Vy),"v_normalWorld").normalize().toVar("normalWorld"),Tx=Rp((e=>e.context.setupNormal()),"vec3").once()().mul(gx).toVar("transformedNormalView"),_x=Tx.transformDirection(Vy).toVar("transformedNormalWorld"),wx=Rp((e=>e.context.setupClearcoatNormal()),"vec3").once()().mul(gx).toVar("transformedClearcoatNormalView"),Sx=Rp((([e,t=Jy])=>{const s=Qp(t),i=e.div(jp(s[0].dot(s[0]),s[1].dot(s[1]),s[2].dot(s[2])));return s.mul(i).xyz})),Mx=Rp((([e],t)=>{const s=t.renderer.nodes.modelNormalViewMatrix;if(null!==s)return s.transformDirection(e);const i=tx.mul(e);return Vy.transformDirection(i)})),Nx=pm(0).onReference((({material:e})=>e)).onRenderUpdate((({material:e})=>e.refractionRatio)),Ax=dx.negate().reflect(Tx),Cx=dx.negate().refract(Tx,Nx),Rx=Ax.transformDirection(Vy).toVar("reflectVector"),Ex=Cx.transformDirection(Vy).toVar("reflectVector");class Bx extends Ey{static get type(){return"CubeTextureNode"}constructor(e,t=null,s=null,i=null){super(e,t,s,i),this.isCubeTextureNode=!0}getInputType(){return"cubeTexture"}getDefaultUV(){const e=this.value;return e.mapping===he?Rx:e.mapping===ue?Ex:(console.error('THREE.CubeTextureNode: Mapping "%s" not supported.',e.mapping),jp(0,0,0))}setUpdateMatrix(){}setupUV(e,t){const s=this.value;return e.renderer.coordinateSystem!==Ds&&s.isRenderTargetTexture?t:jp(t.x.negate(),t.yz)}generateUV(e,t){return t.build(e,"vec3")}}const Ix=Ap(Bx);class Px extends dm{static get type(){return"BufferNode"}constructor(e,t,s=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferCount=s}getElementType(e){return this.getNodeType(e)}getInputType(){return"buffer"}}const Fx=(e,t,s)=>Sp(new Px(e,t,s));class zx extends Vd{static get type(){return"UniformArrayElementNode"}constructor(e,t){super(e,t),this.isArrayBufferElementNode=!0}generate(e){const t=super.generate(e),s=this.getNodeType();return e.format(t,"vec4",s)}}class Ux extends Px{static get type(){return"UniformArrayNode"}constructor(e,t=null){super(null,"vec4"),this.array=e,this.elementType=t,this._elementType=null,this._elementLength=0,this.updateType=Bd.RENDER,this.isArrayBufferNode=!0}getElementType(){return this.elementType||this._elementType}getElementLength(){return this._elementLength}update(){const{array:e,value:t}=this,s=this.getElementLength(),i=this.getElementType();if(1===s)for(let s=0;sSp(new Ux(e,t)),Lx=(e,t)=>(console.warn("TSL.UniformArrayNode: uniforms() has been renamed to uniformArray()."),Sp(new Ux(e,t)));class Vx extends Vd{static get type(){return"ReferenceElementNode"}constructor(e,t){super(e,t),this.referenceNode=e,this.isReferenceElementNode=!0}getNodeType(){return this.referenceNode.uniformType}generate(e){const t=super.generate(e),s=this.referenceNode.getNodeType(),i=this.getNodeType();return e.format(t,s,i)}}class Dx extends Ld{static get type(){return"ReferenceNode"}constructor(e,t,s=null,i=null){super(),this.property=e,this.uniformType=t,this.object=s,this.count=i,this.properties=e.split("."),this.reference=s,this.node=null,this.group=null,this.name=null,this.updateType=Bd.OBJECT}element(e){return Sp(new Vx(this,Sp(e)))}setGroup(e){return this.group=e,this}label(e){return this.name=e,this}setNodeType(e){let t=null;t=null!==this.count?Fx(null,e,this.count):Array.isArray(this.getValueFromReference())?Ox(null,e):"texture"===e?By(null):"cubeTexture"===e?Ix(null):pm(null,e),null!==this.group&&t.setGroup(this.group),null!==this.name&&t.label(this.name),this.node=t.getSelf()}getNodeType(e){return null===this.node&&(this.updateReference(e),this.updateValue()),this.node.getNodeType(e)}getValueFromReference(e=this.reference){const{properties:t}=this;let s=e[t[0]];for(let e=1;eSp(new Dx(e,t,s)),Gx=(e,t,s,i)=>Sp(new Dx(e,t,i,s));class Wx extends Dx{static get type(){return"MaterialReferenceNode"}constructor(e,t,s=null){super(e,t,s),this.material=s,this.isMaterialReferenceNode=!0}updateReference(e){return this.reference=null!==this.material?this.material:e.material,this.reference}}const jx=(e,t,s)=>Sp(new Wx(e,t,s)),Hx=Rp((e=>(!1===e.geometry.hasAttribute("tangent")&&e.geometry.computeTangents(),Sy("tangent","vec4"))))(),qx=Hx.xyz.toVar("tangentLocal"),$x=ix.mul(Xp(qx,0)).xyz.varying("v_tangentView").normalize().toVar("tangentView"),Xx=$x.transformDirection(Vy).varying("v_tangentWorld").normalize().toVar("tangentWorld"),Yx=$x.toVar("transformedTangentView"),Zx=Yx.transformDirection(Vy).normalize().toVar("transformedTangentWorld"),Jx=e=>e.mul(Hx.w).xyz,Kx=Vf(Jx(fx.cross(Hx)),"v_bitangentGeometry").normalize().toVar("bitangentGeometry"),Qx=Vf(Jx(yx.cross(qx)),"v_bitangentLocal").normalize().toVar("bitangentLocal"),eb=Vf(Jx(bx.cross($x)),"v_bitangentView").normalize().toVar("bitangentView"),tb=Vf(Jx(vx.cross(Xx)),"v_bitangentWorld").normalize().toVar("bitangentWorld"),sb=Jx(Tx.cross(Yx)).normalize().toVar("transformedBitangentView"),ib=sb.transformDirection(Vy).normalize().toVar("transformedBitangentWorld"),rb=Qp($x,eb,bx),nb=dx.mul(rb),ob=(e,t)=>e.sub(nb.mul(t)),ab=(()=>{let e=Bm.cross(dx);return e=e.cross(Bm).normalize(),e=Tf(e,Tx,Rm.mul(bm.oneMinus()).oneMinus().pow2().pow2()).normalize(),e})(),hb=Rp((e=>{const{eye_pos:t,surf_norm:s,mapN:i,uv:r}=e,n=t.dFdx(),o=t.dFdy(),a=r.dFdx(),h=r.dFdy(),u=s,l=o.cross(u),c=u.cross(n),d=l.mul(a.x).add(c.mul(h.x)),p=l.mul(a.y).add(c.mul(h.y)),m=d.dot(d).max(p.dot(p)),g=gx.mul(m.inverseSqrt());return Zm(d.mul(i.x,g),p.mul(i.y,g),u.mul(i.z)).normalize()}));class ub extends kd{static get type(){return"NormalMapNode"}constructor(e,t=null){super("vec3"),this.node=e,this.scaleNode=t,this.normalMapType=0}setup(e){const{normalMapType:t,scaleNode:s}=this;let i=this.node.mul(2).sub(1);null!==s&&(i=jp(i.xy.mul(s),i.z));let r=null;if(1===t)r=Mx(i);else if(0===t){r=!0===e.hasGeometryAttribute("tangent")?rb.mul(i).normalize():hb({eye_pos:cx,surf_norm:bx,mapN:i,uv:My()})}return r}}const lb=Ap(ub),cb=Rp((({textureNode:e,bumpScale:t})=>{const s=t=>e.cache().context({getUV:e=>t(e.uvNode||My()),forceUVContext:!0}),i=Up(s((e=>e)));return Dp(Up(s((e=>e.add(e.dFdx())))).sub(i),Up(s((e=>e.add(e.dFdy())))).sub(i)).mul(t)})),db=Rp((e=>{const{surf_pos:t,surf_norm:s,dHdxy:i}=e,r=t.dFdx().normalize(),n=s,o=t.dFdy().normalize().cross(n),a=n.cross(r),h=r.dot(o).mul(gx),u=h.sign().mul(i.x.mul(o).add(i.y.mul(a)));return h.abs().mul(s).sub(u).normalize()}));class pb extends kd{static get type(){return"BumpMapNode"}constructor(e,t=null){super("vec3"),this.textureNode=e,this.scaleNode=t}setup(){const e=null!==this.scaleNode?this.scaleNode:1,t=cb({textureNode:this.textureNode,bumpScale:e});return db({surf_pos:cx,surf_norm:bx,dHdxy:t})}}const mb=Ap(pb),gb=new Map;class fb extends Ld{static get type(){return"MaterialNode"}constructor(e){super(),this.scope=e}getCache(e,t){let s=gb.get(e);return void 0===s&&(s=jx(e,t),gb.set(e,s)),s}getFloat(e){return this.getCache(e,"float")}getColor(e){return this.getCache(e,"color")}getTexture(e){return this.getCache("map"===e?"map":e+"Map","texture")}setup(e){const t=e.context.material,s=this.scope;let i=null;if(s===fb.COLOR){const e=void 0!==t.color?this.getColor(s):jp();i=t.map&&!0===t.map.isTexture?e.mul(this.getTexture("map")):e}else if(s===fb.OPACITY){const e=this.getFloat(s);i=t.alphaMap&&!0===t.alphaMap.isTexture?e.mul(this.getTexture("alpha")):e}else if(s===fb.SPECULAR_STRENGTH)i=t.specularMap&&!0===t.specularMap.isTexture?this.getTexture("specular").r:Up(1);else if(s===fb.SPECULAR_INTENSITY){const e=this.getFloat(s);i=t.specularMap?e.mul(this.getTexture(s).a):e}else if(s===fb.SPECULAR_COLOR){const e=this.getColor(s);i=t.specularColorMap&&!0===t.specularColorMap.isTexture?e.mul(this.getTexture(s).rgb):e}else if(s===fb.ROUGHNESS){const e=this.getFloat(s);i=t.roughnessMap&&!0===t.roughnessMap.isTexture?e.mul(this.getTexture(s).g):e}else if(s===fb.METALNESS){const e=this.getFloat(s);i=t.metalnessMap&&!0===t.metalnessMap.isTexture?e.mul(this.getTexture(s).b):e}else if(s===fb.EMISSIVE){const e=this.getFloat("emissiveIntensity"),r=this.getColor(s).mul(e);i=t.emissiveMap&&!0===t.emissiveMap.isTexture?r.mul(this.getTexture(s)):r}else if(s===fb.NORMAL)t.normalMap?(i=lb(this.getTexture("normal"),this.getCache("normalScale","vec2")),i.normalMapType=t.normalMapType):i=t.bumpMap?mb(this.getTexture("bump").r,this.getFloat("bumpScale")):bx;else if(s===fb.CLEARCOAT){const e=this.getFloat(s);i=t.clearcoatMap&&!0===t.clearcoatMap.isTexture?e.mul(this.getTexture(s).r):e}else if(s===fb.CLEARCOAT_ROUGHNESS){const e=this.getFloat(s);i=t.clearcoatRoughnessMap&&!0===t.clearcoatRoughnessMap.isTexture?e.mul(this.getTexture(s).r):e}else if(s===fb.CLEARCOAT_NORMAL)i=t.clearcoatNormalMap?lb(this.getTexture(s),this.getCache(s+"Scale","vec2")):bx;else if(s===fb.SHEEN){const e=this.getColor("sheenColor").mul(this.getFloat("sheen"));i=t.sheenColorMap&&!0===t.sheenColorMap.isTexture?e.mul(this.getTexture("sheenColor").rgb):e}else if(s===fb.SHEEN_ROUGHNESS){const e=this.getFloat(s);i=t.sheenRoughnessMap&&!0===t.sheenRoughnessMap.isTexture?e.mul(this.getTexture(s).a):e,i=i.clamp(.07,1)}else if(s===fb.ANISOTROPY)if(t.anisotropyMap&&!0===t.anisotropyMap.isTexture){const e=this.getTexture(s);i=Kp(ev.x,ev.y,ev.y.negate(),ev.x).mul(e.rg.mul(2).sub(Dp(1)).normalize().mul(e.b))}else i=ev;else if(s===fb.IRIDESCENCE_THICKNESS){const e=kx("1","float",t.iridescenceThicknessRange);if(t.iridescenceThicknessMap){const r=kx("0","float",t.iridescenceThicknessRange);i=e.sub(r).mul(this.getTexture(s).g).add(r)}else i=e}else if(s===fb.TRANSMISSION){const e=this.getFloat(s);i=t.transmissionMap?e.mul(this.getTexture(s).r):e}else if(s===fb.THICKNESS){const e=this.getFloat(s);i=t.thicknessMap?e.mul(this.getTexture(s).g):e}else if(s===fb.IOR)i=this.getFloat(s);else if(s===fb.LIGHT_MAP)i=this.getTexture(s).rgb.mul(this.getFloat("lightMapIntensity"));else if(s===fb.AO_MAP)i=this.getTexture(s).r.sub(1).mul(this.getFloat("aoMapIntensity")).add(1);else{const t=this.getNodeType(e);i=this.getCache(s,t)}return i}}fb.ALPHA_TEST="alphaTest",fb.COLOR="color",fb.OPACITY="opacity",fb.SHININESS="shininess",fb.SPECULAR="specular",fb.SPECULAR_STRENGTH="specularStrength",fb.SPECULAR_INTENSITY="specularIntensity",fb.SPECULAR_COLOR="specularColor",fb.REFLECTIVITY="reflectivity",fb.ROUGHNESS="roughness",fb.METALNESS="metalness",fb.NORMAL="normal",fb.CLEARCOAT="clearcoat",fb.CLEARCOAT_ROUGHNESS="clearcoatRoughness",fb.CLEARCOAT_NORMAL="clearcoatNormal",fb.EMISSIVE="emissive",fb.ROTATION="rotation",fb.SHEEN="sheen",fb.SHEEN_ROUGHNESS="sheenRoughness",fb.ANISOTROPY="anisotropy",fb.IRIDESCENCE="iridescence",fb.IRIDESCENCE_IOR="iridescenceIOR",fb.IRIDESCENCE_THICKNESS="iridescenceThickness",fb.IOR="ior",fb.TRANSMISSION="transmission",fb.THICKNESS="thickness",fb.ATTENUATION_DISTANCE="attenuationDistance",fb.ATTENUATION_COLOR="attenuationColor",fb.LINE_SCALE="scale",fb.LINE_DASH_SIZE="dashSize",fb.LINE_GAP_SIZE="gapSize",fb.LINE_WIDTH="linewidth",fb.LINE_DASH_OFFSET="dashOffset",fb.POINT_WIDTH="pointWidth",fb.DISPERSION="dispersion",fb.LIGHT_MAP="light",fb.AO_MAP="ao";const yb=Cp(fb,fb.ALPHA_TEST),xb=Cp(fb,fb.COLOR),bb=Cp(fb,fb.SHININESS),vb=Cp(fb,fb.EMISSIVE),Tb=Cp(fb,fb.OPACITY),_b=Cp(fb,fb.SPECULAR),wb=Cp(fb,fb.SPECULAR_INTENSITY),Sb=Cp(fb,fb.SPECULAR_COLOR),Mb=Cp(fb,fb.SPECULAR_STRENGTH),Nb=Cp(fb,fb.REFLECTIVITY),Ab=Cp(fb,fb.ROUGHNESS),Cb=Cp(fb,fb.METALNESS),Rb=Cp(fb,fb.NORMAL).context({getUV:null}),Eb=Cp(fb,fb.CLEARCOAT),Bb=Cp(fb,fb.CLEARCOAT_ROUGHNESS),Ib=Cp(fb,fb.CLEARCOAT_NORMAL).context({getUV:null}),Pb=Cp(fb,fb.ROTATION),Fb=Cp(fb,fb.SHEEN),zb=Cp(fb,fb.SHEEN_ROUGHNESS),Ub=Cp(fb,fb.ANISOTROPY),Ob=Cp(fb,fb.IRIDESCENCE),Lb=Cp(fb,fb.IRIDESCENCE_IOR),Vb=Cp(fb,fb.IRIDESCENCE_THICKNESS),Db=Cp(fb,fb.TRANSMISSION),kb=Cp(fb,fb.THICKNESS),Gb=Cp(fb,fb.IOR),Wb=Cp(fb,fb.ATTENUATION_DISTANCE),jb=Cp(fb,fb.ATTENUATION_COLOR),Hb=Cp(fb,fb.LINE_SCALE),qb=Cp(fb,fb.LINE_DASH_SIZE),$b=Cp(fb,fb.LINE_GAP_SIZE),Xb=Cp(fb,fb.LINE_WIDTH),Yb=Cp(fb,fb.LINE_DASH_OFFSET),Zb=Cp(fb,fb.POINT_WIDTH),Jb=Cp(fb,fb.DISPERSION),Kb=Cp(fb,fb.LIGHT_MAP),Qb=Cp(fb,fb.AO_MAP),ev=pm(new Qs).onReference((function(e){return e.material})).onRenderUpdate((function({material:e}){this.value.set(e.anisotropy*Math.cos(e.anisotropyRotation),e.anisotropy*Math.sin(e.anisotropyRotation))}));class tv extends kd{static get type(){return"ModelViewProjectionNode"}constructor(e=null){super("vec4"),this.positionNode=e}setup(e){if("fragment"===e.shaderStage)return Vf(e.context.mvp);const t=this.positionNode||ax,s=e.renderer.nodes.modelViewMatrix||ix;return Oy.mul(s).mul(t)}}const sv=Ap(tv);class iv extends Ld{static get type(){return"IndexNode"}constructor(e){super("uint"),this.scope=e,this.isInstanceIndexNode=!0}generate(e){const t=this.getNodeType(e),s=this.scope;let i,r;if(s===iv.VERTEX)i=e.getVertexIndex();else if(s===iv.INSTANCE)i=e.getInstanceIndex();else if(s===iv.DRAW)i=e.getDrawIndex();else if(s===iv.INVOCATION_LOCAL)i=e.getInvocationLocalIndex();else if(s===iv.INVOCATION_SUBGROUP)i=e.getInvocationSubgroupIndex();else{if(s!==iv.SUBGROUP)throw new Error("THREE.IndexNode: Unknown scope: "+s);i=e.getSubgroupIndex()}if("vertex"===e.shaderStage||"compute"===e.shaderStage)r=i;else{r=Vf(this).build(e,t)}return r}}iv.VERTEX="vertex",iv.INSTANCE="instance",iv.SUBGROUP="subgroup",iv.INVOCATION_LOCAL="invocationLocal",iv.INVOCATION_SUBGROUP="invocationSubgroup",iv.DRAW="draw";const rv=Cp(iv,iv.VERTEX),nv=Cp(iv,iv.INSTANCE),ov=Cp(iv,iv.SUBGROUP),av=Cp(iv,iv.INVOCATION_SUBGROUP),hv=Cp(iv,iv.INVOCATION_LOCAL),uv=Cp(iv,iv.DRAW);class lv extends Ld{static get type(){return"InstanceNode"}constructor(e){super("void"),this.instanceMesh=e,this.instanceMatrixNode=null,this.instanceColorNode=null,this.updateType=Bd.FRAME,this.buffer=null,this.bufferColor=null}setup(e){let t=this.instanceMatrixNode,s=this.instanceColorNode;const i=this.instanceMesh;if(null===t){const e=i.instanceMatrix;if(i.count<=1e3)t=Fx(e.array,"mat4",Math.max(i.count,1)).element(nv);else{const s=new wc(e.array,16,1);this.buffer=s;const i=e.usage===Rs?oy:ny,r=[i(s,"vec4",16,0),i(s,"vec4",16,4),i(s,"vec4",16,8),i(s,"vec4",16,12)];t=em(...r)}this.instanceMatrixNode=t}const r=i.instanceColor;if(r&&null===s){const e=new Do(r.array,3),t=r.usage===Rs?oy:ny;this.bufferColor=e,s=jp(t(e,"vec3",3,0)),this.instanceColorNode=s}const n=t.mul(ax).xyz;if(ax.assign(n),e.hasGeometryAttribute("normal")){const e=Sx(yx,t);yx.assign(e)}null!==this.instanceColorNode&&fm("vec3","vInstanceColor").assign(this.instanceColorNode)}update(){this.instanceMesh.instanceMatrix.usage!==Rs&&null!=this.buffer&&this.instanceMesh.instanceMatrix.version!==this.buffer.version&&(this.buffer.version=this.instanceMesh.instanceMatrix.version),this.instanceMesh.instanceColor&&this.instanceMesh.instanceColor.usage!==Rs&&null!=this.bufferColor&&this.instanceMesh.instanceColor.version!==this.bufferColor.version&&(this.bufferColor.version=this.instanceMesh.instanceColor.version)}}const cv=Ap(lv);class dv extends Ld{static get type(){return"BatchNode"}constructor(e){super("void"),this.batchMesh=e,this.batchingIdNode=null}setup(e){null===this.batchingIdNode&&(null===e.getDrawIndex()?this.batchingIdNode=nv:this.batchingIdNode=uv);const t=Rp((([e])=>{const t=Ay(Iy(this.batchMesh._indirectTexture),0),s=Op(e).modInt(Op(t)),i=Op(e).div(Op(t));return Iy(this.batchMesh._indirectTexture,kp(s,i)).x})).setLayout({name:"getIndirectIndex",type:"uint",inputs:[{name:"id",type:"int"}]}),s=t(Op(this.batchingIdNode)),i=this.batchMesh._matricesTexture,r=Ay(Iy(i),0),n=Up(s).mul(4).toInt().toVar(),o=n.modInt(r),a=n.div(Op(r)),h=em(Iy(i,kp(o,a)),Iy(i,kp(o.add(1),a)),Iy(i,kp(o.add(2),a)),Iy(i,kp(o.add(3),a))),u=this.batchMesh._colorsTexture;if(null!==u){const e=Rp((([e])=>{const t=Ay(Iy(u),0).x,s=e,i=s.modInt(t),r=s.div(t);return Iy(u,kp(i,r)).rgb})).setLayout({name:"getBatchingColor",type:"vec3",inputs:[{name:"id",type:"int"}]}),t=e(s);fm("vec3","vBatchColor").assign(t)}const l=Qp(h);ax.assign(h.mul(ax));const c=yx.div(jp(l[0].dot(l[0]),l[1].dot(l[1]),l[2].dot(l[2]))),d=l.mul(c).xyz;yx.assign(d),e.hasGeometryAttribute("tangent")&&qx.mulAssign(l)}}const pv=Ap(dv),mv=new WeakMap;class gv extends Ld{static get type(){return"SkinningNode"}constructor(e,t=!1){let s,i,r;super("void"),this.skinnedMesh=e,this.useReference=t,this.updateType=Bd.OBJECT,this.skinIndexNode=Sy("skinIndex","uvec4"),this.skinWeightNode=Sy("skinWeight","vec4"),t?(s=kx("bindMatrix","mat4"),i=kx("bindMatrixInverse","mat4"),r=Gx("skeleton.boneMatrices","mat4",e.skeleton.bones.length)):(s=pm(e.bindMatrix,"mat4"),i=pm(e.bindMatrixInverse,"mat4"),r=Fx(e.skeleton.boneMatrices,"mat4",e.skeleton.bones.length)),this.bindMatrixNode=s,this.bindMatrixInverseNode=i,this.boneMatricesNode=r,this.previousBoneMatricesNode=null}getSkinnedPosition(e=this.boneMatricesNode,t=ax){const{skinIndexNode:s,skinWeightNode:i,bindMatrixNode:r,bindMatrixInverseNode:n}=this,o=e.element(s.x),a=e.element(s.y),h=e.element(s.z),u=e.element(s.w),l=r.mul(t),c=Zm(o.mul(i.x).mul(l),a.mul(i.y).mul(l),h.mul(i.z).mul(l),u.mul(i.w).mul(l));return n.mul(c).xyz}getSkinnedNormal(e=this.boneMatricesNode,t=yx){const{skinIndexNode:s,skinWeightNode:i,bindMatrixNode:r,bindMatrixInverseNode:n}=this,o=e.element(s.x),a=e.element(s.y),h=e.element(s.z),u=e.element(s.w);let l=Zm(i.x.mul(o),i.y.mul(a),i.z.mul(h),i.w.mul(u));return l=n.mul(l).mul(r),l.transformDirection(t).xyz}getPreviousSkinnedPosition(e){const t=e.object;return null===this.previousBoneMatricesNode&&(t.skeleton.previousBoneMatrices=new Float32Array(t.skeleton.boneMatrices),this.previousBoneMatricesNode=Gx("skeleton.previousBoneMatrices","mat4",t.skeleton.bones.length)),this.getSkinnedPosition(this.previousBoneMatricesNode,hx)}needsPreviousBoneMatrices(e){const t=e.renderer.getMRT();return t&&t.has("velocity")}setup(e){this.needsPreviousBoneMatrices(e)&&hx.assign(this.getPreviousSkinnedPosition(e));const t=this.getSkinnedPosition();if(ax.assign(t),e.hasGeometryAttribute("normal")){const t=this.getSkinnedNormal();yx.assign(t),e.hasGeometryAttribute("tangent")&&qx.assign(t)}}generate(e,t){if("void"!==t)return ax.build(e,t)}update(e){const t=(this.useReference?e.object:this.skinnedMesh).skeleton;mv.get(t)!==e.frameId&&(mv.set(t,e.frameId),null!==this.previousBoneMatricesNode&&t.previousBoneMatrices.set(t.boneMatrices),t.update())}}const fv=e=>Sp(new gv(e)),yv=e=>Sp(new gv(e,!0));class xv extends Ld{static get type(){return"LoopNode"}constructor(e=[]){super(),this.params=e}getVarName(e){return String.fromCharCode("i".charCodeAt()+e)}getProperties(e){const t=e.getNodeProperties(this);if(void 0!==t.stackNode)return t;const s={};for(let e=0,t=this.params.length-1;eNumber(n)?">=":"<"));const l={start:r,end:n,condition:h},c=l.start,d=l.end;let p="",m="",g="";u||(u="int"===a||"uint"===a?h.includes("<")?"++":"--":h.includes("<")?"+= 1.":"-= 1."),p+=e.getVar(a,o)+" = "+c,m+=o+" "+h+" "+d,g+=o+" "+u;const f=`for ( ${p}; ${m}; ${g} )`;e.addFlowCode((0===t?"\n":"")+e.tab+f+" {\n\n").addFlowTab()}const r=i.build(e,"void"),n=t.returnsNode?t.returnsNode.build(e):"";e.removeFlowTab().addFlowCode("\n"+e.tab+r);for(let t=0,s=this.params.length-1;tSp(new xv(Np(e,"int"))).append(),vv=()=>yy("continue").append(),Tv=()=>yy("break").append(),_v=(...e)=>(console.warn("TSL.LoopNode: loop() has been renamed to Loop()."),bv(...e)),wv=new WeakMap,Sv=new Ti,Mv=Rp((({bufferMap:e,influence:t,stride:s,width:i,depth:r,offset:n})=>{const o=Op(rv).mul(s).add(n),a=o.div(i),h=o.sub(a.mul(i));return Iy(e,kp(h,a)).depth(r).mul(t)}));class Nv extends Ld{static get type(){return"MorphNode"}constructor(e){super("void"),this.mesh=e,this.morphBaseInfluence=pm(1),this.updateType=Bd.OBJECT}setup(e){const{geometry:t}=e,s=void 0!==t.morphAttributes.position,i=t.hasAttribute("normal")&&void 0!==t.morphAttributes.normal,r=t.morphAttributes.position||t.morphAttributes.normal||t.morphAttributes.color,n=void 0!==r?r.length:0,{texture:o,stride:a,size:h}=function(e){const t=void 0!==e.morphAttributes.position,s=void 0!==e.morphAttributes.normal,i=void 0!==e.morphAttributes.color,r=e.morphAttributes.position||e.morphAttributes.normal||e.morphAttributes.color,n=void 0!==r?r.length:0;let o=wv.get(e);if(void 0===o||o.count!==n){void 0!==o&&o.texture.dispose();const a=e.morphAttributes.position||[],h=e.morphAttributes.normal||[],u=e.morphAttributes.color||[];let l=0;!0===t&&(l=1),!0===s&&(l=2),!0===i&&(l=3);let c=e.attributes.position.count*l,d=1;const p=4096;c>p&&(d=Math.ceil(c/p),c=p);const m=new Float32Array(c*d*4*n),g=new Si(m,c,d,n);g.type=Ie,g.needsUpdate=!0;const f=4*l;for(let x=0;x{const t=Up(0).toVar();this.mesh.count>1&&null!==this.mesh.morphTexture&&void 0!==this.mesh.morphTexture?t.assign(Iy(this.mesh.morphTexture,kp(Op(e).add(1),Op(nv))).r):t.assign(kx("morphTargetInfluences","float").element(e).toVar()),!0===s&&ax.addAssign(Mv({bufferMap:o,influence:t,stride:a,width:u,depth:e,offset:Op(0)})),!0===i&&yx.addAssign(Mv({bufferMap:o,influence:t,stride:a,width:u,depth:e,offset:Op(1)}))}))}update(){const e=this.morphBaseInfluence;this.mesh.geometry.morphTargetsRelative?e.value=1:e.value=1-this.mesh.morphTargetInfluences.reduce(((e,t)=>e+t),0)}}const Av=Ap(Nv),Cv=(e,t)=>{for(const s of t)if(s.isAnalyticLightNode&&s.light.id===e)return s;return null},Rv=new WeakMap;class Ev extends Ld{static get type(){return"LightsNode"}constructor(e=[]){super("vec3"),this.totalDiffuseNode=jp().toVar("totalDiffuse"),this.totalSpecularNode=jp().toVar("totalSpecular"),this.outgoingLightNode=jp().toVar("outgoingLight"),this._lights=e,this._lightNodes=null,this._lightNodesHash=null,this.global=!0}getHash(e){if(null===this._lightNodesHash){null===this._lightNodes&&this.setupLightsNode(e);const t=[];for(const e of this._lightNodes)t.push(e.getHash());this._lightNodesHash="lights-"+t.join(",")}return this._lightNodesHash}analyze(e){const t=e.getDataFromNode(this);for(const s of t.nodes)s.build(e)}setupLightsNode(e){const t=[],s=this._lightNodes,i=(e=>e.sort(((e,t)=>e.id-t.id)))(this._lights),r=e.renderer.nodes.library;for(const e of i)if(e.isNode)t.push(Sp(e));else{let i=null;if(null!==s&&(i=Cv(e.id,s)),null===i){const s=r.getLightNodeClass(e.constructor);if(null===s){console.warn(`LightsNode.setupNodeLights: Light node not found for ${e.constructor.name}`);continue}let i=null;Rv.has(e)?i=Rv.get(e):(i=new s(e),Rv.set(e,i)),t.push(i)}}this._lightNodes=t}setup(e){null===this._lightNodes&&this.setupLightsNode(e);const t=e.context,s=t.lightingModel;let i=this.outgoingLightNode;if(s){const{_lightNodes:r,totalDiffuseNode:n,totalSpecularNode:o}=this;t.outgoingLight=i;const a=e.addStack();e.getDataFromNode(this).nodes=a.nodes,s.start(t,a,e);for(const t of r)t.build(e);s.indirect(t,a,e);const{backdrop:h,backdropAlpha:u}=t,{directDiffuse:l,directSpecular:c,indirectDiffuse:d,indirectSpecular:p}=t.reflectedLight;let m=l.add(d);null!==h&&(m=jp(null!==u?u.mix(m,h):h),t.material.transparent=!0),n.assign(m),o.assign(c.add(p)),i.assign(n.add(o)),s.finish(t,a,e),i=i.bypass(e.removeStack())}return i}setLights(e){return this._lights=e,this._lightNodes=null,this._lightNodesHash=null,this}getLights(){return this._lights}}const Bv=Ap(Ev);class Iv extends Ld{static get type(){return"LightingNode"}constructor(){super("vec3"),this.isLightingNode=!0}generate(){console.warn("Abstract function.")}}class Pv extends Iv{static get type(){return"AONode"}constructor(e=null){super(),this.aoNode=e}setup(e){e.context.ambientOcclusion.mulAssign(this.aoNode)}}class Fv extends Pf{static get type(){return"LightingContextNode"}constructor(e,t=null,s=null,i=null){super(e),this.lightingModel=t,this.backdropNode=s,this.backdropAlphaNode=i,this._value=null}getContext(){const{backdropNode:e,backdropAlphaNode:t}=this,s={directDiffuse:jp().toVar("directDiffuse"),directSpecular:jp().toVar("directSpecular"),indirectDiffuse:jp().toVar("indirectDiffuse"),indirectSpecular:jp().toVar("indirectSpecular")};return{radiance:jp().toVar("radiance"),irradiance:jp().toVar("irradiance"),iblIrradiance:jp().toVar("iblIrradiance"),ambientOcclusion:Up(1).toVar("ambientOcclusion"),reflectedLight:s,backdrop:e,backdropAlpha:t}}setup(e){return this.value=this._value||(this._value=this.getContext()),this.value.lightingModel=this.lightingModel||e.context.lightingModel,super.setup(e)}}const zv=Ap(Fv);class Uv extends Iv{static get type(){return"IrradianceNode"}constructor(e){super(),this.node=e}setup(e){e.context.irradiance.addAssign(this.node)}}let Ov,Lv;class Vv extends Ld{static get type(){return"ScreenNode"}constructor(e){super(),this.scope=e,this.isViewportNode=!0}getNodeType(){return this.scope===Vv.VIEWPORT?"vec4":"vec2"}getUpdateType(){let e=Bd.NONE;return this.scope!==Vv.SIZE&&this.scope!==Vv.VIEWPORT||(e=Bd.RENDER),this.updateType=e,e}update({renderer:e}){const t=e.getRenderTarget();this.scope===Vv.VIEWPORT?null!==t?Lv.copy(t.viewport):(e.getViewport(Lv),Lv.multiplyScalar(e.getPixelRatio())):null!==t?(Ov.width=t.width,Ov.height=t.height):e.getDrawingBufferSize(Ov)}setup(){const e=this.scope;let t=null;return t=e===Vv.SIZE?pm(Ov||(Ov=new Qs)):e===Vv.VIEWPORT?pm(Lv||(Lv=new Ti)):Dp(Gv.div(kv)),t}generate(e){if(this.scope===Vv.COORDINATE){let t=e.getFragCoord();if(e.isFlipY()){const s=e.getNodeProperties(kv).outputNode.build(e);t=`${e.getType("vec2")}( ${t}.x, ${s}.y - ${t}.y )`}return t}return super.generate(e)}}Vv.COORDINATE="coordinate",Vv.VIEWPORT="viewport",Vv.SIZE="size",Vv.UV="uv";const Dv=Cp(Vv,Vv.UV),kv=Cp(Vv,Vv.SIZE),Gv=Cp(Vv,Vv.COORDINATE),Wv=Cp(Vv,Vv.VIEWPORT),jv=Wv.zw,Hv=Gv.sub(Wv.xy),qv=Hv.div(jv),$v=Rp((()=>(console.warn('TSL.ViewportNode: "viewportResolution" is deprecated. Use "screenSize" instead.'),kv)),"vec2").once()(),Xv=Rp((()=>(console.warn('TSL.ViewportNode: "viewportTopLeft" is deprecated. Use "screenUV" instead.'),Dv)),"vec2").once()(),Yv=Rp((()=>(console.warn('TSL.ViewportNode: "viewportBottomLeft" is deprecated. Use "screenUV.flipY()" instead.'),Dv.flipY())),"vec2").once()(),Zv=new Qs;class Jv extends Ey{static get type(){return"ViewportTextureNode"}constructor(e=Dv,t=null,s=null){null===s&&((s=new ja).minFilter=Se),super(s,e,t),this.generateMipmaps=!1,this.isOutputTextureNode=!0,this.updateBeforeType=Bd.FRAME}updateBefore(e){const t=e.renderer;t.getDrawingBufferSize(Zv);const s=this.value;s.image.width===Zv.width&&s.image.height===Zv.height||(s.image.width=Zv.width,s.image.height=Zv.height,s.needsUpdate=!0);const i=s.generateMipmaps;s.generateMipmaps=this.generateMipmaps,t.copyFramebufferToTexture(s),s.generateMipmaps=i}clone(){const e=new this.constructor(this.uvNode,this.levelNode,this.value);return e.generateMipmaps=this.generateMipmaps,e}}const Kv=Ap(Jv),Qv=Ap(Jv,null,null,{generateMipmaps:!0});let eT=null;class tT extends Jv{static get type(){return"ViewportDepthTextureNode"}constructor(e=Dv,t=null){null===eT&&(eT=new Ya),super(e,t,eT)}}const sT=Ap(tT);class iT extends Ld{static get type(){return"ViewportDepthNode"}constructor(e,t=null){super("float"),this.scope=e,this.valueNode=t,this.isViewportDepthNode=!0}generate(e){const{scope:t}=this;return t===iT.DEPTH_BASE?e.getFragDepth():super.generate(e)}setup({camera:e}){const{scope:t}=this,s=this.valueNode;let i=null;if(t===iT.DEPTH_BASE)null!==s&&(i=hT().assign(s));else if(t===iT.DEPTH)i=e.isPerspectiveCamera?oT(cx.z,Fy,zy):rT(cx.z,Fy,zy);else if(t===iT.LINEAR_DEPTH)if(null!==s)if(e.isPerspectiveCamera){const e=aT(s,Fy,zy);i=rT(e,Fy,zy)}else i=s;else i=rT(cx.z,Fy,zy);return i}}iT.DEPTH_BASE="depthBase",iT.DEPTH="depth",iT.LINEAR_DEPTH="linearDepth";const rT=(e,t,s)=>e.add(t).div(t.sub(s)),nT=(e,t,s)=>t.sub(s).mul(e).sub(t),oT=(e,t,s)=>t.add(e).mul(s).div(s.sub(t).mul(e)),aT=(e,t,s)=>t.mul(s).div(s.sub(t).mul(e).sub(s)),hT=Ap(iT,iT.DEPTH_BASE),uT=Cp(iT,iT.DEPTH),lT=Ap(iT,iT.LINEAR_DEPTH),cT=lT(sT());uT.assign=e=>hT(e);class dT extends Ld{static get type(){return"ClippingNode"}constructor(e=dT.DEFAULT){super(),this.scope=e}setup(e){super.setup(e);const t=e.clippingContext,{localClipIntersection:s,localClippingCount:i,globalClippingCount:r}=t,n=r+i,o=s?n-i:n;return this.scope===dT.ALPHA_TO_COVERAGE?this.setupAlphaToCoverage(t.planes,n,o):this.setupDefault(t.planes,n,o)}setupAlphaToCoverage(e,t,s){return Rp((()=>{const i=Ox(e),r=gm("float","distanceToPlane"),n=gm("float","distanceToGradient"),o=gm("float","clipOpacity");let a;if(o.assign(1),bv(s,(({i:e})=>{a=i.element(e),r.assign(cx.dot(a.xyz).negate().add(a.w)),n.assign(r.fwidth().div(2)),o.mulAssign(Mf(n.negate(),n,r)),o.equal(0).discard()})),s{a=i.element(t),r.assign(cx.dot(a.xyz).negate().add(a.w)),n.assign(r.fwidth().div(2)),e.mulAssign(Mf(n.negate(),n,r).oneMinus())})),o.mulAssign(e.oneMinus())}ym.a.mulAssign(o),ym.a.equal(0).discard()}))()}setupDefault(e,t,s){return Rp((()=>{const i=Ox(e);let r;if(bv(s,(({i:e})=>{r=i.element(e),cx.dot(r.xyz).greaterThan(r.w).discard()})),s{r=i.element(t),e.assign(cx.dot(r.xyz).greaterThan(r.w).and(e))})),e.discard()}}))()}}dT.ALPHA_TO_COVERAGE="alphaToCoverage",dT.DEFAULT="default";class pT extends en{static get type(){return"NodeMaterial"}constructor(){super(),this.isNodeMaterial=!0,this.type=this.constructor.type,this.forceSinglePass=!1,this.fog=!0,this.lights=!1,this.lightsNode=null,this.envNode=null,this.aoNode=null,this.colorNode=null,this.normalNode=null,this.opacityNode=null,this.backdropNode=null,this.backdropAlphaNode=null,this.alphaTestNode=null,this.positionNode=null,this.depthNode=null,this.shadowNode=null,this.shadowPositionNode=null,this.outputNode=null,this.mrtNode=null,this.fragmentNode=null,this.vertexNode=null}customProgramCacheKey(){return this.type+wd(this)}build(e){this.setup(e)}setupObserver(e){return new xd(e)}setup(e){let t;e.context.setupNormal=()=>this.setupNormal(e),e.addStack(),e.stack.outputNode=this.vertexNode||this.setupPosition(e),e.addFlow("vertex",e.removeStack()),e.addStack();const s=this.setupClipping(e);if(!0===this.depthWrite&&this.setupDepth(e),null===this.fragmentNode){this.setupDiffuseColor(e),this.setupVariants(e);const i=this.setupLighting(e);null!==s&&e.stack.add(s);const r=Xp(i,ym.a).max(0);t=this.setupOutput(e,r),zm.assign(t),null!==this.outputNode&&(t=this.outputNode);if(null!==e.renderer.getRenderTarget()){const s=e.renderer.getMRT(),i=this.mrtNode;null!==s?(t=s,null!==i&&(t=s.merge(i))):null!==i&&(t=i)}}else{let s=this.fragmentNode;!0!==s.isOutputStructNode&&(s=Xp(s)),t=this.setupOutput(e,s)}e.stack.outputNode=t,e.addFlow("fragment",e.removeStack()),e.monitor=this.setupObserver(e)}setupClipping(e){if(null===e.clippingContext)return null;const{globalClippingCount:t,localClippingCount:s}=e.clippingContext;let i=null;if(t||s){const t=e.renderer.samples;this.alphaToCoverage&&t>1?i=Sp(new dT(dT.ALPHA_TO_COVERAGE)):e.stack.add(Sp(new dT))}return i}setupDepth(e){const{renderer:t}=e;let s=this.depthNode;if(null===s){const e=t.getMRT();if(e&&e.has("depth"))s=e.get("depth");else if(!0===t.logarithmicDepthBuffer){s=sv().w.add(1).log2().mul(Uy).mul(.5)}}null!==s&&uT.assign(s).append()}setupPosition(e){const{object:t}=e,s=t.geometry;if(e.addStack(),(s.morphAttributes.position||s.morphAttributes.normal||s.morphAttributes.color)&&Av(t).append(),!0===t.isSkinnedMesh&&yv(t).append(),this.displacementMap){const e=jx("displacementMap","texture"),t=jx("displacementScale","float"),s=jx("displacementBias","float");ax.addAssign(yx.normalize().mul(e.x.mul(t).add(s)))}t.isBatchedMesh&&pv(t).append(),t.instanceMatrix&&!0===t.instanceMatrix.isInstancedBufferAttribute&&cv(t).append(),null!==this.positionNode&&ax.assign(this.positionNode);const i=sv();return e.context.vertex=e.removeStack(),e.context.mvp=i,i}setupDiffuseColor({object:e,geometry:t}){let s=this.colorNode?Xp(this.colorNode):xb;if(!0===this.vertexColors&&t.hasAttribute("color")&&(s=Xp(s.xyz.mul(Sy("color","vec3")),s.a)),e.instanceColor){s=fm("vec3","vInstanceColor").mul(s)}if(e.isBatchedMesh&&e._colorsTexture){s=fm("vec3","vBatchColor").mul(s)}ym.assign(s);const i=this.opacityNode?Up(this.opacityNode):Tb;if(ym.a.assign(ym.a.mul(i)),null!==this.alphaTestNode||this.alphaTest>0){const e=null!==this.alphaTestNode?Up(this.alphaTestNode):yb;ym.a.lessThanEqual(e).discard()}!1===this.transparent&&1===this.blending&&!1===this.alphaToCoverage&&ym.a.assign(1)}setupVariants(){}setupOutgoingLight(){return!0===this.lights?jp(0):ym.rgb}setupNormal(){return this.normalNode?jp(this.normalNode):Rb}setupEnvironment(){let e=null;return this.envNode?e=this.envNode:this.envMap&&(e=this.envMap.isCubeTexture?jx("envMap","cubeTexture"):jx("envMap","texture")),e}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new Uv(Kb)),t}setupLights(e){const t=[],s=this.setupEnvironment(e);s&&s.isLightingNode&&t.push(s);const i=this.setupLightMap(e);if(i&&i.isLightingNode&&t.push(i),null!==this.aoNode||e.material.aoMap){const e=null!==this.aoNode?this.aoNode:Qb;t.push(new Pv(e))}let r=this.lightsNode||e.lightsNode;return t.length>0&&(r=Bv([...r.getLights(),...t])),r}setupLightingModel(){}setupLighting(e){const{material:t}=e,{backdropNode:s,backdropAlphaNode:i,emissiveNode:r}=this,n=!0===this.lights||null!==this.lightsNode?this.setupLights(e):null;let o=this.setupOutgoingLight(e);if(n&&n.getScope().getLights().length>0){const t=this.setupLightingModel(e);o=zv(n,t,s,i)}else null!==s&&(o=jp(null!==i?Tf(o,s,i):s));return(r&&!0===r.isNode||t.emissive&&!0===t.emissive.isColor)&&(xm.assign(jp(r||vb)),o=o.add(xm)),o}setupOutput(e,t){if(!0===this.fog){const s=e.fogNode;s&&(t=Xp(s.mix(t.rgb,s.colorNode),t.a))}return t}setDefaultValues(e){for(const t in e){const s=e[t];void 0===this[t]&&(this[t]=s,s&&s.clone&&(this[t]=s.clone()))}const t=Object.getOwnPropertyDescriptors(e.constructor.prototype);for(const e in t)void 0===Object.getOwnPropertyDescriptor(this.constructor.prototype,e)&&void 0!==t[e].get&&Object.defineProperty(this.constructor.prototype,e,t[e])}toJSON(e){const t=void 0===e||"string"==typeof e;t&&(e={textures:{},images:{},nodes:{}});const s=en.prototype.toJSON.call(this,e),i=Sd(this);s.inputNodes={};for(const{property:t,childNode:r}of i)s.inputNodes[t]=r.toJSON(e).uuid;function r(e){const t=[];for(const s in e){const i=e[s];delete i.metadata,t.push(i)}return t}if(t){const t=r(e.textures),i=r(e.images),n=r(e.nodes);t.length>0&&(s.textures=t),i.length>0&&(s.images=i),n.length>0&&(s.nodes=n)}return s}copy(e){return this.lightsNode=e.lightsNode,this.envNode=e.envNode,this.colorNode=e.colorNode,this.normalNode=e.normalNode,this.opacityNode=e.opacityNode,this.backdropNode=e.backdropNode,this.backdropAlphaNode=e.backdropAlphaNode,this.alphaTestNode=e.alphaTestNode,this.positionNode=e.positionNode,this.depthNode=e.depthNode,this.shadowNode=e.shadowNode,this.shadowPositionNode=e.shadowPositionNode,this.outputNode=e.outputNode,this.mrtNode=e.mrtNode,this.fragmentNode=e.fragmentNode,this.vertexNode=e.vertexNode,super.copy(e)}}const mT=new za;class gT extends pT{static get type(){return"InstancedPointsNodeMaterial"}constructor(e={}){super(),this.lights=!1,this.useAlphaToCoverage=!0,this.useColor=e.vertexColors,this.pointWidth=1,this.pointColorNode=null,this.pointWidthNode=null,this.setDefaultValues(mT),this.setValues(e)}setup(e){this.setupShaders(e),super.setup(e)}setupShaders({renderer:e}){const t=this.alphaToCoverage,s=this.useColor;this.vertexNode=Rp((()=>{const e=Sy("instancePosition").xyz,t=Xp(ix.mul(Xp(e,1))),s=Wv.z.div(Wv.w),i=Oy.mul(t),r=ox.xy.toVar();return r.mulAssign(this.pointWidthNode?this.pointWidthNode:Zb),r.assign(r.div(Wv.z)),r.y.assign(r.y.mul(s)),r.assign(r.mul(i.w)),i.addAssign(Xp(r,0,0)),i}))(),this.fragmentNode=Rp((()=>{const i=Up(1).toVar(),r=vf(My().mul(2).sub(1));if(t&&e.samples>1){const e=Up(r.fwidth()).toVar();i.assign(Mf(e.oneMinus(),e.add(1),r).oneMinus())}else r.greaterThan(1).discard();let n;if(this.pointColorNode)n=this.pointColorNode;else if(s){n=Sy("instanceColor").mul(xb)}else n=xb;return i.mulAssign(Tb),Xp(n,i)}))()}get alphaToCoverage(){return this.useAlphaToCoverage}set alphaToCoverage(e){this.useAlphaToCoverage!==e&&(this.useAlphaToCoverage=e,this.needsUpdate=!0)}}const fT=new Ta;class yT extends pT{static get type(){return"LineBasicNodeMaterial"}constructor(e){super(),this.isLineBasicNodeMaterial=!0,this.lights=!1,this.setDefaultValues(fT),this.setValues(e)}}const xT=new Bu;class bT extends pT{static get type(){return"LineDashedNodeMaterial"}constructor(e){super(),this.isLineDashedNodeMaterial=!0,this.lights=!1,this.setDefaultValues(xT),this.offsetNode=null,this.dashScaleNode=null,this.dashSizeNode=null,this.gapSizeNode=null,this.setValues(e)}setupVariants(){const e=this.offsetNode,t=this.dashScaleNode?Up(this.dashScaleNode):Hb,s=this.dashSizeNode?Up(this.dashSizeNode):qb,i=this.dashSizeNode?Up(this.dashGapNode):$b;Um.assign(s),Om.assign(i);const r=Vf(Sy("lineDistance").mul(t));(e?r.add(e):r).mod(Um.add(Om)).greaterThan(Um).discard()}}const vT=new Bu;class TT extends pT{static get type(){return"Line2NodeMaterial"}constructor(e={}){super(),this.lights=!1,this.setDefaultValues(vT),this.useAlphaToCoverage=!0,this.useColor=e.vertexColors,this.useDash=e.dashed,this.useWorldUnits=!1,this.dashOffset=0,this.lineWidth=1,this.lineColorNode=null,this.offsetNode=null,this.dashScaleNode=null,this.dashSizeNode=null,this.gapSizeNode=null,this.setValues(e)}setup(e){this.setupShaders(e),super.setup(e)}setupShaders({renderer:e}){const t=this.alphaToCoverage,s=this.useColor,i=this.dashed,r=this.worldUnits,n=Rp((({start:e,end:t})=>{const s=Oy.element(2).element(2),i=Oy.element(3).element(2).mul(-.5).div(s).sub(e.z).div(t.z.sub(e.z));return Xp(Tf(e.xyz,t.xyz,i),t.w)})).setLayout({name:"trimSegment",type:"vec4",inputs:[{name:"start",type:"vec4"},{name:"end",type:"vec4"}]});this.vertexNode=Rp((()=>{const e=Sy("instanceStart"),t=Sy("instanceEnd"),s=Xp(ix.mul(Xp(e,1))).toVar("start"),o=Xp(ix.mul(Xp(t,1))).toVar("end");r&&(fm("vec3","worldStart").assign(s.xyz),fm("vec3","worldEnd").assign(o.xyz));const a=Wv.z.div(Wv.w),h=Oy.element(2).element(3).equal(-1);Pp(h,(()=>{Pp(s.z.lessThan(0).and(o.z.greaterThan(0)),(()=>{o.assign(n({start:s,end:o}))})).ElseIf(o.z.lessThan(0).and(s.z.greaterThanEqual(0)),(()=>{s.assign(n({start:o,end:s}))}))}));const u=Oy.mul(s),l=Oy.mul(o),c=u.xyz.div(u.w),d=l.xyz.div(l.w),p=d.xy.sub(c.xy).toVar();p.x.assign(p.x.mul(a)),p.assign(p.normalize());const m=Xp().toVar();if(r){const e=o.xyz.sub(s.xyz).normalize(),t=Tf(s.xyz,o.xyz,.5).normalize(),r=e.cross(t).normalize(),n=e.cross(r),a=fm("vec4","worldPos");a.assign(ox.y.lessThan(.5).select(s,o));const h=Xb.mul(.5);a.addAssign(Xp(ox.x.lessThan(0).select(r.mul(h),r.mul(h).negate()),0)),i||(a.addAssign(Xp(ox.y.lessThan(.5).select(e.mul(h).negate(),e.mul(h)),0)),a.addAssign(Xp(n.mul(h),0)),Pp(ox.y.greaterThan(1).or(ox.y.lessThan(0)),(()=>{a.subAssign(Xp(n.mul(2).mul(h),0))}))),m.assign(Oy.mul(a));const u=jp().toVar();u.assign(ox.y.lessThan(.5).select(c,d)),m.z.assign(u.z.mul(m.w))}else{const e=Dp(p.y,p.x.negate()).toVar("offset");p.x.assign(p.x.div(a)),e.x.assign(e.x.div(a)),e.assign(ox.x.lessThan(0).select(e.negate(),e)),Pp(ox.y.lessThan(0),(()=>{e.assign(e.sub(p))})).ElseIf(ox.y.greaterThan(1),(()=>{e.assign(e.add(p))})),e.assign(e.mul(Xb)),e.assign(e.div(Wv.w)),m.assign(ox.y.lessThan(.5).select(u,l)),e.assign(e.mul(m.w)),m.assign(m.add(Xp(e,0,0)))}return m}))();const o=Rp((({p1:e,p2:t,p3:s,p4:i})=>{const r=e.sub(s),n=i.sub(s),o=t.sub(e),a=r.dot(n),h=n.dot(o),u=r.dot(o),l=n.dot(n),c=o.dot(o).mul(l).sub(h.mul(h)),d=a.mul(h).sub(u.mul(l)).div(c).clamp(),p=a.add(h.mul(d)).div(l).clamp();return Dp(d,p)}));this.fragmentNode=Rp((()=>{const n=My();if(i){const e=this.offsetNode?Up(this.offsetNodeNode):Yb,t=this.dashScaleNode?Up(this.dashScaleNode):Hb,s=this.dashSizeNode?Up(this.dashSizeNode):qb,i=this.dashSizeNode?Up(this.dashGapNode):$b;Um.assign(s),Om.assign(i);const r=Sy("instanceDistanceStart"),o=Sy("instanceDistanceEnd"),a=ox.y.lessThan(.5).select(t.mul(r),Hb.mul(o)),h=Vf(a.add(Yb)),u=e?h.add(e):h;n.y.lessThan(-1).or(n.y.greaterThan(1)).discard(),u.mod(Um.add(Om)).greaterThan(Um).discard()}const a=Up(1).toVar("alpha");if(r){const s=fm("vec3","worldStart"),r=fm("vec3","worldEnd"),n=fm("vec4","worldPos").xyz.normalize().mul(1e5),h=r.sub(s),u=o({p1:s,p2:r,p3:jp(0,0,0),p4:n}),l=s.add(h.mul(u.x)),c=n.mul(u.y),d=l.sub(c).length().div(Xb);if(!i)if(t&&e.samples>1){const e=d.fwidth();a.assign(Mf(e.negate().add(.5),e.add(.5),d).oneMinus())}else d.greaterThan(.5).discard()}else if(t&&e.samples>1){const e=n.x,t=n.y.greaterThan(0).select(n.y.sub(1),n.y.add(1)),s=e.mul(e).add(t.mul(t)),i=Up(s.fwidth()).toVar("dlen");Pp(n.y.abs().greaterThan(1),(()=>{a.assign(Mf(i.oneMinus(),i.add(1),s).oneMinus())}))}else Pp(n.y.abs().greaterThan(1),(()=>{const e=n.x,t=n.y.greaterThan(0).select(n.y.sub(1),n.y.add(1));e.mul(e).add(t.mul(t)).greaterThan(1).discard()}));let h;if(this.lineColorNode)h=this.lineColorNode;else if(s){const e=Sy("instanceColorStart"),t=Sy("instanceColorEnd");h=ox.y.lessThan(.5).select(e,t).mul(xb)}else h=xb;return Xp(h,a)}))()}get worldUnits(){return this.useWorldUnits}set worldUnits(e){this.useWorldUnits!==e&&(this.useWorldUnits=e,this.needsUpdate=!0)}get dashed(){return this.useDash}set dashed(e){this.useDash!==e&&(this.useDash=e,this.needsUpdate=!0)}get alphaToCoverage(){return this.useAlphaToCoverage}set alphaToCoverage(e){this.useAlphaToCoverage!==e&&(this.useAlphaToCoverage=e,this.needsUpdate=!0)}}const _T=e=>Sp(e).mul(.5).add(.5),wT=e=>Sp(e).mul(2).sub(1),ST=new Nu;class MT extends pT{static get type(){return"MeshNormalNodeMaterial"}constructor(e){super(),this.lights=!1,this.isMeshNormalNodeMaterial=!0,this.setDefaultValues(ST),this.setValues(e)}setupDiffuseColor(){const e=this.opacityNode?Up(this.opacityNode):Tb;ym.assign(Xp(_T(Tx),e))}}class NT extends kd{static get type(){return"EquirectUVNode"}constructor(e=lx){super("vec2"),this.dirNode=e}setup(){const e=this.dirNode,t=e.z.atan2(e.x).mul(1/(2*Math.PI)).add(.5),s=e.y.clamp(-1,1).asin().mul(1/Math.PI).add(.5);return Dp(t,s)}}const AT=Ap(NT);class CT extends Kn{constructor(e=1,t={}){super(e,t),this.isCubeRenderTarget=!0}fromEquirectangularTexture(e,t){const s=t.minFilter,i=t.generateMipmaps;t.generateMipmaps=!0,this.texture.type=t.type,this.texture.colorSpace=t.colorSpace,this.texture.generateMipmaps=t.generateMipmaps,this.texture.minFilter=t.minFilter,this.texture.magFilter=t.magFilter;const r=new kn(5,5,5),n=AT(lx),o=new pT;o.colorNode=By(t,n,0),o.side=d,o.blending=m;const a=new Vn(r,o),h=new to;h.add(a),t.minFilter===Se&&(t.minFilter=Te);const u=new Zn(1,10,this),l=e.getMRT();return e.setMRT(null),u.update(e,h),e.setMRT(l),t.minFilter=s,t.currentGenerateMipmaps=i,a.geometry.dispose(),a.material.dispose(),this}}const RT=new WeakMap;class ET extends kd{static get type(){return"CubeMapNode"}constructor(e){super("vec3"),this.envNode=e,this._cubeTexture=null,this._cubeTextureNode=Ix();const t=new Jn;t.isRenderTargetTexture=!0,this._defaultTexture=t,this.updateBeforeType=Bd.RENDER}updateBefore(e){const{renderer:t,material:s}=e,i=this.envNode;if(i.isTextureNode||i.isMaterialReferenceNode){const e=i.isTextureNode?i.value:s[i.property];if(e&&e.isTexture){const s=e.mapping;if(s===le||s===ce){if(RT.has(e)){const t=RT.get(e);IT(t,e.mapping),this._cubeTexture=t}else{const s=e.image;if(function(e){return null!=e&&e.height>0}(s)){const i=new CT(s.height);i.fromEquirectangularTexture(t,e),IT(i.texture,e.mapping),this._cubeTexture=i.texture,RT.set(e,i.texture),e.addEventListener("dispose",BT)}else this._cubeTexture=this._defaultTexture}this._cubeTextureNode.value=this._cubeTexture}else this._cubeTextureNode=this.envNode}}}setup(e){return this.updateBefore(e),this._cubeTextureNode}}function BT(e){const t=e.target;t.removeEventListener("dispose",BT);const s=RT.get(t);void 0!==s&&(RT.delete(t),s.dispose())}function IT(e,t){t===le?e.mapping=he:t===ce&&(e.mapping=ue)}const PT=Ap(ET);class FT extends Iv{static get type(){return"BasicEnvironmentNode"}constructor(e=null){super(),this.envNode=e}setup(e){e.context.environment=PT(this.envNode)}}class zT extends Iv{static get type(){return"BasicLightMapNode"}constructor(e=null){super(),this.lightMapNode=e}setup(e){const t=Up(1/Math.PI);e.context.irradianceLightMap=this.lightMapNode.mul(t)}}class UT{start(){}finish(){}direct(){}directRectArea(){}indirect(){}ambientOcclusion(){}}class OT extends UT{constructor(){super()}indirect(e,t,s){const i=e.ambientOcclusion,r=e.reflectedLight,n=s.context.irradianceLightMap;r.indirectDiffuse.assign(Xp(0)),n?r.indirectDiffuse.addAssign(n):r.indirectDiffuse.addAssign(Xp(1,1,1,0)),r.indirectDiffuse.mulAssign(i),r.indirectDiffuse.mulAssign(ym.rgb)}finish(e,t,s){const i=s.material,r=e.outgoingLight,n=s.context.environment;if(n)switch(i.combine){case 0:r.rgb.assign(Tf(r.rgb,r.rgb.mul(n.rgb),Mb.mul(Nb)));break;case 1:r.rgb.assign(Tf(r.rgb,n.rgb,Mb.mul(Nb)));break;case 2:r.rgb.addAssign(n.rgb.mul(Mb.mul(Nb)));break;default:console.warn("THREE.BasicLightingModel: Unsupported .combine value:",i.combine)}}}const LT=new tn;class VT extends pT{static get type(){return"MeshBasicNodeMaterial"}constructor(e){super(),this.isMeshBasicNodeMaterial=!0,this.lights=!0,this.setDefaultValues(LT),this.setValues(e)}setupNormal(){return bx}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new FT(t):null}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new zT(Kb)),t}setupOutgoingLight(){return ym.rgb}setupLightingModel(){return new OT}}const DT=Rp((({f0:e,f90:t,dotVH:s})=>{const i=s.mul(-5.55473).sub(6.98316).mul(s).exp2();return e.mul(i.oneMinus()).add(t.mul(i))})),kT=Rp((e=>e.diffuseColor.mul(1/Math.PI))),GT=Rp((({dotNH:e})=>Fm.mul(Up(.5)).add(1).mul(Up(1/Math.PI)).mul(e.pow(Fm)))),WT=Rp((({lightDirection:e})=>{const t=e.add(dx).normalize(),s=Tx.dot(t).clamp(),i=dx.dot(t).clamp(),r=DT({f0:Im,f90:1,dotVH:i}),n=Up(.25),o=GT({dotNH:s});return r.mul(n).mul(o)}));class jT extends OT{constructor(e=!0){super(),this.specular=e}direct({lightDirection:e,lightColor:t,reflectedLight:s}){const i=Tx.dot(e).clamp().mul(t);s.directDiffuse.addAssign(i.mul(kT({diffuseColor:ym.rgb}))),!0===this.specular&&s.directSpecular.addAssign(i.mul(WT({lightDirection:e})).mul(Mb))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:s}){s.indirectDiffuse.addAssign(t.mul(kT({diffuseColor:ym}))),s.indirectDiffuse.mulAssign(e)}}const HT=new Au;class qT extends pT{static get type(){return"MeshLambertNodeMaterial"}constructor(e){super(),this.isMeshLambertNodeMaterial=!0,this.lights=!0,this.setDefaultValues(HT),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new FT(t):null}setupLightingModel(){return new jT(!1)}}const $T=new Su;class XT extends pT{static get type(){return"MeshPhongNodeMaterial"}constructor(e){super(),this.isMeshPhongNodeMaterial=!0,this.lights=!0,this.shininessNode=null,this.specularNode=null,this.setDefaultValues($T),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new FT(t):null}setupLightingModel(){return new jT}setupVariants(){const e=(this.shininessNode?Up(this.shininessNode):bb).max(1e-4);Fm.assign(e);const t=this.specularNode||_b;Im.assign(t)}copy(e){return this.shininessNode=e.shininessNode,this.specularNode=e.specularNode,super.copy(e)}}const YT=Rp((()=>{const e=bx.dFdx().abs().max(bx.dFdy().abs());return e.x.max(e.y).max(e.z)})),ZT=Rp((e=>{const{roughness:t}=e,s=YT();let i=t.max(.0525);return i=i.add(s),i=i.min(1),i})),JT=Rp((({alpha:e,dotNL:t,dotNV:s})=>{const i=e.pow2(),r=t.mul(i.add(i.oneMinus().mul(s.pow2())).sqrt()),n=s.mul(i.add(i.oneMinus().mul(t.pow2())).sqrt());return Qm(.5,r.add(n).max(bg))})).setLayout({name:"V_GGX_SmithCorrelated",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNL",type:"float"},{name:"dotNV",type:"float"}]}),KT=Rp((({alphaT:e,alphaB:t,dotTV:s,dotBV:i,dotTL:r,dotBL:n,dotNV:o,dotNL:a})=>{const h=a.mul(jp(e.mul(s),t.mul(i),o).length()),u=o.mul(jp(e.mul(r),t.mul(n),a).length());return Qm(.5,h.add(u)).saturate()})).setLayout({name:"V_GGX_SmithCorrelated_Anisotropic",type:"float",inputs:[{name:"alphaT",type:"float",qualifier:"in"},{name:"alphaB",type:"float",qualifier:"in"},{name:"dotTV",type:"float",qualifier:"in"},{name:"dotBV",type:"float",qualifier:"in"},{name:"dotTL",type:"float",qualifier:"in"},{name:"dotBL",type:"float",qualifier:"in"},{name:"dotNV",type:"float",qualifier:"in"},{name:"dotNL",type:"float",qualifier:"in"}]}),QT=Rp((({alpha:e,dotNH:t})=>{const s=e.pow2(),i=t.pow2().mul(s.oneMinus()).oneMinus();return s.div(i.pow2()).mul(1/Math.PI)})).setLayout({name:"D_GGX",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNH",type:"float"}]}),e_=Up(1/Math.PI),t_=Rp((({alphaT:e,alphaB:t,dotNH:s,dotTH:i,dotBH:r})=>{const n=e.mul(t),o=jp(t.mul(i),e.mul(r),n.mul(s)),a=o.dot(o),h=n.div(a);return e_.mul(n.mul(h.pow2()))})).setLayout({name:"D_GGX_Anisotropic",type:"float",inputs:[{name:"alphaT",type:"float",qualifier:"in"},{name:"alphaB",type:"float",qualifier:"in"},{name:"dotNH",type:"float",qualifier:"in"},{name:"dotTH",type:"float",qualifier:"in"},{name:"dotBH",type:"float",qualifier:"in"}]}),s_=Rp((e=>{const{lightDirection:t,f0:s,f90:i,roughness:r,f:n,USE_IRIDESCENCE:o,USE_ANISOTROPY:a}=e,h=e.normalView||Tx,u=r.pow2(),l=t.add(dx).normalize(),c=h.dot(t).clamp(),d=h.dot(dx).clamp(),p=h.dot(l).clamp(),m=dx.dot(l).clamp();let g,f,y=DT({f0:s,f90:i,dotVH:m});if(Tp(o)&&(y=Mm.mix(y,n)),Tp(a)){const e=Em.dot(t),s=Em.dot(dx),i=Em.dot(l),r=Bm.dot(t),n=Bm.dot(dx),o=Bm.dot(l);g=KT({alphaT:Cm,alphaB:u,dotTV:s,dotBV:n,dotTL:e,dotBL:r,dotNV:d,dotNL:c}),f=t_({alphaT:Cm,alphaB:u,dotNH:p,dotTH:i,dotBH:o})}else g=JT({alpha:u,dotNL:c,dotNV:d}),f=QT({alpha:u,dotNH:p});return y.mul(g).mul(f)})),i_=Rp((({roughness:e,dotNV:t})=>{const s=Xp(-1,-.0275,-.572,.022),i=Xp(1,.0425,1.04,-.04),r=e.mul(s).add(i),n=r.x.mul(r.x).min(t.mul(-9.28).exp2()).mul(r.x).add(r.y);return Dp(-1.04,1.04).mul(n).add(r.zw)})).setLayout({name:"DFGApprox",type:"vec2",inputs:[{name:"roughness",type:"float"},{name:"dotNV",type:"vec3"}]}),r_=Rp((e=>{const{dotNV:t,specularColor:s,specularF90:i,roughness:r}=e,n=i_({dotNV:t,roughness:r});return s.mul(n.x).add(i.mul(n.y))})),n_=Rp((({f:e,f90:t,dotVH:s})=>{const i=s.oneMinus().saturate(),r=i.mul(i),n=i.mul(r,r).clamp(0,.9999);return e.sub(jp(t).mul(n)).div(n.oneMinus())})).setLayout({name:"Schlick_to_F0",type:"vec3",inputs:[{name:"f",type:"vec3"},{name:"f90",type:"float"},{name:"dotVH",type:"float"}]}),o_=Rp((({roughness:e,dotNH:t})=>{const s=e.pow2(),i=Up(1).div(s),r=t.pow2().oneMinus().max(.0078125);return Up(2).add(i).mul(r.pow(i.mul(.5))).div(2*Math.PI)})).setLayout({name:"D_Charlie",type:"float",inputs:[{name:"roughness",type:"float"},{name:"dotNH",type:"float"}]}),a_=Rp((({dotNV:e,dotNL:t})=>Up(1).div(Up(4).mul(t.add(e).sub(t.mul(e)))))).setLayout({name:"V_Neubelt",type:"float",inputs:[{name:"dotNV",type:"float"},{name:"dotNL",type:"float"}]}),h_=Rp((({lightDirection:e})=>{const t=e.add(dx).normalize(),s=Tx.dot(e).clamp(),i=Tx.dot(dx).clamp(),r=Tx.dot(t).clamp(),n=o_({roughness:Sm,dotNH:r}),o=a_({dotNV:i,dotNL:s});return wm.mul(n).mul(o)})),u_=Rp((({N:e,V:t,roughness:s})=>{const i=e.dot(t).saturate(),r=Dp(s,i.oneMinus().sqrt());return r.assign(r.mul(.984375).add(.0078125)),r})).setLayout({name:"LTC_Uv",type:"vec2",inputs:[{name:"N",type:"vec3"},{name:"V",type:"vec3"},{name:"roughness",type:"float"}]}),l_=Rp((({f:e})=>{const t=e.length();return of(t.mul(t).add(e.z).div(t.add(1)),0)})).setLayout({name:"LTC_ClippedSphereFormFactor",type:"float",inputs:[{name:"f",type:"vec3"}]}),c_=Rp((({v1:e,v2:t})=>{const s=e.dot(t),i=s.abs().toVar(),r=i.mul(.0145206).add(.4965155).mul(i).add(.8543985).toVar(),n=i.add(4.1616724).mul(i).add(3.417594).toVar(),o=r.div(n),a=s.greaterThan(0).select(o,of(s.mul(s).oneMinus(),1e-7).inverseSqrt().mul(.5).sub(o));return e.cross(t).mul(a)})).setLayout({name:"LTC_EdgeVectorFormFactor",type:"vec3",inputs:[{name:"v1",type:"vec3"},{name:"v2",type:"vec3"}]}),d_=Rp((({N:e,V:t,P:s,mInv:i,p0:r,p1:n,p2:o,p3:a})=>{const h=n.sub(r).toVar(),u=a.sub(r).toVar(),l=h.cross(u),c=jp().toVar();return Pp(l.dot(s.sub(r)).greaterThanEqual(0),(()=>{const h=t.sub(e.mul(t.dot(e))).normalize(),u=e.cross(h).negate(),l=i.mul(Qp(h,u,e).transpose()).toVar(),d=l.mul(r.sub(s)).normalize().toVar(),p=l.mul(n.sub(s)).normalize().toVar(),m=l.mul(o.sub(s)).normalize().toVar(),g=l.mul(a.sub(s)).normalize().toVar(),f=jp(0).toVar();f.addAssign(c_({v1:d,v2:p})),f.addAssign(c_({v1:p,v2:m})),f.addAssign(c_({v1:m,v2:g})),f.addAssign(c_({v1:g,v2:d})),c.assign(jp(l_({f:f})))})),c})).setLayout({name:"LTC_Evaluate",type:"vec3",inputs:[{name:"N",type:"vec3"},{name:"V",type:"vec3"},{name:"P",type:"vec3"},{name:"mInv",type:"mat3"},{name:"p0",type:"vec3"},{name:"p1",type:"vec3"},{name:"p2",type:"vec3"},{name:"p3",type:"vec3"}]}),p_=1/6,m_=e=>Km(p_,Km(e,Km(e,e.negate().add(3)).sub(3)).add(1)),g_=e=>Km(p_,Km(e,Km(e,Km(3,e).sub(6))).add(4)),f_=e=>Km(p_,Km(e,Km(e,Km(-3,e).add(3)).add(3)).add(1)),y_=e=>Km(p_,mf(e,3)),x_=e=>m_(e).add(g_(e)),b_=e=>f_(e).add(y_(e)),v_=e=>Zm(-1,g_(e).div(m_(e).add(g_(e)))),T_=e=>Zm(1,y_(e).div(f_(e).add(y_(e)))),__=(e,t,s)=>{const i=e.uvNode,r=Km(i,t.zw).add(.5),n=Fg(r),o=Og(r),a=x_(o.x),h=b_(o.x),u=v_(o.x),l=T_(o.x),c=v_(o.y),d=T_(o.y),p=Dp(n.x.add(u),n.y.add(c)).sub(.5).mul(t.xy),m=Dp(n.x.add(l),n.y.add(c)).sub(.5).mul(t.xy),g=Dp(n.x.add(u),n.y.add(d)).sub(.5).mul(t.xy),f=Dp(n.x.add(l),n.y.add(d)).sub(.5).mul(t.xy),y=x_(o.y).mul(Zm(a.mul(e.uv(p).level(s)),h.mul(e.uv(m).level(s)))),x=b_(o.y).mul(Zm(a.mul(e.uv(g).level(s)),h.mul(e.uv(f).level(s))));return y.add(x)},w_=Rp((([e,t=Up(3)])=>{const s=Dp(e.size(Op(t))),i=Dp(e.size(Op(t.add(1)))),r=Qm(1,s),n=Qm(1,i),o=__(e,Xp(r,s),Fg(t)),a=__(e,Xp(n,i),zg(t));return Og(t).mix(o,a)})),S_=Rp((([e,t,s,i,r])=>{const n=jp(Sf(t.negate(),Ug(e),Qm(1,i))),o=jp(qg(r[0].xyz),qg(r[1].xyz),qg(r[2].xyz));return Ug(n).mul(s.mul(o))})).setLayout({name:"getVolumeTransmissionRay",type:"vec3",inputs:[{name:"n",type:"vec3"},{name:"v",type:"vec3"},{name:"thickness",type:"float"},{name:"ior",type:"float"},{name:"modelMatrix",type:"mat4"}]}),M_=Rp((([e,t])=>e.mul(_f(t.mul(2).sub(2),0,1)))).setLayout({name:"applyIorToRoughness",type:"float",inputs:[{name:"roughness",type:"float"},{name:"ior",type:"float"}]}),N_=Qv(),A_=Rp((([e,t,s])=>{const i=N_.uv(e),r=Bg(Up(kv.x)).mul(M_(t,s));return w_(i,r)})),C_=Rp((([e,t,s])=>(Pp(s.notEqual(0),(()=>{const i=Eg(t).negate().div(s);return Cg(i.negate().mul(e))})),jp(1)))).setLayout({name:"volumeAttenuation",type:"vec3",inputs:[{name:"transmissionDistance",type:"float"},{name:"attenuationColor",type:"vec3"},{name:"attenuationDistance",type:"float"}]}),R_=Rp((([e,t,s,i,r,n,o,a,h,u,l,c,d,p,m])=>{let g,f;if(m){g=Xp().toVar(),f=jp().toVar();const r=l.sub(1).mul(m.mul(.025)),n=jp(l.sub(r),l,l.add(r));bv({start:0,end:3},(({i:r})=>{const l=n.element(r),m=S_(e,t,c,l,a),y=o.add(m),x=u.mul(h.mul(Xp(y,1))),b=Dp(x.xy.div(x.w)).toVar();b.addAssign(1),b.divAssign(2),b.assign(Dp(b.x,b.y.oneMinus()));const v=A_(b,s,l);g.element(r).assign(v.element(r)),g.a.addAssign(v.a),f.element(r).assign(i.element(r).mul(C_(qg(m),d,p).element(r)))})),g.a.divAssign(3)}else{const r=S_(e,t,c,l,a),n=o.add(r),m=u.mul(h.mul(Xp(n,1))),y=Dp(m.xy.div(m.w)).toVar();y.addAssign(1),y.divAssign(2),y.assign(Dp(y.x,y.y.oneMinus())),g=A_(y,s,l),f=i.mul(C_(qg(r),d,p))}const y=f.rgb.mul(g.rgb),x=e.dot(t).clamp(),b=jp(r_({dotNV:x,specularColor:r,specularF90:n,roughness:s})),v=f.r.add(f.g,f.b).div(3);return Xp(b.oneMinus().mul(y),g.a.oneMinus().mul(v).oneMinus())})),E_=Qp(3.2404542,-.969266,.0556434,-1.5371385,1.8760108,-.2040259,-.4985314,.041556,1.0572252),B_=(e,t)=>e.sub(t).div(e.add(t)).pow2(),I_=(e,t)=>{const s=e.mul(2*Math.PI*1e-9),i=jp(54856e-17,44201e-17,52481e-17),r=jp(1681e3,1795300,2208400),n=jp(43278e5,93046e5,66121e5),o=Up(9747e-17*Math.sqrt(2*Math.PI*45282e5)).mul(s.mul(2239900).add(t.x).cos()).mul(s.pow2().mul(-45282e5).exp());let a=i.mul(n.mul(2*Math.PI).sqrt()).mul(r.mul(s).add(t).cos()).mul(s.pow2().negate().mul(n).exp());a=jp(a.x.add(o),a.y,a.z).div(1.0685e-7);return E_.mul(a)},P_=Rp((({outsideIOR:e,eta2:t,cosTheta1:s,thinFilmThickness:i,baseF0:r})=>{const n=Tf(e,t,Mf(0,.03,i)),o=e.div(n).pow2().mul(Up(1).sub(s.pow2())),a=Up(1).sub(o).sqrt(),h=B_(n,e),u=DT({f0:h,f90:1,dotVH:s}),l=u.oneMinus(),c=n.lessThan(e).select(Math.PI,0),d=Up(Math.PI).sub(c),p=(e=>{const t=e.sqrt();return jp(1).add(t).div(jp(1).sub(t))})(r.clamp(0,.9999)),m=B_(p,n.toVec3()),g=DT({f0:m,f90:1,dotVH:a}),f=jp(p.x.lessThan(n).select(Math.PI,0),p.y.lessThan(n).select(Math.PI,0),p.z.lessThan(n).select(Math.PI,0)),y=n.mul(i,a,2),x=jp(d).add(f),b=u.mul(g).clamp(1e-5,.9999),v=b.sqrt(),T=l.pow2().mul(g).div(jp(1).sub(b));let _=u.add(T),w=T.sub(l);for(let e=1;e<=2;++e){w=w.mul(v);const t=I_(Up(e).mul(y),Up(e).mul(x)).mul(2);_=_.add(w.mul(t))}return _.max(jp(0))})).setLayout({name:"evalIridescence",type:"vec3",inputs:[{name:"outsideIOR",type:"float"},{name:"eta2",type:"float"},{name:"cosTheta1",type:"float"},{name:"thinFilmThickness",type:"float"},{name:"baseF0",type:"vec3"}]}),F_=Rp((({normal:e,viewDir:t,roughness:s})=>{const i=e.dot(t).saturate(),r=s.pow2(),n=Bf(s.lessThan(.25),Up(-339.2).mul(r).add(Up(161.4).mul(s)).sub(25.9),Up(-8.48).mul(r).add(Up(14.3).mul(s)).sub(9.95)),o=Bf(s.lessThan(.25),Up(44).mul(r).sub(Up(23.7).mul(s)).add(3.26),Up(1.97).mul(r).sub(Up(3.27).mul(s)).add(.72));return Bf(s.lessThan(.25),0,Up(.1).mul(s).sub(.025)).add(n.mul(i).add(o).exp()).mul(1/Math.PI).saturate()})),z_=jp(.04),U_=Up(1);class O_ extends UT{constructor(e=!1,t=!1,s=!1,i=!1,r=!1,n=!1){super(),this.clearcoat=e,this.sheen=t,this.iridescence=s,this.anisotropy=i,this.transmission=r,this.dispersion=n,this.clearcoatRadiance=null,this.clearcoatSpecularDirect=null,this.clearcoatSpecularIndirect=null,this.sheenSpecularDirect=null,this.sheenSpecularIndirect=null,this.iridescenceFresnel=null,this.iridescenceF0=null}start(e){if(!0===this.clearcoat&&(this.clearcoatRadiance=jp().toVar("clearcoatRadiance"),this.clearcoatSpecularDirect=jp().toVar("clearcoatSpecularDirect"),this.clearcoatSpecularIndirect=jp().toVar("clearcoatSpecularIndirect")),!0===this.sheen&&(this.sheenSpecularDirect=jp().toVar("sheenSpecularDirect"),this.sheenSpecularIndirect=jp().toVar("sheenSpecularIndirect")),!0===this.iridescence){const e=Tx.dot(dx).clamp();this.iridescenceFresnel=P_({outsideIOR:Up(1),eta2:Nm,cosTheta1:e,thinFilmThickness:Am,baseF0:Im}),this.iridescenceF0=n_({f:this.iridescenceFresnel,f90:1,dotVH:e})}if(!0===this.transmission){const t=ux,s=Gy.sub(ux).normalize(),i=_x;e.backdrop=R_(i,s,bm,ym,Im,Pm,t,Jy,Vy,Oy,Vm,km,Wm,Gm,this.dispersion?jm:null),e.backdropAlpha=Dm,ym.a.mulAssign(Tf(1,e.backdrop.a,Dm))}}computeMultiscattering(e,t,s){const i=Tx.dot(dx).clamp(),r=i_({roughness:bm,dotNV:i}),n=(this.iridescenceF0?Mm.mix(Im,this.iridescenceF0):Im).mul(r.x).add(s.mul(r.y)),o=r.x.add(r.y).oneMinus(),a=Im.add(Im.oneMinus().mul(.047619)),h=n.mul(a).div(o.mul(a).oneMinus());e.addAssign(n),t.addAssign(h.mul(o))}direct({lightDirection:e,lightColor:t,reflectedLight:s}){const i=Tx.dot(e).clamp().mul(t);if(!0===this.sheen&&this.sheenSpecularDirect.addAssign(i.mul(h_({lightDirection:e}))),!0===this.clearcoat){const s=wx.dot(e).clamp().mul(t);this.clearcoatSpecularDirect.addAssign(s.mul(s_({lightDirection:e,f0:z_,f90:U_,roughness:_m,normalView:wx})))}s.directDiffuse.addAssign(i.mul(kT({diffuseColor:ym.rgb}))),s.directSpecular.addAssign(i.mul(s_({lightDirection:e,f0:Im,f90:1,roughness:bm,iridescence:this.iridescence,f:this.iridescenceFresnel,USE_IRIDESCENCE:this.iridescence,USE_ANISOTROPY:this.anisotropy})))}directRectArea({lightColor:e,lightPosition:t,halfWidth:s,halfHeight:i,reflectedLight:r,ltc_1:n,ltc_2:o}){const a=t.add(s).sub(i),h=t.sub(s).sub(i),u=t.sub(s).add(i),l=t.add(s).add(i),c=Tx,d=dx,p=cx.toVar(),m=u_({N:c,V:d,roughness:bm}),g=n.uv(m).toVar(),f=o.uv(m).toVar(),y=Qp(jp(g.x,0,g.y),jp(0,1,0),jp(g.z,0,g.w)).toVar(),x=Im.mul(f.x).add(Im.oneMinus().mul(f.y)).toVar();r.directSpecular.addAssign(e.mul(x).mul(d_({N:c,V:d,P:p,mInv:y,p0:a,p1:h,p2:u,p3:l}))),r.directDiffuse.addAssign(e.mul(ym).mul(d_({N:c,V:d,P:p,mInv:Qp(1,0,0,0,1,0,0,0,1),p0:a,p1:h,p2:u,p3:l})))}indirect(e,t,s){this.indirectDiffuse(e,t,s),this.indirectSpecular(e,t,s),this.ambientOcclusion(e,t,s)}indirectDiffuse({irradiance:e,reflectedLight:t}){t.indirectDiffuse.addAssign(e.mul(kT({diffuseColor:ym})))}indirectSpecular({radiance:e,iblIrradiance:t,reflectedLight:s}){if(!0===this.sheen&&this.sheenSpecularIndirect.addAssign(t.mul(wm,F_({normal:Tx,viewDir:dx,roughness:Sm}))),!0===this.clearcoat){const e=wx.dot(dx).clamp(),t=r_({dotNV:e,specularColor:z_,specularF90:U_,roughness:_m});this.clearcoatSpecularIndirect.addAssign(this.clearcoatRadiance.mul(t))}const i=jp().toVar("singleScattering"),r=jp().toVar("multiScattering"),n=t.mul(1/Math.PI);this.computeMultiscattering(i,r,Pm);const o=i.add(r),a=ym.mul(o.r.max(o.g).max(o.b).oneMinus());s.indirectSpecular.addAssign(e.mul(i)),s.indirectSpecular.addAssign(r.mul(n)),s.indirectDiffuse.addAssign(a.mul(n))}ambientOcclusion({ambientOcclusion:e,reflectedLight:t}){const s=Tx.dot(dx).clamp().add(e),i=bm.mul(-16).oneMinus().negate().exp2(),r=e.sub(s.pow(i).oneMinus()).clamp();!0===this.clearcoat&&this.clearcoatSpecularIndirect.mulAssign(e),!0===this.sheen&&this.sheenSpecularIndirect.mulAssign(e),t.indirectDiffuse.mulAssign(e),t.indirectSpecular.mulAssign(r)}finish(e){const{outgoingLight:t}=e;if(!0===this.clearcoat){const e=wx.dot(dx).clamp(),s=DT({dotVH:e,f0:z_,f90:U_}),i=t.mul(Tm.mul(s).oneMinus()).add(this.clearcoatSpecularDirect.add(this.clearcoatSpecularIndirect).mul(Tm));t.assign(i)}if(!0===this.sheen){const e=wm.r.max(wm.g).max(wm.b).mul(.157).oneMinus(),s=t.mul(e).add(this.sheenSpecularDirect,this.sheenSpecularIndirect);t.assign(s)}}}const L_=Up(1),V_=Up(-2),D_=Up(.8),k_=Up(-1),G_=Up(.4),W_=Up(2),j_=Up(.305),H_=Up(3),q_=Up(.21),$_=Up(4),X_=Up(4),Y_=Up(16),Z_=Rp((([e])=>{const t=jp(jg(e)).toVar(),s=Up(-1).toVar();return Pp(t.x.greaterThan(t.z),(()=>{Pp(t.x.greaterThan(t.y),(()=>{s.assign(Bf(e.x.greaterThan(0),0,3))})).Else((()=>{s.assign(Bf(e.y.greaterThan(0),1,4))}))})).Else((()=>{Pp(t.z.greaterThan(t.y),(()=>{s.assign(Bf(e.z.greaterThan(0),2,5))})).Else((()=>{s.assign(Bf(e.y.greaterThan(0),1,4))}))})),s})).setLayout({name:"getFace",type:"float",inputs:[{name:"direction",type:"vec3"}]}),J_=Rp((([e,t])=>{const s=Dp().toVar();return Pp(t.equal(0),(()=>{s.assign(Dp(e.z,e.y).div(jg(e.x)))})).ElseIf(t.equal(1),(()=>{s.assign(Dp(e.x.negate(),e.z.negate()).div(jg(e.y)))})).ElseIf(t.equal(2),(()=>{s.assign(Dp(e.x.negate(),e.y).div(jg(e.z)))})).ElseIf(t.equal(3),(()=>{s.assign(Dp(e.z.negate(),e.y).div(jg(e.x)))})).ElseIf(t.equal(4),(()=>{s.assign(Dp(e.x.negate(),e.z).div(jg(e.y)))})).Else((()=>{s.assign(Dp(e.x,e.y).div(jg(e.z)))})),Km(.5,s.add(1))})).setLayout({name:"getUV",type:"vec2",inputs:[{name:"direction",type:"vec3"},{name:"face",type:"float"}]}),K_=Rp((([e])=>{const t=Up(0).toVar();return Pp(e.greaterThanEqual(D_),(()=>{t.assign(L_.sub(e).mul(k_.sub(V_)).div(L_.sub(D_)).add(V_))})).ElseIf(e.greaterThanEqual(G_),(()=>{t.assign(D_.sub(e).mul(W_.sub(k_)).div(D_.sub(G_)).add(k_))})).ElseIf(e.greaterThanEqual(j_),(()=>{t.assign(G_.sub(e).mul(H_.sub(W_)).div(G_.sub(j_)).add(W_))})).ElseIf(e.greaterThanEqual(q_),(()=>{t.assign(j_.sub(e).mul($_.sub(H_)).div(j_.sub(q_)).add(H_))})).Else((()=>{t.assign(Up(-2).mul(Bg(Km(1.16,e))))})),t})).setLayout({name:"roughnessToMip",type:"float",inputs:[{name:"roughness",type:"float"}]}),Q_=Rp((([e,t])=>{const s=e.toVar();s.assign(Km(2,s).sub(1));const i=jp(s,1).toVar();return Pp(t.equal(0),(()=>{i.assign(i.zyx)})).ElseIf(t.equal(1),(()=>{i.assign(i.xzy),i.xz.mulAssign(-1)})).ElseIf(t.equal(2),(()=>{i.x.mulAssign(-1)})).ElseIf(t.equal(3),(()=>{i.assign(i.zyx),i.xz.mulAssign(-1)})).ElseIf(t.equal(4),(()=>{i.assign(i.xzy),i.xy.mulAssign(-1)})).ElseIf(t.equal(5),(()=>{i.z.mulAssign(-1)})),i})).setLayout({name:"getDirection",type:"vec3",inputs:[{name:"uv",type:"vec2"},{name:"face",type:"float"}]}),ew=Rp((([e,t,s,i,r,n])=>{const o=Up(s),a=jp(t),h=_f(K_(o),V_,n),u=Og(h),l=Fg(h),c=jp(tw(e,a,l,i,r,n)).toVar();return Pp(u.notEqual(0),(()=>{const t=jp(tw(e,a,l.add(1),i,r,n)).toVar();c.assign(Tf(c,t,u))})),c})),tw=Rp((([e,t,s,i,r,n])=>{const o=Up(s).toVar(),a=jp(t),h=Up(Z_(a)).toVar(),u=Up(of(X_.sub(o),0)).toVar();o.assign(of(o,X_));const l=Up(Rg(o)).toVar(),c=Dp(J_(a,h).mul(l.sub(2)).add(1)).toVar();return Pp(h.greaterThan(2),(()=>{c.y.addAssign(l),h.subAssign(3)})),c.x.addAssign(h.mul(l)),c.x.addAssign(u.mul(Km(3,Y_))),c.y.addAssign(Km(4,Rg(n).sub(l))),c.x.mulAssign(i),c.y.mulAssign(r),e.uv(c).grad(Dp(),Dp())})),sw=Rp((({envMap:e,mipInt:t,outputDirection:s,theta:i,axis:r,CUBEUV_TEXEL_WIDTH:n,CUBEUV_TEXEL_HEIGHT:o,CUBEUV_MAX_MIP:a})=>{const h=Vg(i),u=s.mul(h).add(r.cross(s).mul(Lg(i))).add(r.mul(r.dot(s).mul(h.oneMinus())));return tw(e,u,t,n,o,a)})),iw=Rp((({n:e,latitudinal:t,poleAxis:s,outputDirection:i,weights:r,samples:n,dTheta:o,mipInt:a,envMap:h,CUBEUV_TEXEL_WIDTH:u,CUBEUV_TEXEL_HEIGHT:l,CUBEUV_MAX_MIP:c})=>{const d=jp(Bf(t,s,pf(s,i))).toVar();Pp(wg(d.equals(jp(0))),(()=>{d.assign(jp(i.z,0,i.x.negate()))})),d.assign(Ug(d));const p=jp().toVar();return p.addAssign(r.element(Op(0)).mul(sw({theta:0,axis:d,outputDirection:i,mipInt:a,envMap:h,CUBEUV_TEXEL_WIDTH:u,CUBEUV_TEXEL_HEIGHT:l,CUBEUV_MAX_MIP:c}))),bv({start:Op(1),end:e},(({i:e})=>{Pp(e.greaterThanEqual(n),(()=>{Tv()}));const t=Up(o.mul(Up(e))).toVar();p.addAssign(r.element(e).mul(sw({theta:t.mul(-1),axis:d,outputDirection:i,mipInt:a,envMap:h,CUBEUV_TEXEL_WIDTH:u,CUBEUV_TEXEL_HEIGHT:l,CUBEUV_MAX_MIP:c}))),p.addAssign(r.element(e).mul(sw({theta:t,axis:d,outputDirection:i,mipInt:a,envMap:h,CUBEUV_TEXEL_WIDTH:u,CUBEUV_TEXEL_HEIGHT:l,CUBEUV_MAX_MIP:c})))})),Xp(p,1)}));let rw=null;const nw=new WeakMap;function ow(e){let t=nw.get(e);if((void 0!==t?t.pmremVersion:-1)!==e.pmremVersion){const s=e.image;if(e.isCubeTexture){if(!function(e){if(null==e)return!1;let t=0;const s=6;for(let i=0;i0}(s))return null;t=rw.fromEquirectangular(e,t)}t.pmremVersion=e.pmremVersion,nw.set(e,t)}return t.texture}class aw extends kd{static get type(){return"PMREMNode"}constructor(e,t=null,s=null){super("vec3"),this._value=e,this._pmrem=null,this.uvNode=t,this.levelNode=s,this._generator=null;const i=new vi;i.isRenderTargetTexture=!0,this._texture=By(i),this._width=pm(0),this._height=pm(0),this._maxMip=pm(0),this.updateBeforeType=Bd.RENDER}set value(e){this._value=e,this._pmrem=null}get value(){return this._value}updateFromTexture(e){const t=function(e){const t=Math.log2(e)-2,s=1/e;return{texelWidth:1/(3*Math.max(Math.pow(2,t),112)),texelHeight:s,maxMip:t}}(e.image.height);this._texture.value=e,this._width.value=t.texelWidth,this._height.value=t.texelHeight,this._maxMip.value=t.maxMip}updateBefore(){let e=this._pmrem;const t=e?e.pmremVersion:-1,s=this._value;t!==s.pmremVersion&&(e=!0===s.isPMREMTexture?s:ow(s),null!==e&&(this._pmrem=e,this.updateFromTexture(e)))}setup(e){null===rw&&(rw=e.createPMREMGenerator()),this.updateBefore(e);let t=this.uvNode;null===t&&e.context.getUV&&(t=e.context.getUV(this));const s=this.value;e.renderer.coordinateSystem===Vs&&!0!==s.isPMREMTexture&&!0===s.isRenderTargetTexture&&(t=jp(t.x.negate(),t.yz));let i=this.levelNode;return null===i&&e.context.getTextureLevel&&(i=e.context.getTextureLevel(this)),ew(this._texture,t,i,this._width,this._height,this._maxMip)}}const hw=Ap(aw),uw=new WeakMap;class lw extends Iv{static get type(){return"EnvironmentNode"}constructor(e=null){super(),this.envNode=e}setup(e){const{material:t}=e;let s=this.envNode;if(s.isTextureNode||s.isMaterialReferenceNode){const e=s.isTextureNode?s.value:t[s.property];let i=uw.get(e);void 0===i&&(i=hw(e),uw.set(e,i)),s=i}const i=t.envMap?kx("envMapIntensity","float",e.material):kx("environmentIntensity","float",e.scene),r=!0===t.useAnisotropy||t.anisotropy>0?ab:Tx,n=s.context(cw(bm,r)).mul(i),o=s.context(dw(_x)).mul(Math.PI).mul(i),a=ly(n),h=ly(o);e.context.radiance.addAssign(a),e.context.iblIrradiance.addAssign(h);const u=e.context.lightingModel.clearcoatRadiance;if(u){const e=s.context(cw(_m,wx)).mul(i),t=ly(e);u.addAssign(t)}}}const cw=(e,t)=>{let s=null;return{getUV:()=>(null===s&&(s=dx.negate().reflect(t),s=e.mul(e).mix(s,t).normalize(),s=s.transformDirection(Vy)),s),getTextureLevel:()=>e}},dw=e=>({getUV:()=>e,getTextureLevel:()=>Up(1)}),pw=new _u;class mw extends pT{static get type(){return"MeshStandardNodeMaterial"}constructor(e){super(),this.isMeshStandardNodeMaterial=!0,this.lights=!0,this.emissiveNode=null,this.metalnessNode=null,this.roughnessNode=null,this.setDefaultValues(pw),this.setValues(e)}setupEnvironment(e){let t=super.setupEnvironment(e);return null===t&&e.environmentNode&&(t=e.environmentNode),t?new lw(t):null}setupLightingModel(){return new O_}setupSpecular(){const e=Tf(jp(.04),ym.rgb,vm);Im.assign(e),Pm.assign(1)}setupVariants(){const e=this.metalnessNode?Up(this.metalnessNode):Cb;vm.assign(e);let t=this.roughnessNode?Up(this.roughnessNode):Ab;t=ZT({roughness:t}),bm.assign(t),this.setupSpecular(),ym.assign(Xp(ym.rgb.mul(e.oneMinus()),ym.a))}copy(e){return this.emissiveNode=e.emissiveNode,this.metalnessNode=e.metalnessNode,this.roughnessNode=e.roughnessNode,super.copy(e)}}const gw=new wu;class fw extends mw{static get type(){return"MeshPhysicalNodeMaterial"}constructor(e){super(),this.isMeshPhysicalNodeMaterial=!0,this.clearcoatNode=null,this.clearcoatRoughnessNode=null,this.clearcoatNormalNode=null,this.sheenNode=null,this.sheenRoughnessNode=null,this.iridescenceNode=null,this.iridescenceIORNode=null,this.iridescenceThicknessNode=null,this.specularIntensityNode=null,this.specularColorNode=null,this.iorNode=null,this.transmissionNode=null,this.thicknessNode=null,this.attenuationDistanceNode=null,this.attenuationColorNode=null,this.dispersionNode=null,this.anisotropyNode=null,this.setDefaultValues(gw),this.setValues(e)}get useClearcoat(){return this.clearcoat>0||null!==this.clearcoatNode}get useIridescence(){return this.iridescence>0||null!==this.iridescenceNode}get useSheen(){return this.sheen>0||null!==this.sheenNode}get useAnisotropy(){return this.anisotropy>0||null!==this.anisotropyNode}get useTransmission(){return this.transmission>0||null!==this.transmissionNode}get useDispersion(){return this.dispersion>0||null!==this.dispersionNode}setupSpecular(){const e=this.iorNode?Up(this.iorNode):Gb;Vm.assign(e),Im.assign(Tf(nf(gf(Vm.sub(1).div(Vm.add(1))).mul(Sb),jp(1)).mul(wb),ym.rgb,vm)),Pm.assign(Tf(wb,1,vm))}setupLightingModel(){return new O_(this.useClearcoat,this.useSheen,this.useIridescence,this.useAnisotropy,this.useTransmission,this.useDispersion)}setupVariants(e){if(super.setupVariants(e),this.useClearcoat){const e=this.clearcoatNode?Up(this.clearcoatNode):Eb,t=this.clearcoatRoughnessNode?Up(this.clearcoatRoughnessNode):Bb;Tm.assign(e),_m.assign(ZT({roughness:t}))}if(this.useSheen){const e=this.sheenNode?jp(this.sheenNode):Fb,t=this.sheenRoughnessNode?Up(this.sheenRoughnessNode):zb;wm.assign(e),Sm.assign(t)}if(this.useIridescence){const e=this.iridescenceNode?Up(this.iridescenceNode):Ob,t=this.iridescenceIORNode?Up(this.iridescenceIORNode):Lb,s=this.iridescenceThicknessNode?Up(this.iridescenceThicknessNode):Vb;Mm.assign(e),Nm.assign(t),Am.assign(s)}if(this.useAnisotropy){const e=(this.anisotropyNode?Dp(this.anisotropyNode):Ub).toVar();Rm.assign(e.length()),Pp(Rm.equal(0),(()=>{e.assign(Dp(1,0))})).Else((()=>{e.divAssign(Dp(Rm)),Rm.assign(Rm.saturate())})),Cm.assign(Rm.pow2().mix(bm.pow2(),1)),Em.assign(rb[0].mul(e.x).add(rb[1].mul(e.y))),Bm.assign(rb[1].mul(e.x).sub(rb[0].mul(e.y)))}if(this.useTransmission){const e=this.transmissionNode?Up(this.transmissionNode):Db,t=this.thicknessNode?Up(this.thicknessNode):kb,s=this.attenuationDistanceNode?Up(this.attenuationDistanceNode):Wb,i=this.attenuationColorNode?jp(this.attenuationColorNode):jb;if(Dm.assign(e),km.assign(t),Gm.assign(s),Wm.assign(i),this.useDispersion){const e=this.dispersionNode?Up(this.dispersionNode):Jb;jm.assign(e)}}}setupClearcoatNormal(){return this.clearcoatNormalNode?jp(this.clearcoatNormalNode):Ib}setup(e){e.context.setupClearcoatNormal=()=>this.setupClearcoatNormal(e),super.setup(e)}copy(e){return this.clearcoatNode=e.clearcoatNode,this.clearcoatRoughnessNode=e.clearcoatRoughnessNode,this.clearcoatNormalNode=e.clearcoatNormalNode,this.sheenNode=e.sheenNode,this.sheenRoughnessNode=e.sheenRoughnessNode,this.iridescenceNode=e.iridescenceNode,this.iridescenceIORNode=e.iridescenceIORNode,this.iridescenceThicknessNode=e.iridescenceThicknessNode,this.specularIntensityNode=e.specularIntensityNode,this.specularColorNode=e.specularColorNode,this.transmissionNode=e.transmissionNode,this.thicknessNode=e.thicknessNode,this.attenuationDistanceNode=e.attenuationDistanceNode,this.attenuationColorNode=e.attenuationColorNode,this.dispersionNode=e.dispersionNode,this.anisotropyNode=e.anisotropyNode,super.copy(e)}}class yw extends O_{constructor(e,t,s,i){super(e,t,s),this.useSSS=i}direct({lightDirection:e,lightColor:t,reflectedLight:s},i,r){if(!0===this.useSSS){const i=r.material,{thicknessColorNode:n,thicknessDistortionNode:o,thicknessAmbientNode:a,thicknessAttenuationNode:h,thicknessPowerNode:u,thicknessScaleNode:l}=i,c=e.add(Tx.mul(o)).normalize(),d=Up(dx.dot(c.negate()).saturate().pow(u).mul(l)),p=jp(d.add(a).mul(n));s.directDiffuse.addAssign(p.mul(h.mul(t)))}super.direct({lightDirection:e,lightColor:t,reflectedLight:s},i,r)}}class xw extends fw{static get type(){return"MeshSSSNodeMaterial"}constructor(e){super(e),this.thicknessColorNode=null,this.thicknessDistortionNode=Up(.1),this.thicknessAmbientNode=Up(0),this.thicknessAttenuationNode=Up(.1),this.thicknessPowerNode=Up(2),this.thicknessScaleNode=Up(10)}get useSSS(){return null!==this.thicknessColorNode}setupLightingModel(){return new yw(this.useClearcoat,this.useSheen,this.useIridescence,this.useSSS)}copy(e){return this.thicknessColorNode=e.thicknessColorNode,this.thicknessDistortionNode=e.thicknessDistortionNode,this.thicknessAmbientNode=e.thicknessAmbientNode,this.thicknessAttenuationNode=e.thicknessAttenuationNode,this.thicknessPowerNode=e.thicknessPowerNode,this.thicknessScaleNode=e.thicknessScaleNode,super.copy(e)}}const bw=Rp((({normal:e,lightDirection:t,builder:s})=>{const i=e.dot(t),r=Dp(i.mul(.5).add(.5),0);if(s.material.gradientMap){const e=jx("gradientMap","texture").context({getUV:()=>r});return jp(e.r)}{const e=r.fwidth().mul(.5);return Tf(jp(.7),jp(1),Mf(Up(.7).sub(e.x),Up(.7).add(e.x),r.x))}}));class vw extends UT{direct({lightDirection:e,lightColor:t,reflectedLight:s},i,r){const n=bw({normal:fx,lightDirection:e,builder:r}).mul(t);s.directDiffuse.addAssign(n.mul(kT({diffuseColor:ym.rgb})))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:s}){s.indirectDiffuse.addAssign(t.mul(kT({diffuseColor:ym}))),s.indirectDiffuse.mulAssign(e)}}const Tw=new Mu;class _w extends pT{static get type(){return"MeshToonNodeMaterial"}constructor(e){super(),this.isMeshToonNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Tw),this.setValues(e)}setupLightingModel(){return new vw}}class ww extends kd{static get type(){return"MatcapUVNode"}constructor(){super("vec2")}setup(){const e=jp(dx.z,0,dx.x.negate()).normalize(),t=dx.cross(e);return Dp(e.dot(Tx),t.dot(Tx)).mul(.495).add(.5)}}const Sw=Cp(ww),Mw=new Eu;class Nw extends pT{static get type(){return"MeshMatcapNodeMaterial"}constructor(e){super(),this.lights=!1,this.isMeshMatcapNodeMaterial=!0,this.setDefaultValues(Mw),this.setValues(e)}setupVariants(e){const t=Sw;let s;s=e.material.matcap?jx("matcap","texture").context({getUV:()=>t}):jp(Tf(.2,.8,t.y)),ym.rgb.mulAssign(s.rgb)}}const Aw=new za;class Cw extends pT{static get type(){return"PointsNodeMaterial"}constructor(e){super(),this.isPointsNodeMaterial=!0,this.lights=!1,this.transparent=!0,this.sizeNode=null,this.setDefaultValues(Aw),this.setValues(e)}copy(e){return this.sizeNode=e.sizeNode,super.copy(e)}}class Rw extends kd{static get type(){return"RotateNode"}constructor(e,t){super(),this.positionNode=e,this.rotationNode=t}getNodeType(e){return this.positionNode.getNodeType(e)}setup(e){const{rotationNode:t,positionNode:s}=this;if("vec2"===this.getNodeType(e)){const e=t.cos(),i=t.sin();return Kp(e,i,i.negate(),e).mul(s)}{const e=t,i=em(Xp(1,0,0,0),Xp(0,Vg(e.x),Lg(e.x).negate(),0),Xp(0,Lg(e.x),Vg(e.x),0),Xp(0,0,0,1)),r=em(Xp(Vg(e.y),0,Lg(e.y),0),Xp(0,1,0,0),Xp(Lg(e.y).negate(),0,Vg(e.y),0),Xp(0,0,0,1)),n=em(Xp(Vg(e.z),Lg(e.z).negate(),0,0),Xp(Lg(e.z),Vg(e.z),0,0),Xp(0,0,1,0),Xp(0,0,0,1));return i.mul(r).mul(n).mul(Xp(s,1)).xyz}}}const Ew=Ap(Rw),Bw=new no;class Iw extends pT{static get type(){return"SpriteNodeMaterial"}constructor(e){super(),this.isSpriteNodeMaterial=!0,this.lights=!1,this._useSizeAttenuation=!0,this.positionNode=null,this.rotationNode=null,this.scaleNode=null,this.setDefaultValues(Bw),this.setValues(e)}setupPosition({object:e,camera:t,context:s}){const i=this.sizeAttenuation,{positionNode:r,rotationNode:n,scaleNode:o}=this,a=ax;let h=ix.mul(jp(r||0)),u=Dp(Jy[0].xyz.length(),Jy[1].xyz.length());null!==o&&(u=u.mul(o)),!i&&t.isPerspectiveCamera&&(u=u.mul(h.z.negate()));let l=a.xy;if(e.center&&!0===e.center.isVector2){const e=((e,t,s)=>Sp(new Zf(e,t,s)))("center","vec2");l=l.sub(e.sub(.5))}l=l.mul(u);const c=Up(n||Pb),d=Ew(l,c);h=Xp(h.xy.add(d),h.zw);const p=Oy.mul(h);return s.vertex=a,p}copy(e){return this.positionNode=e.positionNode,this.rotationNode=e.rotationNode,this.scaleNode=e.scaleNode,super.copy(e)}get sizeAttenuation(){return this._useSizeAttenuation}set sizeAttenuation(e){this._useSizeAttenuation!==e&&(this._useSizeAttenuation=e,this.needsUpdate=!0)}}class Pw extends UT{constructor(){super(),this.shadowNode=Up(1).toVar("shadowMask")}direct({shadowMask:e}){this.shadowNode.mulAssign(e)}finish(e){ym.a.mulAssign(this.shadowNode.oneMinus()),e.outgoingLight.rgb.assign(ym.rgb)}}const Fw=new vu;class zw extends pT{static get type(){return"ShadowNodeMaterial"}constructor(e){super(),this.isShadowNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Fw),this.setValues(e)}setupLightingModel(){return new Pw}}const Uw=Rp((({texture:e,uv:t})=>{const s=1e-4,i=jp().toVar();return Pp(t.x.lessThan(s),(()=>{i.assign(jp(1,0,0))})).ElseIf(t.y.lessThan(s),(()=>{i.assign(jp(0,1,0))})).ElseIf(t.z.lessThan(s),(()=>{i.assign(jp(0,0,1))})).ElseIf(t.x.greaterThan(.9999),(()=>{i.assign(jp(-1,0,0))})).ElseIf(t.y.greaterThan(.9999),(()=>{i.assign(jp(0,-1,0))})).ElseIf(t.z.greaterThan(.9999),(()=>{i.assign(jp(0,0,-1))})).Else((()=>{const s=.01,r=e.uv(t.add(jp(-.01,0,0))).r.sub(e.uv(t.add(jp(s,0,0))).r),n=e.uv(t.add(jp(0,-.01,0))).r.sub(e.uv(t.add(jp(0,s,0))).r),o=e.uv(t.add(jp(0,0,-.01))).r.sub(e.uv(t.add(jp(0,0,s))).r);i.assign(jp(r,n,o))})),i.normalize()}));class Ow extends Ey{static get type(){return"Texture3DNode"}constructor(e,t=null,s=null){super(e,t,s),this.isTexture3DNode=!0}getInputType(){return"texture3D"}getDefaultUV(){return jp(.5,.5,.5)}setUpdateMatrix(){}setupUV(e,t){return t}generateUV(e,t){return t.build(e,"vec3")}normal(e){return Uw({texture:this,uv:e})}}const Lw=Ap(Ow);class Vw extends pT{static get type(){return"VolumeNodeMaterial"}constructor(e={}){super(),this.lights=!1,this.isVolumeNodeMaterial=!0,this.testNode=null,this.setValues(e)}setup(e){const t=Lw(this.map,null,0),s=Rp((({orig:e,dir:t})=>{const s=jp(-.5),i=jp(.5),r=t.reciprocal(),n=s.sub(e).mul(r),o=i.sub(e).mul(r),a=nf(n,o),h=of(n,o),u=of(a.x,of(a.y,a.z)),l=nf(h.x,nf(h.y,h.z));return Dp(u,l)}));this.fragmentNode=Rp((()=>{const e=Vf(jp(sx.mul(Xp(Gy,1)))),i=Vf(ox.sub(e)).normalize(),r=Dp(s({orig:e,dir:i})).toVar();r.x.greaterThan(r.y).discard(),r.assign(Dp(of(r.x,0),r.y));const n=jp(e.add(r.x.mul(i))).toVar(),o=jp(i.abs().reciprocal()).toVar(),a=Up(nf(o.x,nf(o.y,o.z))).toVar("delta");a.divAssign(jx("steps","float"));const h=Xp(jx("base","color"),0).toVar();return bv({type:"float",start:r.x,end:r.y,update:"+= delta"},(()=>{const e=gm("float","d").assign(t.uv(n.add(.5)).r);null!==this.testNode?this.testNode({map:t,mapValue:e,probe:n,finalColor:h}).append():(h.a.assign(1),Tv()),n.addAssign(i.mul(a))})),h.a.equal(0).discard(),Xp(h)}))(),super.setup(e)}}class Dw{constructor(e,t){this.nodes=e,this.info=t,this.animationLoop=null,this.requestId=null,this._init()}_init(){const e=(t,s)=>{this.requestId=self.requestAnimationFrame(e),!0===this.info.autoReset&&this.info.reset(),this.nodes.nodeFrame.update(),this.info.frame=this.nodes.nodeFrame.frameId,null!==this.animationLoop&&this.animationLoop(t,s)};e()}dispose(){self.cancelAnimationFrame(this.requestId),this.requestId=null}setAnimationLoop(e){this.animationLoop=e}}class kw{constructor(){this.weakMap=new WeakMap}get(e){let t=this.weakMap;for(let s=0;s{this.dispose()},this.material.addEventListener("dispose",this.onMaterialDispose)}updateClipping(e){const t=this.material;let s=this.clippingContext;Array.isArray(t.clippingPlanes)?(s!==e&&s||(s=new Ww,this.clippingContext=s),s.update(e,t)):this.clippingContext!==e&&(this.clippingContext=e)}get clippingNeedsUpdate(){return this.clippingContext.version!==this.clippingContextVersion&&(this.clippingContextVersion=this.clippingContext.version,!0)}getNodeBuilderState(){return this._nodeBuilderState||(this._nodeBuilderState=this._nodes.getForRender(this))}getMonitor(){return this._monitor||(this._monitor=this.getNodeBuilderState().monitor)}getBindings(){return this._bindings||(this._bindings=this.getNodeBuilderState().createBindings())}getIndex(){return this._geometries.getIndex(this)}getChainArray(){return[this.object,this.material,this.context,this.lightsNode]}getAttributes(){if(null!==this.attributes)return this.attributes;const e=this.getNodeBuilderState().nodeAttributes,t=this.geometry,s=[],i=new Set;for(const r of e){const e=r.node&&r.node.attribute?r.node.attribute:t.getAttribute(r.name);if(void 0===e)continue;s.push(e);const n=e.isInterleavedBufferAttribute?e.data:e;i.add(n)}return this.attributes=s,this.vertexBuffers=Array.from(i.values()),s}getVertexBuffers(){return null===this.vertexBuffers&&this.getAttributes(),this.vertexBuffers}getDrawParameters(){const{object:e,material:t,geometry:s,group:i,drawRange:r}=this,n=this.drawParams||(this.drawParams={vertexCount:0,firstVertex:0,instanceCount:0,firstInstance:0}),o=this.getIndex(),a=null!==o,h=s.isInstancedBufferGeometry?s.instanceCount:e.count>1?e.count:1;if(0===h)return null;if(n.instanceCount=h,!0===e.isBatchedMesh)return n;let u=1;!0!==t.wireframe||e.isPoints||e.isLineSegments||e.isLine||e.isLineLoop||(u=2);let l=r.start*u,c=(r.start+r.count)*u;null!==i&&(l=Math.max(l,i.start*u),c=Math.min(c,(i.start+i.count)*u));const d=!0===a?o.count:s.attributes.position.count;l=Math.max(l,0),c=Math.min(c,d);const p=c-l;return p<0||p===1/0?null:(n.vertexCount=p,n.firstVertex=l,n)}getGeometryCacheKey(){const{geometry:e}=this;let t="";for(const s of Object.keys(e.attributes).sort()){const i=e.attributes[s];t+=s+",",i.data&&(t+=i.data.stride+","),i.offset&&(t+=i.offset+","),i.itemSize&&(t+=i.itemSize+","),i.normalized&&(t+="n,")}return e.index&&(t+="index,"),t}getMaterialCacheKey(){const{object:e,material:t}=this;let s=t.customProgramCacheKey();for(const e of function(e){const t=Object.keys(e);let s=Object.getPrototypeOf(e);for(;s;){const e=Object.getOwnPropertyDescriptors(s);for(const s in e)if(void 0!==e[s]){const i=e[s];i&&"function"==typeof i.get&&t.push(s)}s=Object.getPrototypeOf(s)}return t}(t)){if(/^(is[A-Z]|_)|^(visible|version|uuid|name|opacity|userData)$/.test(e))continue;const i=t[e];let r;if(null!==i){const e=typeof i;"number"===e?r=0!==i?"1":"0":"object"===e?(r="{",i.isTexture&&(r+=i.mapping),r+="}"):r=String(i)}else r=String(i);s+=r+","}return s+=this.clippingContext.cacheKey+",",e.geometry&&(s+=this.getGeometryCacheKey()),e.skeleton&&(s+=e.skeleton.bones.length+","),e.morphTargetInfluences&&(s+=e.morphTargetInfluences.length+","),e.isBatchedMesh&&(s+=e._matricesTexture.uuid+",",null!==e._colorsTexture&&(s+=e._colorsTexture.uuid+",")),e.count>1&&(s+=e.uuid+","),vd(s)}get needsUpdate(){return this.initialNodesCacheKey!==this.getDynamicCacheKey()||this.clippingNeedsUpdate}getDynamicCacheKey(){let e=this._nodes.getCacheKey(this.scene,this.lightsNode);return this.object.receiveShadow&&(e+=1),e}getCacheKey(){return this.getMaterialCacheKey()+this.getDynamicCacheKey()}dispose(){this.material.removeEventListener("dispose",this.onMaterialDispose),this.onDispose()}}const qw=[];class $w{constructor(e,t,s,i,r,n){this.renderer=e,this.nodes=t,this.geometries=s,this.pipelines=i,this.bindings=r,this.info=n,this.chainMaps={}}get(e,t,s,i,r,n,o){const a=this.getChainMap(o);qw[0]=e,qw[1]=t,qw[2]=n,qw[3]=r;let h=a.get(qw);return void 0===h?(h=this.createRenderObject(this.nodes,this.geometries,this.renderer,e,t,s,i,r,n,o),a.set(qw,h)):(h.updateClipping(n.clippingContext),(h.version!==t.version||h.needsUpdate)&&(h.initialCacheKey!==h.getCacheKey()?(h.dispose(),h=this.get(e,t,s,i,r,n,o)):h.version=t.version)),h}getChainMap(e="default"){return this.chainMaps[e]||(this.chainMaps[e]=new kw)}dispose(){this.chainMaps={}}createRenderObject(e,t,s,i,r,n,o,a,h,u){const l=this.getChainMap(u),c=new Hw(e,t,s,i,r,n,o,a,h);return c.onDispose=()=>{this.pipelines.delete(c),this.bindings.delete(c),this.nodes.delete(c),l.delete(c.getChainArray())},c}}class Xw{constructor(){this.data=new WeakMap}get(e){let t=this.data.get(e);return void 0===t&&(t={},this.data.set(e,t)),t}delete(e){let t;return this.data.has(e)&&(t=this.data.get(e),this.data.delete(e)),t}has(e){return this.data.has(e)}dispose(){this.data=new WeakMap}}const Yw=1,Zw=2,Jw=4,Kw=16;class Qw extends Xw{constructor(e){super(),this.backend=e}delete(e){const t=super.delete(e);return void 0!==t&&this.backend.destroyAttribute(e),t}update(e,t){const s=this.get(e);if(void 0===s.version)t===Yw?this.backend.createAttribute(e):t===Zw?this.backend.createIndexAttribute(e):t===Jw&&this.backend.createStorageAttribute(e),s.version=this._getBufferAttribute(e).version;else{const t=this._getBufferAttribute(e);(s.version=0;--t)if(e[t]>=65535)return!0;return!1}(t)?yn:gn)(t,1);return r.version=eS(e),r}class sS extends Xw{constructor(e,t){super(),this.attributes=e,this.info=t,this.wireframes=new WeakMap,this.attributeCall=new WeakMap}has(e){const t=e.geometry;return super.has(t)&&!0===this.get(t).initialized}updateForRender(e){!1===this.has(e)&&this.initGeometry(e),this.updateAttributes(e)}initGeometry(e){const t=e.geometry;this.get(t).initialized=!0,this.info.memory.geometries++;const s=()=>{this.info.memory.geometries--;const i=t.index,r=e.getAttributes();null!==i&&this.attributes.delete(i);for(const e of r)this.attributes.delete(e);const n=this.wireframes.get(t);void 0!==n&&this.attributes.delete(n),t.removeEventListener("dispose",s)};t.addEventListener("dispose",s)}updateAttributes(e){const t=e.getAttributes();for(const e of t)e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute?this.updateAttribute(e,Jw):this.updateAttribute(e,Yw);const s=this.getIndex(e);null!==s&&this.updateAttribute(s,Zw)}updateAttribute(e,t){const s=this.info.render.calls;e.isInterleavedBufferAttribute?void 0===this.attributeCall.get(e)?(this.attributes.update(e,t),this.attributeCall.set(e,s)):this.attributeCall.get(e.data)!==s&&(this.attributes.update(e,t),this.attributeCall.set(e.data,s),this.attributeCall.set(e,s)):this.attributeCall.get(e)!==s&&(this.attributes.update(e,t),this.attributeCall.set(e,s))}getIndex(e){const{geometry:t,material:s}=e;let i=t.index;if(!0===s.wireframe){const e=this.wireframes;let s=e.get(t);void 0===s?(s=tS(t),e.set(t,s)):s.version!==eS(t)&&(this.attributes.delete(s),s=tS(t),e.set(t,s)),i=s}return i}}class iS{constructor(){this.autoReset=!0,this.frame=0,this.calls=0,this.render={calls:0,frameCalls:0,drawCalls:0,triangles:0,points:0,lines:0,timestamp:0,previousFrameCalls:0,timestampCalls:0},this.compute={calls:0,frameCalls:0,timestamp:0,previousFrameCalls:0,timestampCalls:0},this.memory={geometries:0,textures:0}}update(e,t,s){this.render.drawCalls++,e.isMesh||e.isSprite?this.render.triangles+=s*(t/3):e.isPoints?this.render.points+=s*t:e.isLineSegments?this.render.lines+=s*(t/2):e.isLine?this.render.lines+=s*(t-1):console.error("THREE.WebGPUInfo: Unknown object type.")}updateTimestamp(e,t){0===this[e].timestampCalls&&(this[e].timestamp=0),this[e].timestamp+=t,this[e].timestampCalls++,this[e].timestampCalls>=this[e].previousFrameCalls&&(this[e].timestampCalls=0)}reset(){const e=this.render.frameCalls;this.render.previousFrameCalls=e;const t=this.compute.frameCalls;this.compute.previousFrameCalls=t,this.render.drawCalls=0,this.render.frameCalls=0,this.compute.frameCalls=0,this.render.triangles=0,this.render.points=0,this.render.lines=0}dispose(){this.reset(),this.calls=0,this.render.calls=0,this.compute.calls=0,this.render.timestamp=0,this.compute.timestamp=0,this.memory.geometries=0,this.memory.textures=0}}class rS{constructor(e){this.cacheKey=e,this.usedTimes=0}}class nS extends rS{constructor(e,t,s){super(e),this.vertexProgram=t,this.fragmentProgram=s}}class oS extends rS{constructor(e,t){super(e),this.computeProgram=t,this.isComputePipeline=!0}}let aS=0;class hS{constructor(e,t,s=null,i=null){this.id=aS++,this.code=e,this.stage=t,this.transforms=s,this.attributes=i,this.usedTimes=0}}class uS extends Xw{constructor(e,t){super(),this.backend=e,this.nodes=t,this.bindings=null,this.caches=new Map,this.programs={vertex:new Map,fragment:new Map,compute:new Map}}getForCompute(e,t){const{backend:s}=this,i=this.get(e);if(this._needsComputeUpdate(e)){const r=i.pipeline;r&&(r.usedTimes--,r.computeProgram.usedTimes--);const n=this.nodes.getForCompute(e);let o=this.programs.compute.get(n.computeShader);void 0===o&&(r&&0===r.computeProgram.usedTimes&&this._releaseProgram(r.computeProgram),o=new hS(n.computeShader,"compute",n.transforms,n.nodeAttributes),this.programs.compute.set(n.computeShader,o),s.createProgram(o));const a=this._getComputeCacheKey(e,o);let h=this.caches.get(a);void 0===h&&(r&&0===r.usedTimes&&this._releasePipeline(r),h=this._getComputePipeline(e,o,a,t)),h.usedTimes++,o.usedTimes++,i.version=e.version,i.pipeline=h}return i.pipeline}getForRender(e,t=null){const{backend:s}=this,i=this.get(e);if(this._needsRenderUpdate(e)){const r=i.pipeline;r&&(r.usedTimes--,r.vertexProgram.usedTimes--,r.fragmentProgram.usedTimes--);const n=e.getNodeBuilderState();let o=this.programs.vertex.get(n.vertexShader);void 0===o&&(r&&0===r.vertexProgram.usedTimes&&this._releaseProgram(r.vertexProgram),o=new hS(n.vertexShader,"vertex"),this.programs.vertex.set(n.vertexShader,o),s.createProgram(o));let a=this.programs.fragment.get(n.fragmentShader);void 0===a&&(r&&0===r.fragmentProgram.usedTimes&&this._releaseProgram(r.fragmentProgram),a=new hS(n.fragmentShader,"fragment"),this.programs.fragment.set(n.fragmentShader,a),s.createProgram(a));const h=this._getRenderCacheKey(e,o,a);let u=this.caches.get(h);void 0===u?(r&&0===r.usedTimes&&this._releasePipeline(r),u=this._getRenderPipeline(e,o,a,h,t)):e.pipeline=u,u.usedTimes++,o.usedTimes++,a.usedTimes++,i.pipeline=u}return i.pipeline}delete(e){const t=this.get(e).pipeline;return t&&(t.usedTimes--,0===t.usedTimes&&this._releasePipeline(t),t.isComputePipeline?(t.computeProgram.usedTimes--,0===t.computeProgram.usedTimes&&this._releaseProgram(t.computeProgram)):(t.fragmentProgram.usedTimes--,t.vertexProgram.usedTimes--,0===t.vertexProgram.usedTimes&&this._releaseProgram(t.vertexProgram),0===t.fragmentProgram.usedTimes&&this._releaseProgram(t.fragmentProgram))),super.delete(e)}dispose(){super.dispose(),this.caches=new Map,this.programs={vertex:new Map,fragment:new Map,compute:new Map}}updateForRender(e){this.getForRender(e)}_getComputePipeline(e,t,s,i){s=s||this._getComputeCacheKey(e,t);let r=this.caches.get(s);return void 0===r&&(r=new oS(s,t),this.caches.set(s,r),this.backend.createComputePipeline(r,i)),r}_getRenderPipeline(e,t,s,i,r){i=i||this._getRenderCacheKey(e,t,s);let n=this.caches.get(i);return void 0===n&&(n=new nS(i,t,s),this.caches.set(i,n),e.pipeline=n,this.backend.createRenderPipeline(e,r)),n}_getComputeCacheKey(e,t){return e.id+","+t.id}_getRenderCacheKey(e,t,s){return t.id+","+s.id+","+this.backend.getRenderCacheKey(e)}_releasePipeline(e){this.caches.delete(e.cacheKey)}_releaseProgram(e){const t=e.code,s=e.stage;this.programs[s].delete(t)}_needsComputeUpdate(e){const t=this.get(e);return void 0===t.pipeline||t.version!==e.version}_needsRenderUpdate(e){return void 0===this.get(e).pipeline||this.backend.needsRenderUpdate(e)}}class lS extends Xw{constructor(e,t,s,i,r,n){super(),this.backend=e,this.textures=s,this.pipelines=r,this.attributes=i,this.nodes=t,this.info=n,this.pipelines.bindings=this}getForRender(e){const t=e.getBindings();for(const e of t){const s=this.get(e);void 0===s.bindGroup&&(this._init(e),this.backend.createBindings(e,t),s.bindGroup=e)}return t}getForCompute(e){const t=this.nodes.getForCompute(e).bindings;for(const e of t){const s=this.get(e);void 0===s.bindGroup&&(this._init(e),this.backend.createBindings(e,t),s.bindGroup=e)}return t}updateForCompute(e){this._updateBindings(this.getForCompute(e))}updateForRender(e){this._updateBindings(this.getForRender(e))}_updateBindings(e){for(const t of e)this._update(t,e)}_init(e){for(const t of e.bindings)if(t.isSampledTexture)this.textures.updateTexture(t.texture);else if(t.isStorageBuffer){const e=t.attribute;this.attributes.update(e,Jw)}}_update(e,t){const{backend:s}=this;let i=!1;for(const t of e.bindings){if(t.isNodeUniformsGroup){if(!this.nodes.updateGroup(t))continue}if(t.isUniformBuffer){t.update()&&s.updateBinding(t)}else if(t.isSampler)t.update();else if(t.isSampledTexture){t.needsBindingsUpdate(this.textures.get(t.texture).generation)&&(i=!0);const e=t.update(),r=t.texture;e&&this.textures.updateTexture(r);const n=s.get(r);if(!0===s.isWebGPUBackend&&void 0===n.texture&&void 0===n.externalTexture&&(console.error("Bindings._update: binding should be available:",t,e,r,t.textureNode.value,i),this.textures.updateTexture(r),i=!0),!0===r.isStorageTexture){const e=this.get(r);!0===t.store?e.needsMipmap=!0:!0===r.generateMipmaps&&this.textures.needsMipmaps(r)&&!0===e.needsMipmap&&(this.backend.generateMipmaps(r),e.needsMipmap=!1)}}}!0===i&&this.backend.updateBindings(e,t)}}class cS{constructor(e,t,s=null){this.isNodeAttribute=!0,this.name=e,this.type=t,this.node=s}}class dS{constructor(e,t,s){this.isNodeUniform=!0,this.name=e,this.type=t,this.node=s.getSelf()}get value(){return this.node.value}set value(e){this.node.value=e}get id(){return this.node.id}get groupNode(){return this.node.groupNode}}class pS{constructor(e,t){this.isNodeVar=!0,this.name=e,this.type=t}}class mS extends pS{constructor(e,t){super(e,t),this.needsInterpolation=!1,this.isNodeVarying=!0}}class gS{constructor(e,t,s=""){this.name=e,this.type=t,this.code=s,Object.defineProperty(this,"isNodeCode",{value:!0})}}let fS=0;class yS{constructor(e=null){this.id=fS++,this.nodesData=new WeakMap,this.parent=e}getData(e){let t=this.nodesData.get(e);return void 0===t&&null!==this.parent&&(t=this.parent.getData(e)),t}setData(e,t){this.nodesData.set(e,t)}}class xS extends mm{static get type(){return"ParameterNode"}constructor(e,t=null){super(e,t),this.isParameterNode=!0}getHash(){return this.uuid}generate(){return this.name}}const bS=(e,t)=>Sp(new xS(e,t));class vS extends Ld{static get type(){return"CodeNode"}constructor(e="",t=[],s=""){super("code"),this.isCodeNode=!0,this.code=e,this.language=s,this.includes=t}isGlobal(){return!0}setIncludes(e){return this.includes=e,this}getIncludes(){return this.includes}generate(e){const t=this.getIncludes(e);for(const s of t)s.build(e);const s=e.getCodeFromNode(this,this.getNodeType(e));return s.code=this.code,s.code}serialize(e){super.serialize(e),e.code=this.code,e.language=this.language}deserialize(e){super.deserialize(e),this.code=e.code,this.language=e.language}}const TS=Ap(vS),_S=(e,t)=>TS(e,t,"js"),wS=(e,t)=>TS(e,t,"wgsl"),SS=(e,t)=>TS(e,t,"glsl");class MS extends vS{static get type(){return"FunctionNode"}constructor(e="",t=[],s=""){super(e,t,s)}getNodeType(e){return this.getNodeFunction(e).type}getInputs(e){return this.getNodeFunction(e).inputs}getNodeFunction(e){const t=e.getDataFromNode(this);let s=t.nodeFunction;return void 0===s&&(s=e.parser.parseFunction(this.code),t.nodeFunction=s),s}generate(e,t){super.generate(e);const s=this.getNodeFunction(e),i=s.name,r=s.type,n=e.getCodeFromNode(this,r);""!==i&&(n.name=i);const o=e.getPropertyName(n),a=this.getNodeFunction(e).getCode(o);return n.code=a+"\n","property"===t?o:e.format(`${o}()`,r,t)}}const NS=(e,t=[],s="")=>{for(let e=0;ei.call(...e);return r.functionNode=i,r},AS=(e,t)=>NS(e,t,"glsl"),CS=(e,t)=>NS(e,t,"wgsl");class RS{constructor(e,t){this.name=e,this.value=t,this.boundary=0,this.itemSize=0,this.offset=0}setValue(e){this.value=e}getValue(){return this.value}}class ES extends RS{constructor(e,t=0){super(e,t),this.isNumberUniform=!0,this.boundary=4,this.itemSize=1}}class BS extends RS{constructor(e,t=new Qs){super(e,t),this.isVector2Uniform=!0,this.boundary=8,this.itemSize=2}}class IS extends RS{constructor(e,t=new Ri){super(e,t),this.isVector3Uniform=!0,this.boundary=16,this.itemSize=3}}class PS extends RS{constructor(e,t=new Ti){super(e,t),this.isVector4Uniform=!0,this.boundary=16,this.itemSize=4}}class FS extends RS{constructor(e,t=new Jr){super(e,t),this.isColorUniform=!0,this.boundary=16,this.itemSize=3}}class zS extends RS{constructor(e,t=new ei){super(e,t),this.isMatrix3Uniform=!0,this.boundary=48,this.itemSize=12}}class US extends RS{constructor(e,t=new nr){super(e,t),this.isMatrix4Uniform=!0,this.boundary=64,this.itemSize=16}}class OS extends ES{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class LS extends BS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class VS extends IS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class DS extends PS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class kS extends FS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class GS extends zS{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class WS extends US{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}}class jS extends Ld{static get type(){return"StackNode"}constructor(e=null){super(),this.nodes=[],this.outputNode=null,this.parent=e,this._currentCond=null,this.isStackNode=!0}getNodeType(e){return this.outputNode?this.outputNode.getNodeType(e):"void"}add(e){return this.nodes.push(e),this}If(e,t){const s=new wp(t);return this._currentCond=Bf(e,s),this.add(this._currentCond)}ElseIf(e,t){const s=new wp(t),i=Bf(e,s);return this._currentCond.elseNode=i,this._currentCond=i,this}Else(e){return this._currentCond.elseNode=new wp(e),this}build(e,...t){const s=Ip();Bp(this);for(const t of this.nodes)t.build(e,"void");return Bp(s),this.outputNode?this.outputNode.build(e,...t):super.build(e,...t)}else(...e){return console.warn("TSL.StackNode: .else() has been renamed to .Else()."),this.Else(...e)}elseif(...e){return console.warn("TSL.StackNode: .elseif() has been renamed to .ElseIf()."),this.ElseIf(...e)}}const HS=Ap(jS),qS=[.125,.215,.35,.446,.526,.582],$S=20,XS=new Sl(-1,1,1,-1,0,1),YS=new Xn(90,1),ZS=new Jr;let JS=null,KS=0,QS=0;const eM=(1+Math.sqrt(5))/2,tM=1/eM,sM=[new Ri(-eM,tM,0),new Ri(eM,tM,0),new Ri(-tM,0,eM),new Ri(tM,0,eM),new Ri(0,eM,-tM),new Ri(0,eM,tM),new Ri(-1,1,-1),new Ri(1,1,-1),new Ri(-1,1,1),new Ri(1,1,1)],iM=[3,1,5,0,4,2],rM=Q_(My(),Sy("faceIndex")).normalize(),nM=jp(rM.x,rM.y.negate(),rM.z);class oM{constructor(e){this._renderer=e,this._pingPongRenderTarget=null,this._lodMax=0,this._cubeSize=0,this._lodPlanes=[],this._sizeLods=[],this._sigmas=[],this._lodMeshes=[],this._blurMaterial=null,this._cubemapMaterial=null,this._equirectMaterial=null,this._backgroundBox=null}fromScene(e,t=0,s=.1,i=100){JS=this._renderer.getRenderTarget(),KS=this._renderer.getActiveCubeFace(),QS=this._renderer.getActiveMipmapLevel(),this._setSize(256);const r=this._allocateTargets();return r.depthBuffer=!0,this._sceneToCubeUV(e,s,i,r),t>0&&this._blur(r,0,0,t),this._applyPMREM(r),this._cleanup(r),r}fromEquirectangular(e,t=null){return this._fromTexture(e,t)}fromCubemap(e,t=null){return this._fromTexture(e,t)}async compileCubemapShader(){null===this._cubemapMaterial&&(this._cubemapMaterial=lM(),await this._compileMaterial(this._cubemapMaterial))}async compileEquirectangularShader(){null===this._equirectMaterial&&(this._equirectMaterial=cM(),await this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),null!==this._cubemapMaterial&&this._cubemapMaterial.dispose(),null!==this._equirectMaterial&&this._equirectMaterial.dispose(),null!==this._backgroundBox&&(this._backgroundBox.geometry.dispose(),this._backgroundBox.material.dispose())}_setSize(e){this._lodMax=Math.floor(Math.log2(e)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){null!==this._blurMaterial&&this._blurMaterial.dispose(),null!==this._pingPongRenderTarget&&this._pingPongRenderTarget.dispose();for(let e=0;ee-4?h=qS[a-e+4-1]:0===a&&(h=0),i.push(h);const u=1/(o-2),l=-u,c=1+u,d=[l,l,c,l,c,c,l,l,c,c,l,c],p=6,m=6,g=3,f=2,y=1,x=new Float32Array(g*m*p),b=new Float32Array(f*m*p),v=new Float32Array(y*m*p);for(let e=0;e2?0:-1,i=[t,s,0,t+2/3,s,0,t+2/3,s+1,0,t,s,0,t+2/3,s+1,0,t,s+1,0],r=iM[e];x.set(i,g*m*r),b.set(d,f*m*r);const n=[r,r,r,r,r,r];v.set(n,y*m*r)}const T=new An;T.setAttribute("position",new ln(x,g)),T.setAttribute("uv",new ln(b,f)),T.setAttribute("faceIndex",new ln(v,y)),t.push(T),r.push(new Vn(T,null)),n>4&&n--}return{lodPlanes:t,sizeLods:s,sigmas:i,lodMeshes:r}}(i)),this._blurMaterial=function(e,t,s){const i=Ox(new Array($S).fill(0)),r=pm(new Ri(0,1,0)),n=pm(0),o=Up($S),a=pm(0),h=pm(1),u=By(null),l=pm(0),c=Up(1/t),d=Up(1/s),p=Up(e),m={n:o,latitudinal:a,weights:i,poleAxis:r,outputDirection:nM,dTheta:n,samples:h,envMap:u,mipInt:l,CUBEUV_TEXEL_WIDTH:c,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:p},g=uM("blur");return g.uniforms=m,g.fragmentNode=iw({...m,latitudinal:a.equal(1)}),g}(i,e,t)}return i}async _compileMaterial(e){const t=new Vn(this._lodPlanes[0],e);await this._renderer.compile(t,XS)}_sceneToCubeUV(e,t,s,i){const r=YS;r.near=t,r.far=s;const n=[-1,1,-1,-1,-1,-1],o=[1,1,1,-1,-1,-1],a=this._renderer,h=a.autoClear;a.getClearColor(ZS),a.autoClear=!1;let u=this._backgroundBox;if(null===u){const e=new tn({name:"PMREM.Background",side:d,depthWrite:!1,depthTest:!1});u=new Vn(new kn,e)}let l=!1;const c=e.background;c?c.isColor&&(u.material.color.copy(c),e.background=null,l=!0):(u.material.color.copy(ZS),l=!0),a.setRenderTarget(i),a.clear(),l&&a.render(u,r);for(let t=0;t<6;t++){const s=t%3;0===s?(r.up.set(0,n[t],0),r.lookAt(o[t],0,0)):1===s?(r.up.set(0,0,n[t]),r.lookAt(0,o[t],0)):(r.up.set(0,n[t],0),r.lookAt(0,0,o[t]));const h=this._cubeSize;hM(i,s*h,t>2?h:0,h,h),a.render(e,r)}a.autoClear=h,e.background=c}_textureToCubeUV(e,t){const s=this._renderer,i=e.mapping===he||e.mapping===ue;i?null===this._cubemapMaterial&&(this._cubemapMaterial=lM(e)):null===this._equirectMaterial&&(this._equirectMaterial=cM(e));const r=i?this._cubemapMaterial:this._equirectMaterial;r.fragmentNode.value=e;const n=this._lodMeshes[0];n.material=r;const o=this._cubeSize;hM(t,0,0,3*o,2*o),s.setRenderTarget(t),s.render(n,XS)}_applyPMREM(e){const t=this._renderer,s=t.autoClear;t.autoClear=!1;const i=this._lodPlanes.length;for(let t=1;t$S&&console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${m} samples when the maximum is set to 20`);const g=[];let f=0;for(let e=0;e<$S;++e){const t=e/p,s=Math.exp(-t*t/2);g.push(s),0===e?f+=s:ey-4?i-y+4:0),4*(this._cubeSize-x),3*x,2*x),a.setRenderTarget(t),a.render(u,XS)}}function aM(e,t,s){const i=new _i(e,t,s);return i.texture.mapping=de,i.texture.name="PMREM.cubeUv",i.texture.isPMREMTexture=!0,i.scissorTest=!0,i}function hM(e,t,s,i,r){e.viewport.set(t,s,i,r),e.scissor.set(t,s,i,r)}function uM(e){const t=new pT;return t.depthTest=!1,t.depthWrite=!1,t.blending=m,t.name=`PMREM_${e}`,t}function lM(e){const t=uM("cubemap");return t.fragmentNode=Ix(e,nM),t}function cM(e){const t=uM("equirect");return t.fragmentNode=By(e,AT(nM),0),t}let dM=0;class pM{constructor(e="",t=[],s=0,i=[]){this.name=e,this.bindings=t,this.index=s,this.bindingsReference=i,this.id=dM++}}const mM=new WeakMap,gM=new Map([[2,"vec2"],[3,"vec3"],[4,"vec4"],[9,"mat3"],[16,"mat4"]]),fM=new Map([[Int8Array,"int"],[Int16Array,"int"],[Int32Array,"int"],[Uint8Array,"uint"],[Uint16Array,"uint"],[Uint32Array,"uint"],[Float32Array,"float"]]),yM=e=>(e=Number(e))+(e%1?"":".0");class xM{constructor(e,t,s){this.object=e,this.material=e&&e.material||null,this.geometry=e&&e.geometry||null,this.renderer=t,this.parser=s,this.scene=null,this.camera=null,this.nodes=[],this.updateNodes=[],this.updateBeforeNodes=[],this.updateAfterNodes=[],this.hashNodes={},this.monitor=null,this.lightsNode=null,this.environmentNode=null,this.fogNode=null,this.clippingContext=null,this.vertexShader=null,this.fragmentShader=null,this.computeShader=null,this.flowNodes={vertex:[],fragment:[],compute:[]},this.flowCode={vertex:"",fragment:"",compute:""},this.uniforms={vertex:[],fragment:[],compute:[],index:0},this.structs={vertex:[],fragment:[],compute:[],index:0},this.bindings={vertex:{},fragment:{},compute:{}},this.bindingsIndexes={},this.bindGroups=null,this.attributes=[],this.bufferAttributes=[],this.varyings=[],this.codes={},this.vars={},this.flow={code:""},this.chaining=[],this.stack=HS(),this.stacks=[],this.tab="\t",this.currentFunctionNode=null,this.context={material:this.material},this.cache=new yS,this.globalCache=this.cache,this.flowsData=new WeakMap,this.shaderStage=null,this.buildStage=null,this.useComparisonMethod=!1}getBindGroupsCache(){let e=mM.get(this.renderer);return void 0===e&&(e=new kw,mM.set(this.renderer,e)),e}createRenderTarget(e,t,s){return new _i(e,t,s)}createCubeRenderTarget(e,t){return new CT(e,t)}createPMREMGenerator(){return new oM(this.renderer)}includes(e){return this.nodes.includes(e)}_getBindGroup(e,t){const s=this.getBindGroupsCache(),i=[];let r,n=!0;for(const e of t)i.push(e),n=n&&!0!==e.groupNode.shared;return n?(r=s.get(i),void 0===r&&(r=new pM(e,i,this.bindingsIndexes[e].group,i),s.set(i,r))):r=new pM(e,i,this.bindingsIndexes[e].group,i),r}getBindGroupArray(e,t){const s=this.bindings[t];let i=s[e];return void 0===i&&(void 0===this.bindingsIndexes[e]&&(this.bindingsIndexes[e]={binding:0,group:Object.keys(this.bindingsIndexes).length}),s[e]=i=[]),i}getBindings(){let e=this.bindGroups;if(null===e){const t={},s=this.bindings;for(const e of zd)for(const i in s[e]){const r=s[e][i];(t[i]||(t[i]=[])).push(...r)}e=[];for(const s in t){const i=t[s],r=this._getBindGroup(s,i);e.push(r)}this.bindGroups=e}return e}sortBindingGroups(){const e=this.getBindings();e.sort(((e,t)=>e.bindings[0].groupNode.order-t.bindings[0].groupNode.order));for(let t=0;t=0?`${Math.round(t)}u`:"0u";if("bool"===e)return t?"true":"false";if("color"===e)return`${this.getType("vec3")}( ${yM(t.r)}, ${yM(t.g)}, ${yM(t.b)} )`;const s=this.getTypeLength(e),i=this.getComponentType(e),r=e=>this.generateConst(i,e);if(2===s)return`${this.getType(e)}( ${r(t.x)}, ${r(t.y)} )`;if(3===s)return`${this.getType(e)}( ${r(t.x)}, ${r(t.y)}, ${r(t.z)} )`;if(4===s)return`${this.getType(e)}( ${r(t.x)}, ${r(t.y)}, ${r(t.z)}, ${r(t.w)} )`;if(s>4&&t&&(t.isMatrix3||t.isMatrix4))return`${this.getType(e)}( ${t.elements.map(r).join(", ")} )`;if(s>4)return`${this.getType(e)}()`;throw new Error(`NodeBuilder: Type '${e}' not found in generate constant attempt.`)}getType(e){return"color"===e?"vec3":e}hasGeometryAttribute(e){return this.geometry&&void 0!==this.geometry.getAttribute(e)}getAttribute(e,t){const s=this.attributes;for(const t of s)if(t.name===e)return t;const i=new cS(e,t);return s.push(i),i}getPropertyName(e){return e.name}isVector(e){return/vec\d/.test(e)}isMatrix(e){return/mat\d/.test(e)}isReference(e){return"void"===e||"property"===e||"sampler"===e||"texture"===e||"cubeTexture"===e||"storageTexture"===e||"depthTexture"===e||"texture3D"===e}needsToWorkingColorSpace(){return!1}getComponentTypeFromTexture(e){const t=e.type;if(e.isDataTexture){if(t===Ee)return"int";if(t===Be)return"uint"}return"float"}getElementType(e){return"mat2"===e?"vec2":"mat3"===e?"vec3":"mat4"===e?"vec4":this.getComponentType(e)}getComponentType(e){if("float"===(e=this.getVectorType(e))||"bool"===e||"int"===e||"uint"===e)return e;const t=/(b|i|u|)(vec|mat)([2-4])/.exec(e);return null===t?null:"b"===t[1]?"bool":"i"===t[1]?"int":"u"===t[1]?"uint":"float"}getVectorType(e){return"color"===e?"vec3":"texture"===e||"cubeTexture"===e||"storageTexture"===e||"texture3D"===e?"vec4":e}getTypeFromLength(e,t="float"){if(1===e)return t;const s=gM.get(e);return("float"===t?"":t[0])+s}getTypeFromArray(e){return fM.get(e.constructor)}getTypeFromAttribute(e){let t=e;e.isInterleavedBufferAttribute&&(t=e.data);const s=t.array,i=e.itemSize,r=e.normalized;let n;return e instanceof xn||!0===r||(n=this.getTypeFromArray(s)),this.getTypeFromLength(i,n)}getTypeLength(e){const t=this.getVectorType(e),s=/vec([2-4])/.exec(t);return null!==s?Number(s[1]):"float"===t||"bool"===t||"int"===t||"uint"===t?1:!0===/mat2/.test(e)?4:!0===/mat3/.test(e)?9:!0===/mat4/.test(e)?16:0}getVectorFromMatrix(e){return e.replace("mat","vec")}changeComponentType(e,t){return this.getTypeFromLength(this.getTypeLength(e),t)}getIntegerType(e){const t=this.getComponentType(e);return"int"===t||"uint"===t?e:this.changeComponentType(e,"int")}addStack(){return this.stack=HS(this.stack),this.stacks.push(Ip()||this.stack),Bp(this.stack),this.stack}removeStack(){const e=this.stack;return this.stack=e.parent,Bp(this.stacks.pop()),e}getDataFromNode(e,t=this.shaderStage,s=null){let i=(s=null===s?e.isGlobal(this)?this.globalCache:this.cache:s).getData(e);return void 0===i&&(i={},s.setData(e,i)),void 0===i[t]&&(i[t]={}),i[t]}getNodeProperties(e,t="any"){const s=this.getDataFromNode(e,t);return s.properties||(s.properties={outputNode:null})}getBufferAttributeFromNode(e,t){const s=this.getDataFromNode(e);let i=s.bufferAttribute;if(void 0===i){const r=this.uniforms.index++;i=new cS("nodeAttribute"+r,t,e),this.bufferAttributes.push(i),s.bufferAttribute=i}return i}getStructTypeFromNode(e,t=this.shaderStage){const s=this.getDataFromNode(e,t);if(void 0===s.structType){const i=this.structs.index++;e.name=`StructType${i}`,this.structs[t].push(e),s.structType=e}return e}getUniformFromNode(e,t,s=this.shaderStage,i=null){const r=this.getDataFromNode(e,s,this.globalCache);let n=r.uniform;if(void 0===n){const o=this.uniforms.index++;n=new dS(i||"nodeUniform"+o,t,e),this.uniforms[s].push(n),r.uniform=n}return n}getVarFromNode(e,t=null,s=e.getNodeType(this),i=this.shaderStage){const r=this.getDataFromNode(e,i);let n=r.variable;if(void 0===n){const e=this.vars[i]||(this.vars[i]=[]);null===t&&(t="nodeVar"+e.length),n=new pS(t,s),e.push(n),r.variable=n}return n}getVaryingFromNode(e,t=null,s=e.getNodeType(this)){const i=this.getDataFromNode(e,"any");let r=i.varying;if(void 0===r){const e=this.varyings,n=e.length;null===t&&(t="nodeVarying"+n),r=new mS(t,s),e.push(r),i.varying=r}return r}getCodeFromNode(e,t,s=this.shaderStage){const i=this.getDataFromNode(e);let r=i.code;if(void 0===r){const e=this.codes[s]||(this.codes[s]=[]),n=e.length;r=new gS("nodeCode"+n,t),e.push(r),i.code=r}return r}addFlowCodeHierarchy(e,t){const{flowCodes:s,flowCodeBlock:i}=this.getDataFromNode(e);let r=!0,n=t;for(;n;){if(!0===i.get(n)){r=!1;break}n=this.getDataFromNode(n).parentNodeBlock}if(r)for(const e of s)this.addLineFlowCode(e)}addLineFlowCodeBlock(e,t,s){const i=this.getDataFromNode(e),r=i.flowCodes||(i.flowCodes=[]),n=i.flowCodeBlock||(i.flowCodeBlock=new WeakMap);r.push(t),n.set(s,!0)}addLineFlowCode(e,t=null){return""===e||(null!==t&&this.context.nodeBlock&&this.addLineFlowCodeBlock(t,e,this.context.nodeBlock),e=this.tab+e,/;\s*$/.test(e)||(e+=";\n"),this.flow.code+=e),this}addFlowCode(e){return this.flow.code+=e,this}addFlowTab(){return this.tab+="\t",this}removeFlowTab(){return this.tab=this.tab.slice(0,-1),this}getFlowData(e){return this.flowsData.get(e)}flowNode(e){const t=e.getNodeType(this),s=this.flowChildNode(e,t);return this.flowsData.set(e,s),s}buildFunctionNode(e){const t=new MS,s=this.currentFunctionNode;return this.currentFunctionNode=t,t.code=this.buildFunctionCode(e),this.currentFunctionNode=s,t}flowShaderNode(e){const t=e.layout,s={[Symbol.iterator](){let e=0;const t=Object.values(this);return{next:()=>({value:t[e],done:e++>=t.length})}}};for(const e of t.inputs)s[e.name]=new xS(e.type,e.name);e.layout=null;const i=e.call(s),r=this.flowStagesNode(i,t.type);return e.layout=t,r}flowStagesNode(e,t=null){const s=this.flow,i=this.vars,r=this.cache,n=this.buildStage,o=this.stack,a={code:""};this.flow=a,this.vars={},this.cache=new yS,this.stack=HS();for(const s of Fd)this.setBuildStage(s),a.result=e.build(this,t);return a.vars=this.getVars(this.shaderStage),this.flow=s,this.vars=i,this.cache=r,this.stack=o,this.setBuildStage(n),a}getFunctionOperator(){return null}flowChildNode(e,t=null){const s=this.flow,i={code:""};return this.flow=i,i.result=e.build(this,t),this.flow=s,i}flowNodeFromShaderStage(e,t,s=null,i=null){const r=this.shaderStage;this.setShaderStage(e);const n=this.flowChildNode(t,s);return null!==i&&(n.code+=`${this.tab+i} = ${n.result};\n`),this.flowCode[e]=this.flowCode[e]+n.code,this.setShaderStage(r),n}getAttributesArray(){return this.attributes.concat(this.bufferAttributes)}getAttributes(){console.warn("Abstract function.")}getVaryings(){console.warn("Abstract function.")}getVar(e,t){return`${this.getType(e)} ${t}`}getVars(e){let t="";const s=this.vars[e];if(void 0!==s)for(const e of s)t+=`${this.getVar(e.type,e.name)}; `;return t}getUniforms(){console.warn("Abstract function.")}getCodes(e){const t=this.codes[e];let s="";if(void 0!==t)for(const e of t)s+=e.code+"\n";return s}getHash(){return this.vertexShader+this.fragmentShader+this.computeShader}setShaderStage(e){this.shaderStage=e}getShaderStage(){return this.shaderStage}setBuildStage(e){this.buildStage=e}getBuildStage(){return this.buildStage}buildCode(){console.warn("Abstract function.")}build(){const{object:e,material:t,renderer:s}=this;if(null!==t){let e=s.nodes.library.fromMaterial(t);null===e&&(console.error(`NodeMaterial: Material "${t.type}" is not compatible.`),e=new pT),e.build(this)}else this.addFlow("compute",e);for(const e of Fd){this.setBuildStage(e),this.context.vertex&&this.context.vertex.isNode&&this.flowNodeFromShaderStage("vertex",this.context.vertex);for(const t of zd){this.setShaderStage(t);const s=this.flowNodes[t];for(const t of s)"generate"===e?this.flowNode(t):t.build(this)}}return this.setBuildStage(null),this.setShaderStage(null),this.buildCode(),this.buildUpdateNodes(),this}getNodeUniform(e,t){if("float"===t||"int"===t||"uint"===t)return new OS(e);if("vec2"===t||"ivec2"===t||"uvec2"===t)return new LS(e);if("vec3"===t||"ivec3"===t||"uvec3"===t)return new VS(e);if("vec4"===t||"ivec4"===t||"uvec4"===t)return new DS(e);if("color"===t)return new kS(e);if("mat3"===t)return new GS(e);if("mat4"===t)return new WS(e);throw new Error(`Uniform "${t}" not declared.`)}createNodeMaterial(e="NodeMaterial"){throw new Error(`THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${e}() instead.`)}format(e,t,s){if((t=this.getVectorType(t))===(s=this.getVectorType(s))||null===s||this.isReference(s))return e;const i=this.getTypeLength(t),r=this.getTypeLength(s);return 16===i&&9===r?`${this.getType(s)}(${e}[0].xyz, ${e}[1].xyz, ${e}[2].xyz)`:9===i&&4===r?`${this.getType(s)}(${e}[0].xy, ${e}[1].xy)`:i>4||r>4||0===r?e:i===r?`${this.getType(s)}( ${e} )`:i>r?this.format(`${e}.${"xyz".slice(0,r)}`,this.getTypeFromLength(r,this.getComponentType(t)),s):4===r&&i>1?`${this.getType(s)}( ${this.format(e,t,"vec3")}, 1.0 )`:2===i?`${this.getType(s)}( ${this.format(e,t,"vec2")}, 0.0 )`:(1===i&&r>1&&t!==this.getComponentType(s)&&(e=`${this.getType(this.getComponentType(s))}( ${e} )`),`${this.getType(s)}( ${e} )`)}getSignature(){return`// Three.js r${e} - Node System\n`}}class bM{constructor(){this.time=0,this.deltaTime=0,this.frameId=0,this.renderId=0,this.startTime=null,this.updateMap=new WeakMap,this.updateBeforeMap=new WeakMap,this.updateAfterMap=new WeakMap,this.renderer=null,this.material=null,this.camera=null,this.object=null,this.scene=null}_getMaps(e,t){let s=e.get(t);return void 0===s&&(s={renderMap:new WeakMap,frameMap:new WeakMap},e.set(t,s)),s}updateBeforeNode(e){const t=e.getUpdateBeforeType(),s=e.updateReference(this);if(t===Bd.FRAME){const{frameMap:t}=this._getMaps(this.updateBeforeMap,s);t.get(s)!==this.frameId&&!1!==e.updateBefore(this)&&t.set(s,this.frameId)}else if(t===Bd.RENDER){const{renderMap:t}=this._getMaps(this.updateBeforeMap,s);t.get(s)!==this.renderId&&!1!==e.updateBefore(this)&&t.set(s,this.renderId)}else t===Bd.OBJECT&&e.updateBefore(this)}updateAfterNode(e){const t=e.getUpdateAfterType(),s=e.updateReference(this);if(t===Bd.FRAME){const{frameMap:t}=this._getMaps(this.updateAfterMap,s);t.get(s)!==this.frameId&&!1!==e.updateAfter(this)&&t.set(s,this.frameId)}else if(t===Bd.RENDER){const{renderMap:t}=this._getMaps(this.updateAfterMap,s);t.get(s)!==this.renderId&&!1!==e.updateAfter(this)&&t.set(s,this.renderId)}else t===Bd.OBJECT&&e.updateAfter(this)}updateNode(e){const t=e.getUpdateType(),s=e.updateReference(this);if(t===Bd.FRAME){const{frameMap:t}=this._getMaps(this.updateMap,s);t.get(s)!==this.frameId&&!1!==e.update(this)&&t.set(s,this.frameId)}else if(t===Bd.RENDER){const{renderMap:t}=this._getMaps(this.updateMap,s);t.get(s)!==this.renderId&&!1!==e.update(this)&&t.set(s,this.renderId)}else t===Bd.OBJECT&&e.update(this)}update(){this.frameId++,void 0===this.lastTime&&(this.lastTime=performance.now()),this.deltaTime=(performance.now()-this.lastTime)/1e3,this.lastTime=performance.now(),this.time+=this.deltaTime}}class vM{constructor(e,t,s=null,i="",r=!1){this.type=e,this.name=t,this.count=s,this.qualifier=i,this.isConst=r}}vM.isNodeFunctionInput=!0;class TM extends Ld{static get type(){return"StructTypeNode"}constructor(e){super(),this.types=e,this.isStructTypeNode=!0}getMemberTypes(){return this.types}}class _M extends Ld{static get type(){return"OutputStructNode"}constructor(...e){super(),this.members=e,this.isOutputStructNode=!0}setup(e){super.setup(e);const t=this.members,s=[];for(let i=0;ir&&(i=s,r=n)}}this._candidateFnCall=s=i(...t)}return s}}const CM=Ap(AM),RM=e=>(...t)=>CM(e,...t);class EM extends dm{static get type(){return"TimerNode"}constructor(e=EM.LOCAL,t=1,s=0){super(s),this.scope=e,this.scale=t,this.updateType=Bd.FRAME}update(e){const t=this.scope,s=this.scale;t===EM.LOCAL?this.value+=e.deltaTime*s:t===EM.DELTA?this.value=e.deltaTime*s:t===EM.FRAME?this.value=e.frameId:this.value=e.time*s}serialize(e){super.serialize(e),e.scope=this.scope,e.scale=this.scale}deserialize(e){super.deserialize(e),this.scope=e.scope,this.scale=e.scale}}EM.LOCAL="local",EM.GLOBAL="global",EM.DELTA="delta",EM.FRAME="frame";const BM=(e,t=0)=>Sp(new EM(EM.LOCAL,e,t)),IM=(e,t=0)=>Sp(new EM(EM.GLOBAL,e,t)),PM=(e,t=0)=>Sp(new EM(EM.DELTA,e,t)),FM=Cp(EM,EM.FRAME).toUint();class zM extends Ld{static get type(){return"OscNode"}constructor(e=zM.SINE,t=BM()){super(),this.method=e,this.timeNode=t}getNodeType(e){return this.timeNode.getNodeType(e)}setup(){const e=this.method,t=Sp(this.timeNode);let s=null;return e===zM.SINE?s=t.add(.75).mul(2*Math.PI).sin().mul(.5).add(.5):e===zM.SQUARE?s=t.fract().round():e===zM.TRIANGLE?s=t.add(.5).fract().mul(2).sub(1).abs():e===zM.SAWTOOTH&&(s=t.fract()),s}serialize(e){super.serialize(e),e.method=this.method}deserialize(e){super.deserialize(e),this.method=e.method}}zM.SINE="sine",zM.SQUARE="square",zM.TRIANGLE="triangle",zM.SAWTOOTH="sawtooth";const UM=Ap(zM,zM.SINE),OM=Ap(zM,zM.SQUARE),LM=Ap(zM,zM.TRIANGLE),VM=Ap(zM,zM.SAWTOOTH);class DM extends Ld{static get type(){return"SpriteSheetUVNode"}constructor(e,t=My(),s=Up(0)){super("vec2"),this.countNode=e,this.uvNode=t,this.frameNode=s}setup(){const{frameNode:e,uvNode:t,countNode:s}=this,{width:i,height:r}=s,n=e.mod(i.mul(r)).floor(),o=n.mod(i),a=r.sub(n.add(1).div(i).ceil()),h=s.reciprocal(),u=Dp(o,a);return t.add(u).mul(h)}}const kM=Ap(DM);class GM extends Vd{static get type(){return"StorageArrayElementNode"}constructor(e,t){super(e,t),this.isStorageArrayElementNode=!0}set storageBufferNode(e){this.node=e}get storageBufferNode(){return this.node}setup(e){return!1===e.isAvailable("storageBuffer")&&!0===this.node.bufferObject&&e.setupPBO(this.node),super.setup(e)}generate(e,t){let s;const i=e.context.assign;if(s=!1===e.isAvailable("storageBuffer")?!0===this.node.bufferObject&&!0!==i?e.generatePBO(this):this.node.build(e):super.generate(e),!0!==i){const i=this.getNodeType(e);s=e.format(s,i,t)}return s}}const WM=Ap(GM);class jM extends Ld{static get type(){return"TriplanarTexturesNode"}constructor(e,t=null,s=null,i=Up(1),r=ax,n=yx){super("vec4"),this.textureXNode=e,this.textureYNode=t,this.textureZNode=s,this.scaleNode=i,this.positionNode=r,this.normalNode=n}setup(){const{textureXNode:e,textureYNode:t,textureZNode:s,scaleNode:i,positionNode:r,normalNode:n}=this;let o=n.abs().normalize();o=o.div(o.dot(jp(1)));const a=r.yz.mul(i),h=r.zx.mul(i),u=r.xy.mul(i),l=e.value,c=null!==t?t.value:l,d=null!==s?s.value:l,p=By(l,a).mul(o.x),m=By(c,h).mul(o.y),g=By(d,u).mul(o.z);return Zm(p,m,g)}}const HM=Ap(jM),qM=(...e)=>HM(...e),$M=new Ko,XM=new Ri,YM=new Ri,ZM=new Ri,JM=new nr,KM=new Ri(0,0,-1),QM=new Ti,eN=new Ri,tN=new Ri,sN=new Ti,iN=new Qs,rN=new _i,nN=Dv.flipX();let oN=!1;class aN extends Ey{static get type(){return"ReflectorNode"}constructor(e={}){super(rN.texture,nN);const{target:t=new Ir,resolution:s=1,generateMipmaps:i=!1,bounces:r=!0}=e;this.target=t,this.resolution=s,this.generateMipmaps=i,this.bounces=r,this.updateBeforeType=r?Bd.RENDER:Bd.FRAME,this.virtualCameras=new WeakMap,this.renderTargets=new WeakMap}_updateResolution(e,t){const s=this.resolution;t.getDrawingBufferSize(iN),e.setSize(Math.round(iN.width*s),Math.round(iN.height*s))}setup(e){return this._updateResolution(rN,e.renderer),super.setup(e)}getTextureNode(){return this.textureNode}getVirtualCamera(e){let t=this.virtualCameras.get(e);return void 0===t&&(t=e.clone(),this.virtualCameras.set(e,t)),t}getRenderTarget(e){let t=this.renderTargets.get(e);return void 0===t&&(t=new _i(0,0,{type:Pe}),!0===this.generateMipmaps&&(t.texture.minFilter=1008,t.texture.generateMipmaps=!0),this.renderTargets.set(e,t)),t}updateBefore(e){if(!1===this.bounces&&oN)return!1;oN=!0;const{scene:t,camera:s,renderer:i,material:r}=e,{target:n}=this,o=this.getVirtualCamera(s),a=this.getRenderTarget(o);if(i.getDrawingBufferSize(iN),this._updateResolution(a,i),YM.setFromMatrixPosition(n.matrixWorld),ZM.setFromMatrixPosition(s.matrixWorld),JM.extractRotation(n.matrixWorld),XM.set(0,0,1),XM.applyMatrix4(JM),eN.subVectors(YM,ZM),eN.dot(XM)>0)return;eN.reflect(XM).negate(),eN.add(YM),JM.extractRotation(s.matrixWorld),KM.set(0,0,-1),KM.applyMatrix4(JM),KM.add(ZM),tN.subVectors(YM,KM),tN.reflect(XM).negate(),tN.add(YM),o.coordinateSystem=s.coordinateSystem,o.position.copy(eN),o.up.set(0,1,0),o.up.applyMatrix4(JM),o.up.reflect(XM),o.lookAt(tN),o.near=s.near,o.far=s.far,o.updateMatrixWorld(),o.projectionMatrix.copy(s.projectionMatrix),$M.setFromNormalAndCoplanarPoint(XM,YM),$M.applyMatrix4(o.matrixWorldInverse),QM.set($M.normal.x,$M.normal.y,$M.normal.z,$M.constant);const h=o.projectionMatrix;sN.x=(Math.sign(QM.x)+h.elements[8])/h.elements[0],sN.y=(Math.sign(QM.y)+h.elements[9])/h.elements[5],sN.z=-1,sN.w=(1+h.elements[10])/h.elements[14],QM.multiplyScalar(1/QM.dot(sN));h.elements[2]=QM.x,h.elements[6]=QM.y,h.elements[10]=QM.z-0,h.elements[14]=QM.w,this.value=a.texture,r.visible=!1;const u=i.getRenderTarget(),l=i.getMRT();i.setMRT(null),i.setRenderTarget(a),i.render(t,o),i.setMRT(l),i.setRenderTarget(u),r.visible=!0,oN=!1}}const hN=e=>Sp(new aN(e)),uN=new Sl(-1,1,1,-1,0,1);class lN extends An{constructor(e=!1){super();const t=!1===e?[0,-1,0,1,2,1]:[0,2,0,0,2,0];this.setAttribute("position",new bn([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new bn(t,2))}}const cN=new lN;class dN extends Vn{constructor(e=null){super(cN,e),this.camera=uN,this.isQuadMesh=!0}renderAsync(e){return e.renderAsync(this,uN)}render(e){e.render(this,uN)}}const pN=new Qs;class mN extends Ey{static get type(){return"RTTNode"}constructor(e,t=null,s=null,i={type:Pe}){const r=new _i(t,s,i);super(r.texture,My()),this.node=e,this.width=t,this.height=s,this.renderTarget=r,this.textureNeedsUpdate=!0,this.autoUpdate=!0,this.updateMap=new WeakMap,this._rttNode=null,this._quadMesh=new dN(new pT),this.updateBeforeType=Bd.RENDER}get autoSize(){return null===this.width}setup(e){return this._rttNode=this.node.context(e.getSharedContext()),this._quadMesh.material.name="RTT",this._quadMesh.material.needsUpdate=!0,super.setup(e)}setSize(e,t){this.width=e,this.height=t;const s=e*this.pixelRatio,i=t*this.pixelRatio;this.renderTarget.setSize(s,i),this.textureNeedsUpdate=!0}setPixelRatio(e){this.pixelRatio=e,this.setSize(this.width,this.height)}updateBefore({renderer:e}){if(!1===this.textureNeedsUpdate&&!1===this.autoUpdate)return;if(this.textureNeedsUpdate=!1,!0===this.autoSize){this.pixelRatio=e.getPixelRatio();const t=e.getSize(pN);this.setSize(t.width,t.height)}this._quadMesh.material.fragmentNode=this._rttNode;const t=e.getRenderTarget();e.setRenderTarget(this.renderTarget),this._quadMesh.render(e),e.setRenderTarget(t)}clone(){const e=new Ey(this.value,this.uvNode,this.levelNode);return e.sampler=this.sampler,e.referenceNode=this,e}}const gN=(e,...t)=>Sp(new mN(Sp(e),...t)),fN=(e,...t)=>e.isTextureNode?e:gN(e,...t);class yN extends wy{static get type(){return"VertexColorNode"}constructor(e=0){super(null,"vec4"),this.isVertexColorNode=!0,this.index=e}getAttributeName(){const e=this.index;return"color"+(e>0?e:"")}generate(e){const t=this.getAttributeName(e);let s;return s=!0===e.hasGeometryAttribute(t)?super.generate(e):e.generateConst(this.nodeType,new Ti(1,1,1,1)),s}serialize(e){super.serialize(e),e.index=this.index}deserialize(e){super.deserialize(e),this.index=e.index}}const xN=(...e)=>Sp(new yN(...e));class bN extends Ld{static get type(){return"PointUVNode"}constructor(){super("vec2"),this.isPointUVNode=!0}generate(){return"vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )"}}const vN=Cp(bN);class TN extends Ld{static get type(){return"SceneNode"}constructor(e=TN.BACKGROUND_BLURRINESS,t=null){super(),this.scope=e,this.scene=t}setup(e){const t=this.scope,s=null!==this.scene?this.scene:e.scene;let i;return t===TN.BACKGROUND_BLURRINESS?i=kx("backgroundBlurriness","float",s):t===TN.BACKGROUND_INTENSITY?i=kx("backgroundIntensity","float",s):console.error("THREE.SceneNode: Unknown scope:",t),i}}TN.BACKGROUND_BLURRINESS="backgroundBlurriness",TN.BACKGROUND_INTENSITY="backgroundIntensity";const _N=Cp(TN,TN.BACKGROUND_BLURRINESS),wN=Cp(TN,TN.BACKGROUND_INTENSITY),SN="point-list",MN="line-list",NN="line-strip",AN="triangle-list",CN="triangle-strip",RN="never",EN="less",BN="equal",IN="less-equal",PN="greater",FN="not-equal",zN="greater-equal",UN="always",ON="store",LN="load",VN="clear",DN="ccw",kN="none",GN="front",WN="back",jN="uint16",HN="uint32",qN={R8Unorm:"r8unorm",R8Snorm:"r8snorm",R8Uint:"r8uint",R8Sint:"r8sint",R16Uint:"r16uint",R16Sint:"r16sint",R16Float:"r16float",RG8Unorm:"rg8unorm",RG8Snorm:"rg8snorm",RG8Uint:"rg8uint",RG8Sint:"rg8sint",R32Uint:"r32uint",R32Sint:"r32sint",R32Float:"r32float",RG16Uint:"rg16uint",RG16Sint:"rg16sint",RG16Float:"rg16float",RGBA8Unorm:"rgba8unorm",RGBA8UnormSRGB:"rgba8unorm-srgb",RGBA8Snorm:"rgba8snorm",RGBA8Uint:"rgba8uint",RGBA8Sint:"rgba8sint",BGRA8Unorm:"bgra8unorm",BGRA8UnormSRGB:"bgra8unorm-srgb",RGB9E5UFloat:"rgb9e5ufloat",RGB10A2Unorm:"rgb10a2unorm",RG11B10uFloat:"rgb10a2unorm",RG32Uint:"rg32uint",RG32Sint:"rg32sint",RG32Float:"rg32float",RGBA16Uint:"rgba16uint",RGBA16Sint:"rgba16sint",RGBA16Float:"rgba16float",RGBA32Uint:"rgba32uint",RGBA32Sint:"rgba32sint",RGBA32Float:"rgba32float",Stencil8:"stencil8",Depth16Unorm:"depth16unorm",Depth24Plus:"depth24plus",Depth24PlusStencil8:"depth24plus-stencil8",Depth32Float:"depth32float",Depth32FloatStencil8:"depth32float-stencil8",BC1RGBAUnorm:"bc1-rgba-unorm",BC1RGBAUnormSRGB:"bc1-rgba-unorm-srgb",BC2RGBAUnorm:"bc2-rgba-unorm",BC2RGBAUnormSRGB:"bc2-rgba-unorm-srgb",BC3RGBAUnorm:"bc3-rgba-unorm",BC3RGBAUnormSRGB:"bc3-rgba-unorm-srgb",BC4RUnorm:"bc4-r-unorm",BC4RSnorm:"bc4-r-snorm",BC5RGUnorm:"bc5-rg-unorm",BC5RGSnorm:"bc5-rg-snorm",BC6HRGBUFloat:"bc6h-rgb-ufloat",BC6HRGBFloat:"bc6h-rgb-float",BC7RGBAUnorm:"bc7-rgba-unorm",BC7RGBAUnormSRGB:"bc7-rgba-srgb",ETC2RGB8Unorm:"etc2-rgb8unorm",ETC2RGB8UnormSRGB:"etc2-rgb8unorm-srgb",ETC2RGB8A1Unorm:"etc2-rgb8a1unorm",ETC2RGB8A1UnormSRGB:"etc2-rgb8a1unorm-srgb",ETC2RGBA8Unorm:"etc2-rgba8unorm",ETC2RGBA8UnormSRGB:"etc2-rgba8unorm-srgb",EACR11Unorm:"eac-r11unorm",EACR11Snorm:"eac-r11snorm",EACRG11Unorm:"eac-rg11unorm",EACRG11Snorm:"eac-rg11snorm",ASTC4x4Unorm:"astc-4x4-unorm",ASTC4x4UnormSRGB:"astc-4x4-unorm-srgb",ASTC5x4Unorm:"astc-5x4-unorm",ASTC5x4UnormSRGB:"astc-5x4-unorm-srgb",ASTC5x5Unorm:"astc-5x5-unorm",ASTC5x5UnormSRGB:"astc-5x5-unorm-srgb",ASTC6x5Unorm:"astc-6x5-unorm",ASTC6x5UnormSRGB:"astc-6x5-unorm-srgb",ASTC6x6Unorm:"astc-6x6-unorm",ASTC6x6UnormSRGB:"astc-6x6-unorm-srgb",ASTC8x5Unorm:"astc-8x5-unorm",ASTC8x5UnormSRGB:"astc-8x5-unorm-srgb",ASTC8x6Unorm:"astc-8x6-unorm",ASTC8x6UnormSRGB:"astc-8x6-unorm-srgb",ASTC8x8Unorm:"astc-8x8-unorm",ASTC8x8UnormSRGB:"astc-8x8-unorm-srgb",ASTC10x5Unorm:"astc-10x5-unorm",ASTC10x5UnormSRGB:"astc-10x5-unorm-srgb",ASTC10x6Unorm:"astc-10x6-unorm",ASTC10x6UnormSRGB:"astc-10x6-unorm-srgb",ASTC10x8Unorm:"astc-10x8-unorm",ASTC10x8UnormSRGB:"astc-10x8-unorm-srgb",ASTC10x10Unorm:"astc-10x10-unorm",ASTC10x10UnormSRGB:"astc-10x10-unorm-srgb",ASTC12x10Unorm:"astc-12x10-unorm",ASTC12x10UnormSRGB:"astc-12x10-unorm-srgb",ASTC12x12Unorm:"astc-12x12-unorm",ASTC12x12UnormSRGB:"astc-12x12-unorm-srgb"},$N="clamp-to-edge",XN="repeat",YN="mirror-repeat",ZN="linear",JN="nearest",KN="zero",QN="one",eA="src",tA="one-minus-src",sA="src-alpha",iA="one-minus-src-alpha",rA="dst",nA="one-minus-dst",oA="dst-alpha",aA="one-minus-dst-alpha",hA="src-alpha-saturated",uA="constant",lA="one-minus-constant",cA="add",dA="subtract",pA="reverse-subtract",mA="min",gA="max",fA=0,yA=15,xA="keep",bA="zero",vA="replace",TA="invert",_A="increment-clamp",wA="decrement-clamp",SA="increment-wrap",MA="decrement-wrap",NA="storage",AA="read-only-storage",CA="write-only",RA="read-only",EA="float",BA="unfilterable-float",IA="depth",PA="sint",FA="uint",zA="2d",UA="3d",OA="2d",LA="2d-array",VA="cube",DA="3d",kA="all",GA="vertex",WA="instance",jA={DepthClipControl:"depth-clip-control",Depth32FloatStencil8:"depth32float-stencil8",TextureCompressionBC:"texture-compression-bc",TextureCompressionETC2:"texture-compression-etc2",TextureCompressionASTC:"texture-compression-astc",TimestampQuery:"timestamp-query",IndirectFirstInstance:"indirect-first-instance",ShaderF16:"shader-f16",RG11B10UFloat:"rg11b10ufloat-renderable",BGRA8UNormStorage:"bgra8unorm-storage",Float32Filterable:"float32-filterable",ClipDistances:"clip-distances",DualSourceBlending:"dual-source-blending",Subgroups:"subgroups"};class HA extends Px{static get type(){return"StorageBufferNode"}constructor(e,t,s=0){super(e,t,s),this.isStorageBufferNode=!0,this.access=NA,this.isAtomic=!1,this.bufferObject=!1,this.bufferCount=s,this._attribute=null,this._varying=null,this.global=!0,!0!==e.isStorageBufferAttribute&&!0!==e.isStorageInstancedBufferAttribute&&(e.isInstancedBufferAttribute?e.isStorageInstancedBufferAttribute=!0:e.isStorageBufferAttribute=!0)}getHash(e){if(0===this.bufferCount){let t=e.globalCache.getData(this.value);return void 0===t&&(t={node:this},e.globalCache.setData(this.value,t)),t.node.uuid}return this.uuid}getInputType(){return"storageBuffer"}element(e){return WM(this,e)}setBufferObject(e){return this.bufferObject=e,this}setAccess(e){return this.access=e,this}toReadOnly(){return this.setAccess(AA)}setAtomic(e){return this.isAtomic=e,this}toAtomic(){return this.setAtomic(!0)}generate(e){if(e.isAvailable("storageBuffer"))return super.generate(e);const t=this.getNodeType(e);null===this._attribute&&(this._attribute=iy(this.value),this._varying=Vf(this._attribute));const s=this._varying.build(e,t);return e.registerTransform(s,this._attribute),s}}const qA=(e,t,s)=>Sp(new HA(e,t,s)),$A=(e,t,s)=>Sp(new HA(e,t,s).setBufferObject(!0));class XA extends Ey{static get type(){return"StorageTextureNode"}constructor(e,t,s=null){super(e,t),this.storeNode=s,this.isStorageTextureNode=!0,this.access=CA}getInputType(){return"storageTexture"}setup(e){super.setup(e);e.getNodeProperties(this).storeNode=this.storeNode}setAccess(e){return this.access=e,this}generate(e,t){let s;return s=null!==this.storeNode?this.generateStore(e):super.generate(e,t),s}toReadOnly(){return this.setAccess(RA)}toWriteOnly(){return this.setAccess(CA)}generateStore(e){const t=e.getNodeProperties(this),{uvNode:s,storeNode:i}=t,r=super.generate(e,"property"),n=s.build(e,"uvec2"),o=i.build(e,"vec4"),a=e.generateTextureStore(e,r,n,o);e.addLineFlowCode(a,this)}}const YA=Ap(XA),ZA=(e,t,s)=>{const i=YA(e,t,s);return null!==s&&i.append(),i};class JA extends Dx{static get type(){return"UserDataNode"}constructor(e,t,s=null){super(e,t,s),this.userData=s}updateReference(e){return this.reference=null!==this.userData?this.userData:e.object.userData,this.reference}}const KA=(e,t,s)=>Sp(new JA(e,t,s));class QA extends kd{static get type(){return"PosterizeNode"}constructor(e,t){super(),this.sourceNode=e,this.stepsNode=t}setup(){const{sourceNode:e,stepsNode:t}=this;return e.mul(t).floor().div(t)}}const eC=Ap(QA);let tC=null;class sC extends Jv{static get type(){return"ViewportSharedTextureNode"}constructor(e=Dv,t=null){null===tC&&(tC=new ja),super(e,t,tC)}updateReference(){return this}}const iC=Ap(sC),rC=new Qs;class nC extends Ey{static get type(){return"PassTextureNode"}constructor(e,t){super(t),this.passNode=e,this.setUpdateMatrix(!1)}setup(e){return e.object.isQuadMesh&&this.passNode.build(e),super.setup(e)}clone(){return new this.constructor(this.passNode,this.value)}}class oC extends nC{static get type(){return"PassMultipleTextureNode"}constructor(e,t,s=!1){super(e,null),this.textureName=t,this.previousTexture=s}updateTexture(){this.value=this.previousTexture?this.passNode.getPreviousTexture(this.textureName):this.passNode.getTexture(this.textureName)}setup(e){return this.updateTexture(),super.setup(e)}clone(){return new this.constructor(this.passNode,this.textureName,this.previousTexture)}}class aC extends kd{static get type(){return"PassNode"}constructor(e,t,s,i={}){super("vec4"),this.scope=e,this.scene=t,this.camera=s,this.options=i,this._pixelRatio=1,this._width=1,this._height=1;const r=new Ya;r.isRenderTargetTexture=!0,r.name="depth";const n=new _i(this._width*this._pixelRatio,this._height*this._pixelRatio,{type:Pe,...i});n.texture.name="output",n.depthTexture=r,this.renderTarget=n,this.updateBeforeType=Bd.FRAME,this._textures={output:n.texture,depth:r},this._textureNodes={},this._linearDepthNodes={},this._viewZNodes={},this._previousTextures={},this._previousTextureNodes={},this._cameraNear=pm(0),this._cameraFar=pm(0),this._mrt=null,this.isPassNode=!0}setMRT(e){return this._mrt=e,this}getMRT(){return this._mrt}isGlobal(){return!0}getTexture(e){let t=this._textures[e];if(void 0===t){t=this.renderTarget.texture.clone(),t.isRenderTargetTexture=!0,t.name=e,this._textures[e]=t,this.renderTarget.textures.push(t)}return t}getPreviousTexture(e){let t=this._previousTextures[e];return void 0===t&&(t=this.getTexture(e).clone(),t.isRenderTargetTexture=!0,this._previousTextures[e]=t),t}toggleTexture(e){const t=this._previousTextures[e];if(void 0!==t){const s=this._textures[e],i=this.renderTarget.textures.indexOf(s);this.renderTarget.textures[i]=t,this._textures[e]=t,this._previousTextures[e]=s,this._textureNodes[e].updateTexture(),this._previousTextureNodes[e].updateTexture()}}getTextureNode(e="output"){let t=this._textureNodes[e];return void 0===t&&(this._textureNodes[e]=t=Sp(new oC(this,e)),this._textureNodes[e].updateTexture()),t}getPreviousTextureNode(e="output"){let t=this._previousTextureNodes[e];return void 0===t&&(void 0===this._textureNodes[e]&&this.getTextureNode(e),this._previousTextureNodes[e]=t=Sp(new oC(this,e,!0)),this._previousTextureNodes[e].updateTexture()),t}getViewZNode(e="depth"){let t=this._viewZNodes[e];if(void 0===t){const s=this._cameraNear,i=this._cameraFar;this._viewZNodes[e]=t=aT(this.getTextureNode(e),s,i)}return t}getLinearDepthNode(e="depth"){let t=this._linearDepthNodes[e];if(void 0===t){const s=this._cameraNear,i=this._cameraFar,r=this.getViewZNode(e);this._linearDepthNodes[e]=t=rT(r,s,i)}return t}setup({renderer:e}){return this.renderTarget.samples=void 0===this.options.samples?e.samples:this.options.samples,!0===e.backend.isWebGLBackend&&(this.renderTarget.samples=0),this.renderTarget.depthTexture.isMultisampleRenderTargetTexture=this.renderTarget.samples>1,this.scope===aC.COLOR?this.getTextureNode():this.getLinearDepthNode()}updateBefore(e){const{renderer:t}=e,{scene:s,camera:i}=this;this._pixelRatio=t.getPixelRatio();const r=t.getSize(rC);this.setSize(r.width,r.height);const n=t.getRenderTarget(),o=t.getMRT();this._cameraNear.value=i.near,this._cameraFar.value=i.far;for(const e in this._previousTextures)this.toggleTexture(e);t.setRenderTarget(this.renderTarget),t.setMRT(this._mrt),t.render(s,i),t.setRenderTarget(n),t.setMRT(o)}setSize(e,t){this._width=e,this._height=t;const s=this._width*this._pixelRatio,i=this._height*this._pixelRatio;this.renderTarget.setSize(s,i)}setPixelRatio(e){this._pixelRatio=e,this.setSize(this._width,this._height)}dispose(){this.renderTarget.dispose()}}aC.COLOR="color",aC.DEPTH="depth";const hC=(e,t,s)=>Sp(new aC(aC.COLOR,e,t,s)),uC=(e,t)=>Sp(new nC(e,t)),lC=(e,t)=>Sp(new aC(aC.DEPTH,e,t)),cC=new dN,dC=new dN;class pC extends kd{static get type(){return"GaussianBlurNode"}constructor(e,t=null,s=2){super("vec4"),this.textureNode=e,this.directionNode=t,this.sigma=s,this._invSize=pm(new Qs),this._passDirection=pm(new Qs),this._horizontalRT=new _i,this._horizontalRT.texture.name="GaussianBlurNode.horizontal",this._verticalRT=new _i,this._verticalRT.texture.name="GaussianBlurNode.vertical",this._textureNode=uC(this,this._verticalRT.texture),this.updateBeforeType=Bd.RENDER,this.resolution=new Qs(1,1)}setSize(e,t){e=Math.max(Math.round(e*this.resolution.x),1),t=Math.max(Math.round(t*this.resolution.y),1),this._invSize.value.set(1/e,1/t),this._horizontalRT.setSize(e,t),this._verticalRT.setSize(e,t)}updateBefore(e){const{renderer:t}=e,s=this.textureNode,i=s.value,r=t.getRenderTarget(),n=t.getMRT(),o=s.value;cC.material=this._material,dC.material=this._material,this.setSize(i.image.width,i.image.height);const a=i.type;this._horizontalRT.texture.type=a,this._verticalRT.texture.type=a,t.setMRT(null),t.setRenderTarget(this._horizontalRT),this._passDirection.value.set(1,0),cC.render(t),s.value=this._horizontalRT.texture,t.setRenderTarget(this._verticalRT),this._passDirection.value.set(0,1),dC.render(t),t.setRenderTarget(r),t.setMRT(n),s.value=o}getTextureNode(){return this._textureNode}setup(e){const t=this.textureNode;if(!0!==t.isTextureNode)return console.error("GaussianBlurNode requires a TextureNode."),Xp();const s=t.uvNode||My(),i=Dp(this.directionNode||1),r=e=>t.uv(e),n=Rp((()=>{const e=3+2*this.sigma,t=this._getCoefficients(e),n=this._invSize,o=i.mul(this._passDirection),a=Up(t[0]).toVar(),h=Xp(r(s).mul(a)).toVar();for(let i=1;iSp(new pC(fN(e),t,s)),gC=new Qs,fC=new dN;class yC extends kd{static get type(){return"AfterImageNode"}constructor(e,t=.96){super(e),this.textureNode=e,this.textureNodeOld=By(),this.damp=pm(t),this._compRT=new _i,this._compRT.texture.name="AfterImageNode.comp",this._oldRT=new _i,this._oldRT.texture.name="AfterImageNode.old",this._textureNode=uC(this,this._compRT.texture),this.updateBeforeType=Bd.RENDER}getTextureNode(){return this._textureNode}setSize(e,t){this._compRT.setSize(e,t),this._oldRT.setSize(e,t)}updateBefore(e){const{renderer:t}=e,s=this.textureNode,i=s.value.type;this._compRT.texture.type=i,this._oldRT.texture.type=i,t.getDrawingBufferSize(gC),this.setSize(gC.x,gC.y);const r=t.getRenderTarget(),n=s.value;this.textureNodeOld.value=this._oldRT.texture,t.setRenderTarget(this._compRT),fC.render(t);const o=this._oldRT;this._oldRT=this._compRT,this._compRT=o,t.setRenderTarget(r),s.value=n}setup(e){const t=this.textureNode,s=this.textureNodeOld,i=t.uvNode||My();s.uvNode=i;const r=Rp((([e,t])=>{const s=Up(t).toVar(),i=Xp(e).toVar();return of(Hg(i.sub(s)),0)})),n=Rp((()=>{const e=Xp(s),n=Xp((e=>t.uv(e))(i));return e.mulAssign(this.damp.mul(r(e,.1))),of(n,e)})),o=this._materialComposed||(this._materialComposed=new pT);o.name="AfterImage",o.fragmentNode=n(),fC.material=o;return e.getNodeProperties(this).textureNode=t,this._textureNode}dispose(){this._compRT.dispose(),this._oldRT.dispose()}}const xC=(e,t)=>Sp(new yC(fN(e),t)),bC=Rp((([e])=>SC(e.rgb))),vC=Rp((([e,t=Up(1)])=>t.mix(SC(e.rgb),e.rgb))),TC=Rp((([e,t=Up(1)])=>{const s=Zm(e.r,e.g,e.b).div(3),i=e.r.max(e.g.max(e.b)),r=i.sub(s).mul(t).mul(-3);return Tf(e.rgb,i,r)})),_C=Rp((([e,t=Up(1)])=>{const s=jp(.57735,.57735,.57735),i=t.cos();return jp(e.rgb.mul(i).add(s.cross(e.rgb).mul(t.sin()).add(s.mul(df(s,e.rgb).mul(i.oneMinus())))))})),wC=new Ri,SC=(e,t=jp(...ci.getLuminanceCoefficients(wC)))=>df(e,t),MC=(e,t)=>Tf(jp(0),e,SC(e).sub(t).max(0)),NC=new dN;class AC extends kd{static get type(){return"AnamorphicNode"}constructor(e,t,s,i){super("vec4"),this.textureNode=e,this.tresholdNode=t,this.scaleNode=s,this.colorNode=jp(.1,0,1),this.samples=i,this.resolution=new Qs(1,1),this._renderTarget=new _i,this._renderTarget.texture.name="anamorphic",this._invSize=pm(new Qs),this._textureNode=uC(this,this._renderTarget.texture),this.updateBeforeType=Bd.RENDER}getTextureNode(){return this._textureNode}setSize(e,t){this._invSize.value.set(1/e,1/t),e=Math.max(Math.round(e*this.resolution.x),1),t=Math.max(Math.round(t*this.resolution.y),1),this._renderTarget.setSize(e,t)}updateBefore(e){const{renderer:t}=e,s=this.textureNode,i=s.value;this._renderTarget.texture.type=i.type;const r=t.getRenderTarget(),n=s.value;NC.material=this._material,this.setSize(i.image.width,i.image.height),t.setRenderTarget(this._renderTarget),NC.render(t),t.setRenderTarget(r),s.value=n}setup(e){const t=this.textureNode,s=t.uvNode||My(),i=Rp((()=>{const e=this.samples,i=Math.floor(e/2),r=jp(0).toVar();return bv({start:-i,end:i},(({i:e})=>{const n=Up(e).abs().div(i).oneMinus(),o=(e=>t.uv(e))(Dp(s.x.add(this._invSize.x.mul(e).mul(this.scaleNode)),s.y)),a=MC(o,this.tresholdNode).mul(n);r.addAssign(a)})),r.mul(this.colorNode)})),r=this._material||(this._material=new pT);r.name="Anamorphic",r.fragmentNode=i();return e.getNodeProperties(this).textureNode=t,this._textureNode}dispose(){this._renderTarget.dispose()}}const CC=(e,t=.9,s=3,i=32)=>Sp(new AC(fN(e),Sp(t),Sp(s),i));class RC extends kd{static get type(){return"SobelOperatorNode"}constructor(e){super(),this.textureNode=e,this.updateBeforeType=Bd.RENDER,this._invSize=pm(new Qs)}updateBefore(){const e=this.textureNode.value;this._invSize.value.set(1/e.image.width,1/e.image.height)}setup(){const{textureNode:e}=this,t=e.uvNode||My(),s=t=>e.uv(t);return Rp((()=>{const e=this._invSize,i=Qp(-1,-2,-1,0,0,0,1,2,1),r=Qp(-1,0,1,-2,0,2,-1,0,1),n=SC(s(t.add(e.mul(Dp(-1,-1)))).xyz),o=SC(s(t.add(e.mul(Dp(-1,0)))).xyz),a=SC(s(t.add(e.mul(Dp(-1,1)))).xyz),h=SC(s(t.add(e.mul(Dp(0,-1)))).xyz),u=SC(s(t.add(e.mul(Dp(0,0)))).xyz),l=SC(s(t.add(e.mul(Dp(0,1)))).xyz),c=SC(s(t.add(e.mul(Dp(1,-1)))).xyz),d=SC(s(t.add(e.mul(Dp(1,0)))).xyz),p=SC(s(t.add(e.mul(Dp(1,1)))).xyz),m=Zm(i[0][0].mul(n),i[1][0].mul(h),i[2][0].mul(c),i[0][1].mul(o),i[1][1].mul(u),i[2][1].mul(d),i[0][2].mul(a),i[1][2].mul(l),i[2][2].mul(p)),g=Zm(r[0][0].mul(n),r[1][0].mul(h),r[2][0].mul(c),r[0][1].mul(o),r[1][1].mul(u),r[2][1].mul(d),r[0][2].mul(a),r[1][2].mul(l),r[2][2].mul(p)),f=m.mul(m).add(g.mul(g)).sqrt();return Xp(jp(f),1)}))()}}const EC=e=>Sp(new RC(fN(e)));class BC extends kd{static get type(){return"DepthOfFieldNode"}constructor(e,t,s,i,r){super(),this.textureNode=e,this.viewZNode=t,this.focusNode=s,this.apertureNode=i,this.maxblurNode=r,this._aspect=pm(0),this.updateBeforeType=Bd.RENDER}updateBefore(){const e=this.textureNode.value;this._aspect.value=e.image.width/e.image.height}setup(){const e=this.textureNode,t=e.uvNode||My(),s=t=>e.uv(t);return Rp((()=>{const e=Dp(1,this._aspect),i=this.focusNode.add(this.viewZNode),r=Dp(_f(i.mul(this.apertureNode),this.maxblurNode.negate(),this.maxblurNode)),n=r.mul(.9),o=r.mul(.7),a=r.mul(.4);let h=Xp(0);return h=h.add(s(t)),h=h.add(s(t.add(Dp(0,.4).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.15,.37).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.29,.29).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.37,.15).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.4,0).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.37,-.15).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.29,-.29).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.15,-.37).mul(e).mul(r)))),h=h.add(s(t.add(Dp(0,-.4).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.15,.37).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.29,.29).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.37,.15).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.4,0).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.37,-.15).mul(e).mul(r)))),h=h.add(s(t.add(Dp(-.29,-.29).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.15,-.37).mul(e).mul(r)))),h=h.add(s(t.add(Dp(.15,.37).mul(e).mul(n)))),h=h.add(s(t.add(Dp(-.37,.15).mul(e).mul(n)))),h=h.add(s(t.add(Dp(.37,-.15).mul(e).mul(n)))),h=h.add(s(t.add(Dp(-.15,-.37).mul(e).mul(n)))),h=h.add(s(t.add(Dp(-.15,.37).mul(e).mul(n)))),h=h.add(s(t.add(Dp(.37,.15).mul(e).mul(n)))),h=h.add(s(t.add(Dp(-.37,-.15).mul(e).mul(n)))),h=h.add(s(t.add(Dp(.15,-.37).mul(e).mul(n)))),h=h.add(s(t.add(Dp(.29,.29).mul(e).mul(o)))),h=h.add(s(t.add(Dp(.4,0).mul(e).mul(o)))),h=h.add(s(t.add(Dp(.29,-.29).mul(e).mul(o)))),h=h.add(s(t.add(Dp(0,-.4).mul(e).mul(o)))),h=h.add(s(t.add(Dp(-.29,.29).mul(e).mul(o)))),h=h.add(s(t.add(Dp(-.4,0).mul(e).mul(o)))),h=h.add(s(t.add(Dp(-.29,-.29).mul(e).mul(o)))),h=h.add(s(t.add(Dp(0,.4).mul(e).mul(o)))),h=h.add(s(t.add(Dp(.29,.29).mul(e).mul(a)))),h=h.add(s(t.add(Dp(.4,0).mul(e).mul(a)))),h=h.add(s(t.add(Dp(.29,-.29).mul(e).mul(a)))),h=h.add(s(t.add(Dp(0,-.4).mul(e).mul(a)))),h=h.add(s(t.add(Dp(-.29,.29).mul(e).mul(a)))),h=h.add(s(t.add(Dp(-.4,0).mul(e).mul(a)))),h=h.add(s(t.add(Dp(-.29,-.29).mul(e).mul(a)))),h=h.add(s(t.add(Dp(0,.4).mul(e).mul(a)))),h=h.div(41),h.a=1,Xp(h)}))()}}const IC=(e,t,s=1,i=.025,r=1)=>Sp(new BC(fN(e),Sp(t),Sp(s),Sp(i),Sp(r)));class PC extends kd{static get type(){return"DotScreenNode"}constructor(e,t=new Qs(.5,.5),s=1.57,i=1){super("vec4"),this.inputNode=e,this.center=pm(t),this.angle=pm(s),this.scale=pm(i)}setup(){const e=this.inputNode,t=Rp((()=>{const e=Lg(this.angle),t=Vg(this.angle),s=My().mul(kv).sub(this.center),i=Dp(t.mul(s.x).sub(e.mul(s.y)),e.mul(s.x).add(t.mul(s.y))).mul(this.scale);return Lg(i.x).mul(Lg(i.y)).mul(4)})),s=Rp((()=>{const s=e,i=Zm(s.r,s.g,s.b).div(3);return Xp(jp(i.mul(10).sub(5).add(t())),s.a)}));return s()}}const FC=(e,t,s,i)=>Sp(new PC(Sp(e),t,s,i));class zC extends kd{static get type(){return"RGBShiftNode"}constructor(e,t=.005,s=0){super("vec4"),this.textureNode=e,this.amount=pm(t),this.angle=pm(s)}setup(){const{textureNode:e}=this,t=e.uvNode||My(),s=t=>e.uv(t);return Rp((()=>{const e=Dp(Vg(this.angle),Lg(this.angle)).mul(this.amount),i=s(t.add(e)),r=s(t),n=s(t.sub(e));return Xp(i.r,r.g,n.b,r.a)}))()}}const UC=(e,t,s)=>Sp(new zC(fN(e),t,s));class OC extends kd{static get type(){return"FilmNode"}constructor(e,t=null,s=null){super(),this.inputNode=e,this.intensityNode=t,this.uvNode=s}setup(){const e=this.uvNode||My(),t=Rp((()=>{const t=this.inputNode.rgb,s=Af(Og(e.add(BM())));let i=t.add(t.mul(_f(s.add(.1),0,1)));return null!==this.intensityNode&&(i=Tf(t,i,this.intensityNode)),Xp(i,this.inputNode.a)}));return t()}}const LC=Ap(OC);class VC extends kd{static get type(){return"Lut3DNode"}constructor(e,t,s,i){super(),this.inputNode=e,this.lutNode=t,this.size=pm(s),this.intensityNode=i}setup(){const{inputNode:e,lutNode:t}=this,s=Rp((()=>{const s=e,i=Up(1).div(this.size),r=Up(.5).div(this.size),n=jp(r).add(s.rgb.mul(Up(1).sub(i))),o=Xp((e=>t.uv(e))(n).rgb,s.a);return Xp(Tf(s,o,this.intensityNode))}));return s()}}const DC=(e,t,s,i)=>Sp(new VC(Sp(e),Sp(t),s,Sp(i))),kC=new dN,GC=new Jr,WC=new Qs;class jC extends kd{static get type(){return"GTAONode"}constructor(e,t,s){super(),this.depthNode=e,this.normalNode=t,this.radius=pm(.25),this.resolution=pm(new Qs),this.thickness=pm(1),this.distanceExponent=pm(1),this.distanceFallOff=pm(1),this.scale=pm(1),this.noiseNode=By(function(e=5){const t=Math.floor(e)%2==0?Math.floor(e)+1:Math.floor(e),s=function(e){const t=Math.floor(e)%2==0?Math.floor(e)+1:Math.floor(e),s=t*t,i=Array(s).fill(0);let r=Math.floor(t/2),n=t-1;for(let e=1;e<=s;)-1===r&&n===t?(n=t-2,r=0):(n===t&&(n=0),r<0&&(r=t-1)),0===i[r*t+n]?(i[r*t+n]=e++,n++,r--):(n-=2,r++);return i}(t),i=s.length,r=new Uint8Array(4*i);for(let e=0;ethis.depthNode.uv(e).x,i=e=>this.noiseNode.uv(e),r=Rp((([e])=>{const t=this.cameraProjectionMatrix.mul(Xp(e,1));let i=t.xy.div(t.w).mul(.5).add(.5).toVar();i=Dp(i.x,i.y.oneMinus());const r=s(i);return jp(i,r)})),n=Rp((([e,t])=>{e=Dp(e.x,e.y.oneMinus()).mul(2).sub(1);const s=Xp(jp(e,t),1),i=Xp(this.cameraProjectionMatrixInverse.mul(s));return i.xyz.div(i.w)})),o=Rp((()=>{const e=s(t);e.greaterThanEqual(1).discard();const o=n(t,e),a=this.normalNode.rgb.normalize(),h=this.radius,u=Ay(this.noiseNode,0);let l=Dp(t.x,t.y.oneMinus());l=l.mul(this.resolution.div(u));const c=i(l),d=c.xyz.mul(2).sub(1),p=jp(d.xy,0).normalize(),m=jp(p.y.mul(-1),p.x,0),g=Qp(p,m,jp(0,0,1)),f=this.SAMPLES.lessThan(30).select(3,5),y=Zm(this.SAMPLES,f.sub(1)).div(f),x=Up(0).toVar();return bv({start:Op(0),end:f,type:"int",condition:"<"},(({i:e})=>{const t=Up(e).div(Up(f)).mul(Tg),s=Xp(Vg(t),Lg(t),0,Zm(.5,Km(.5,c.w)));s.xyz=Ug(g.mul(s.xyz));const i=Ug(o.xyz.negate()),u=Ug(pf(s.xyz,i)),l=pf(u,i),d=Ug(a.sub(u.mul(df(a,u)))),p=pf(d,u),m=Dp(df(i,p),df(i,p.negate())).toVar();bv({end:y,type:"int",name:"j",condition:"<"},(({j:e})=>{const t=s.xyz.mul(h).mul(s.w).mul(mf(Qm(Up(e).add(1),Up(y)),this.distanceExponent)),a=r(o.add(t)),u=n(a.xy,a.z).sub(o);Pp(jg(u.z).lessThan(this.thickness),(()=>{const t=df(i,Ug(u));m.x.addAssign(of(0,Km(t.sub(m.x),Tf(1,Up(2).div(Up(e).add(2)),this.distanceFallOff))))}));const l=r(o.sub(t)),c=n(l.xy,l.z).sub(o);Pp(jg(c.z).lessThan(this.thickness),(()=>{const t=df(i,Ug(c));m.y.addAssign(of(0,Km(t.sub(m.y),Tf(1,Up(2).div(Up(e).add(2)),this.distanceFallOff))))}))}));const b=Ig(Jm(1,m.mul(m))),v=df(d,l),T=df(d,i),_=Km(.5,Gg(m.y).sub(Gg(m.x)).add(b.x.mul(m.x).sub(b.y.mul(m.y)))),w=Km(.5,Jm(2,m.x.mul(m.x)).sub(m.y.mul(m.y))),S=v.mul(_).add(T.mul(w));x.addAssign(S)})),x.assign(_f(x.div(f),0,1)),x.assign(mf(x,this.scale)),Xp(jp(x),1)})),a=this._material||(this._material=new pT);return a.fragmentNode=o().context(e.getSharedContext()),a.name="GTAO",a.needsUpdate=!0,this._textureNode}dispose(){this._aoRenderTarget.dispose()}}const HC=(e,t,s)=>Sp(new jC(Sp(e),Sp(t),s));class qC extends kd{static get type(){return"DenoiseNode"}constructor(e,t,s,i,r){super(),this.textureNode=e,this.depthNode=t,this.normalNode=s,this.noiseNode=i,this.cameraProjectionMatrixInverse=pm(r.projectionMatrixInverse),this.lumaPhi=pm(5),this.depthPhi=pm(5),this.normalPhi=pm(5),this.radius=pm(5),this.index=pm(0),this._resolution=pm(new Qs),this._sampleVectors=Ox(function(e,t,s){const i=function(e,t,s){const i=[];for(let r=0;rthis.textureNode.uv(e),s=e=>this.depthNode.uv(e).x,i=e=>this.normalNode.uv(e),r=e=>this.noiseNode.uv(e),n=Rp((([e,t])=>{e=Dp(e.x,e.y.oneMinus()).mul(2).sub(1);const s=Xp(jp(e,t),1),i=Xp(this.cameraProjectionMatrixInverse.mul(s));return i.xyz.div(i.w)})),o=Rp((([e,r,o,a])=>{const h=t(a),u=s(a),l=i(a).rgb.normalize(),c=h.rgb,d=n(a,u),p=df(r,l).toVar(),m=mf(of(p,0),this.normalPhi).toVar(),g=jg(SC(c).sub(SC(e))).toVar(),f=of(Up(1).sub(g.div(this.lumaPhi)),0).toVar(),y=jg(df(o.sub(d),r)).toVar(),x=of(Up(1).sub(y.div(this.depthPhi)),0),b=f.mul(x).mul(m);return Xp(c.mul(b),b)})),a=Rp((([e])=>{const a=s(e),h=i(e).rgb.normalize(),u=t(e);Pp(a.greaterThanEqual(1).or(df(h,h).equal(0)),(()=>u));const l=jp(u.rgb),c=n(e,a),d=Ay(this.noiseNode,0);let p=Dp(e.x,e.y.oneMinus());p=p.mul(this._resolution.div(d));const m=r(p),g=Lg(m.element(this.index.mod(4).mul(2).mul(Tg))),f=Vg(m.element(this.index.mod(4).mul(2).mul(Tg))),y=Dp(g,f),x=Kp(y.x,y.y.negate(),y.x,y.y),b=Up(1).toVar(),v=jp(u.rgb).toVar();return bv({start:Op(0),end:Op(16),type:"int",condition:"<"},(({i:t})=>{const s=this._sampleVectors.element(t).toVar(),i=x.mul(s.xy.mul(Up(1).add(s.z.mul(this.radius.sub(1))))).div(this._resolution).toVar(),r=e.add(i).toVar(),n=o(l,h,c,r);v.addAssign(n.xyz),b.addAssign(n.w)})),Pp(b.greaterThan(Up(0)),(()=>{v.divAssign(b)})),Xp(v,u.a)})).setLayout({name:"denoise",type:"vec4",inputs:[{name:"uv",type:"vec2"}]});return Rp((()=>a(e)))()}}const $C=(e,t,s,i,r)=>Sp(new qC(fN(e),Sp(t),Sp(s),Sp(i),r));class XC extends kd{static get type(){return"FXAANode"}constructor(e){super(),this.textureNode=e,this.updateBeforeType=Bd.RENDER,this._invSize=pm(new Qs)}updateBefore(){const e=this.textureNode.value;this._invSize.value.set(1/e.image.width,1/e.image.height)}setup(){const e=this.textureNode.bias(-100),t=e.uvNode||My(),s=t=>e.uv(t),i=(t,s,i)=>e.uv(t.add(s.mul(i))),r=Op(5),n=Rp((([e,t])=>{const s=Xp(t).toVar(),i=Xp(e).toVar(),r=Xp(jg(i.sub(s))).toVar();return of(of(of(r.r,r.g),r.b),r.a)})),o=Rp((([e,t,o,a])=>{const h=s(e).toVar(),u=i(e,Dp(0,-1),t.xy).toVar(),l=i(e,Dp(1,0),t.xy).toVar(),c=i(e,Dp(0,1),t.xy).toVar(),d=i(e,Dp(-1,0),t.xy).toVar(),p=n(h,c).toVar(),m=n(h,u).toVar(),g=n(h,l).toVar(),f=n(h,d).toVar(),y=of(p,of(m,of(g,f))).toVar();Pp(y.lessThan(o),(()=>h));const x=Jm(p.add(m),g.add(f)).toVar();x.mulAssign(a),Pp(jg(x).lessThan(.3),(()=>{const s=g.greaterThan(f).select(1,-1).toVar(),r=m.greaterThan(p).select(1,-1).toVar(),o=Dp(s,r).toVar(),y=i(e,Dp(o.x,o.y),t.xy),b=n(h,y).toVar(),v=i(e,Dp(o.x.negate(),o.y.negate()),t.xy),T=n(h,v).toVar();x.assign(T.sub(b)),x.mulAssign(a),Pp(jg(x).lessThan(.3),(()=>{const e=c.add(u).add(l).add(d);return Tf(h,e.mul(.25),.4)}))}));const b=Dp().toVar();Pp(x.lessThanEqual(0),(()=>{c.assign(d),u.assign(l),b.x.assign(0),b.y.assign(t.y)})).Else((()=>{b.x.assign(t.x),b.y.assign(0)}));const v=n(h,c).toVar(),T=n(h,u).toVar();Pp(v.lessThanEqual(T),(()=>{c.assign(u)}));const _=Op(0).toVar(),w=Op(0).toVar(),S=Up(0).toVar(),M=Up(0).toVar(),N=Dp(e).toVar(),A=Dp(e).toVar(),C=Op(0).toVar(),R=Op(0).toVar();bv(r,(({i:t})=>{const i=t.add(1).toVar();Pp(_.equal(0),(()=>{S.addAssign(i),N.assign(e.add(b.mul(S)));const r=s(N.xy),o=n(r,h).toVar(),a=n(r,c).toVar();Pp(o.greaterThan(a),(()=>{_.assign(1)})),C.assign(t)})),Pp(w.equal(0),(()=>{M.addAssign(i),A.assign(e.sub(b.mul(M)));const r=s(A.xy),o=n(r,h).toVar(),a=n(r,c).toVar();Pp(o.greaterThan(a),(()=>{w.assign(1)})),R.assign(t)})),Pp(_.equal(1).or(w.equal(1)),(()=>{Tv()}))})),Pp(_.equal(0).and(w.equal(0)),(()=>h));const E=Up(1).toVar(),B=Up(1).toVar();Pp(_.equal(1),(()=>{E.assign(Up(C).div(Up(r.sub(1))))})),Pp(w.equal(1),(()=>{B.assign(Up(R).div(Up(r.sub(1))))}));const I=nf(E,B);return I.assign(mf(I,.5)),I.assign(Up(1).sub(I)),Tf(h,c,I.mul(.5))})).setLayout({name:"FxaaPixelShader",type:"vec4",inputs:[{name:"uv",type:"vec2"},{name:"fxaaQualityRcpFrame",type:"vec2"},{name:"fxaaQualityEdgeThreshold",type:"float"},{name:"fxaaQualityinvEdgeThreshold",type:"float"}]});return Rp((()=>{const e=Up(.2),s=Up(1).div(e);return o(t,this._invSize,e,s)}))()}}const YC=e=>Sp(new XC(fN(e))),ZC=new dN,JC=new Jr(0,0,0),KC=new Jr,QC=new Qs,eR=new Qs(1,0),tR=new Qs(0,1);class sR extends kd{static get type(){return"BloomNode"}constructor(e,t=1,s=0,i=0){super(),this.inputNode=e,this.strength=pm(t),this.radius=pm(s),this.threshold=pm(i),this.smoothWidth=pm(.01),this._renderTargetsHorizontal=[],this._renderTargetsVertical=[],this._nMips=5,this._renderTargetBright=new _i(1,1,{type:Pe}),this._renderTargetBright.texture.name="UnrealBloomPass.bright",this._renderTargetBright.texture.generateMipmaps=!1;for(let e=0;e{const e=this.inputNode,t=SC(e.rgb),s=Mf(this.threshold,this.threshold.add(this.smoothWidth),t);return Tf(Xp(0),e,s)}));this._highPassFilterMaterial=this._highPassFilterMaterial||new pT,this._highPassFilterMaterial.fragmentNode=t().context(e.getSharedContext()),this._highPassFilterMaterial.name="Bloom_highPass",this._highPassFilterMaterial.needsUpdate=!0;const s=[3,5,7,9,11];for(let t=0;t{const s=Up(1.2).sub(e);return Tf(e,s,t)})).setLayout({name:"lerpBloomFactor",type:"float",inputs:[{name:"factor",type:"float"},{name:"radius",type:"float"}]}),o=Rp((()=>{const e=n(i.element(0),this.radius).mul(Xp(r.element(0),1)).mul(this._textureNodeBlur0),t=n(i.element(1),this.radius).mul(Xp(r.element(1),1)).mul(this._textureNodeBlur1),s=n(i.element(2),this.radius).mul(Xp(r.element(2),1)).mul(this._textureNodeBlur2),o=n(i.element(3),this.radius).mul(Xp(r.element(3),1)).mul(this._textureNodeBlur3),a=n(i.element(4),this.radius).mul(Xp(r.element(4),1)).mul(this._textureNodeBlur4);return e.add(t).add(s).add(o).add(a).mul(this.strength)}));return this._compositeMaterial=this._compositeMaterial||new pT,this._compositeMaterial.fragmentNode=o().context(e.getSharedContext()),this._compositeMaterial.name="Bloom_comp",this._compositeMaterial.needsUpdate=!0,this._textureOutput}dispose(){for(let e=0;ei.uv(e),u=Rp((()=>{const e=r.element(0).toVar(),s=h(a).rgb.mul(e).toVar();return bv({start:Op(1),end:Op(t),type:"int",condition:"<"},(({i:t})=>{const i=Up(t),u=r.element(t),l=o.mul(n).mul(i),c=h(a.add(l)).rgb,d=h(a.sub(l)).rgb;s.addAssign(Zm(c,d).mul(u)),e.addAssign(Up(2).mul(u))})),Xp(s.div(e),1)})),l=new pT;return l.fragmentNode=u().context(e.getSharedContext()),l.name="Bloom_seperable",l.needsUpdate=!0,l.colorTexture=i,l.direction=o,l.invSize=n,l}}const iR=(e,t,s,i)=>Sp(new sR(Sp(e),t,s,i));class rR extends kd{static get type(){return"TransitionNode"}constructor(e,t,s,i,r,n){super(),this.textureNodeA=e,this.textureNodeB=t,this.mixTextureNode=s,this.mixRatioNode=i,this.thresholdNode=r,this.useTextureNode=n}setup(){const{textureNodeA:e,textureNodeB:t,mixTextureNode:s,mixRatioNode:i,thresholdNode:r,useTextureNode:n}=this,o=e=>{const t=e.uvNode||My();return e.uv(t)},a=Rp((()=>{const a=o(e),h=o(t),u=Xp().toVar();return Pp(n.equal(Op(1)),(()=>{const e=o(s),t=i.mul(r.mul(2).add(1)).sub(r),n=_f(Jm(e.r,t).mul(Up(1).div(r)),0,1);u.assign(Tf(a,h,n))})).Else((()=>{u.assign(Tf(h,a,i))})),u}));return a()}}const nR=(e,t,s,i=0,r=.1,n=0)=>Sp(new rR(fN(e),fN(t),fN(s),Sp(i),Sp(r),Sp(n)));class oR extends kd{static get type(){return"PixelationNode"}constructor(e,t,s,i,r,n){super(),this.textureNode=e,this.depthNode=t,this.normalNode=s,this.pixelSize=i,this.normalEdgeStrength=r,this.depthEdgeStrength=n,this._resolution=pm(new Ti),this.updateBeforeType=Bd.RENDER}updateBefore(){const e=this.textureNode.value,t=e.image.width,s=e.image.height;this._resolution.value.set(t,s,1/t,1/s)}setup(){const{textureNode:e,depthNode:t,normalNode:s}=this,i=e.uvNode||My(),r=t.uvNode||My(),n=s.uvNode||My(),o=(e,s)=>t.uv(r.add(Dp(e,s).mul(this._resolution.zw))).r,a=(e,t)=>s.uv(n.add(Dp(e,t).mul(this._resolution.zw))).rgb.normalize(),h=(e,t,s,i)=>{const r=o(e,t).sub(s),n=a(e,t),h=jp(1,1,1),u=df(i.sub(n),h),l=_f(Mf(-.01,.01,u),0,1),c=_f(Hg(r.mul(.25).add(.0025)),0,1);return Up(1).sub(df(i,n)).mul(c).mul(l)},u=Rp((()=>{const t=e.uv(i),s=gm("float","depth"),r=gm("vec3","normal");Pp(this.depthEdgeStrength.greaterThan(0).or(this.normalEdgeStrength.greaterThan(0)),(()=>{s.assign(o(0,0)),r.assign(a(0,0))}));const n=gm("float","dei");Pp(this.depthEdgeStrength.greaterThan(0),(()=>{n.assign((e=>{const t=gm("float","diff");return t.addAssign(_f(o(1,0).sub(e))),t.addAssign(_f(o(-1,0).sub(e))),t.addAssign(_f(o(0,1).sub(e))),t.addAssign(_f(o(0,-1).sub(e))),Fg(Mf(.01,.02,t).mul(2)).div(2)})(s))}));const u=gm("float","nei");Pp(this.normalEdgeStrength.greaterThan(0),(()=>{u.assign(((e,t)=>{const s=gm("float","indicator");return s.addAssign(h(0,-1,e,t)),s.addAssign(h(0,1,e,t)),s.addAssign(h(-1,0,e,t)),s.addAssign(h(1,0,e,t)),hf(.1,s)})(s,r))}));const l=n.greaterThan(0).select(Up(1).sub(n.mul(this.depthEdgeStrength)),u.mul(this.normalEdgeStrength).add(1));return t.mul(l)}));return u()}}class aR extends aC{static get type(){return"PixelationPassNode"}constructor(e,t,s=6,i=.3,r=.4){super("color",e,t,{minFilter:fe,magFilter:fe}),this.pixelSize=s,this.normalEdgeStrength=i,this.depthEdgeStrength=r,this.isPixelationPassNode=!0,this._mrt=NM({output:zm,normal:bx})}setSize(e,t){const s=this.pixelSize.value?this.pixelSize.value:this.pixelSize,i=Math.floor(e/s),r=Math.floor(t/s);super.setSize(i,r)}setup(){return((e,t,s,i=6,r=.3,n=.4)=>Sp(new oR(fN(e),fN(t),fN(s),Sp(i),Sp(r),Sp(n))))(super.getTextureNode("output"),super.getTextureNode("depth"),super.getTextureNode("normal"),this.pixelSize,this.normalEdgeStrength,this.depthEdgeStrength)}}const hR=(e,t,s,i,r)=>Sp(new aR(e,t,s,i,r)),uR=new Qs;class lR extends aC{static get type(){return"SSAAPassNode"}constructor(e,t){super(aC.COLOR,e,t),this.isSSAAPassNode=!0,this.sampleLevel=4,this.unbiased=!0,this.clearColor=new Jr(0),this.clearAlpha=0,this._currentClearColor=new Jr,this.sampleWeight=pm(1),this.sampleRenderTarget=null,this._quadMesh=new dN}updateBefore(e){const{renderer:t}=e,{scene:s,camera:i}=this;this._pixelRatio=t.getPixelRatio();const r=t.getSize(uR);this.setSize(r.width,r.height),this.sampleRenderTarget.setSize(this.renderTarget.width,this.renderTarget.height),t.getClearColor(this._currentClearColor);const n=t.getClearAlpha(),o=t.getRenderTarget(),a=t.getMRT(),h=t.autoClear;this._cameraNear.value=i.near,this._cameraFar.value=i.far,t.setMRT(this.getMRT()),t.autoClear=!1;const u=cR[Math.max(0,Math.min(this.sampleLevel,5))],l=1/u.length,c={fullWidth:this.renderTarget.width,fullHeight:this.renderTarget.height,offsetX:0,offsetY:0,width:this.renderTarget.width,height:this.renderTarget.height},d=Object.assign({},i.view);d.enabled&&Object.assign(c,d);for(let e=0;e=0&&(e[t]=By(this.sampleRenderTarget.textures[s]).mul(this.sampleWeight))}t=NM(e)}else t=By(this.sampleRenderTarget.texture).mul(this.sampleWeight);return this._quadMesh.material=new pT,this._quadMesh.material.fragmentNode=t,this._quadMesh.material.transparent=!0,this._quadMesh.material.depthTest=!1,this._quadMesh.material.depthWrite=!1,this._quadMesh.material.premultipliedAlpha=!0,this._quadMesh.material.blending=2,this._quadMesh.material.normals=!1,this._quadMesh.material.name="SSAA",super.setup(e)}dispose(){super.dispose(),null!==this.sampleRenderTarget&&this.sampleRenderTarget.dispose()}}const cR=[[[0,0]],[[4,4],[-4,-4]],[[-2,-6],[6,-2],[-6,2],[2,6]],[[1,-3],[-1,3],[5,1],[-3,-5],[-5,5],[-7,-1],[3,7],[7,-7]],[[1,1],[-1,-3],[-3,2],[4,-1],[-5,-2],[2,5],[5,3],[3,-5],[-2,6],[0,-7],[-4,-6],[-6,4],[-8,0],[7,-4],[6,7],[-7,-8]],[[-4,-7],[-7,-5],[-3,-5],[-5,-4],[-1,-4],[-2,-2],[-6,-1],[-4,0],[-7,1],[-1,2],[-6,3],[-3,3],[-7,6],[-3,6],[-5,7],[-1,7],[5,-7],[1,-6],[6,-5],[4,-4],[2,-3],[7,-2],[1,-1],[4,-1],[2,1],[6,2],[0,4],[4,4],[2,5],[7,5],[5,6],[3,7]]],dR=(e,t)=>Sp(new lR(e,t)),pR=new Qs;class mR extends aC{static get type(){return"StereoPassNode"}constructor(e,t){super(aC.COLOR,e,t),this.isStereoPassNode=!0,this.stereo=new ql,this.stereo.aspect=.5}updateBefore(e){const{renderer:t}=e,{scene:s,camera:i,stereo:r,renderTarget:n}=this;this._pixelRatio=t.getPixelRatio(),r.cameraL.coordinateSystem=t.coordinateSystem,r.cameraR.coordinateSystem=t.coordinateSystem,r.update(i);const o=t.getSize(pR);this.setSize(o.width,o.height);const a=t.autoClear;t.autoClear=!1;const h=t.getRenderTarget(),u=t.getMRT();this._cameraNear.value=i.near,this._cameraFar.value=i.far;for(const e in this._previousTextures)this.toggleTexture(e);t.setRenderTarget(n),t.setMRT(this._mrt),t.clear(),n.scissorTest=!0,n.scissor.set(0,0,n.width/2,n.height),n.viewport.set(0,0,n.width/2,n.height),t.render(s,r.cameraL),n.scissor.set(n.width/2,0,n.width/2,n.height),n.viewport.set(n.width/2,0,n.width/2,n.height),t.render(s,r.cameraR),n.scissorTest=!1,t.setRenderTarget(h),t.setMRT(u),t.autoClear=a}}const gR=(e,t)=>Sp(new mR(e,t)),fR=new Qs,yR=new dN;class xR extends aC{static get type(){return"StereoCompositePassNode"}constructor(e,t){super(aC.COLOR,e,t),this.isStereoCompositePassNode=!0,this.stereo=new ql;const s={minFilter:Te,magFilter:fe,type:Pe};this._renderTargetL=new _i(1,1,s),this._renderTargetR=new _i(1,1,s),this._mapLeft=By(this._renderTargetL.texture),this._mapRight=By(this._renderTargetR.texture),this._material=null}updateStereoCamera(e){this.stereo.cameraL.coordinateSystem=e,this.stereo.cameraR.coordinateSystem=e,this.stereo.update(this.camera)}setSize(e,t){super.setSize(e,t),this._renderTargetL.setSize(this.renderTarget.width,this.renderTarget.height),this._renderTargetR.setSize(this.renderTarget.width,this.renderTarget.height)}updateBefore(e){const{renderer:t}=e,{scene:s,stereo:i,renderTarget:r}=this;this._pixelRatio=t.getPixelRatio(),this.updateStereoCamera(t.coordinateSystem);const n=t.getSize(fR);this.setSize(n.width,n.height);const o=t.getRenderTarget();t.setRenderTarget(this._renderTargetL),t.render(s,i.cameraL),t.setRenderTarget(this._renderTargetR),t.render(s,i.cameraR),t.setRenderTarget(r),yR.material=this._material,yR.render(t),t.setRenderTarget(o)}dispose(){super.dispose(),this._renderTargetL.dispose(),this._renderTargetR.dispose(),null!==this._material&&this._material.dispose()}}class bR extends xR{static get type(){return"AnaglyphPassNode"}constructor(e,t){super(e,t),this.isAnaglyphPassNode=!0,this._colorMatrixLeft=pm((new ei).fromArray([.4561,-.0400822,-.0152161,.500484,-.0378246,-.0205971,.176381,-.0157589,-.00546856])),this._colorMatrixRight=pm((new ei).fromArray([-.0434706,.378476,-.0721527,-.0879388,.73364,-.112961,-.00155529,-.0184503,1.2264]))}setup(e){const t=My(),s=Rp((()=>{const e=this._mapLeft.uv(t),s=this._mapRight.uv(t),i=_f(this._colorMatrixLeft.mul(e.rgb).add(this._colorMatrixRight.mul(s.rgb)));return Xp(i.rgb,of(e.a,s.a))})),i=this._material||(this._material=new pT);return i.fragmentNode=s().context(e.getSharedContext()),i.name="Anaglyph",i.needsUpdate=!0,super.setup(e)}}const vR=(e,t)=>Sp(new bR(e,t));class TR extends xR{static get type(){return"ParallaxBarrierPassNode"}constructor(e,t){super(e,t),this.isParallaxBarrierPassNode=!0}setup(e){const t=My(),s=Rp((()=>{const e=Xp().toVar();return Pp(af(Gv.y,2).greaterThan(1),(()=>{e.assign(this._mapLeft.uv(t))})).Else((()=>{e.assign(this._mapRight.uv(t))})),e})),i=this._material||(this._material=new pT);return i.fragmentNode=s().context(e.getSharedContext()),i.needsUpdate=!0,super.setup(e)}}const _R=(e,t)=>Sp(new TR(e,t));class wR extends aC{static get type(){return"ToonOutlinePassNode"}constructor(e,t,s,i,r){super(aC.COLOR,e,t),this.colorNode=s,this.thicknessNode=i,this.alphaNode=r,this._materialCache=new WeakMap}updateBefore(e){const{renderer:t}=e,s=t.getRenderObjectFunction();t.setRenderObjectFunction(((e,s,i,r,n,o,a)=>{if((n.isMeshToonMaterial||n.isMeshToonNodeMaterial)&&!1===n.wireframe){const h=this._getOutlineMaterial(n);t.renderObject(e,s,i,r,h,o,a)}t.renderObject(e,s,i,r,n,o,a)})),super.updateBefore(e),t.setRenderObjectFunction(s)}_createMaterial(){const e=new pT;e.isMeshToonOutlineMaterial=!0,e.name="Toon_Outline",e.side=d;const t=yx.negate(),s=Oy.mul(ix),i=Up(1),r=s.mul(Xp(ax,1)),n=s.mul(Xp(ax.add(t),1)),o=Ug(r.sub(n));return e.vertexNode=r.add(o.mul(this.thicknessNode).mul(r.w).mul(i)),e.colorNode=Xp(this.colorNode,this.alphaNode),e}_getOutlineMaterial(e){let t=this._materialCache.get(e);return void 0===t&&(t=this._createMaterial(),this._materialCache.set(e,t)),t}}const SR=(e,t,s=new Jr(0,0,0),i=.003,r=1)=>Sp(new wR(e,t,Sp(s),Sp(i),Sp(r)));class MR extends Ld{static get type(){return"ScriptableValueNode"}constructor(e=null){super(),this._value=e,this._cache=null,this.inputType=null,this.outpuType=null,this.events=new ks,this.isScriptableValueNode=!0}get isScriptableOutputNode(){return null!==this.outputType}set value(e){this._value!==e&&(this._cache&&"URL"===this.inputType&&this.value.value instanceof ArrayBuffer&&(URL.revokeObjectURL(this._cache),this._cache=null),this._value=e,this.events.dispatchEvent({type:"change"}),this.refresh())}get value(){return this._value}refresh(){this.events.dispatchEvent({type:"refresh"})}getValue(){const e=this.value;if(e&&null===this._cache&&"URL"===this.inputType&&e.value instanceof ArrayBuffer)this._cache=URL.createObjectURL(new Blob([e.value]));else if(e&&null!==e.value&&void 0!==e.value&&(("URL"===this.inputType||"String"===this.inputType)&&"string"==typeof e.value||"Number"===this.inputType&&"number"==typeof e.value||"Vector2"===this.inputType&&e.value.isVector2||"Vector3"===this.inputType&&e.value.isVector3||"Vector4"===this.inputType&&e.value.isVector4||"Color"===this.inputType&&e.value.isColor||"Matrix3"===this.inputType&&e.value.isMatrix3||"Matrix4"===this.inputType&&e.value.isMatrix4))return e.value;return this._cache||e}getNodeType(e){return this.value&&this.value.isNode?this.value.getNodeType(e):"float"}setup(){return this.value&&this.value.isNode?this.value:Up()}serialize(e){super.serialize(e),null!==this.value?"ArrayBuffer"===this.inputType?e.value=Ad(this.value):e.value=this.value?this.value.toJSON(e.meta).uuid:null:e.value=null,e.inputType=this.inputType,e.outputType=this.outputType}deserialize(e){super.deserialize(e);let t=null;null!==e.value&&(t="ArrayBuffer"===e.inputType?Cd(e.value):"Texture"===e.inputType?e.meta.textures[e.value]:e.meta.nodes[e.value]||null),this.value=t,this.inputType=e.inputType,this.outputType=e.outputType}}const NR=Ap(MR);class AR extends Map{get(e,t=null,...s){if(this.has(e))return super.get(e);if(null!==t){const i=t(...s);return this.set(e,i),i}}}class CR{constructor(e){this.scriptableNode=e}get parameters(){return this.scriptableNode.parameters}get layout(){return this.scriptableNode.getLayout()}getInputLayout(e){return this.scriptableNode.getInputLayout(e)}get(e){const t=this.parameters[e];return t?t.getValue():null}}const RR=new AR;class ER extends Ld{static get type(){return"ScriptableNode"}constructor(e=null,t={}){super(),this.codeNode=e,this.parameters=t,this._local=new AR,this._output=NR(),this._outputs={},this._source=this.source,this._method=null,this._object=null,this._value=null,this._needsOutputUpdate=!0,this.onRefresh=this.onRefresh.bind(this),this.isScriptableNode=!0}get source(){return this.codeNode?this.codeNode.code:""}setLocal(e,t){return this._local.set(e,t)}getLocal(e){return this._local.get(e)}onRefresh(){this._refresh()}getInputLayout(e){for(const t of this.getLayout())if(t.inputType&&(t.id===e||t.name===e))return t}getOutputLayout(e){for(const t of this.getLayout())if(t.outputType&&(t.id===e||t.name===e))return t}setOutput(e,t){const s=this._outputs;return void 0===s[e]?s[e]=NR(t):s[e].value=t,this}getOutput(e){return this._outputs[e]}getParameter(e){return this.parameters[e]}setParameter(e,t){const s=this.parameters;return t&&t.isScriptableNode?(this.deleteParameter(e),s[e]=t,s[e].getDefaultOutput().events.addEventListener("refresh",this.onRefresh)):t&&t.isScriptableValueNode?(this.deleteParameter(e),s[e]=t,s[e].events.addEventListener("refresh",this.onRefresh)):void 0===s[e]?(s[e]=NR(t),s[e].events.addEventListener("refresh",this.onRefresh)):s[e].value=t,this}getValue(){return this.getDefaultOutput().getValue()}deleteParameter(e){let t=this.parameters[e];return t&&(t.isScriptableNode&&(t=t.getDefaultOutput()),t.events.removeEventListener("refresh",this.onRefresh)),this}clearParameters(){for(const e of Object.keys(this.parameters))this.deleteParameter(e);return this.needsUpdate=!0,this}call(e,...t){const s=this.getObject()[e];if("function"==typeof s)return s(...t)}async callAsync(e,...t){const s=this.getObject()[e];if("function"==typeof s)return"AsyncFunction"===s.constructor.name?await s(...t):s(...t)}getNodeType(e){return this.getDefaultOutputNode().getNodeType(e)}refresh(e=null){null!==e?this.getOutput(e).refresh():this._refresh()}getObject(){if(this.needsUpdate&&this.dispose(),null!==this._object)return this._object;const e=new CR(this),t=RR.get("THREE"),s=RR.get("TSL"),i=this.getMethod(this.codeNode),r=[e,this._local,RR,()=>this.refresh(),(e,t)=>this.setOutput(e,t),t,s];this._object=i(...r);const n=this._object.layout;if(n&&(!1===n.cache&&this._local.clear(),this._output.outputType=n.outputType||null,Array.isArray(n.elements)))for(const e of n.elements){const t=e.id||e.name;e.inputType&&(void 0===this.getParameter(t)&&this.setParameter(t,null),this.getParameter(t).inputType=e.inputType),e.outputType&&(void 0===this.getOutput(t)&&this.setOutput(t,null),this.getOutput(t).outputType=e.outputType)}return this._object}deserialize(e){super.deserialize(e);for(const e in this.parameters){let t=this.parameters[e];t.isScriptableNode&&(t=t.getDefaultOutput()),t.events.addEventListener("refresh",this.onRefresh)}}getLayout(){return this.getObject().layout}getDefaultOutputNode(){const e=this.getDefaultOutput().value;return e&&e.isNode?e:Up()}getDefaultOutput(){return this._exec()._output}getMethod(){if(this.needsUpdate&&this.dispose(),null!==this._method)return this._method;const e=["layout","init","main","dispose"].join(", "),t="\nreturn { ...output, "+e+" };",s="var "+e+"; var output = {};\n"+this.codeNode.code+t;return this._method=new Function(...["parameters","local","global","refresh","setOutput","THREE","TSL"],s),this._method}dispose(){null!==this._method&&(this._object&&"function"==typeof this._object.dispose&&this._object.dispose(),this._method=null,this._object=null,this._source=null,this._value=null,this._needsOutputUpdate=!0,this._output.value=null,this._outputs={})}setup(){return this.getDefaultOutputNode()}getCacheKey(e){const t=[vd(this.source),this.getDefaultOutputNode().getCacheKey(e)];for(const s in this.parameters)t.push(this.parameters[s].getCacheKey(e));return Td(t)}set needsUpdate(e){!0===e&&this.dispose()}get needsUpdate(){return this.source!==this._source}_exec(){return null===this.codeNode||(!0===this._needsOutputUpdate&&(this._value=this.call("main"),this._needsOutputUpdate=!1),this._output.value=this._value),this}_refresh(){this.needsUpdate=!0,this._exec(),this._output.refresh()}}const BR=Ap(ER);class IR extends Ld{static get type(){return"FogNode"}constructor(e,t){super("float"),this.isFogNode=!0,this.colorNode=e,this.factorNode=t}getViewZNode(e){let t;const s=e.context.getViewZ;return void 0!==s&&(t=s(this)),(t||cx.z).negate()}setup(){return this.factorNode}}const PR=Ap(IR);class FR extends IR{static get type(){return"FogRangeNode"}constructor(e,t,s){super(e),this.isFogRangeNode=!0,this.nearNode=t,this.farNode=s}setup(e){const t=this.getViewZNode(e);return Mf(this.nearNode,this.farNode,t)}}const zR=Ap(FR);class UR extends IR{static get type(){return"FogExp2Node"}constructor(e,t){super(e),this.isFogExp2Node=!0,this.densityNode=t}setup(e){const t=this.getViewZNode(e),s=this.densityNode;return s.mul(s,t,t).negate().exp().oneMinus()}}const OR=Ap(UR);let LR=null,VR=null;class DR extends Ld{static get type(){return"RangeNode"}constructor(e=Up(),t=Up()){super(),this.minNode=e,this.maxNode=t}getVectorLength(e){const t=e.getTypeLength(Md(this.minNode.value)),s=e.getTypeLength(Md(this.maxNode.value));return t>s?t:s}getNodeType(e){return e.object.count>1?e.getTypeFromLength(this.getVectorLength(e)):"float"}setup(e){const t=e.object;let s=null;if(t.count>1){const i=this.minNode.value,r=this.maxNode.value,n=e.getTypeLength(Md(i)),o=e.getTypeLength(Md(r));LR=LR||new Ti,VR=VR||new Ti,LR.setScalar(0),VR.setScalar(0),1===n?LR.setScalar(i):i.isColor?LR.set(i.r,i.g,i.b):LR.set(i.x,i.y,i.z||0,i.w||0),1===o?VR.setScalar(r):r.isColor?VR.set(r.r,r.g,r.b):VR.set(r.x,r.y,r.z||0,r.w||0);const a=4,h=a*t.count,u=new Float32Array(h);for(let e=0;eBy(e,t.xy).compare(t.z))),WR=Rp((({depthTexture:e,shadowCoord:t,shadow:s})=>{const i=(t,s)=>By(e,t).compare(s),r=kx("mapSize","vec2",s).setGroup(lm),n=kx("radius","float",s).setGroup(lm),o=Dp(1).div(r),a=o.x.negate().mul(n),h=o.y.negate().mul(n),u=o.x.mul(n),l=o.y.mul(n),c=a.div(2),d=h.div(2),p=u.div(2),m=l.div(2);return Zm(i(t.xy.add(Dp(a,h)),t.z),i(t.xy.add(Dp(0,h)),t.z),i(t.xy.add(Dp(u,h)),t.z),i(t.xy.add(Dp(c,d)),t.z),i(t.xy.add(Dp(0,d)),t.z),i(t.xy.add(Dp(p,d)),t.z),i(t.xy.add(Dp(a,0)),t.z),i(t.xy.add(Dp(c,0)),t.z),i(t.xy,t.z),i(t.xy.add(Dp(p,0)),t.z),i(t.xy.add(Dp(u,0)),t.z),i(t.xy.add(Dp(c,m)),t.z),i(t.xy.add(Dp(0,m)),t.z),i(t.xy.add(Dp(p,m)),t.z),i(t.xy.add(Dp(a,l)),t.z),i(t.xy.add(Dp(0,l)),t.z),i(t.xy.add(Dp(u,l)),t.z)).mul(1/17)})),jR=Rp((({depthTexture:e,shadowCoord:t,shadow:s})=>{const i=(t,s)=>By(e,t).compare(s),r=kx("mapSize","vec2",s).setGroup(lm),n=Dp(1).div(r),o=n.x,a=n.y,h=t.xy,u=Og(h.mul(r).add(.5));return h.subAssign(u.mul(n)),Zm(i(h,t.z),i(h.add(Dp(o,0)),t.z),i(h.add(Dp(0,a)),t.z),i(h.add(n),t.z),Tf(i(h.add(Dp(o.negate(),0)),t.z),i(h.add(Dp(o.mul(2),0)),t.z),u.x),Tf(i(h.add(Dp(o.negate(),a)),t.z),i(h.add(Dp(o.mul(2),a)),t.z),u.x),Tf(i(h.add(Dp(0,a.negate())),t.z),i(h.add(Dp(0,a.mul(2))),t.z),u.y),Tf(i(h.add(Dp(o,a.negate())),t.z),i(h.add(Dp(o,a.mul(2))),t.z),u.y),Tf(Tf(i(h.add(Dp(o.negate(),a.negate())),t.z),i(h.add(Dp(o.mul(2),a.negate())),t.z),u.x),Tf(i(h.add(Dp(o.negate(),a.mul(2))),t.z),i(h.add(Dp(o.mul(2),a.mul(2))),t.z),u.x),u.y)).mul(1/9)})),HR=Rp((({depthTexture:e,shadowCoord:t})=>{const s=Up(1).toVar(),i=By(e).uv(t.xy).rg,r=hf(t.z,i.x);return Pp(r.notEqual(Up(1)),(()=>{const e=t.z.sub(i.x),n=of(0,i.y.mul(i.y));let o=n.div(n.add(e.mul(e)));o=_f(Jm(o,.3).div(.95-.3)),s.assign(_f(of(r,o)))})),s})),qR=Rp((({samples:e,radius:t,size:s,shadowPass:i})=>{const r=Up(0).toVar(),n=Up(0).toVar(),o=e.lessThanEqual(Up(1)).select(Up(0),Up(2).div(e.sub(1))),a=e.lessThanEqual(Up(1)).select(Up(0),Up(-1));bv({start:Op(0),end:Op(e),type:"int",condition:"<"},(({i:e})=>{const h=a.add(Up(e).mul(o)),u=i.uv(Zm(Gv.xy,Dp(0,h).mul(t)).div(s)).x;r.addAssign(u),n.addAssign(u.mul(u))})),r.divAssign(e),n.divAssign(e);const h=Ig(n.sub(r.mul(r)));return Dp(r,h)})),$R=Rp((({samples:e,radius:t,size:s,shadowPass:i})=>{const r=Up(0).toVar(),n=Up(0).toVar(),o=e.lessThanEqual(Up(1)).select(Up(0),Up(2).div(e.sub(1))),a=e.lessThanEqual(Up(1)).select(Up(0),Up(-1));bv({start:Op(0),end:Op(e),type:"int",condition:"<"},(({i:e})=>{const h=a.add(Up(e).mul(o)),u=i.uv(Zm(Gv.xy,Dp(h,0).mul(t)).div(s));r.addAssign(u.x),n.addAssign(Zm(u.y.mul(u.y),u.x.mul(u.x)))})),r.divAssign(e),n.divAssign(e);const h=Ig(n.sub(r.mul(r)));return Dp(r,h)})),XR=[GR,WR,jR,HR];let YR=null;const ZR=new dN;class JR extends Iv{static get type(){return"AnalyticLightNode"}constructor(e=null){super(),this.updateType=Bd.FRAME,this.light=e,this.color=new Jr,this.colorNode=pm(this.color).setGroup(lm),this.baseColorNode=null,this.shadowMap=null,this.shadowNode=null,this.shadowColorNode=null,this.vsmShadowMapVertical=null,this.vsmShadowMapHorizontal=null,this.vsmMaterialVertical=null,this.vsmMaterialHorizontal=null,this.isAnalyticLightNode=!0}getCacheKey(){return _d(super.getCacheKey(),this.light.id,this.light.castShadow?1:0)}getHash(){return this.light.uuid}setupShadow(e){const{object:t,renderer:s}=e;if(!1===s.shadowMap.enabled)return;let i=this.shadowColorNode;if(null===i){null===YR&&(YR=new pT,YR.fragmentNode=Xp(0,0,0,1),YR.isShadowNodeMaterial=!0,YR.name="ShadowMaterial");const r=s.shadowMap.type,n=this.light.shadow,o=new Ya;o.compareFunction=Ts;const a=e.createRenderTarget(n.mapSize.width,n.mapSize.height);if(a.depthTexture=o,n.camera.updateProjectionMatrix(),3===r){o.compareFunction=null,this.vsmShadowMapVertical=e.createRenderTarget(n.mapSize.width,n.mapSize.height,{format:$e,type:Pe}),this.vsmShadowMapHorizontal=e.createRenderTarget(n.mapSize.width,n.mapSize.height,{format:$e,type:Pe});const t=By(o),s=By(this.vsmShadowMapVertical.texture),i=kx("blurSamples","float",n).setGroup(lm),r=kx("radius","float",n).setGroup(lm),a=kx("mapSize","vec2",n).setGroup(lm);let h=this.vsmMaterialVertical||(this.vsmMaterialVertical=new pT);h.fragmentNode=qR({samples:i,radius:r,size:a,shadowPass:t}).context(e.getSharedContext()),h.name="VSMVertical",h=this.vsmMaterialHorizontal||(this.vsmMaterialHorizontal=new pT),h.fragmentNode=$R({samples:i,radius:r,size:a,shadowPass:s}).context(e.getSharedContext()),h.name="VSMHorizontal"}const h=kx("intensity","float",n).setGroup(lm),u=kx("bias","float",n).setGroup(lm),l=kx("normalBias","float",n).setGroup(lm),c=t.material.shadowPositionNode||ux;let d=pm(n.matrix).setGroup(lm).mul(c.add(vx.mul(l)));d=d.xyz.div(d.w);let p=d.z.add(u);s.coordinateSystem===Ds&&(p=p.mul(2).sub(1)),d=jp(d.x,d.y.oneMinus(),p);const m=d.x.greaterThanEqual(0).and(d.x.lessThanEqual(1)).and(d.y.greaterThanEqual(0)).and(d.y.lessThanEqual(1)).and(d.z.lessThanEqual(1)),g=n.filterNode||XR[s.shadowMap.type]||null;if(null===g)throw new Error("THREE.WebGPURenderer: Shadow map type not supported yet.");const f=By(a.texture,d),y=m.select(g({depthTexture:3===r?this.vsmShadowMapHorizontal.texture:o,shadowCoord:d,shadow:n}),Up(1));this.shadowMap=a,this.light.shadow.map=a,this.shadowNode=y,this.shadowColorNode=i=this.colorNode.mul(Tf(1,y.rgb.mix(f,1),h.mul(f.a))),this.baseColorNode=this.colorNode}this.colorNode=i,this.updateBeforeType=Bd.RENDER}setup(e){this.colorNode=this.baseColorNode||this.colorNode,this.light.castShadow?e.object.receiveShadow&&this.setupShadow(e):null!==this.shadowNode&&this.disposeShadow()}updateShadow(e){const{shadowMap:t,light:s}=this,{renderer:i,scene:r,camera:n}=e,o=i.shadowMap.type,a=t.depthTexture.version;this._depthVersionCached=a;const h=r.overrideMaterial;r.overrideMaterial=YR,t.setSize(s.shadow.mapSize.width,s.shadow.mapSize.height),s.shadow.updateMatrices(s),s.shadow.camera.layers.mask=n.layers.mask;const u=i.getRenderTarget(),l=i.getRenderObjectFunction();i.setRenderObjectFunction(((e,...t)=>{(!0===e.castShadow||e.receiveShadow&&3===o)&&i.renderObject(e,...t)})),i.setRenderTarget(t),i.render(r,s.shadow.camera),i.setRenderObjectFunction(l),!0!==s.isPointLight&&3===o&&this.vsmPass(e,s),i.setRenderTarget(u),r.overrideMaterial=h}vsmPass(e,t){const{renderer:s}=e;this.vsmShadowMapVertical.setSize(t.shadow.mapSize.width,t.shadow.mapSize.height),this.vsmShadowMapHorizontal.setSize(t.shadow.mapSize.width,t.shadow.mapSize.height),s.setRenderTarget(this.vsmShadowMapVertical),ZR.material=this.vsmMaterialVertical,ZR.render(s),s.setRenderTarget(this.vsmShadowMapHorizontal),ZR.material=this.vsmMaterialHorizontal,ZR.render(s)}disposeShadow(){this.shadowMap.dispose(),this.shadowMap=null,null!==this.vsmShadowMapVertical&&(this.vsmShadowMapVertical.dispose(),this.vsmShadowMapVertical=null,this.vsmMaterialVertical.dispose(),this.vsmMaterialVertical=null),null!==this.vsmShadowMapHorizontal&&(this.vsmShadowMapHorizontal.dispose(),this.vsmShadowMapHorizontal=null,this.vsmMaterialHorizontal.dispose(),this.vsmMaterialHorizontal=null),this.shadowNode=null,this.shadowColorNode=null,this.baseColorNode=null,this.updateBeforeType=Bd.NONE}updateBefore(e){const t=this.light.shadow;(t.needsUpdate||t.autoUpdate)&&(this.updateShadow(e),this.shadowMap.depthTexture.version===this._depthVersionCached&&(t.needsUpdate=!1))}update(){const{light:e}=this;this.color.copy(e.color).multiplyScalar(e.intensity)}}const KR=Rp((e=>{const{lightDistance:t,cutoffDistance:s,decayExponent:i}=e,r=t.pow(i).max(.01).reciprocal();return s.greaterThan(0).select(r.mul(t.div(s).pow4().oneMinus().clamp().pow2()),r)}));let QR;function eE(e){QR=QR||new WeakMap;let t=QR.get(e);return void 0===t&&QR.set(e,t={}),t}function tE(e){const t=eE(e);return t.position||(t.position=pm(new Ri).setGroup(lm).onRenderUpdate(((t,s)=>s.value.setFromMatrixPosition(e.matrixWorld))))}function sE(e){const t=eE(e);return t.targetPosition||(t.targetPosition=pm(new Ri).setGroup(lm).onRenderUpdate(((t,s)=>s.value.setFromMatrixPosition(e.target.matrixWorld))))}function iE(e){const t=eE(e);return t.viewPosition||(t.viewPosition=pm(new Ri).setGroup(lm).onRenderUpdate((({camera:t},s)=>{s.value=s.value||new Ri,s.value.setFromMatrixPosition(e.matrixWorld),s.value.applyMatrix4(t.matrixWorldInverse)})))}const rE=e=>Vy.transformDirection(tE(e).sub(sE(e))),nE=Rp((([e])=>{const t=e.toUint().mul(747796405).add(2891336453),s=t.shiftRight(t.shiftRight(28).add(4)).bitXor(t).mul(277803737);return s.shiftRight(22).bitXor(s).toFloat().mul(1/2**32)})),oE=(e,t)=>mf(Km(4,e.mul(Jm(1,e))),t),aE=(e,t)=>e.lessThan(.5)?oE(e.mul(2),t).div(2):Jm(1,oE(Km(Jm(1,e),2),t).div(2)),hE=(e,t,s)=>mf(Qm(mf(e,t),Zm(mf(e,t),mf(Jm(1,e),s))),1/t),uE=(e,t)=>Lg(Tg.mul(t.mul(e).sub(1))).div(Tg.mul(t.mul(e).sub(1))),lE=Rp((([e])=>e.fract().sub(.5).abs())).setLayout({name:"tri",type:"float",inputs:[{name:"x",type:"float"}]}),cE=Rp((([e])=>jp(lE(e.z.add(lE(e.y.mul(1)))),lE(e.z.add(lE(e.x.mul(1)))),lE(e.y.add(lE(e.x.mul(1))))))).setLayout({name:"tri3",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),dE=Rp((([e,t,s])=>{const i=jp(e).toVar(),r=Up(1.4).toVar(),n=Up(0).toVar(),o=jp(i).toVar();return bv({start:Up(0),end:Up(3),type:"float",condition:"<="},(()=>{const e=jp(cE(o.mul(2))).toVar();i.addAssign(e.add(s.mul(Up(.1).mul(t)))),o.mulAssign(1.8),r.mulAssign(1.5),i.mulAssign(1.2);const a=Up(lE(i.z.add(lE(i.x.add(lE(i.y)))))).toVar();n.addAssign(a.div(r)),o.addAssign(.14)})),n})).setLayout({name:"triNoise3D",type:"float",inputs:[{name:"p",type:"vec3"},{name:"spd",type:"float"},{name:"time",type:"float"}]}),pE=Rp((([e,t,s=Dp(.5)])=>Ew(e.sub(s),t).add(s))),mE=Rp((([e,t,s=Dp(.5)])=>{const i=e.sub(s),r=i.dot(i),n=r.mul(r).mul(t);return e.add(i.mul(n))})),gE=Rp((({position:e=null,horizontal:t=!0,vertical:s=!1})=>{let i;null!==e?(i=Jy.toVar(),i[3][0]=e.x,i[3][1]=e.y,i[3][2]=e.z):i=Jy;const r=Vy.mul(i);return Tp(t)&&(r[0][0]=Jy[0].length(),r[0][1]=0,r[0][2]=0),Tp(s)&&(r[1][0]=0,r[1][1]=Jy[1].length(),r[1][2]=0),r[2][0]=0,r[2][1]=0,r[2][2]=1,Oy.mul(r).mul(ax)})),fE=Rp((([e=null])=>{const t=lT();return lT(sT(e)).sub(t).lessThan(0).select(Dv,e)})),yE=new WeakMap;class xE extends kd{static get type(){return"VelocityNode"}constructor(){super("vec2"),this.updateType=Bd.OBJECT,this.updateAfterType=Bd.OBJECT,this.previousModelWorldMatrix=pm(new nr),this.previousProjectionMatrix=pm(new nr).setGroup(lm),this.previousCameraViewMatrix=pm(new nr)}update({frameId:e,camera:t,object:s}){const i=vE(s);this.previousModelWorldMatrix.value.copy(i);const r=bE(t);r.frameId!==e&&(r.frameId=e,void 0===r.previousProjectionMatrix?(r.previousProjectionMatrix=new nr,r.previousCameraViewMatrix=new nr,r.currentProjectionMatrix=new nr,r.currentCameraViewMatrix=new nr,r.previousProjectionMatrix.copy(t.projectionMatrix),r.previousCameraViewMatrix.copy(t.matrixWorldInverse)):(r.previousProjectionMatrix.copy(r.currentProjectionMatrix),r.previousCameraViewMatrix.copy(r.currentCameraViewMatrix)),r.currentProjectionMatrix.copy(t.projectionMatrix),r.currentCameraViewMatrix.copy(t.matrixWorldInverse),this.previousProjectionMatrix.value.copy(r.previousProjectionMatrix),this.previousCameraViewMatrix.value.copy(r.previousCameraViewMatrix))}updateAfter({object:e}){vE(e).copy(e.matrixWorld)}setup(){const e=this.previousCameraViewMatrix.mul(this.previousModelWorldMatrix),t=Oy.mul(ix).mul(ax),s=this.previousProjectionMatrix.mul(e).mul(hx),i=t.xy.div(t.w),r=s.xy.div(s.w);return Jm(i,r)}}function bE(e){let t=yE.get(e);return void 0===t&&(t={},yE.set(e,t)),t}function vE(e,t=0){const s=bE(e);let i=s[t];return void 0===i&&(s[t]=i=new nr),i}const TE=Cp(xE),_E=Rp((([e,t])=>nf(1,e.oneMinus().div(t)).oneMinus())).setLayout({name:"burnBlend",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),wE=Rp((([e,t])=>nf(e.div(t.oneMinus()),1))).setLayout({name:"dodgeBlend",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),SE=Rp((([e,t])=>e.oneMinus().mul(t.oneMinus()).oneMinus())).setLayout({name:"screenBlend",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),ME=Rp((([e,t])=>Tf(e.mul(2).mul(t),e.oneMinus().mul(2).mul(t.oneMinus()).oneMinus(),hf(.5,e)))).setLayout({name:"overlayBlend",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),NE=Rp((([e,t,s=Op(16)])=>{const i=t=>e.uv(t),r=My(),n=i(r).toVar(),o=Up(s);return bv({start:Op(1),end:s,type:"int",condition:"<="},(({i:e})=>{const s=t.mul(Up(e).div(o.sub(1)).sub(.5));n.addAssign(i(r.add(s)))})),n.divAssign(o),n})),AE=Rp((([e,t=1])=>{const s=e,i=SC(s.rgb),r=jp(i),n=nf(1,of(0,Up(10).mul(i.sub(.45)))),o=r.mul(s.rgb).mul(2),a=Up(2).mul(r.oneMinus()).mul(s.rgb.oneMinus()).oneMinus(),h=Tf(o,a,n),u=s.a.mul(t),l=u.mul(h.rgb);return l.addAssign(s.rgb.mul(u.oneMinus())),Xp(l,s.a)})),CE=Rp((([e])=>{const t=jp(e);return Xp(df(t,jp(.393,.769,.189)),df(t,jp(.349,.686,.168)),df(t,jp(.272,.534,.131)),e.a)})),RE=Rp((([e])=>{const t=e.mul(.9478672986).add(.0521327014).pow(2.4),s=e.mul(.0773993808),i=e.lessThanEqual(.04045);return Tf(t,s,i)})).setLayout({name:"sRGBToLinearSRGB",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),EE=Rp((([e])=>{const t=e.pow(.41666).mul(1.055).sub(.055),s=e.mul(12.92),i=e.lessThanEqual(.0031308);return Tf(t,s,i)})).setLayout({name:"linearSRGBTosRGB",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),BE=Rp((([e,t])=>e.mul(t).clamp())).setLayout({name:"linearToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),IE=Rp((([e,t])=>(e=e.mul(t)).div(e.add(1)).clamp())).setLayout({name:"reinhardToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),PE=Rp((([e,t])=>{const s=(e=(e=e.mul(t)).sub(.004).max(0)).mul(e.mul(6.2).add(.5)),i=e.mul(e.mul(6.2).add(1.7)).add(.06);return s.div(i).pow(2.2)})).setLayout({name:"cineonToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),FE=Rp((([e])=>{const t=e.mul(e.add(.0245786)).sub(90537e-9),s=e.mul(e.add(.432951).mul(.983729)).add(.238081);return t.div(s)})),zE=Rp((([e,t])=>{const s=Qp(.59719,.35458,.04823,.076,.90834,.01566,.0284,.13383,.83777),i=Qp(1.60475,-.53108,-.07367,-.10208,1.10813,-.00605,-.00327,-.07276,1.07602);return e=e.mul(t).div(.6),e=s.mul(e),e=FE(e),(e=i.mul(e)).clamp()})).setLayout({name:"acesFilmicToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),UE=Qp(jp(1.6605,-.1246,-.0182),jp(-.5876,1.1329,-.1006),jp(-.0728,-.0083,1.1187)),OE=Qp(jp(.6274,.0691,.0164),jp(.3293,.9195,.088),jp(.0433,.0113,.8956)),LE=Rp((([e])=>{const t=jp(e).toVar(),s=jp(t.mul(t)).toVar(),i=jp(s.mul(s)).toVar();return Up(15.5).mul(i.mul(s)).sub(Km(40.14,i.mul(t))).add(Km(31.96,i).sub(Km(6.868,s.mul(t))).add(Km(.4298,s).add(Km(.1191,t).sub(.00232))))})),VE=Rp((([e,t])=>{const s=jp(e).toVar(),i=Qp(jp(.856627153315983,.137318972929847,.11189821299995),jp(.0951212405381588,.761241990602591,.0767994186031903),jp(.0482516061458583,.101439036467562,.811302368396859)),r=Qp(jp(1.1271005818144368,-.1413297634984383,-.14132976349843826),jp(-.11060664309660323,1.157823702216272,-.11060664309660294),jp(-.016493938717834573,-.016493938717834257,1.2519364065950405)),n=Up(-12.47393),o=Up(4.026069);return s.mulAssign(t),s.assign(OE.mul(s)),s.assign(i.mul(s)),s.assign(of(s,1e-10)),s.assign(Bg(s)),s.assign(s.sub(n).div(o.sub(n))),s.assign(_f(s,0,1)),s.assign(LE(s)),s.assign(r.mul(s)),s.assign(mf(of(jp(0),s),jp(2.2))),s.assign(UE.mul(s)),s.assign(_f(s,0,1)),s})).setLayout({name:"agxToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),DE=Rp((([e,t])=>{const s=Up(.76),i=Up(.15);e=e.mul(t);const r=nf(e.r,nf(e.g,e.b)),n=Bf(r.lessThan(.08),r.sub(Km(6.25,r.mul(r))),.04);e.subAssign(n);const o=of(e.r,of(e.g,e.b));Pp(o.lessThan(s),(()=>e));const a=Jm(1,s),h=Jm(1,a.mul(a).div(o.add(a.sub(s))));e.mulAssign(h.div(o));const u=Jm(1,Qm(1,i.mul(o.sub(h)).add(1)));return Tf(e,jp(h),u)})).setLayout({name:"neutralToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]});class kE extends Ld{static get type(){return"ComputeBuiltinNode"}constructor(e,t){super(t),this._builtinName=e}getHash(e){return this.getBuiltinName(e)}getNodeType(){return this.nodeType}setBuiltinName(e){return this._builtinName=e,this}getBuiltinName(){return this._builtinName}hasBuiltin(e){e.hasBuiltin(this._builtinName)}generate(e,t){const s=this.getBuiltinName(e),i=this.getNodeType(e);return"compute"===e.shaderStage?e.format(s,i,t):(console.warn(`ComputeBuiltinNode: Compute built-in value ${s} can not be accessed in the ${e.shaderStage} stage`),e.generateConst(i))}serialize(e){super.serialize(e),e.global=this.global,e._builtinName=this._builtinName}deserialize(e){super.deserialize(e),this.global=e.global,this._builtinName=e._builtinName}}const GE=(e,t)=>Sp(new kE(e,t)),WE=GE("numWorkgroups","uvec3"),jE=GE("workgroupId","uvec3"),HE=GE("localId","uvec3"),qE=GE("subgroupSize","uint");const $E=Ap(class extends Ld{constructor(e){super(),this.scope=e}generate(e){const{scope:t}=this,{renderer:s}=e;!0===s.backend.isWebGLBackend?e.addFlowCode(`\t// ${t}Barrier \n`):e.addLineFlowCode(`${t}Barrier()`,this)}}),XE=()=>$E("workgroup").append(),YE=()=>$E("storage").append(),ZE=()=>$E("texture").append();class JE extends Vd{constructor(e,t){super(e,t),this.isWorkgroupInfoElementNode=!0}generate(e,t){let s;const i=e.context.assign;if(s=super.generate(e),!0!==i){const i=this.getNodeType(e);s=e.format(s,i,t)}return s}}class KE extends Ld{constructor(e,t,s=0){super(t),this.bufferType=t,this.bufferCount=s,this.isWorkgroupInfoNode=!0,this.scope=e}label(e){return this.name=e,this}getHash(){return this.uuid}setScope(e){return this.scope=e,this}getInputType(){return`${this.scope}Array`}element(e){return Sp(new JE(this,e))}generate(e){return e.getScopedArray(this.name||`${this.scope}Array_${this.id}`,this.scope.toLowerCase(),this.bufferType,this.bufferCount)}}const QE=(e,t)=>Sp(new KE("Workgroup",e,t));class eB extends kd{static get type(){return"AtomicFunctionNode"}constructor(e,t,s,i=null){super("uint"),this.method=e,this.pointerNode=t,this.valueNode=s,this.storeNode=i}getInputType(e){return this.pointerNode.getNodeType(e)}getNodeType(e){return this.getInputType(e)}generate(e){const t=this.method,s=this.getNodeType(e),i=this.getInputType(e),r=this.pointerNode,n=this.valueNode,o=[];o.push(`&${r.build(e,i)}`),o.push(n.build(e,i));const a=`${e.getMethod(t,s)}( ${o.join(", ")} )`;if(null!==this.storeNode){const t=this.storeNode.build(e,i);e.addLineFlowCode(`${t} = ${a}`,this)}else e.addLineFlowCode(a,this)}}eB.ATOMIC_LOAD="atomicLoad",eB.ATOMIC_STORE="atomicStore",eB.ATOMIC_ADD="atomicAdd",eB.ATOMIC_SUB="atomicSub",eB.ATOMIC_MAX="atomicMax",eB.ATOMIC_MIN="atomicMin",eB.ATOMIC_AND="atomicAnd",eB.ATOMIC_OR="atomicOr",eB.ATOMIC_XOR="atomicXor";const tB=Ap(eB),sB=(e,t,s,i)=>{const r=tB(e,t,s,i);return r.append(),r},iB=(e,t,s=null)=>sB(eB.ATOMIC_STORE,e,t,s),rB=(e,t,s=null)=>sB(eB.ATOMIC_ADD,e,t,s),nB=(e,t,s=null)=>sB(eB.ATOMIC_SUB,e,t,s),oB=(e,t,s=null)=>sB(eB.ATOMIC_MAX,e,t,s),aB=(e,t,s=null)=>sB(eB.ATOMIC_MIN,e,t,s),hB=(e,t,s=null)=>sB(eB.ATOMIC_AND,e,t,s),uB=(e,t,s=null)=>sB(eB.ATOMIC_OR,e,t,s),lB=(e,t,s=null)=>sB(eB.ATOMIC_XOR,e,t,s),cB=Rp((([e=t()])=>{const t=e.mul(2),s=t.x.floor(),i=t.y.floor();return s.add(i).mod(2).sign()})),dB=Rp((([e,t,s])=>{const i=Up(s).toVar(),r=Up(t).toVar(),n=Vp(e).toVar();return Bf(n,r,i)})).setLayout({name:"mx_select",type:"float",inputs:[{name:"b",type:"bool"},{name:"t",type:"float"},{name:"f",type:"float"}]}),pB=Rp((([e,t])=>{const s=Vp(t).toVar(),i=Up(e).toVar();return Bf(s,i.negate(),i)})).setLayout({name:"mx_negate_if",type:"float",inputs:[{name:"val",type:"float"},{name:"b",type:"bool"}]}),mB=Rp((([e])=>{const t=Up(e).toVar();return Op(Fg(t))})).setLayout({name:"mx_floor",type:"int",inputs:[{name:"x",type:"float"}]}),gB=Rp((([e,t])=>{const s=Up(e).toVar();return t.assign(mB(s)),s.sub(Up(t))})),fB=RM([Rp((([e,t,s,i,r,n])=>{const o=Up(n).toVar(),a=Up(r).toVar(),h=Up(i).toVar(),u=Up(s).toVar(),l=Up(t).toVar(),c=Up(e).toVar(),d=Up(Jm(1,a)).toVar();return Jm(1,o).mul(c.mul(d).add(l.mul(a))).add(o.mul(u.mul(d).add(h.mul(a))))})).setLayout({name:"mx_bilerp_0",type:"float",inputs:[{name:"v0",type:"float"},{name:"v1",type:"float"},{name:"v2",type:"float"},{name:"v3",type:"float"},{name:"s",type:"float"},{name:"t",type:"float"}]}),Rp((([e,t,s,i,r,n])=>{const o=Up(n).toVar(),a=Up(r).toVar(),h=jp(i).toVar(),u=jp(s).toVar(),l=jp(t).toVar(),c=jp(e).toVar(),d=Up(Jm(1,a)).toVar();return Jm(1,o).mul(c.mul(d).add(l.mul(a))).add(o.mul(u.mul(d).add(h.mul(a))))})).setLayout({name:"mx_bilerp_1",type:"vec3",inputs:[{name:"v0",type:"vec3"},{name:"v1",type:"vec3"},{name:"v2",type:"vec3"},{name:"v3",type:"vec3"},{name:"s",type:"float"},{name:"t",type:"float"}]})]),yB=RM([Rp((([e,t,s,i,r,n,o,a,h,u,l])=>{const c=Up(l).toVar(),d=Up(u).toVar(),p=Up(h).toVar(),m=Up(a).toVar(),g=Up(o).toVar(),f=Up(n).toVar(),y=Up(r).toVar(),x=Up(i).toVar(),b=Up(s).toVar(),v=Up(t).toVar(),T=Up(e).toVar(),_=Up(Jm(1,p)).toVar(),w=Up(Jm(1,d)).toVar();return Up(Jm(1,c)).toVar().mul(w.mul(T.mul(_).add(v.mul(p))).add(d.mul(b.mul(_).add(x.mul(p))))).add(c.mul(w.mul(y.mul(_).add(f.mul(p))).add(d.mul(g.mul(_).add(m.mul(p))))))})).setLayout({name:"mx_trilerp_0",type:"float",inputs:[{name:"v0",type:"float"},{name:"v1",type:"float"},{name:"v2",type:"float"},{name:"v3",type:"float"},{name:"v4",type:"float"},{name:"v5",type:"float"},{name:"v6",type:"float"},{name:"v7",type:"float"},{name:"s",type:"float"},{name:"t",type:"float"},{name:"r",type:"float"}]}),Rp((([e,t,s,i,r,n,o,a,h,u,l])=>{const c=Up(l).toVar(),d=Up(u).toVar(),p=Up(h).toVar(),m=jp(a).toVar(),g=jp(o).toVar(),f=jp(n).toVar(),y=jp(r).toVar(),x=jp(i).toVar(),b=jp(s).toVar(),v=jp(t).toVar(),T=jp(e).toVar(),_=Up(Jm(1,p)).toVar(),w=Up(Jm(1,d)).toVar();return Up(Jm(1,c)).toVar().mul(w.mul(T.mul(_).add(v.mul(p))).add(d.mul(b.mul(_).add(x.mul(p))))).add(c.mul(w.mul(y.mul(_).add(f.mul(p))).add(d.mul(g.mul(_).add(m.mul(p))))))})).setLayout({name:"mx_trilerp_1",type:"vec3",inputs:[{name:"v0",type:"vec3"},{name:"v1",type:"vec3"},{name:"v2",type:"vec3"},{name:"v3",type:"vec3"},{name:"v4",type:"vec3"},{name:"v5",type:"vec3"},{name:"v6",type:"vec3"},{name:"v7",type:"vec3"},{name:"s",type:"float"},{name:"t",type:"float"},{name:"r",type:"float"}]})]),xB=Rp((([e,t,s])=>{const i=Up(s).toVar(),r=Up(t).toVar(),n=Lp(e).toVar(),o=Lp(n.bitAnd(Lp(7))).toVar(),a=Up(dB(o.lessThan(Lp(4)),r,i)).toVar(),h=Up(Km(2,dB(o.lessThan(Lp(4)),i,r))).toVar();return pB(a,Vp(o.bitAnd(Lp(1)))).add(pB(h,Vp(o.bitAnd(Lp(2)))))})).setLayout({name:"mx_gradient_float_0",type:"float",inputs:[{name:"hash",type:"uint"},{name:"x",type:"float"},{name:"y",type:"float"}]}),bB=Rp((([e,t,s,i])=>{const r=Up(i).toVar(),n=Up(s).toVar(),o=Up(t).toVar(),a=Lp(e).toVar(),h=Lp(a.bitAnd(Lp(15))).toVar(),u=Up(dB(h.lessThan(Lp(8)),o,n)).toVar(),l=Up(dB(h.lessThan(Lp(4)),n,dB(h.equal(Lp(12)).or(h.equal(Lp(14))),o,r))).toVar();return pB(u,Vp(h.bitAnd(Lp(1)))).add(pB(l,Vp(h.bitAnd(Lp(2)))))})).setLayout({name:"mx_gradient_float_1",type:"float",inputs:[{name:"hash",type:"uint"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]}),vB=RM([xB,bB]),TB=Rp((([e,t,s])=>{const i=Up(s).toVar(),r=Up(t).toVar(),n=qp(e).toVar();return jp(vB(n.x,r,i),vB(n.y,r,i),vB(n.z,r,i))})).setLayout({name:"mx_gradient_vec3_0",type:"vec3",inputs:[{name:"hash",type:"uvec3"},{name:"x",type:"float"},{name:"y",type:"float"}]}),_B=Rp((([e,t,s,i])=>{const r=Up(i).toVar(),n=Up(s).toVar(),o=Up(t).toVar(),a=qp(e).toVar();return jp(vB(a.x,o,n,r),vB(a.y,o,n,r),vB(a.z,o,n,r))})).setLayout({name:"mx_gradient_vec3_1",type:"vec3",inputs:[{name:"hash",type:"uvec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]}),wB=RM([TB,_B]),SB=Rp((([e])=>{const t=Up(e).toVar();return Km(.6616,t)})).setLayout({name:"mx_gradient_scale2d_0",type:"float",inputs:[{name:"v",type:"float"}]}),MB=Rp((([e])=>{const t=Up(e).toVar();return Km(.982,t)})).setLayout({name:"mx_gradient_scale3d_0",type:"float",inputs:[{name:"v",type:"float"}]}),NB=RM([SB,Rp((([e])=>{const t=jp(e).toVar();return Km(.6616,t)})).setLayout({name:"mx_gradient_scale2d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),AB=RM([MB,Rp((([e])=>{const t=jp(e).toVar();return Km(.982,t)})).setLayout({name:"mx_gradient_scale3d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),CB=Rp((([e,t])=>{const s=Op(t).toVar(),i=Lp(e).toVar();return i.shiftLeft(s).bitOr(i.shiftRight(Op(32).sub(s)))})).setLayout({name:"mx_rotl32",type:"uint",inputs:[{name:"x",type:"uint"},{name:"k",type:"int"}]}),RB=Rp((([e,t,s])=>{e.subAssign(s),e.bitXorAssign(CB(s,Op(4))),s.addAssign(t),t.subAssign(e),t.bitXorAssign(CB(e,Op(6))),e.addAssign(s),s.subAssign(t),s.bitXorAssign(CB(t,Op(8))),t.addAssign(e),e.subAssign(s),e.bitXorAssign(CB(s,Op(16))),s.addAssign(t),t.subAssign(e),t.bitXorAssign(CB(e,Op(19))),e.addAssign(s),s.subAssign(t),s.bitXorAssign(CB(t,Op(4))),t.addAssign(e)})),EB=Rp((([e,t,s])=>{const i=Lp(s).toVar(),r=Lp(t).toVar(),n=Lp(e).toVar();return i.bitXorAssign(r),i.subAssign(CB(r,Op(14))),n.bitXorAssign(i),n.subAssign(CB(i,Op(11))),r.bitXorAssign(n),r.subAssign(CB(n,Op(25))),i.bitXorAssign(r),i.subAssign(CB(r,Op(16))),n.bitXorAssign(i),n.subAssign(CB(i,Op(4))),r.bitXorAssign(n),r.subAssign(CB(n,Op(14))),i.bitXorAssign(r),i.subAssign(CB(r,Op(24))),i})).setLayout({name:"mx_bjfinal",type:"uint",inputs:[{name:"a",type:"uint"},{name:"b",type:"uint"},{name:"c",type:"uint"}]}),BB=Rp((([e])=>{const t=Lp(e).toVar();return Up(t).div(Up(Lp(Op(4294967295))))})).setLayout({name:"mx_bits_to_01",type:"float",inputs:[{name:"bits",type:"uint"}]}),IB=Rp((([e])=>{const t=Up(e).toVar();return t.mul(t).mul(t).mul(t.mul(t.mul(6).sub(15)).add(10))})).setLayout({name:"mx_fade",type:"float",inputs:[{name:"t",type:"float"}]}),PB=RM([Rp((([e])=>{const t=Op(e).toVar(),s=Lp(Lp(1)).toVar(),i=Lp(Lp(Op(3735928559)).add(s.shiftLeft(Lp(2))).add(Lp(13))).toVar();return EB(i.add(Lp(t)),i,i)})).setLayout({name:"mx_hash_int_0",type:"uint",inputs:[{name:"x",type:"int"}]}),Rp((([e,t])=>{const s=Op(t).toVar(),i=Op(e).toVar(),r=Lp(Lp(2)).toVar(),n=Lp().toVar(),o=Lp().toVar(),a=Lp().toVar();return n.assign(o.assign(a.assign(Lp(Op(3735928559)).add(r.shiftLeft(Lp(2))).add(Lp(13))))),n.addAssign(Lp(i)),o.addAssign(Lp(s)),EB(n,o,a)})).setLayout({name:"mx_hash_int_1",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Op(t).toVar(),n=Op(e).toVar(),o=Lp(Lp(3)).toVar(),a=Lp().toVar(),h=Lp().toVar(),u=Lp().toVar();return a.assign(h.assign(u.assign(Lp(Op(3735928559)).add(o.shiftLeft(Lp(2))).add(Lp(13))))),a.addAssign(Lp(n)),h.addAssign(Lp(r)),u.addAssign(Lp(i)),EB(a,h,u)})).setLayout({name:"mx_hash_int_2",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]}),Rp((([e,t,s,i])=>{const r=Op(i).toVar(),n=Op(s).toVar(),o=Op(t).toVar(),a=Op(e).toVar(),h=Lp(Lp(4)).toVar(),u=Lp().toVar(),l=Lp().toVar(),c=Lp().toVar();return u.assign(l.assign(c.assign(Lp(Op(3735928559)).add(h.shiftLeft(Lp(2))).add(Lp(13))))),u.addAssign(Lp(a)),l.addAssign(Lp(o)),c.addAssign(Lp(n)),RB(u,l,c),u.addAssign(Lp(r)),EB(u,l,c)})).setLayout({name:"mx_hash_int_3",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"},{name:"xx",type:"int"}]}),Rp((([e,t,s,i,r])=>{const n=Op(r).toVar(),o=Op(i).toVar(),a=Op(s).toVar(),h=Op(t).toVar(),u=Op(e).toVar(),l=Lp(Lp(5)).toVar(),c=Lp().toVar(),d=Lp().toVar(),p=Lp().toVar();return c.assign(d.assign(p.assign(Lp(Op(3735928559)).add(l.shiftLeft(Lp(2))).add(Lp(13))))),c.addAssign(Lp(u)),d.addAssign(Lp(h)),p.addAssign(Lp(a)),RB(c,d,p),c.addAssign(Lp(o)),d.addAssign(Lp(n)),EB(c,d,p)})).setLayout({name:"mx_hash_int_4",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"},{name:"xx",type:"int"},{name:"yy",type:"int"}]})]),FB=RM([Rp((([e,t])=>{const s=Op(t).toVar(),i=Op(e).toVar(),r=Lp(PB(i,s)).toVar(),n=qp().toVar();return n.x.assign(r.bitAnd(Op(255))),n.y.assign(r.shiftRight(Op(8)).bitAnd(Op(255))),n.z.assign(r.shiftRight(Op(16)).bitAnd(Op(255))),n})).setLayout({name:"mx_hash_vec3_0",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Op(t).toVar(),n=Op(e).toVar(),o=Lp(PB(n,r,i)).toVar(),a=qp().toVar();return a.x.assign(o.bitAnd(Op(255))),a.y.assign(o.shiftRight(Op(8)).bitAnd(Op(255))),a.z.assign(o.shiftRight(Op(16)).bitAnd(Op(255))),a})).setLayout({name:"mx_hash_vec3_1",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]})]),zB=RM([Rp((([e])=>{const t=Dp(e).toVar(),s=Op().toVar(),i=Op().toVar(),r=Up(gB(t.x,s)).toVar(),n=Up(gB(t.y,i)).toVar(),o=Up(IB(r)).toVar(),a=Up(IB(n)).toVar(),h=Up(fB(vB(PB(s,i),r,n),vB(PB(s.add(Op(1)),i),r.sub(1),n),vB(PB(s,i.add(Op(1))),r,n.sub(1)),vB(PB(s.add(Op(1)),i.add(Op(1))),r.sub(1),n.sub(1)),o,a)).toVar();return NB(h)})).setLayout({name:"mx_perlin_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"}]}),Rp((([e])=>{const t=jp(e).toVar(),s=Op().toVar(),i=Op().toVar(),r=Op().toVar(),n=Up(gB(t.x,s)).toVar(),o=Up(gB(t.y,i)).toVar(),a=Up(gB(t.z,r)).toVar(),h=Up(IB(n)).toVar(),u=Up(IB(o)).toVar(),l=Up(IB(a)).toVar(),c=Up(yB(vB(PB(s,i,r),n,o,a),vB(PB(s.add(Op(1)),i,r),n.sub(1),o,a),vB(PB(s,i.add(Op(1)),r),n,o.sub(1),a),vB(PB(s.add(Op(1)),i.add(Op(1)),r),n.sub(1),o.sub(1),a),vB(PB(s,i,r.add(Op(1))),n,o,a.sub(1)),vB(PB(s.add(Op(1)),i,r.add(Op(1))),n.sub(1),o,a.sub(1)),vB(PB(s,i.add(Op(1)),r.add(Op(1))),n,o.sub(1),a.sub(1)),vB(PB(s.add(Op(1)),i.add(Op(1)),r.add(Op(1))),n.sub(1),o.sub(1),a.sub(1)),h,u,l)).toVar();return AB(c)})).setLayout({name:"mx_perlin_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"}]})]),UB=RM([Rp((([e])=>{const t=Dp(e).toVar(),s=Op().toVar(),i=Op().toVar(),r=Up(gB(t.x,s)).toVar(),n=Up(gB(t.y,i)).toVar(),o=Up(IB(r)).toVar(),a=Up(IB(n)).toVar(),h=jp(fB(wB(FB(s,i),r,n),wB(FB(s.add(Op(1)),i),r.sub(1),n),wB(FB(s,i.add(Op(1))),r,n.sub(1)),wB(FB(s.add(Op(1)),i.add(Op(1))),r.sub(1),n.sub(1)),o,a)).toVar();return NB(h)})).setLayout({name:"mx_perlin_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),Rp((([e])=>{const t=jp(e).toVar(),s=Op().toVar(),i=Op().toVar(),r=Op().toVar(),n=Up(gB(t.x,s)).toVar(),o=Up(gB(t.y,i)).toVar(),a=Up(gB(t.z,r)).toVar(),h=Up(IB(n)).toVar(),u=Up(IB(o)).toVar(),l=Up(IB(a)).toVar(),c=jp(yB(wB(FB(s,i,r),n,o,a),wB(FB(s.add(Op(1)),i,r),n.sub(1),o,a),wB(FB(s,i.add(Op(1)),r),n,o.sub(1),a),wB(FB(s.add(Op(1)),i.add(Op(1)),r),n.sub(1),o.sub(1),a),wB(FB(s,i,r.add(Op(1))),n,o,a.sub(1)),wB(FB(s.add(Op(1)),i,r.add(Op(1))),n.sub(1),o,a.sub(1)),wB(FB(s,i.add(Op(1)),r.add(Op(1))),n,o.sub(1),a.sub(1)),wB(FB(s.add(Op(1)),i.add(Op(1)),r.add(Op(1))),n.sub(1),o.sub(1),a.sub(1)),h,u,l)).toVar();return AB(c)})).setLayout({name:"mx_perlin_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"}]})]),OB=RM([Rp((([e])=>{const t=Up(e).toVar(),s=Op(mB(t)).toVar();return BB(PB(s))})).setLayout({name:"mx_cell_noise_float_0",type:"float",inputs:[{name:"p",type:"float"}]}),Rp((([e])=>{const t=Dp(e).toVar(),s=Op(mB(t.x)).toVar(),i=Op(mB(t.y)).toVar();return BB(PB(s,i))})).setLayout({name:"mx_cell_noise_float_1",type:"float",inputs:[{name:"p",type:"vec2"}]}),Rp((([e])=>{const t=jp(e).toVar(),s=Op(mB(t.x)).toVar(),i=Op(mB(t.y)).toVar(),r=Op(mB(t.z)).toVar();return BB(PB(s,i,r))})).setLayout({name:"mx_cell_noise_float_2",type:"float",inputs:[{name:"p",type:"vec3"}]}),Rp((([e])=>{const t=Xp(e).toVar(),s=Op(mB(t.x)).toVar(),i=Op(mB(t.y)).toVar(),r=Op(mB(t.z)).toVar(),n=Op(mB(t.w)).toVar();return BB(PB(s,i,r,n))})).setLayout({name:"mx_cell_noise_float_3",type:"float",inputs:[{name:"p",type:"vec4"}]})]),LB=RM([Rp((([e])=>{const t=Up(e).toVar(),s=Op(mB(t)).toVar();return jp(BB(PB(s,Op(0))),BB(PB(s,Op(1))),BB(PB(s,Op(2))))})).setLayout({name:"mx_cell_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"float"}]}),Rp((([e])=>{const t=Dp(e).toVar(),s=Op(mB(t.x)).toVar(),i=Op(mB(t.y)).toVar();return jp(BB(PB(s,i,Op(0))),BB(PB(s,i,Op(1))),BB(PB(s,i,Op(2))))})).setLayout({name:"mx_cell_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),Rp((([e])=>{const t=jp(e).toVar(),s=Op(mB(t.x)).toVar(),i=Op(mB(t.y)).toVar(),r=Op(mB(t.z)).toVar();return jp(BB(PB(s,i,r,Op(0))),BB(PB(s,i,r,Op(1))),BB(PB(s,i,r,Op(2))))})).setLayout({name:"mx_cell_noise_vec3_2",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),Rp((([e])=>{const t=Xp(e).toVar(),s=Op(mB(t.x)).toVar(),i=Op(mB(t.y)).toVar(),r=Op(mB(t.z)).toVar(),n=Op(mB(t.w)).toVar();return jp(BB(PB(s,i,r,n,Op(0))),BB(PB(s,i,r,n,Op(1))),BB(PB(s,i,r,n,Op(2))))})).setLayout({name:"mx_cell_noise_vec3_3",type:"vec3",inputs:[{name:"p",type:"vec4"}]})]),VB=Rp((([e,t,s,i])=>{const r=Up(i).toVar(),n=Up(s).toVar(),o=Op(t).toVar(),a=jp(e).toVar(),h=Up(0).toVar(),u=Up(1).toVar();return bv(o,(()=>{h.addAssign(u.mul(zB(a))),u.mulAssign(r),a.mulAssign(n)})),h})).setLayout({name:"mx_fractal_noise_float",type:"float",inputs:[{name:"p",type:"vec3"},{name:"octaves",type:"int"},{name:"lacunarity",type:"float"},{name:"diminish",type:"float"}]}),DB=Rp((([e,t,s,i])=>{const r=Up(i).toVar(),n=Up(s).toVar(),o=Op(t).toVar(),a=jp(e).toVar(),h=jp(0).toVar(),u=Up(1).toVar();return bv(o,(()=>{h.addAssign(u.mul(UB(a))),u.mulAssign(r),a.mulAssign(n)})),h})).setLayout({name:"mx_fractal_noise_vec3",type:"vec3",inputs:[{name:"p",type:"vec3"},{name:"octaves",type:"int"},{name:"lacunarity",type:"float"},{name:"diminish",type:"float"}]}),kB=Rp((([e,t,s,i])=>{const r=Up(i).toVar(),n=Up(s).toVar(),o=Op(t).toVar(),a=jp(e).toVar();return Dp(VB(a,o,n,r),VB(a.add(jp(Op(19),Op(193),Op(17))),o,n,r))})).setLayout({name:"mx_fractal_noise_vec2",type:"vec2",inputs:[{name:"p",type:"vec3"},{name:"octaves",type:"int"},{name:"lacunarity",type:"float"},{name:"diminish",type:"float"}]}),GB=Rp((([e,t,s,i])=>{const r=Up(i).toVar(),n=Up(s).toVar(),o=Op(t).toVar(),a=jp(e).toVar(),h=jp(DB(a,o,n,r)).toVar(),u=Up(VB(a.add(jp(Op(19),Op(193),Op(17))),o,n,r)).toVar();return Xp(h,u)})).setLayout({name:"mx_fractal_noise_vec4",type:"vec4",inputs:[{name:"p",type:"vec3"},{name:"octaves",type:"int"},{name:"lacunarity",type:"float"},{name:"diminish",type:"float"}]}),WB=Rp((([e,t,s,i,r,n,o])=>{const a=Op(o).toVar(),h=Up(n).toVar(),u=Op(r).toVar(),l=Op(i).toVar(),c=Op(s).toVar(),d=Op(t).toVar(),p=Dp(e).toVar(),m=jp(LB(Dp(d.add(l),c.add(u)))).toVar(),g=Dp(m.x,m.y).toVar();g.subAssign(.5),g.mulAssign(h),g.addAssign(.5);const f=Dp(Dp(Up(d),Up(c)).add(g)).toVar(),y=Dp(f.sub(p)).toVar();return Pp(a.equal(Op(2)),(()=>jg(y.x).add(jg(y.y)))),Pp(a.equal(Op(3)),(()=>of(jg(y.x),jg(y.y)))),df(y,y)})).setLayout({name:"mx_worley_distance_0",type:"float",inputs:[{name:"p",type:"vec2"},{name:"x",type:"int"},{name:"y",type:"int"},{name:"xoff",type:"int"},{name:"yoff",type:"int"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),jB=RM([WB,Rp((([e,t,s,i,r,n,o,a,h])=>{const u=Op(h).toVar(),l=Up(a).toVar(),c=Op(o).toVar(),d=Op(n).toVar(),p=Op(r).toVar(),m=Op(i).toVar(),g=Op(s).toVar(),f=Op(t).toVar(),y=jp(e).toVar(),x=jp(LB(jp(f.add(p),g.add(d),m.add(c)))).toVar();x.subAssign(.5),x.mulAssign(l),x.addAssign(.5);const b=jp(jp(Up(f),Up(g),Up(m)).add(x)).toVar(),v=jp(b.sub(y)).toVar();return Pp(u.equal(Op(2)),(()=>jg(v.x).add(jg(v.y)).add(jg(v.z)))),Pp(u.equal(Op(3)),(()=>of(of(jg(v.x),jg(v.y)),jg(v.z)))),df(v,v)})).setLayout({name:"mx_worley_distance_1",type:"float",inputs:[{name:"p",type:"vec3"},{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"},{name:"xoff",type:"int"},{name:"yoff",type:"int"},{name:"zoff",type:"int"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),HB=Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Up(t).toVar(),n=Dp(e).toVar(),o=Op().toVar(),a=Op().toVar(),h=Dp(gB(n.x,o),gB(n.y,a)).toVar(),u=Up(1e6).toVar();return bv({start:-1,end:Op(1),name:"x",condition:"<="},(({x:e})=>{bv({start:-1,end:Op(1),name:"y",condition:"<="},(({y:t})=>{const s=Up(jB(h,e,t,o,a,r,i)).toVar();u.assign(nf(u,s))}))})),Pp(i.equal(Op(0)),(()=>{u.assign(Ig(u))})),u})).setLayout({name:"mx_worley_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),qB=Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Up(t).toVar(),n=Dp(e).toVar(),o=Op().toVar(),a=Op().toVar(),h=Dp(gB(n.x,o),gB(n.y,a)).toVar(),u=Dp(1e6,1e6).toVar();return bv({start:-1,end:Op(1),name:"x",condition:"<="},(({x:e})=>{bv({start:-1,end:Op(1),name:"y",condition:"<="},(({y:t})=>{const s=Up(jB(h,e,t,o,a,r,i)).toVar();Pp(s.lessThan(u.x),(()=>{u.y.assign(u.x),u.x.assign(s)})).ElseIf(s.lessThan(u.y),(()=>{u.y.assign(s)}))}))})),Pp(i.equal(Op(0)),(()=>{u.assign(Ig(u))})),u})).setLayout({name:"mx_worley_noise_vec2_0",type:"vec2",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),$B=Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Up(t).toVar(),n=Dp(e).toVar(),o=Op().toVar(),a=Op().toVar(),h=Dp(gB(n.x,o),gB(n.y,a)).toVar(),u=jp(1e6,1e6,1e6).toVar();return bv({start:-1,end:Op(1),name:"x",condition:"<="},(({x:e})=>{bv({start:-1,end:Op(1),name:"y",condition:"<="},(({y:t})=>{const s=Up(jB(h,e,t,o,a,r,i)).toVar();Pp(s.lessThan(u.x),(()=>{u.z.assign(u.y),u.y.assign(u.x),u.x.assign(s)})).ElseIf(s.lessThan(u.y),(()=>{u.z.assign(u.y),u.y.assign(s)})).ElseIf(s.lessThan(u.z),(()=>{u.z.assign(s)}))}))})),Pp(i.equal(Op(0)),(()=>{u.assign(Ig(u))})),u})).setLayout({name:"mx_worley_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),XB=RM([HB,Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Up(t).toVar(),n=jp(e).toVar(),o=Op().toVar(),a=Op().toVar(),h=Op().toVar(),u=jp(gB(n.x,o),gB(n.y,a),gB(n.z,h)).toVar(),l=Up(1e6).toVar();return bv({start:-1,end:Op(1),name:"x",condition:"<="},(({x:e})=>{bv({start:-1,end:Op(1),name:"y",condition:"<="},(({y:t})=>{bv({start:-1,end:Op(1),name:"z",condition:"<="},(({z:s})=>{const n=Up(jB(u,e,t,s,o,a,h,r,i)).toVar();l.assign(nf(l,n))}))}))})),Pp(i.equal(Op(0)),(()=>{l.assign(Ig(l))})),l})).setLayout({name:"mx_worley_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),YB=RM([qB,Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Up(t).toVar(),n=jp(e).toVar(),o=Op().toVar(),a=Op().toVar(),h=Op().toVar(),u=jp(gB(n.x,o),gB(n.y,a),gB(n.z,h)).toVar(),l=Dp(1e6,1e6).toVar();return bv({start:-1,end:Op(1),name:"x",condition:"<="},(({x:e})=>{bv({start:-1,end:Op(1),name:"y",condition:"<="},(({y:t})=>{bv({start:-1,end:Op(1),name:"z",condition:"<="},(({z:s})=>{const n=Up(jB(u,e,t,s,o,a,h,r,i)).toVar();Pp(n.lessThan(l.x),(()=>{l.y.assign(l.x),l.x.assign(n)})).ElseIf(n.lessThan(l.y),(()=>{l.y.assign(n)}))}))}))})),Pp(i.equal(Op(0)),(()=>{l.assign(Ig(l))})),l})).setLayout({name:"mx_worley_noise_vec2_1",type:"vec2",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),ZB=RM([$B,Rp((([e,t,s])=>{const i=Op(s).toVar(),r=Up(t).toVar(),n=jp(e).toVar(),o=Op().toVar(),a=Op().toVar(),h=Op().toVar(),u=jp(gB(n.x,o),gB(n.y,a),gB(n.z,h)).toVar(),l=jp(1e6,1e6,1e6).toVar();return bv({start:-1,end:Op(1),name:"x",condition:"<="},(({x:e})=>{bv({start:-1,end:Op(1),name:"y",condition:"<="},(({y:t})=>{bv({start:-1,end:Op(1),name:"z",condition:"<="},(({z:s})=>{const n=Up(jB(u,e,t,s,o,a,h,r,i)).toVar();Pp(n.lessThan(l.x),(()=>{l.z.assign(l.y),l.y.assign(l.x),l.x.assign(n)})).ElseIf(n.lessThan(l.y),(()=>{l.z.assign(l.y),l.y.assign(n)})).ElseIf(n.lessThan(l.z),(()=>{l.z.assign(n)}))}))}))})),Pp(i.equal(Op(0)),(()=>{l.assign(Ig(l))})),l})).setLayout({name:"mx_worley_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),JB=Rp((([e])=>{const t=e.y,s=e.z,i=jp().toVar();return Pp(t.lessThan(1e-4),(()=>{i.assign(jp(s,s,s))})).Else((()=>{let r=e.x;r=r.sub(Fg(r)).mul(6).toVar();const n=Op(Qg(r)),o=r.sub(Up(n)),a=s.mul(t.oneMinus()),h=s.mul(t.mul(o).oneMinus()),u=s.mul(t.mul(o.oneMinus()).oneMinus());Pp(n.equal(Op(0)),(()=>{i.assign(jp(s,u,a))})).ElseIf(n.equal(Op(1)),(()=>{i.assign(jp(h,s,a))})).ElseIf(n.equal(Op(2)),(()=>{i.assign(jp(a,s,u))})).ElseIf(n.equal(Op(3)),(()=>{i.assign(jp(a,h,s))})).ElseIf(n.equal(Op(4)),(()=>{i.assign(jp(u,a,s))})).Else((()=>{i.assign(jp(s,a,h))}))})),i})).setLayout({name:"mx_hsvtorgb",type:"vec3",inputs:[{name:"hsv",type:"vec3"}]}),KB=Rp((([e])=>{const t=jp(e).toVar(),s=Up(t.x).toVar(),i=Up(t.y).toVar(),r=Up(t.z).toVar(),n=Up(nf(s,nf(i,r))).toVar(),o=Up(of(s,of(i,r))).toVar(),a=Up(o.sub(n)).toVar(),h=Up().toVar(),u=Up().toVar(),l=Up().toVar();return l.assign(o),Pp(o.greaterThan(0),(()=>{u.assign(a.div(o))})).Else((()=>{u.assign(0)})),Pp(u.lessThanEqual(0),(()=>{h.assign(0)})).Else((()=>{Pp(s.greaterThanEqual(o),(()=>{h.assign(i.sub(r).div(a))})).ElseIf(i.greaterThanEqual(o),(()=>{h.assign(Zm(2,r.sub(s).div(a)))})).Else((()=>{h.assign(Zm(4,s.sub(i).div(a)))})),h.mulAssign(1/6),Pp(h.lessThan(0),(()=>{h.addAssign(1)}))})),jp(h,u,l)})).setLayout({name:"mx_rgbtohsv",type:"vec3",inputs:[{name:"c",type:"vec3"}]}),QB=Rp((([e])=>{const t=jp(e).toVar(),s=$p(rg(t,jp(.04045))).toVar(),i=jp(t.div(12.92)).toVar(),r=jp(mf(of(t.add(jp(.055)),jp(0)).div(1.055),jp(2.4))).toVar();return Tf(i,r,s)})).setLayout({name:"mx_srgb_texture_to_lin_rec709",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),eI=(e,t)=>{e=Up(e),t=Up(t);const s=Dp(t.dFdx(),t.dFdy()).length().mul(.7071067811865476);return Mf(e.sub(s),e.add(s),t)},tI=(e,t,s,i)=>Tf(e,t,s[i].clamp()),sI=(e,t,s=My())=>tI(e,t,s,"x"),iI=(e,t,s=My())=>tI(e,t,s,"y"),rI=(e,t,s,i,r)=>Tf(e,t,eI(s,i[r])),nI=(e,t,s,i=My())=>rI(e,t,s,i,"x"),oI=(e,t,s,i=My())=>rI(e,t,s,i,"y"),aI=(e=1,t=0,s=My())=>s.mul(e).add(t),hI=(e,t=1)=>(e=Up(e)).abs().pow(t).mul(e.sign()),uI=(e,t=1,s=.5)=>Up(e).sub(s).mul(t).add(s),lI=(e=My(),t=1,s=0)=>zB(e.convert("vec2|vec3")).mul(t).add(s),cI=(e=My(),t=1,s=0)=>UB(e.convert("vec2|vec3")).mul(t).add(s),dI=(e=My(),t=1,s=0)=>{e=e.convert("vec2|vec3");return Xp(UB(e),zB(e.add(Dp(19,73)))).mul(t).add(s)},pI=(e=My(),t=1)=>XB(e.convert("vec2|vec3"),t,Op(1)),mI=(e=My(),t=1)=>YB(e.convert("vec2|vec3"),t,Op(1)),gI=(e=My(),t=1)=>ZB(e.convert("vec2|vec3"),t,Op(1)),fI=(e=My())=>OB(e.convert("vec2|vec3")),yI=(e=My(),t=3,s=2,i=.5,r=1)=>VB(e,Op(t),s,i).mul(r),xI=(e=My(),t=3,s=2,i=.5,r=1)=>kB(e,Op(t),s,i).mul(r),bI=(e=My(),t=3,s=2,i=.5,r=1)=>DB(e,Op(t),s,i).mul(r),vI=(e=My(),t=3,s=2,i=.5,r=1)=>GB(e,Op(t),s,i).mul(r),TI=Rp((([e,t])=>{const s=e.x,i=e.y,r=e.z;let n=t.element(0).mul(.886227);return n=n.add(t.element(1).mul(1.023328).mul(i)),n=n.add(t.element(2).mul(1.023328).mul(r)),n=n.add(t.element(3).mul(1.023328).mul(s)),n=n.add(t.element(4).mul(.858086).mul(s).mul(i)),n=n.add(t.element(5).mul(.858086).mul(i).mul(r)),n=n.add(t.element(6).mul(r.mul(r).mul(.743125).sub(.247708))),n=n.add(t.element(7).mul(.858086).mul(s).mul(r)),n=n.add(t.element(8).mul(.429043).mul(Km(s,s).sub(Km(i,i)))),n}));class _I extends JR{static get type(){return"PointLightNode"}constructor(e=null){super(e),this.cutoffDistanceNode=pm(0).setGroup(lm),this.decayExponentNode=pm(0).setGroup(lm)}update(e){const{light:t}=this;super.update(e),this.cutoffDistanceNode.value=t.distance,this.decayExponentNode.value=t.decay}setup(e){const{colorNode:t,cutoffDistanceNode:s,decayExponentNode:i,light:r}=this,n=e.context.lightingModel,o=iE(r).sub(cx),a=o.normalize(),h=o.length(),u=KR({lightDistance:h,cutoffDistance:s,decayExponent:i}),l=t.mul(u),c=e.context.reflectedLight;n.direct({lightDirection:a,lightColor:l,reflectedLight:c},e.stack,e)}}class wI extends JR{static get type(){return"DirectionalLightNode"}constructor(e=null){super(e)}setup(e){super.setup(e);const t=e.context.lightingModel,s=this.colorNode,i=rE(this.light),r=e.context.reflectedLight;t.direct({lightDirection:i,lightColor:s,reflectedLight:r},e.stack,e)}}const SI=new nr,MI=new nr;let NI=null;class AI extends JR{static get type(){return"RectAreaLightNode"}constructor(e=null){super(e),this.halfHeight=pm(new Ri).setGroup(lm),this.halfWidth=pm(new Ri).setGroup(lm)}update(e){super.update(e);const{light:t}=this,s=e.camera.matrixWorldInverse;MI.identity(),SI.copy(t.matrixWorld),SI.premultiply(s),MI.extractRotation(SI),this.halfWidth.value.set(.5*t.width,0,0),this.halfHeight.value.set(0,.5*t.height,0),this.halfWidth.value.applyMatrix4(MI),this.halfHeight.value.applyMatrix4(MI)}setup(e){let t,s;super.setup(e),e.isAvailable("float32Filterable")?(t=By(NI.LTC_FLOAT_1),s=By(NI.LTC_FLOAT_2)):(t=By(NI.LTC_HALF_1),s=By(NI.LTC_HALF_2));const{colorNode:i,light:r}=this,n=e.context.lightingModel,o=iE(r),a=e.context.reflectedLight;n.directRectArea({lightColor:i,lightPosition:o,halfWidth:this.halfWidth,halfHeight:this.halfHeight,reflectedLight:a,ltc_1:t,ltc_2:s},e.stack,e)}static setLTC(e){NI=e}}class CI extends JR{static get type(){return"SpotLightNode"}constructor(e=null){super(e),this.coneCosNode=pm(0).setGroup(lm),this.penumbraCosNode=pm(0).setGroup(lm),this.cutoffDistanceNode=pm(0).setGroup(lm),this.decayExponentNode=pm(0).setGroup(lm)}update(e){super.update(e);const{light:t}=this;this.coneCosNode.value=Math.cos(t.angle),this.penumbraCosNode.value=Math.cos(t.angle*(1-t.penumbra)),this.cutoffDistanceNode.value=t.distance,this.decayExponentNode.value=t.decay}getSpotAttenuation(e){const{coneCosNode:t,penumbraCosNode:s}=this;return Mf(t,s,e)}setup(e){super.setup(e);const t=e.context.lightingModel,{colorNode:s,cutoffDistanceNode:i,decayExponentNode:r,light:n}=this,o=iE(n).sub(cx),a=o.normalize(),h=a.dot(rE(n)),u=this.getSpotAttenuation(h),l=o.length(),c=KR({lightDistance:l,cutoffDistance:i,decayExponent:r}),d=s.mul(u).mul(c),p=e.context.reflectedLight;t.direct({lightDirection:a,lightColor:d,reflectedLight:p},e.stack,e)}}class RI extends CI{static get type(){return"IESSpotLightNode"}getSpotAttenuation(e){const t=this.light.iesMap;let s=null;if(t&&!0===t.isTexture){const i=e.acos().mul(1/Math.PI);s=By(t,Dp(i,0),0).r}else s=super.getSpotAttenuation(e);return s}}class EI extends JR{static get type(){return"AmbientLightNode"}constructor(e=null){super(e)}setup({context:e}){e.irradiance.addAssign(this.colorNode)}}class BI extends JR{static get type(){return"HemisphereLightNode"}constructor(e=null){super(e),this.lightPositionNode=tE(e),this.lightDirectionNode=this.lightPositionNode.normalize(),this.groundColorNode=pm(new Jr).setGroup(lm)}update(e){const{light:t}=this;super.update(e),this.lightPositionNode.object3d=t,this.groundColorNode.value.copy(t.groundColor).multiplyScalar(t.intensity)}setup(e){const{colorNode:t,groundColorNode:s,lightDirectionNode:i}=this,r=bx.dot(i).mul(.5).add(.5),n=Tf(s,t,r);e.context.irradiance.addAssign(n)}}class II extends JR{static get type(){return"LightProbeNode"}constructor(e=null){super(e);const t=[];for(let e=0;e<9;e++)t.push(new Ri);this.lightProbe=Ox(t)}update(e){const{light:t}=this;super.update(e);for(let e=0;e<9;e++)this.lightProbe.array[e].copy(t.sh.coefficients[e]).multiplyScalar(t.intensity)}setup(e){const t=TI(vx,this.lightProbe);e.context.irradiance.addAssign(t)}}class PI{parseFunction(){console.warn("Abstract function.")}}class FI{constructor(e,t,s="",i=""){this.type=e,this.inputs=t,this.name=s,this.precision=i}getCode(){console.warn("Abstract function.")}}FI.isNodeFunction=!0;const zI=/^\s*(highp|mediump|lowp)?\s*([a-z_0-9]+)\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)/i,UI=/[a-z_0-9]+/gi,OI="#pragma main";class LI extends FI{constructor(e){const{type:t,inputs:s,name:i,precision:r,inputsCode:n,blockCode:o,headerCode:a}=(e=>{const t=(e=e.trim()).indexOf(OI),s=-1!==t?e.slice(t+12):e,i=s.match(zI);if(null!==i&&5===i.length){const r=i[4],n=[];let o=null;for(;null!==(o=UI.exec(r));)n.push(o);const a=[];let h=0;for(;h0?this.transparent:this.opaque).push(o)}unshift(e,t,s,i,r,n){const o=this.getNextRenderItem(e,t,s,i,r,n);(!0===s.transparent?this.transparent:this.opaque).unshift(o)}pushBundle(e){this.bundles.push(e)}pushLight(e){this.lightsArray.push(e)}getLightsNode(){return this.lightsNode.fromLights(this.lightsArray)}sort(e,t){this.opaque.length>1&&this.opaque.sort(e||DI),this.transparent.length>1&&this.transparent.sort(t||kI)}finish(){this.lightsNode.setLights(this.lightsArray);for(let e=this.renderItemsIndex,t=this.renderItems.length;e>t,h=o.height>>t;let u=e.depthTexture||r[t],l=!1;void 0===u&&(u=new Ya,u.format=e.stencilBuffer?je:We,u.type=e.stencilBuffer?Ue:Be,u.image.width=a,u.image.height=h,r[t]=u),s.width===o.width&&o.height===s.height||(l=!0,u.needsUpdate=!0,u.image.width=a,u.image.height=h),s.width=o.width,s.height=o.height,s.textures=n,s.depthTexture=u,s.depth=e.depthBuffer,s.stencil=e.stencilBuffer,s.renderTarget=e,s.sampleCount!==i&&(l=!0,u.needsUpdate=!0,s.sampleCount=i);const c={sampleCount:i};for(let e=0;e{e.removeEventListener("dispose",t);for(let e=0;e0){const i=e.image;if(void 0===i)console.warn("THREE.Renderer: Texture marked for update but image is undefined.");else if(!1===i.complete)console.warn("THREE.Renderer: Texture marked for update but image is incomplete.");else{if(e.images){const s=[];for(const t of e.images)s.push(t);t.images=s}else t.image=i;void 0!==s.isDefaultTexture&&!0!==s.isDefaultTexture||(r.createTexture(e,t),s.isDefaultTexture=!1,s.generation=e.version),!0===e.source.dataReady&&r.updateTexture(e,t),t.needsMipmaps&&0===e.mipmaps.length&&r.generateMipmaps(e)}}else r.createDefaultTexture(e),s.isDefaultTexture=!0,s.generation=e.version}if(!0!==s.initialized){s.initialized=!0,s.generation=e.version,this.info.memory.textures++;const t=()=>{e.removeEventListener("dispose",t),this._destroyTexture(e),this.info.memory.textures--};e.addEventListener("dispose",t)}s.version=e.version}getSize(e,t=XI){let s=e.images?e.images[0]:e.image;return s?(void 0!==s.image&&(s=s.image),t.width=s.width,t.height=s.height,t.depth=e.isCubeTexture?6:s.depth||1):t.width=t.height=t.depth=1,t}getMipLevels(e,t,s){let i;return i=e.isCompressedTexture?e.mipmaps.length:Math.floor(Math.log2(Math.max(t,s)))+1,i}needsMipmaps(e){return!!this.isEnvironmentTexture(e)||(!0===e.isCompressedTexture||e.minFilter!==fe&&e.minFilter!==Te)}isEnvironmentTexture(e){const t=e.mapping;return t===le||t===ce||t===he||t===ue}_destroyTexture(e){this.backend.destroySampler(e),this.backend.destroyTexture(e),this.delete(e)}}class ZI extends Jr{constructor(e,t,s,i=1){super(e,t,s),this.a=i}set(e,t,s,i=1){return this.a=i,super.set(e,t,s)}copy(e){return void 0!==e.a&&(this.a=e.a),super.copy(e)}clone(){return new this.constructor(this.r,this.g,this.b,this.a)}}const JI=new ZI;class KI extends Xw{constructor(e,t){super(),this.renderer=e,this.nodes=t}update(e,t,s){const i=this.renderer,r=this.nodes.getBackgroundNode(e)||e.background;let n=!1;if(null===r)i._clearColor.getRGB(JI,Jt),JI.a=i._clearColor.a;else if(!0===r.isColor)r.getRGB(JI,Jt),JI.a=1,n=!0;else if(!0===r.isNode){const s=this.get(e),n=r;JI.copy(i._clearColor);let o=s.backgroundMesh;if(void 0===o){const e=Ff(Xp(n).mul(wN),{getUV:()=>vx,getTextureLevel:()=>_N});let t=sv();t=t.setZ(t.w);const i=new pT;i.name="Background.material",i.side=d,i.depthTest=!1,i.depthWrite=!1,i.fog=!1,i.lights=!1,i.vertexNode=t,i.colorNode=e,s.backgroundMeshNode=e,s.backgroundMesh=o=new Vn(new du(1,32,32),i),o.frustumCulled=!1,o.name="Background.mesh",o.onBeforeRender=function(e,t,s){this.matrixWorld.copyPosition(s.matrixWorld)}}const a=n.getCacheKey();s.backgroundCacheKey!==a&&(s.backgroundMeshNode.node=Xp(n).mul(wN),s.backgroundMeshNode.needsUpdate=!0,o.material.needsUpdate=!0,s.backgroundCacheKey=a),t.unshift(o,o.geometry,o.material,0,0,null)}else console.error("THREE.Renderer: Unsupported background configuration.",r);if(!0===i.autoClear||!0===n){JI.multiplyScalar(JI.a);const e=s.clearColorValue;e.r=JI.r,e.g=JI.g,e.b=JI.b,e.a=JI.a,s.depthClearValue=i._clearDepth,s.stencilClearValue=i._clearStencil,s.clearColor=!0===i.autoClearColor,s.clearDepth=!0===i.autoClearDepth,s.clearStencil=!0===i.autoClearStencil}else s.clearColor=!1,s.clearDepth=!1,s.clearStencil=!1}}class QI{constructor(e,t,s,i,r,n,o,a,h,u=[]){this.vertexShader=e,this.fragmentShader=t,this.computeShader=s,this.transforms=u,this.nodeAttributes=i,this.bindings=r,this.updateNodes=n,this.updateBeforeNodes=o,this.updateAfterNodes=a,this.monitor=h,this.usedTimes=0}createBindings(){const e=[];for(const t of this.bindings){if(!0!==t.bindings[0].groupNode.shared){const s=new pM(t.name,[],t.index,t);e.push(s);for(const e of t.bindings)s.bindings.push(e.clone())}else e.push(t)}return e}}const eP=new WeakMap;class tP extends Xw{constructor(e,t){super(),this.renderer=e,this.backend=t,this.nodeFrame=new bM,this.nodeBuilderCache=new Map,this.callHashCache=new kw,this.groupsData=new kw}updateGroup(e){const t=e.groupNode,s=t.name;if(s===cm.name)return!0;if(s===lm.name){const t=this.get(e),s=this.nodeFrame.renderId;return t.renderId!==s&&(t.renderId=s,!0)}if(s===um.name){const t=this.get(e),s=this.nodeFrame.frameId;return t.frameId!==s&&(t.frameId=s,!0)}const i=[t,e];let r=this.groupsData.get(i);return void 0===r&&this.groupsData.set(i,r={}),r.version!==t.version&&(r.version=t.version,!0)}getForRenderCacheKey(e){return e.initialCacheKey}getForRender(e){const t=this.get(e);let s=t.nodeBuilderState;if(void 0===s){const{nodeBuilderCache:i}=this,r=this.getForRenderCacheKey(e);if(s=i.get(r),void 0===s){const t=this.backend.createNodeBuilder(e.object,this.renderer);t.scene=e.scene,t.material=e.material,t.camera=e.camera,t.context.material=e.material,t.lightsNode=e.lightsNode,t.environmentNode=this.getEnvironmentNode(e.scene),t.fogNode=this.getFogNode(e.scene),t.clippingContext=e.clippingContext,t.build(),s=this._createNodeBuilderState(t),i.set(r,s)}s.usedTimes++,t.nodeBuilderState=s}return s}delete(e){if(e.isRenderObject){const t=this.get(e).nodeBuilderState;t.usedTimes--,0===t.usedTimes&&this.nodeBuilderCache.delete(this.getForRenderCacheKey(e))}return super.delete(e)}getForCompute(e){const t=this.get(e);let s=t.nodeBuilderState;if(void 0===s){const i=this.backend.createNodeBuilder(e,this.renderer);i.build(),s=this._createNodeBuilderState(i),t.nodeBuilderState=s}return s}_createNodeBuilderState(e){return new QI(e.vertexShader,e.fragmentShader,e.computeShader,e.getAttributesArray(),e.getBindings(),e.updateNodes,e.updateBeforeNodes,e.updateAfterNodes,e.monitor,e.transforms)}getEnvironmentNode(e){return e.environmentNode||this.get(e).environmentNode||null}getBackgroundNode(e){return e.backgroundNode||this.get(e).backgroundNode||null}getFogNode(e){return e.fogNode||this.get(e).fogNode||null}getCacheKey(e,t){const s=[e,t],i=this.renderer.info.calls;let r=this.callHashCache.get(s);if(void 0===r||r.callId!==i){const n=this.getEnvironmentNode(e),o=this.getFogNode(e),a=[];t&&a.push(t.getCacheKey(!0)),n&&a.push(n.getCacheKey()),o&&a.push(o.getCacheKey()),a.push(this.renderer.shadowMap.enabled?1:0),r={callId:i,cacheKey:Td(a)},this.callHashCache.set(s,r)}return r.cacheKey}updateScene(e){this.updateEnvironment(e),this.updateFog(e),this.updateBackground(e)}get isToneMappingState(){return!this.renderer.getRenderTarget()}updateBackground(e){const t=this.get(e),s=e.background;if(s){const i=0===e.backgroundBlurriness&&t.backgroundBlurriness>0||e.backgroundBlurriness>0&&0===t.backgroundBlurriness;if(t.background!==s||i){let i=null;if(!0===s.isCubeTexture||s.mapping===le||s.mapping===ce||s.mapping===de)if(e.backgroundBlurriness>0||s.mapping===de)i=hw(s,vx);else{let e;e=!0===s.isCubeTexture?Ix(s):By(s),i=PT(e)}else!0===s.isTexture?i=By(s,Dv.flipY()).setUpdateMatrix(!0):!0!==s.isColor&&console.error("WebGPUNodes: Unsupported background configuration.",s);t.backgroundNode=i,t.background=s,t.backgroundBlurriness=e.backgroundBlurriness}}else t.backgroundNode&&(delete t.backgroundNode,delete t.background)}updateFog(e){const t=this.get(e),s=e.fog;if(s){if(t.fog!==s){let e=null;if(s.isFogExp2){const t=kx("color","color",s).setGroup(lm),i=kx("density","float",s).setGroup(lm);e=OR(t,i)}else if(s.isFog){const t=kx("color","color",s).setGroup(lm),i=kx("near","float",s).setGroup(lm),r=kx("far","float",s).setGroup(lm);e=zR(t,i,r)}else console.error("WebGPUNodes: Unsupported fog configuration.",s);t.fogNode=e,t.fog=s}}else delete t.fogNode,delete t.fog}updateEnvironment(e){const t=this.get(e),s=e.environment;if(s){if(t.environment!==s){let e=null;!0===s.isCubeTexture?e=Ix(s):!0===s.isTexture?e=By(s):console.error("Nodes: Unsupported environment configuration.",s),t.environmentNode=e,t.environment=s}}else t.environmentNode&&(delete t.environmentNode,delete t.environment)}getNodeFrame(e=this.renderer,t=null,s=null,i=null,r=null){const n=this.nodeFrame;return n.renderer=e,n.scene=t,n.object=s,n.camera=i,n.material=r,n}getNodeFrameForRender(e){return this.getNodeFrame(e.renderer,e.scene,e.object,e.camera,e.material)}getOutputCacheKey(){const e=this.renderer;return e.toneMapping+","+e.currentColorSpace}hasOutputChange(e){return eP.get(e)!==this.getOutputCacheKey()}getOutputNode(e){const t=this.renderer,s=this.getOutputCacheKey(),i=By(e,Dv).renderOutput(t.toneMapping,t.currentColorSpace);return eP.set(e,s),i}updateBefore(e){const t=e.getNodeBuilderState();for(const s of t.updateBeforeNodes)this.getNodeFrameForRender(e).updateBeforeNode(s)}updateAfter(e){const t=e.getNodeBuilderState();for(const s of t.updateAfterNodes)this.getNodeFrameForRender(e).updateAfterNode(s)}updateForCompute(e){const t=this.getNodeFrame(),s=this.getForCompute(e);for(const e of s.updateNodes)t.updateNode(e)}updateForRender(e){const t=this.getNodeFrameForRender(e),s=e.getNodeBuilderState();for(const e of s.updateNodes)t.updateNode(e)}needsRefresh(e){const t=this.getNodeFrameForRender(e);return e.getMonitor().needsRefresh(e,t)}dispose(){super.dispose(),this.nodeFrame=new bM,this.nodeBuilderCache=new Map}}class sP{constructor(e,t){this.scene=e,this.camera=t}clone(){return Object.assign(new this.constructor,this)}}class iP{constructor(){this.lists=new kw}get(e,t){const s=this.lists,i=[e,t];let r=s.get(i);return void 0===r&&(r=new sP(e,t),s.set(i,r)),r}dispose(){this.lists=new kw}}class rP{constructor(){this.lightNodes=new WeakMap,this.materialNodes=new Map,this.toneMappingNodes=new Map,this.colorSpaceNodes=new Map}fromMaterial(e){if(e.isNodeMaterial)return e;let t=null;const s=this.getMaterialNodeClass(e.type);if(null!==s){t=new s;for(const s in e)t[s]=e[s]}return t}addColorSpace(e,t){this.addType(e,t,this.colorSpaceNodes)}getColorSpaceFunction(e){return this.colorSpaceNodes.get(e)||null}addToneMapping(e,t){this.addType(e,t,this.toneMappingNodes)}getToneMappingFunction(e){return this.toneMappingNodes.get(e)||null}getMaterialNodeClass(e){return this.materialNodes.get(e)||null}addMaterial(e,t){this.addType(e,t.name,this.materialNodes)}getLightNodeClass(e){return this.lightNodes.get(e)||null}addLight(e,t){this.addClass(e,t,this.lightNodes)}addType(e,t,s){if(s.has(t))console.warn(`Redefinition of node ${t}`);else{if("function"!=typeof e)throw new Error(`Node class ${e.name} is not a class.`);if("function"==typeof t||"object"==typeof t)throw new Error(`Base class ${t} is not a class.`);s.set(t,e)}}addClass(e,t,s){if(s.has(t))console.warn(`Redefinition of node ${t.name}`);else{if("function"!=typeof e)throw new Error(`Node class ${e.name} is not a class.`);if("function"!=typeof t)throw new Error(`Base class ${t.name} is not a class.`);s.set(t,e)}}}const nP=new to,oP=new Qs,aP=new Ti,hP=new ta,uP=new nr,lP=new Ti;class cP{constructor(e,t={}){this.isRenderer=!0;const{logarithmicDepthBuffer:s=!1,alpha:i=!0,depth:r=!0,stencil:n=!1,antialias:o=!1,samples:a=0,getFallback:h=null}=t;this.domElement=e.getDomElement(),this.backend=e,this.samples=a||!0===o?4:0,this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.alpha=i,this.logarithmicDepthBuffer=s,this.outputColorSpace=Zt,this.toneMapping=0,this.toneMappingExposure=1,this.sortObjects=!0,this.depth=r,this.stencil=n,this.clippingPlanes=[],this.info=new iS,this.nodes={library:new rP,modelViewMatrix:null,modelNormalViewMatrix:null},this._getFallback=h,this._pixelRatio=1,this._width=this.domElement.width,this._height=this.domElement.height,this._viewport=new Ti(0,0,this._width,this._height),this._scissor=new Ti(0,0,this._width,this._height),this._scissorTest=!1,this._attributes=null,this._geometries=null,this._nodes=null,this._animation=null,this._bindings=null,this._objects=null,this._pipelines=null,this._bundles=null,this._renderLists=null,this._renderContexts=null,this._textures=null,this._background=null,this._quad=new dN(new pT),this._quad.material.type="Renderer_output",this._currentRenderContext=null,this._opaqueSort=null,this._transparentSort=null,this._frameBufferTarget=null;const u=!0===this.alpha?0:1;this._clearColor=new ZI(0,0,0,u),this._clearDepth=1,this._clearStencil=0,this._renderTarget=null,this._activeCubeFace=0,this._activeMipmapLevel=0,this._mrt=null,this._renderObjectFunction=null,this._currentRenderObjectFunction=null,this._currentRenderBundle=null,this._handleObjectFunction=this._renderObjectDirect,this._initialized=!1,this._initPromise=null,this._compilationPromises=null,this.transparent=!0,this.opaque=!0,this.shadowMap={enabled:!1,type:1},this.xr={enabled:!1},this.debug={checkShaderErrors:!0,onShaderError:null,getShaderAsync:async(e,t,s)=>{await this.compileAsync(e,t);const i=this._renderLists.get(e,t),r=this._renderContexts.get(e,t,this._renderTarget),n=e.overrideMaterial||s.material,o=this._objects.get(s,n,e,t,i.lightsNode,r),{fragmentShader:a,vertexShader:h}=o.getNodeBuilderState();return{fragmentShader:a,vertexShader:h}}}}async init(){if(this._initialized)throw new Error("Renderer: Backend has already been initialized.");return null!==this._initPromise||(this._initPromise=new Promise((async(e,t)=>{let s=this.backend;try{await s.init(this)}catch(e){if(null===this._getFallback)return void t(e);try{this.backend=s=this._getFallback(e),await s.init(this)}catch(e){return void t(e)}}this._nodes=new tP(this,s),this._animation=new Dw(this._nodes,this.info),this._attributes=new Qw(s),this._background=new KI(this,this._nodes),this._geometries=new sS(this._attributes,this.info),this._textures=new YI(this,s,this.info),this._pipelines=new uS(s,this._nodes),this._bindings=new lS(s,this._nodes,this._textures,this._attributes,this._pipelines,this.info),this._objects=new $w(this,this._nodes,this._geometries,this._pipelines,this._bindings,this.info),this._renderLists=new WI,this._bundles=new iP,this._renderContexts=new $I,this._initialized=!0,e()}))),this._initPromise}get coordinateSystem(){return this.backend.coordinateSystem}async compileAsync(e,t,s=null){!1===this._initialized&&await this.init();const i=this._nodes.nodeFrame,r=i.renderId,n=this._currentRenderContext,o=this._currentRenderObjectFunction,a=this._compilationPromises,h=!0===e.isScene?e:nP;null===s&&(s=e);const u=this._renderTarget,l=this._renderContexts.get(s,t,u),c=this._activeMipmapLevel,d=[];this._currentRenderContext=l,this._currentRenderObjectFunction=this.renderObject,this._handleObjectFunction=this._createObjectPipeline,this._compilationPromises=d,i.renderId++,i.update(),l.depth=this.depth,l.stencil=this.stencil,l.clippingContext||(l.clippingContext=new Ww),l.clippingContext.updateGlobal(this,t),h.onBeforeRender(this,e,t,u);const p=this._renderLists.get(e,t);if(p.begin(),this._projectObject(e,t,0,p),s!==e&&s.traverseVisible((function(e){e.isLight&&e.layers.test(t.layers)&&p.pushLight(e)})),p.finish(),null!==u){this._textures.updateRenderTarget(u,c);const e=this._textures.get(u);l.textures=e.textures,l.depthTexture=e.depthTexture}else l.textures=null,l.depthTexture=null;this._nodes.updateScene(h),this._background.update(h,p,l);const m=p.opaque,g=p.transparent,f=p.lightsNode;!0===this.opaque&&m.length>0&&this._renderObjects(m,t,h,f),!0===this.transparent&&g.length>0&&this._renderObjects(g,t,h,f),i.renderId=r,this._currentRenderContext=n,this._currentRenderObjectFunction=o,this._compilationPromises=a,this._handleObjectFunction=this._renderObjectDirect,await Promise.all(d)}async renderAsync(e,t){!1===this._initialized&&await this.init();const s=this._renderScene(e,t);await this.backend.resolveTimestampAsync(s,"render")}setMRT(e){return this._mrt=e,this}getMRT(){return this._mrt}_renderBundle(e,t,s){const{bundleGroup:i,camera:r,renderList:n}=e,o=this._currentRenderContext,a=this._bundles.get(i,r),h=this.backend.get(a);void 0===h.renderContexts&&(h.renderContexts=new Set);const u=i.version!==h.version,l=!1===h.renderContexts.has(o)||u;if(h.renderContexts.add(o),l){this.backend.beginBundle(o),(void 0===h.renderObjects||u)&&(h.renderObjects=[]),this._currentRenderBundle=a;const e=n.opaque;e.length>0&&this._renderObjects(e,r,t,s),this._currentRenderBundle=null,this.backend.finishBundle(o,a),h.version=i.version}else{const{renderObjects:e}=h;for(let t=0,s=e.length;t>=c,p.viewportValue.height>>=c,p.viewportValue.minDepth=x,p.viewportValue.maxDepth=b,p.viewport=!1===p.viewportValue.equals(aP),p.scissorValue.copy(f).multiplyScalar(y).floor(),p.scissor=this._scissorTest&&!1===p.scissorValue.equals(aP),p.scissorValue.width>>=c,p.scissorValue.height>>=c,p.clippingContext||(p.clippingContext=new Ww),p.clippingContext.updateGlobal(this,t),h.onBeforeRender(this,e,t,d),uP.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),hP.setFromProjectionMatrix(uP,m);const v=this._renderLists.get(e,t);if(v.begin(),this._projectObject(e,t,0,v),v.finish(),!0===this.sortObjects&&v.sort(this._opaqueSort,this._transparentSort),null!==d){this._textures.updateRenderTarget(d,c);const e=this._textures.get(d);p.textures=e.textures,p.depthTexture=e.depthTexture,p.width=e.width,p.height=e.height,p.renderTarget=d,p.depth=d.depthBuffer,p.stencil=d.stencilBuffer}else p.textures=null,p.depthTexture=null,p.width=this.domElement.width,p.height=this.domElement.height,p.depth=this.depth,p.stencil=this.stencil;p.width>>=c,p.height>>=c,p.activeCubeFace=l,p.activeMipmapLevel=c,p.occlusionQueryCount=v.occlusionQueryCount,this._nodes.updateScene(h),this._background.update(h,v,p),this.backend.beginRender(p);const{bundles:T,lightsNode:_,transparent:w,opaque:S}=v;if(T.length>0&&this._renderBundles(T,h,_),!0===this.opaque&&S.length>0&&this._renderObjects(S,t,h,_),!0===this.transparent&&w.length>0&&this._renderObjects(w,t,h,_),this.backend.finishRender(p),r.renderId=n,this._currentRenderContext=o,this._currentRenderObjectFunction=a,null!==i){this.setRenderTarget(u,l,c);const e=this._quad;this._nodes.hasOutputChange(d.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(d.texture),e.material.needsUpdate=!0),this._renderScene(e,e.camera,!1)}return h.onAfterRender(this,e,t,d),p}getMaxAnisotropy(){return this.backend.getMaxAnisotropy()}getActiveCubeFace(){return this._activeCubeFace}getActiveMipmapLevel(){return this._activeMipmapLevel}async setAnimationLoop(e){!1===this._initialized&&await this.init(),this._animation.setAnimationLoop(e)}async getArrayBufferAsync(e){return await this.backend.getArrayBufferAsync(e)}getContext(){return this.backend.getContext()}getPixelRatio(){return this._pixelRatio}getDrawingBufferSize(e){return e.set(this._width*this._pixelRatio,this._height*this._pixelRatio).floor()}getSize(e){return e.set(this._width,this._height)}setPixelRatio(e=1){this._pixelRatio=e,this.setSize(this._width,this._height,!1)}setDrawingBufferSize(e,t,s){this._width=e,this._height=t,this._pixelRatio=s,this.domElement.width=Math.floor(e*s),this.domElement.height=Math.floor(t*s),this.setViewport(0,0,e,t),this._initialized&&this.backend.updateSize()}setSize(e,t,s=!0){this._width=e,this._height=t,this.domElement.width=Math.floor(e*this._pixelRatio),this.domElement.height=Math.floor(t*this._pixelRatio),!0===s&&(this.domElement.style.width=e+"px",this.domElement.style.height=t+"px"),this.setViewport(0,0,e,t),this._initialized&&this.backend.updateSize()}setOpaqueSort(e){this._opaqueSort=e}setTransparentSort(e){this._transparentSort=e}getScissor(e){const t=this._scissor;return e.x=t.x,e.y=t.y,e.width=t.width,e.height=t.height,e}setScissor(e,t,s,i){const r=this._scissor;e.isVector4?r.copy(e):r.set(e,t,s,i)}getScissorTest(){return this._scissorTest}setScissorTest(e){this._scissorTest=e,this.backend.setScissorTest(e)}getViewport(e){return e.copy(this._viewport)}setViewport(e,t,s,i,r=0,n=1){const o=this._viewport;e.isVector4?o.copy(e):o.set(e,t,s,i),o.minDepth=r,o.maxDepth=n}getClearColor(e){return e.copy(this._clearColor)}setClearColor(e,t=1){this._clearColor.set(e),this._clearColor.a=t}getClearAlpha(){return this._clearColor.a}setClearAlpha(e){this._clearColor.a=e}getClearDepth(){return this._clearDepth}setClearDepth(e){this._clearDepth=e}getClearStencil(){return this._clearStencil}setClearStencil(e){this._clearStencil=e}isOccluded(e){const t=this._currentRenderContext;return t&&this.backend.isOccluded(t,e)}clear(e=!0,t=!0,s=!0){if(!1===this._initialized)return console.warn("THREE.Renderer: .clear() called before the backend is initialized. Try using .clearAsync() instead."),this.clearAsync(e,t,s);const i=this._renderTarget||this._getFrameBufferTarget();let r=null;if(null!==i&&(this._textures.updateRenderTarget(i),r=this._textures.get(i)),this.backend.clear(e,t,s,r),null!==i&&null===this._renderTarget){const e=this._quad;this._nodes.hasOutputChange(i.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(i.texture),e.material.needsUpdate=!0),this._renderScene(e,e.camera,!1)}}clearColor(){return this.clear(!0,!1,!1)}clearDepth(){return this.clear(!1,!0,!1)}clearStencil(){return this.clear(!1,!1,!0)}async clearAsync(e=!0,t=!0,s=!0){!1===this._initialized&&await this.init(),this.clear(e,t,s)}clearColorAsync(){return this.clearAsync(!0,!1,!1)}clearDepthAsync(){return this.clearAsync(!1,!0,!1)}clearStencilAsync(){return this.clearAsync(!1,!1,!0)}get currentToneMapping(){return null!==this._renderTarget?0:this.toneMapping}get currentColorSpace(){return null!==this._renderTarget?Jt:this.outputColorSpace}dispose(){this.info.dispose(),this._animation.dispose(),this._objects.dispose(),this._pipelines.dispose(),this._nodes.dispose(),this._bindings.dispose(),this._renderLists.dispose(),this._renderContexts.dispose(),this._textures.dispose(),this.setRenderTarget(null),this.setAnimationLoop(null)}setRenderTarget(e,t=0,s=0){this._renderTarget=e,this._activeCubeFace=t,this._activeMipmapLevel=s}getRenderTarget(){return this._renderTarget}setRenderObjectFunction(e){this._renderObjectFunction=e}getRenderObjectFunction(){return this._renderObjectFunction}async computeAsync(e){!1===this._initialized&&await this.init();const t=this._nodes.nodeFrame,s=t.renderId;this.info.calls++,this.info.compute.calls++,this.info.compute.frameCalls++,t.renderId=this.info.calls;const i=this.backend,r=this._pipelines,n=this._bindings,o=this._nodes,a=Array.isArray(e)?e:[e];if(void 0===a[0]||!0!==a[0].isComputeNode)throw new Error("THREE.Renderer: .compute() expects a ComputeNode.");i.beginCompute(e);for(const t of a){if(!1===r.has(t)){const e=()=>{t.removeEventListener("dispose",e),r.delete(t),n.delete(t),o.delete(t)};t.addEventListener("dispose",e),t.onInit({renderer:this})}o.updateForCompute(t),n.updateForCompute(t);const s=n.getForCompute(t),a=r.getForCompute(t,s);i.compute(e,t,s,a)}i.finishCompute(e),await this.backend.resolveTimestampAsync(e,"compute"),t.renderId=s}async hasFeatureAsync(e){return!1===this._initialized&&await this.init(),this.backend.hasFeature(e)}hasFeature(e){return!1===this._initialized?(console.warn("THREE.Renderer: .hasFeature() called before the backend is initialized. Try using .hasFeatureAsync() instead."),!1):this.backend.hasFeature(e)}copyFramebufferToTexture(e,t=null){const s=this._currentRenderContext;this._textures.updateTexture(e),t=null===t?lP.set(0,0,e.image.width,e.image.height):t,this.backend.copyFramebufferToTexture(e,s,t)}copyTextureToTexture(e,t,s=null,i=null,r=0){this._textures.updateTexture(e),this._textures.updateTexture(t),this.backend.copyTextureToTexture(e,t,s,i,r)}readRenderTargetPixelsAsync(e,t,s,i,r,n=0,o=0){return this.backend.copyTextureToBuffer(e.textures[n],t,s,i,r,o)}_projectObject(e,t,s,i){if(!1===e.visible)return;if(e.layers.test(t.layers))if(e.isGroup)s=e.renderOrder;else if(e.isLOD)!0===e.autoUpdate&&e.update(t);else if(e.isLight)i.pushLight(e);else if(e.isSprite){if(!e.frustumCulled||hP.intersectsSprite(e)){!0===this.sortObjects&&lP.setFromMatrixPosition(e.matrixWorld).applyMatrix4(uP);const{geometry:t,material:r}=e;r.visible&&i.push(e,t,r,s,lP.z,null)}}else if(e.isLineLoop)console.error("THREE.Renderer: Objects of type THREE.LineLoop are not supported. Please use THREE.Line or THREE.LineSegments.");else if((e.isMesh||e.isLine||e.isPoints)&&(!e.frustumCulled||hP.intersectsObject(e))){const{geometry:t,material:r}=e;if(!0===this.sortObjects&&(null===t.boundingSphere&&t.computeBoundingSphere(),lP.copy(t.boundingSphere.center).applyMatrix4(e.matrixWorld).applyMatrix4(uP)),Array.isArray(r)){const n=t.groups;for(let o=0,a=n.length;o0?i:"";t=`${e.name} {\n\t${s} ${r.name}[${n}];\n};\n`}else{t=`${this.getVectorType(r.type)} ${this.getPropertyName(r,e)};`,n=!0}const o=r.node.precision;if(null!==o&&(t=NP[o]+" "+t),n){t="\t"+t;const e=r.groupNode.name;(i[e]||(i[e]=[])).push(t)}else t="uniform "+t,s.push(t)}let r="";for(const t in i){const s=i[t];r+=this._getGLSLUniformStruct(e+"_"+t,s.join("\n"))+"\n"}return r+=s.join("\n"),r}getTypeFromAttribute(e){let t=super.getTypeFromAttribute(e);if(/^[iu]/.test(t)&&e.gpuType!==Ee){let s=e;e.isInterleavedBufferAttribute&&(s=e.data);const i=s.array;!1==(i instanceof Uint32Array||i instanceof Int32Array)&&(t=t.slice(1))}return t}getAttributes(e){let t="";if("vertex"===e||"compute"===e){const e=this.getAttributesArray();let s=0;for(const i of e)t+=`layout( location = ${s++} ) in ${i.type} ${i.name};\n`}return t}getStructMembers(e){const t=[],s=e.getMemberTypes();for(let e=0;ee*t),1)}u`}getDrawIndex(){return this.renderer.backend.extensions.has("WEBGL_multi_draw")?"uint( gl_DrawID )":null}getFrontFacing(){return"gl_FrontFacing"}getFragCoord(){return"gl_FragCoord.xy"}getFragDepth(){return"gl_FragDepth"}enableExtension(e,t,s=this.shaderStage){const i=this.extensions[s]||(this.extensions[s]=new Map);!1===i.has(e)&&i.set(e,{name:e,behavior:t})}getExtensions(e){const t=[];if("vertex"===e){const t=this.renderer.backend.extensions;this.object.isBatchedMesh&&t.has("WEBGL_multi_draw")&&this.enableExtension("GL_ANGLE_multi_draw","require",e)}const s=this.extensions[e];if(void 0!==s)for(const{name:e,behavior:i}of s.values())t.push(`#extension ${e} : ${i}`);return t.join("\n")}isAvailable(e){let t=AP[e];if(void 0===t){if("float32Filterable"===e){const e=this.renderer.backend.extensions;e.has("OES_texture_float_linear")?(e.get("OES_texture_float_linear"),t=!0):t=!1}AP[e]=t}return t}isFlipY(){return!0}registerTransform(e,t){this.transforms.push({varyingName:e,attributeNode:t})}getTransforms(){const e=this.transforms;let t="";for(let s=0;s0&&(s+="\n"),s+=`\t// flow -> ${n}\n\t`),s+=`${i.code}\n\t`,e===r&&"compute"!==t&&(s+="// result\n\t","vertex"===t?(s+="gl_Position = ",s+=`${i.result};`):"fragment"===t&&(e.outputNode.isOutputStructNode||(s+="fragColor = ",s+=`${i.result};`)))}const n=e[t];n.extensions=this.getExtensions(t),n.uniforms=this.getUniforms(t),n.attributes=this.getAttributes(t),n.varyings=this.getVaryings(t),n.vars=this.getVars(t),n.structs=this.getStructs(t),n.codes=this.getCodes(t),n.transforms=this.getTransforms(t),n.flow=s}null!==this.material?(this.vertexShader=this._getGLSLVertexCode(e.vertex),this.fragmentShader=this._getGLSLFragmentCode(e.fragment)):this.computeShader=this._getGLSLVertexCode(e.compute)}getUniformFromNode(e,t,s,i=null){const r=super.getUniformFromNode(e,t,s,i),n=this.getDataFromNode(e,s,this.globalCache);let o=n.uniformGPU;if(void 0===o){const i=e.groupNode,a=i.name,h=this.getBindGroupArray(a,s);if("texture"===t)o=new _P(r.name,r.node,i),h.push(o);else if("cubeTexture"===t)o=new wP(r.name,r.node,i),h.push(o);else if("texture3D"===t)o=new SP(r.name,r.node,i),h.push(o);else if("buffer"===t){e.name=`NodeBuffer_${e.id}`,r.name=`buffer${e.id}`;const t=new fP(e,i);t.name=e.name,h.push(t),o=t}else{const e=this.uniformGroups[s]||(this.uniformGroups[s]={});let n=e[a];void 0===n&&(n=new bP(s+"_"+a,i),e[a]=n,h.push(n)),o=this.getNodeUniform(r,t),n.addUniform(o)}n.uniformGPU=o}return r}}let EP=null,BP=null,IP=null;class PP{constructor(e={}){this.parameters=Object.assign({},e),this.data=new WeakMap,this.renderer=null,this.domElement=null}async init(e){this.renderer=e}begin(){}finish(){}draw(){}createProgram(){}destroyProgram(){}createBindings(){}updateBindings(){}createRenderPipeline(){}createComputePipeline(){}destroyPipeline(){}needsRenderUpdate(){}getRenderCacheKey(){}createNodeBuilder(){}createSampler(){}createDefaultTexture(){}createTexture(){}copyTextureToBuffer(){}createAttribute(){}createIndexAttribute(){}updateAttribute(){}destroyAttribute(){}getContext(){}updateSize(){}resolveTimestampAsync(){}hasFeatureAsync(){}hasFeature(){}getInstanceCount(e){const{object:t,geometry:s}=e;return s.isInstancedBufferGeometry?s.instanceCount:t.count>1?t.count:1}getDrawingBufferSize(){return EP=EP||new Qs,this.renderer.getDrawingBufferSize(EP)}getScissor(){return BP=BP||new Ti,this.renderer.getScissor(BP)}setScissorTest(){}getClearColor(){const e=this.renderer;return IP=IP||new ZI,e.getClearColor(IP),IP.getRGB(IP,this.renderer.currentColorSpace),IP}getDomElement(){let t=this.domElement;return null===t&&(t=void 0!==this.parameters.canvas?this.parameters.canvas:ni(),"setAttribute"in t&&t.setAttribute("data-engine",`three.js r${e} webgpu`),this.domElement=t),t}set(e,t){this.data.set(e,t)}get(e){let t=this.data.get(e);return void 0===t&&(t={},this.data.set(e,t)),t}has(e){return this.data.has(e)}delete(e){this.data.delete(e)}}let FP=0;class zP{constructor(e,t){this.buffers=[e.bufferGPU,t],this.type=e.type,this.bufferType=e.bufferType,this.pbo=e.pbo,this.byteLength=e.byteLength,this.bytesPerElement=e.BYTES_PER_ELEMENT,this.version=e.version,this.isInteger=e.isInteger,this.activeBufferIndex=0,this.baseId=e.id}get id(){return`${this.baseId}|${this.activeBufferIndex}`}get bufferGPU(){return this.buffers[this.activeBufferIndex]}get transformBuffer(){return this.buffers[1^this.activeBufferIndex]}switchBuffers(){this.activeBufferIndex^=1}}class UP{constructor(e){this.backend=e}createAttribute(e,t){const s=this.backend,{gl:i}=s,r=e.array,n=e.usage||i.STATIC_DRAW,o=e.isInterleavedBufferAttribute?e.data:e,a=s.get(o);let h,u=a.bufferGPU;if(void 0===u&&(u=this._createBuffer(i,t,r,n),a.bufferGPU=u,a.bufferType=t,a.version=o.version),r instanceof Float32Array)h=i.FLOAT;else if(r instanceof Uint16Array)h=e.isFloat16BufferAttribute?i.HALF_FLOAT:i.UNSIGNED_SHORT;else if(r instanceof Int16Array)h=i.SHORT;else if(r instanceof Uint32Array)h=i.UNSIGNED_INT;else if(r instanceof Int32Array)h=i.INT;else if(r instanceof Int8Array)h=i.BYTE;else if(r instanceof Uint8Array)h=i.UNSIGNED_BYTE;else{if(!(r instanceof Uint8ClampedArray))throw new Error("THREE.WebGLBackend: Unsupported buffer data format: "+r);h=i.UNSIGNED_BYTE}let l={bufferGPU:u,bufferType:t,type:h,byteLength:r.byteLength,bytesPerElement:r.BYTES_PER_ELEMENT,version:e.version,pbo:e.pbo,isInteger:h===i.INT||h===i.UNSIGNED_INT||e.gpuType===Ee,id:FP++};if(e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute){const e=this._createBuffer(i,t,r,n);l=new zP(l,e)}s.set(e,l)}updateAttribute(e){const t=this.backend,{gl:s}=t,i=e.array,r=e.isInterleavedBufferAttribute?e.data:e,n=t.get(r),o=n.bufferType,a=e.isInterleavedBufferAttribute?e.data.updateRanges:e.updateRanges;if(s.bindBuffer(o,n.bufferGPU),0===a.length)s.bufferSubData(o,0,i);else{for(let e=0,t=a.length;e1?this.enable(s.SAMPLE_ALPHA_TO_COVERAGE):this.disable(s.SAMPLE_ALPHA_TO_COVERAGE)}setPolygonOffset(e,t,s){const{gl:i}=this;e?(this.enable(i.POLYGON_OFFSET_FILL),this.currentPolygonOffsetFactor===t&&this.currentPolygonOffsetUnits===s||(i.polygonOffset(t,s),this.currentPolygonOffsetFactor=t,this.currentPolygonOffsetUnits=s)):this.disable(i.POLYGON_OFFSET_FILL)}useProgram(e){return this.currentProgram!==e&&(this.gl.useProgram(e),this.currentProgram=e,!0)}bindFramebuffer(e,t){const{gl:s,currentBoundFramebuffers:i}=this;return i[e]!==t&&(s.bindFramebuffer(e,t),i[e]=t,e===s.DRAW_FRAMEBUFFER&&(i[s.FRAMEBUFFER]=t),e===s.FRAMEBUFFER&&(i[s.DRAW_FRAMEBUFFER]=t),!0)}drawBuffers(e,t){const{gl:s}=this;let i=[],r=!1;if(null!==e.textures){i=this.currentDrawbuffers.get(t),void 0===i&&(i=[],this.currentDrawbuffers.set(t,i));const n=e.textures;if(i.length!==n.length||i[0]!==s.COLOR_ATTACHMENT0){for(let e=0,t=n.length;e{!function r(){const n=e.clientWaitSync(t,e.SYNC_FLUSH_COMMANDS_BIT,0);if(n===e.WAIT_FAILED)return e.deleteSync(t),void i();n!==e.TIMEOUT_EXPIRED?(e.deleteSync(t),s()):requestAnimationFrame(r)}()}))}}let GP,WP,jP,HP=!1;class qP{constructor(e){this.backend=e,this.gl=e.gl,this.extensions=e.extensions,this.defaultTextures={},!1===HP&&(this._init(this.gl),HP=!0)}_init(e){GP={[pe]:e.REPEAT,[me]:e.CLAMP_TO_EDGE,[ge]:e.MIRRORED_REPEAT},WP={[fe]:e.NEAREST,[ye]:e.NEAREST_MIPMAP_NEAREST,[be]:e.NEAREST_MIPMAP_LINEAR,[Te]:e.LINEAR,[_e]:e.LINEAR_MIPMAP_NEAREST,[Se]:e.LINEAR_MIPMAP_LINEAR},jP={512:e.NEVER,519:e.ALWAYS,[Ts]:e.LESS,515:e.LEQUAL,514:e.EQUAL,518:e.GEQUAL,516:e.GREATER,517:e.NOTEQUAL}}filterFallback(e){const{gl:t}=this;return e===fe||e===ye||e===be?t.NEAREST:t.LINEAR}getGLTextureType(e){const{gl:t}=this;let s;return s=!0===e.isCubeTexture?t.TEXTURE_CUBE_MAP:!0===e.isDataArrayTexture||!0===e.isCompressedArrayTexture?t.TEXTURE_2D_ARRAY:!0===e.isData3DTexture?t.TEXTURE_3D:t.TEXTURE_2D,s}getInternalFormat(e,t,s,i,r=!1){const{gl:n,extensions:o}=this;if(null!==e){if(void 0!==n[e])return n[e];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+e+"'")}let a=t;return t===n.RED&&(s===n.FLOAT&&(a=n.R32F),s===n.HALF_FLOAT&&(a=n.R16F),s===n.UNSIGNED_BYTE&&(a=n.R8),s===n.UNSIGNED_SHORT&&(a=n.R16),s===n.UNSIGNED_INT&&(a=n.R32UI),s===n.BYTE&&(a=n.R8I),s===n.SHORT&&(a=n.R16I),s===n.INT&&(a=n.R32I)),t===n.RED_INTEGER&&(s===n.UNSIGNED_BYTE&&(a=n.R8UI),s===n.UNSIGNED_SHORT&&(a=n.R16UI),s===n.UNSIGNED_INT&&(a=n.R32UI),s===n.BYTE&&(a=n.R8I),s===n.SHORT&&(a=n.R16I),s===n.INT&&(a=n.R32I)),t===n.RG&&(s===n.FLOAT&&(a=n.RG32F),s===n.HALF_FLOAT&&(a=n.RG16F),s===n.UNSIGNED_BYTE&&(a=n.RG8),s===n.UNSIGNED_SHORT&&(a=n.RG16),s===n.UNSIGNED_INT&&(a=n.RG32UI),s===n.BYTE&&(a=n.RG8I),s===n.SHORT&&(a=n.RG16I),s===n.INT&&(a=n.RG32I)),t===n.RG_INTEGER&&(s===n.UNSIGNED_BYTE&&(a=n.RG8UI),s===n.UNSIGNED_SHORT&&(a=n.RG16UI),s===n.UNSIGNED_INT&&(a=n.RG32UI),s===n.BYTE&&(a=n.RG8I),s===n.SHORT&&(a=n.RG16I),s===n.INT&&(a=n.RG32I)),t===n.RGB&&(s===n.FLOAT&&(a=n.RGB32F),s===n.HALF_FLOAT&&(a=n.RGB16F),s===n.UNSIGNED_BYTE&&(a=n.RGB8),s===n.UNSIGNED_SHORT&&(a=n.RGB16),s===n.UNSIGNED_INT&&(a=n.RGB32UI),s===n.BYTE&&(a=n.RGB8I),s===n.SHORT&&(a=n.RGB16I),s===n.INT&&(a=n.RGB32I),s===n.UNSIGNED_BYTE&&(a=i===Zt&&!1===r?n.SRGB8:n.RGB8),s===n.UNSIGNED_SHORT_5_6_5&&(a=n.RGB565),s===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1),s===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGB4),s===n.UNSIGNED_INT_5_9_9_9_REV&&(a=n.RGB9_E5)),t===n.RGB_INTEGER&&(s===n.UNSIGNED_BYTE&&(a=n.RGB8UI),s===n.UNSIGNED_SHORT&&(a=n.RGB16UI),s===n.UNSIGNED_INT&&(a=n.RGB32UI),s===n.BYTE&&(a=n.RGB8I),s===n.SHORT&&(a=n.RGB16I),s===n.INT&&(a=n.RGB32I)),t===n.RGBA&&(s===n.FLOAT&&(a=n.RGBA32F),s===n.HALF_FLOAT&&(a=n.RGBA16F),s===n.UNSIGNED_BYTE&&(a=n.RGBA8),s===n.UNSIGNED_SHORT&&(a=n.RGBA16),s===n.UNSIGNED_INT&&(a=n.RGBA32UI),s===n.BYTE&&(a=n.RGBA8I),s===n.SHORT&&(a=n.RGBA16I),s===n.INT&&(a=n.RGBA32I),s===n.UNSIGNED_BYTE&&(a=i===Zt&&!1===r?n.SRGB8_ALPHA8:n.RGBA8),s===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGBA4),s===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1)),t===n.RGBA_INTEGER&&(s===n.UNSIGNED_BYTE&&(a=n.RGBA8UI),s===n.UNSIGNED_SHORT&&(a=n.RGBA16UI),s===n.UNSIGNED_INT&&(a=n.RGBA32UI),s===n.BYTE&&(a=n.RGBA8I),s===n.SHORT&&(a=n.RGBA16I),s===n.INT&&(a=n.RGBA32I)),t===n.DEPTH_COMPONENT&&(s===n.UNSIGNED_INT&&(a=n.DEPTH24_STENCIL8),s===n.FLOAT&&(a=n.DEPTH_COMPONENT32F)),t===n.DEPTH_STENCIL&&s===n.UNSIGNED_INT_24_8&&(a=n.DEPTH24_STENCIL8),a!==n.R16F&&a!==n.R32F&&a!==n.RG16F&&a!==n.RG32F&&a!==n.RGBA16F&&a!==n.RGBA32F||o.get("EXT_color_buffer_float"),a}setTextureParameters(e,t){const{gl:s,extensions:i,backend:r}=this;s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL,t.flipY),s.pixelStorei(s.UNPACK_PREMULTIPLY_ALPHA_WEBGL,t.premultiplyAlpha),s.pixelStorei(s.UNPACK_ALIGNMENT,t.unpackAlignment),s.pixelStorei(s.UNPACK_COLORSPACE_CONVERSION_WEBGL,s.NONE),s.texParameteri(e,s.TEXTURE_WRAP_S,GP[t.wrapS]),s.texParameteri(e,s.TEXTURE_WRAP_T,GP[t.wrapT]),e!==s.TEXTURE_3D&&e!==s.TEXTURE_2D_ARRAY||s.texParameteri(e,s.TEXTURE_WRAP_R,GP[t.wrapR]),s.texParameteri(e,s.TEXTURE_MAG_FILTER,WP[t.magFilter]);const n=void 0!==t.mipmaps&&t.mipmaps.length>0,o=t.minFilter===Te&&n?Se:t.minFilter;if(s.texParameteri(e,s.TEXTURE_MIN_FILTER,WP[o]),t.compareFunction&&(s.texParameteri(e,s.TEXTURE_COMPARE_MODE,s.COMPARE_REF_TO_TEXTURE),s.texParameteri(e,s.TEXTURE_COMPARE_FUNC,jP[t.compareFunction])),!0===i.has("EXT_texture_filter_anisotropic")){if(t.magFilter===fe)return;if(t.minFilter!==be&&t.minFilter!==Se)return;if(t.type===Ie&&!1===i.has("OES_texture_float_linear"))return;if(t.anisotropy>1){const n=i.get("EXT_texture_filter_anisotropic");s.texParameterf(e,n.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(t.anisotropy,r.getMaxAnisotropy()))}}}createDefaultTexture(e){const{gl:t,backend:s,defaultTextures:i}=this,r=this.getGLTextureType(e);let n=i[r];void 0===n&&(n=t.createTexture(),s.state.bindTexture(r,n),t.texParameteri(r,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(r,t.TEXTURE_MAG_FILTER,t.NEAREST),i[r]=n),s.set(e,{textureGPU:n,glTextureType:r,isDefault:!0})}createTexture(e,t){const{gl:s,backend:i}=this,{levels:r,width:n,height:o,depth:a}=t,h=i.utils.convert(e.format,e.colorSpace),u=i.utils.convert(e.type),l=this.getInternalFormat(e.internalFormat,h,u,e.colorSpace,e.isVideoTexture),c=s.createTexture(),d=this.getGLTextureType(e);i.state.bindTexture(d,c),this.setTextureParameters(d,e),e.isDataArrayTexture||e.isCompressedArrayTexture?s.texStorage3D(s.TEXTURE_2D_ARRAY,r,l,n,o,a):e.isData3DTexture?s.texStorage3D(s.TEXTURE_3D,r,l,n,o,a):e.isVideoTexture||s.texStorage2D(d,r,l,n,o),i.set(e,{textureGPU:c,glTextureType:d,glFormat:h,glType:u,glInternalFormat:l})}copyBufferToTexture(e,t){const{gl:s,backend:i}=this,{textureGPU:r,glTextureType:n,glFormat:o,glType:a}=i.get(t),{width:h,height:u}=t.source.data;s.bindBuffer(s.PIXEL_UNPACK_BUFFER,e),i.state.bindTexture(n,r),s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL,!1),s.pixelStorei(s.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),s.texSubImage2D(n,0,0,0,h,u,o,a,0),s.bindBuffer(s.PIXEL_UNPACK_BUFFER,null),i.state.unbindTexture()}updateTexture(e,t){const{gl:s}=this,{width:i,height:r}=t,{textureGPU:n,glTextureType:o,glFormat:a,glType:h,glInternalFormat:u}=this.backend.get(e);if(e.isRenderTargetTexture||void 0===n)return;const l=e=>e.isDataTexture?e.image.data:e instanceof ImageBitmap||e instanceof OffscreenCanvas||e instanceof HTMLImageElement||e instanceof HTMLCanvasElement?e:e.data;if(this.backend.state.bindTexture(o,n),this.setTextureParameters(o,e),e.isCompressedTexture){const i=e.mipmaps,r=t.image;for(let t=0;t0,c=t.renderTarget?t.renderTarget.height:this.backend.gerDrawingBufferSize().y;if(l){const s=0!==o||0!==a;let l,d;if(!0===e.isDepthTexture?(l=i.DEPTH_BUFFER_BIT,d=i.DEPTH_ATTACHMENT,t.stencil&&(l|=i.STENCIL_BUFFER_BIT)):(l=i.COLOR_BUFFER_BIT,d=i.COLOR_ATTACHMENT0),s){const e=this.backend.get(t.renderTarget),s=e.framebuffers[t.getCacheKey()],d=e.msaaFrameBuffer;r.bindFramebuffer(i.DRAW_FRAMEBUFFER,s),r.bindFramebuffer(i.READ_FRAMEBUFFER,d);const p=c-a-u;i.blitFramebuffer(o,p,o+h,p+u,o,p,o+h,p+u,l,i.NEAREST),r.bindFramebuffer(i.READ_FRAMEBUFFER,s),r.bindTexture(i.TEXTURE_2D,n),i.copyTexSubImage2D(i.TEXTURE_2D,0,0,0,o,p,h,u),r.unbindTexture()}else{const e=i.createFramebuffer();r.bindFramebuffer(i.DRAW_FRAMEBUFFER,e),i.framebufferTexture2D(i.DRAW_FRAMEBUFFER,d,i.TEXTURE_2D,n,0),i.blitFramebuffer(0,0,h,u,0,0,h,u,l,i.NEAREST),i.deleteFramebuffer(e)}}else r.bindTexture(i.TEXTURE_2D,n),i.copyTexSubImage2D(i.TEXTURE_2D,0,0,0,o,c-u-a,h,u),r.unbindTexture();e.generateMipmaps&&this.generateMipmaps(e),this.backend._setFramebuffer(t)}setupRenderBufferStorage(e,t){const{gl:s}=this,i=t.renderTarget,{samples:r,depthTexture:n,depthBuffer:o,stencilBuffer:a,width:h,height:u}=i;if(s.bindRenderbuffer(s.RENDERBUFFER,e),o&&!a){let t=s.DEPTH_COMPONENT24;r>0?(n&&n.isDepthTexture&&n.type===s.FLOAT&&(t=s.DEPTH_COMPONENT32F),s.renderbufferStorageMultisample(s.RENDERBUFFER,r,t,h,u)):s.renderbufferStorage(s.RENDERBUFFER,t,h,u),s.framebufferRenderbuffer(s.FRAMEBUFFER,s.DEPTH_ATTACHMENT,s.RENDERBUFFER,e)}else o&&a&&(r>0?s.renderbufferStorageMultisample(s.RENDERBUFFER,r,s.DEPTH24_STENCIL8,h,u):s.renderbufferStorage(s.RENDERBUFFER,s.DEPTH_STENCIL,h,u),s.framebufferRenderbuffer(s.FRAMEBUFFER,s.DEPTH_STENCIL_ATTACHMENT,s.RENDERBUFFER,e))}async copyTextureToBuffer(e,t,s,i,r,n){const{backend:o,gl:a}=this,{textureGPU:h,glFormat:u,glType:l}=this.backend.get(e),c=a.createFramebuffer();a.bindFramebuffer(a.READ_FRAMEBUFFER,c);const d=e.isCubeTexture?a.TEXTURE_CUBE_MAP_POSITIVE_X+n:a.TEXTURE_2D;a.framebufferTexture2D(a.READ_FRAMEBUFFER,a.COLOR_ATTACHMENT0,d,h,0);const p=this._getTypedArrayType(l),m=i*r*this._getBytesPerTexel(l,u),g=a.createBuffer();a.bindBuffer(a.PIXEL_PACK_BUFFER,g),a.bufferData(a.PIXEL_PACK_BUFFER,m,a.STREAM_READ),a.readPixels(t,s,i,r,u,l,0),a.bindBuffer(a.PIXEL_PACK_BUFFER,null),await o.utils._clientWaitAsync();const f=new p(m/p.BYTES_PER_ELEMENT);return a.bindBuffer(a.PIXEL_PACK_BUFFER,g),a.getBufferSubData(a.PIXEL_PACK_BUFFER,0,f),a.bindBuffer(a.PIXEL_PACK_BUFFER,null),a.deleteFramebuffer(c),f}_getTypedArrayType(e){const{gl:t}=this;if(e===t.UNSIGNED_BYTE)return Uint8Array;if(e===t.UNSIGNED_SHORT_4_4_4_4)return Uint16Array;if(e===t.UNSIGNED_SHORT_5_5_5_1)return Uint16Array;if(e===t.UNSIGNED_SHORT_5_6_5)return Uint16Array;if(e===t.UNSIGNED_SHORT)return Uint16Array;if(e===t.UNSIGNED_INT)return Uint32Array;if(e===t.HALF_FLOAT)return Uint16Array;if(e===t.FLOAT)return Float32Array;throw new Error(`Unsupported WebGL type: ${e}`)}_getBytesPerTexel(e,t){const{gl:s}=this;let i=0;return e===s.UNSIGNED_BYTE&&(i=1),e!==s.UNSIGNED_SHORT_4_4_4_4&&e!==s.UNSIGNED_SHORT_5_5_5_1&&e!==s.UNSIGNED_SHORT_5_6_5&&e!==s.UNSIGNED_SHORT&&e!==s.HALF_FLOAT||(i=2),e!==s.UNSIGNED_INT&&e!==s.FLOAT||(i=4),t===s.RGBA?4*i:t===s.RGB?3*i:t===s.ALPHA?i:void 0}}class $P{constructor(e){this.backend=e,this.gl=this.backend.gl,this.availableExtensions=this.gl.getSupportedExtensions(),this.extensions={}}get(e){let t=this.extensions[e];return void 0===t&&(t=this.gl.getExtension(e),this.extensions[e]=t),t}has(e){return this.availableExtensions.includes(e)}}class XP{constructor(e){this.backend=e,this.maxAnisotropy=null}getMaxAnisotropy(){if(null!==this.maxAnisotropy)return this.maxAnisotropy;const e=this.backend.gl,t=this.backend.extensions;if(!0===t.has("EXT_texture_filter_anisotropic")){const s=t.get("EXT_texture_filter_anisotropic");this.maxAnisotropy=e.getParameter(s.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else this.maxAnisotropy=0;return this.maxAnisotropy}}const YP={WEBGL_multi_draw:"WEBGL_multi_draw",WEBGL_compressed_texture_astc:"texture-compression-astc",WEBGL_compressed_texture_etc:"texture-compression-etc2",WEBGL_compressed_texture_etc1:"texture-compression-etc1",WEBGL_compressed_texture_pvrtc:"texture-compression-pvrtc",WEBKIT_WEBGL_compressed_texture_pvrtc:"texture-compression-pvrtc",WEBGL_compressed_texture_s3tc:"texture-compression-bc",EXT_texture_compression_bptc:"texture-compression-bptc",EXT_disjoint_timer_query_webgl2:"timestamp-query"};class ZP{constructor(e){this.gl=e.gl,this.extensions=e.extensions,this.info=e.renderer.info,this.mode=null,this.index=0,this.type=null,this.object=null}render(e,t){const{gl:s,mode:i,object:r,type:n,info:o,index:a}=this;0!==a?s.drawElements(i,t,n,e):s.drawArrays(i,e,t),o.update(r,t,i,1)}renderInstances(e,t,s){const{gl:i,mode:r,type:n,index:o,object:a,info:h}=this;0!==s&&(0!==o?i.drawElementsInstanced(r,t,n,e,s):i.drawArraysInstanced(r,e,t,s),h.update(a,t,r,s))}renderMultiDraw(e,t,s){const{extensions:i,mode:r,object:n,info:o}=this;if(0===s)return;const a=i.get("WEBGL_multi_draw");if(null===a)for(let i=0;i0)){const e=t.queryQueue.shift();this.initTimestampQuery(e)}}async resolveTimestampAsync(e,t="render"){if(!this.disjoint||!this.trackTimestamp)return;const s=this.get(e);s.gpuQueries||(s.gpuQueries=[]);for(let e=0;e0&&(s.currentOcclusionQueries=s.occlusionQueries,s.currentOcclusionQueryObjects=s.occlusionQueryObjects,s.lastOcclusionObject=null,s.occlusionQueries=new Array(i),s.occlusionQueryObjects=new Array(i),s.occlusionQueryIndex=0)}finishRender(e){const{gl:t,state:s}=this,i=this.get(e),r=i.previousContext,n=e.occlusionQueryCount;n>0&&(n>i.occlusionQueryIndex&&t.endQuery(t.ANY_SAMPLES_PASSED),this.resolveOccludedAsync(e));const o=e.textures;if(null!==o)for(let e=0;e0){const r=i.framebuffers[e.getCacheKey()],n=t.COLOR_BUFFER_BIT,o=i.msaaFrameBuffer,a=e.textures;s.bindFramebuffer(t.READ_FRAMEBUFFER,o),s.bindFramebuffer(t.DRAW_FRAMEBUFFER,r);for(let s=0;s{let o=0;for(let t=0;t0&&e.add(i[t]),s[t]=null,r.deleteQuery(n),o++))}o1?m.renderInstances(y,g,f):m.render(y,g),o.bindVertexArray(null)}needsRenderUpdate(){return!1}getRenderCacheKey(){return""}createDefaultTexture(e){this.textureUtils.createDefaultTexture(e)}createTexture(e,t){this.textureUtils.createTexture(e,t)}updateTexture(e,t){this.textureUtils.updateTexture(e,t)}generateMipmaps(e){this.textureUtils.generateMipmaps(e)}destroyTexture(e){this.textureUtils.destroyTexture(e)}copyTextureToBuffer(e,t,s,i,r,n){return this.textureUtils.copyTextureToBuffer(e,t,s,i,r,n)}createSampler(){}destroySampler(){}createNodeBuilder(e,t){return new RP(e,t)}createProgram(e){const t=this.gl,{stage:s,code:i}=e,r="fragment"===s?t.createShader(t.FRAGMENT_SHADER):t.createShader(t.VERTEX_SHADER);t.shaderSource(r,i),t.compileShader(r),this.set(e,{shaderGPU:r})}destroyProgram(){console.warn("Abstract class.")}createRenderPipeline(e,t){const s=this.gl,i=e.pipeline,{fragmentProgram:r,vertexProgram:n}=i,o=s.createProgram(),a=this.get(r).shaderGPU,h=this.get(n).shaderGPU;if(s.attachShader(o,a),s.attachShader(o,h),s.linkProgram(o),this.set(i,{programGPU:o,fragmentShader:a,vertexShader:h}),null!==t&&this.parallel){const r=new Promise((t=>{const r=this.parallel,n=()=>{s.getProgramParameter(o,r.COMPLETION_STATUS_KHR)?(this._completeCompile(e,i),t()):requestAnimationFrame(n)};n()}));t.push(r)}else this._completeCompile(e,i)}_handleSource(e,t){const s=e.split("\n"),i=[],r=Math.max(t-6,0),n=Math.min(t+6,s.length);for(let e=r;e":" "} ${r}: ${s[e]}`)}return i.join("\n")}_getShaderErrors(e,t,s){const i=e.getShaderParameter(t,e.COMPILE_STATUS),r=e.getShaderInfoLog(t).trim();if(i&&""===r)return"";const n=/ERROR: 0:(\d+)/.exec(r);if(n){const i=parseInt(n[1]);return s.toUpperCase()+"\n\n"+r+"\n\n"+this._handleSource(e.getShaderSource(t),i)}return r}_logProgramError(e,t,s){if(this.renderer.debug.checkShaderErrors){const i=this.gl,r=i.getProgramInfoLog(e).trim();if(!1===i.getProgramParameter(e,i.LINK_STATUS))if("function"==typeof this.renderer.debug.onShaderError)this.renderer.debug.onShaderError(i,e,s,t);else{const n=this._getShaderErrors(i,s,"vertex"),o=this._getShaderErrors(i,t,"fragment");console.error("THREE.WebGLProgram: Shader Error "+i.getError()+" - VALIDATE_STATUS "+i.getProgramParameter(e,i.VALIDATE_STATUS)+"\n\nProgram Info Log: "+r+"\n"+n+"\n"+o)}else""!==r&&console.warn("THREE.WebGLProgram: Program Info Log:",r)}}_completeCompile(e,t){const{state:s,gl:i}=this,r=this.get(t),{programGPU:n,fragmentShader:o,vertexShader:a}=r;!1===i.getProgramParameter(n,i.LINK_STATUS)&&this._logProgramError(n,o,a),s.useProgram(n);const h=e.getBindings();this._setupBindings(h,n),this.set(t,{programGPU:n})}createComputePipeline(e,t){const{state:s,gl:i}=this,r={stage:"fragment",code:"#version 300 es\nprecision highp float;\nvoid main() {}"};this.createProgram(r);const{computeProgram:n}=e,o=i.createProgram(),a=this.get(r).shaderGPU,h=this.get(n).shaderGPU,u=n.transforms,l=[],c=[];for(let e=0;eYP[t]===e)),s=this.extensions;for(let e=0;e0){if(void 0===l){const i=[];l=t.createFramebuffer(),s.bindFramebuffer(t.FRAMEBUFFER,l);const r=[],u=e.textures;for(let s=0;s,\n\t@location( 0 ) vTex : vec2\n};\n\n@vertex\nfn main( @builtin( vertex_index ) vertexIndex : u32 ) -> VarysStruct {\n\n\tvar Varys : VarysStruct;\n\n\tvar pos = array< vec2, 4 >(\n\t\tvec2( -1.0, 1.0 ),\n\t\tvec2( 1.0, 1.0 ),\n\t\tvec2( -1.0, -1.0 ),\n\t\tvec2( 1.0, -1.0 )\n\t);\n\n\tvar tex = array< vec2, 4 >(\n\t\tvec2( 0.0, 0.0 ),\n\t\tvec2( 1.0, 0.0 ),\n\t\tvec2( 0.0, 1.0 ),\n\t\tvec2( 1.0, 1.0 )\n\t);\n\n\tVarys.vTex = tex[ vertexIndex ];\n\tVarys.Position = vec4( pos[ vertexIndex ], 0.0, 1.0 );\n\n\treturn Varys;\n\n}\n"}),this.mipmapFragmentShaderModule=e.createShaderModule({label:"mipmapFragment",code:"\n@group( 0 ) @binding( 0 )\nvar imgSampler : sampler;\n\n@group( 0 ) @binding( 1 )\nvar img : texture_2d;\n\n@fragment\nfn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 {\n\n\treturn textureSample( img, imgSampler, vTex );\n\n}\n"}),this.flipYFragmentShaderModule=e.createShaderModule({label:"flipYFragment",code:"\n@group( 0 ) @binding( 0 )\nvar imgSampler : sampler;\n\n@group( 0 ) @binding( 1 )\nvar img : texture_2d;\n\n@fragment\nfn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 {\n\n\treturn textureSample( img, imgSampler, vec2( vTex.x, 1.0 - vTex.y ) );\n\n}\n"})}getTransferPipeline(e){let t=this.transferPipelines[e];return void 0===t&&(t=this.device.createRenderPipeline({label:`mipmap-${e}`,vertex:{module:this.mipmapVertexShaderModule,entryPoint:"main"},fragment:{module:this.mipmapFragmentShaderModule,entryPoint:"main",targets:[{format:e}]},primitive:{topology:CN,stripIndexFormat:HN},layout:"auto"}),this.transferPipelines[e]=t),t}getFlipYPipeline(e){let t=this.flipYPipelines[e];return void 0===t&&(t=this.device.createRenderPipeline({label:`flipY-${e}`,vertex:{module:this.mipmapVertexShaderModule,entryPoint:"main"},fragment:{module:this.flipYFragmentShaderModule,entryPoint:"main",targets:[{format:e}]},primitive:{topology:CN,stripIndexFormat:HN},layout:"auto"}),this.flipYPipelines[e]=t),t}flipY(e,t,s=0){const i=t.format,{width:r,height:n}=t.size,o=this.getTransferPipeline(i),a=this.getFlipYPipeline(i),h=this.device.createTexture({size:{width:r,height:n,depthOrArrayLayers:1},format:i,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING}),u=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:OA,baseArrayLayer:s}),l=h.createView({baseMipLevel:0,mipLevelCount:1,dimension:OA,baseArrayLayer:0}),c=this.device.createCommandEncoder({}),d=(e,t,s)=>{const i=e.getBindGroupLayout(0),r=this.device.createBindGroup({layout:i,entries:[{binding:0,resource:this.flipYSampler},{binding:1,resource:t}]}),n=c.beginRenderPass({colorAttachments:[{view:s,loadOp:VN,storeOp:ON,clearValue:[0,0,0,0]}]});n.setPipeline(e),n.setBindGroup(0,r),n.draw(4,1,0,0),n.end()};d(o,u,l),d(a,l,u),this.device.queue.submit([c.finish()]),h.destroy()}generateMipmaps(e,t,s=0){const i=this.get(e);void 0===i.useCount&&(i.useCount=0,i.layers=[]);const r=i.layers[s]||this._mipmapCreateBundles(e,t,s),n=this.device.createCommandEncoder({});this._mipmapRunBundles(n,r),this.device.queue.submit([n.finish()]),0!==i.useCount&&(i.layers[s]=r),i.useCount++}_mipmapCreateBundles(e,t,s){const i=this.getTransferPipeline(t.format),r=i.getBindGroupLayout(0);let n=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:OA,baseArrayLayer:s});const o=[];for(let a=1;a1&&!e.isMultisampleRenderTargetTexture){const e=Object.assign({},p);e.label=e.label+"-msaa",e.sampleCount=l,i.msaaTexture=s.device.createTexture(e)}i.initialized=!0,i.textureDescriptorGPU=p}destroyTexture(e){const t=this.backend,s=t.get(e);s.texture.destroy(),void 0!==s.msaaTexture&&s.msaaTexture.destroy(),t.delete(e)}destroySampler(e){delete this.backend.get(e).sampler}generateMipmaps(e){const t=this.backend.get(e);if(e.isCubeTexture)for(let e=0;e<6;e++)this._generateMipmaps(t.texture,t.textureDescriptorGPU,e);else{const s=e.image.depth||1;for(let e=0;e1;for(let o=0;o]*\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/i,uF=/([a-z_0-9]+)\s*:\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/gi,lF={f32:"float",i32:"int",u32:"uint",bool:"bool","vec2":"vec2","vec2":"ivec2","vec2":"uvec2","vec2":"bvec2",vec2f:"vec2",vec2i:"ivec2",vec2u:"uvec2",vec2b:"bvec2","vec3":"vec3","vec3":"ivec3","vec3":"uvec3","vec3":"bvec3",vec3f:"vec3",vec3i:"ivec3",vec3u:"uvec3",vec3b:"bvec3","vec4":"vec4","vec4":"ivec4","vec4":"uvec4","vec4":"bvec4",vec4f:"vec4",vec4i:"ivec4",vec4u:"uvec4",vec4b:"bvec4","mat2x2":"mat2",mat2x2f:"mat2","mat3x3":"mat3",mat3x3f:"mat3","mat4x4":"mat4",mat4x4f:"mat4",sampler:"sampler",texture_1d:"texture",texture_2d:"texture",texture_2d_array:"texture",texture_multisampled_2d:"cubeTexture",texture_depth_2d:"depthTexture",texture_3d:"texture3D",texture_cube:"cubeTexture",texture_cube_array:"cubeTexture",texture_storage_1d:"storageTexture",texture_storage_2d:"storageTexture",texture_storage_2d_array:"storageTexture",texture_storage_3d:"storageTexture"};class cF extends FI{constructor(e){const{type:t,inputs:s,name:i,inputsCode:r,blockCode:n,outputType:o}=(e=>{const t=(e=e.trim()).match(hF);if(null!==t&&4===t.length){const s=t[2],i=[];let r=null;for(;null!==(r=uF.exec(s));)i.push({name:r[1],type:r[2]});const n=[];for(let e=0;e "+this.outputType:"";return`fn ${e} ( ${this.inputsCode.trim()} ) ${t}`+this.blockCode}}class dF extends PI{parseFunction(e){return new cF(e)}}const pF=self.GPUShaderStage,mF={vertex:pF?pF.VERTEX:1,fragment:pF?pF.FRAGMENT:2,compute:pF?pF.COMPUTE:4},gF={instance:!0,swizzleAssign:!1,storageBuffer:!0},fF={"^^":"tsl_xor"},yF={float:"f32",int:"i32",uint:"u32",bool:"bool",color:"vec3",vec2:"vec2",ivec2:"vec2",uvec2:"vec2",bvec2:"vec2",vec3:"vec3",ivec3:"vec3",uvec3:"vec3",bvec3:"vec3",vec4:"vec4",ivec4:"vec4",uvec4:"vec4",bvec4:"vec4",mat2:"mat2x2",imat2:"mat2x2",umat2:"mat2x2",bmat2:"mat2x2",mat3:"mat3x3",imat3:"mat3x3",umat3:"mat3x3",bmat3:"mat3x3",mat4:"mat4x4",imat4:"mat4x4",umat4:"mat4x4",bmat4:"mat4x4"},xF={tsl_xor:new vS("fn tsl_xor( a : bool, b : bool ) -> bool { return ( a || b ) && !( a && b ); }"),mod_float:new vS("fn tsl_mod_float( x : f32, y : f32 ) -> f32 { return x - y * floor( x / y ); }"),mod_vec2:new vS("fn tsl_mod_vec2( x : vec2f, y : vec2f ) -> vec2f { return x - y * floor( x / y ); }"),mod_vec3:new vS("fn tsl_mod_vec3( x : vec3f, y : vec3f ) -> vec3f { return x - y * floor( x / y ); }"),mod_vec4:new vS("fn tsl_mod_vec4( x : vec4f, y : vec4f ) -> vec4f { return x - y * floor( x / y ); }"),equals_bool:new vS("fn tsl_equals_bool( a : bool, b : bool ) -> bool { return a == b; }"),equals_bvec2:new vS("fn tsl_equals_bvec2( a : vec2f, b : vec2f ) -> vec2 { return vec2( a.x == b.x, a.y == b.y ); }"),equals_bvec3:new vS("fn tsl_equals_bvec3( a : vec3f, b : vec3f ) -> vec3 { return vec3( a.x == b.x, a.y == b.y, a.z == b.z ); }"),equals_bvec4:new vS("fn tsl_equals_bvec4( a : vec4f, b : vec4f ) -> vec4 { return vec4( a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w ); }"),repeatWrapping:new vS("\nfn tsl_repeatWrapping( uv : vec2, dimension : vec2 ) -> vec2 {\n\n\tlet uvScaled = vec2( uv * vec2( dimension ) );\n\n\treturn ( ( uvScaled % dimension ) + dimension ) % dimension;\n\n}\n"),biquadraticTexture:new vS("\nfn tsl_biquadraticTexture( map : texture_2d, coord : vec2f, level : i32 ) -> vec4f {\n\n\tlet iRes = vec2i( textureDimensions( map, level ) );\n\tlet res = vec2f( iRes );\n\n\tlet uvScaled = coord * res;\n\tlet uvWrapping = ( ( uvScaled % res ) + res ) % res;\n\n\t// https://www.shadertoy.com/view/WtyXRy\n\n\tlet uv = uvWrapping - 0.5;\n\tlet iuv = floor( uv );\n\tlet f = fract( uv );\n\n\tlet rg1 = textureLoad( map, vec2i( iuv + vec2( 0.5, 0.5 ) ) % iRes, level );\n\tlet rg2 = textureLoad( map, vec2i( iuv + vec2( 1.5, 0.5 ) ) % iRes, level );\n\tlet rg3 = textureLoad( map, vec2i( iuv + vec2( 0.5, 1.5 ) ) % iRes, level );\n\tlet rg4 = textureLoad( map, vec2i( iuv + vec2( 1.5, 1.5 ) ) % iRes, level );\n\n\treturn mix( mix( rg1, rg2, f.x ), mix( rg3, rg4, f.x ), f.y );\n\n}\n")},bF={dFdx:"dpdx",dFdy:"- dpdy",mod_float:"tsl_mod_float",mod_vec2:"tsl_mod_vec2",mod_vec3:"tsl_mod_vec3",mod_vec4:"tsl_mod_vec4",equals_bool:"tsl_equals_bool",equals_bvec2:"tsl_equals_bvec2",equals_bvec3:"tsl_equals_bvec3",equals_bvec4:"tsl_equals_bvec4",inversesqrt:"inverseSqrt",bitcast:"bitcast"};/Windows/g.test(navigator.userAgent)&&(xF.pow_float=new vS("fn tsl_pow_float( a : f32, b : f32 ) -> f32 { return select( -pow( -a, b ), pow( a, b ), a > 0.0 ); }"),xF.pow_vec2=new vS("fn tsl_pow_vec2( a : vec2f, b : vec2f ) -> vec2f { return vec2f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ) ); }",[xF.pow_float]),xF.pow_vec3=new vS("fn tsl_pow_vec3( a : vec3f, b : vec3f ) -> vec3f { return vec3f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ), tsl_pow_float( a.z, b.z ) ); }",[xF.pow_float]),xF.pow_vec4=new vS("fn tsl_pow_vec4( a : vec4f, b : vec4f ) -> vec4f { return vec4f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ), tsl_pow_float( a.z, b.z ), tsl_pow_float( a.w, b.w ) ); }",[xF.pow_float]),bF.pow_float="tsl_pow_float",bF.pow_vec2="tsl_pow_vec2",bF.pow_vec3="tsl_pow_vec3",bF.pow_vec4="tsl_pow_vec4");let vF="";!0!==/Firefox/g.test(navigator.userAgent)&&(vF+="diagnostic( off, derivative_uniformity );\n");class TF extends xM{constructor(e,t){super(e,t,new dF),this.uniformGroups={},this.builtins={},this.directives={},this.scopedArrays=new Map}needsToWorkingColorSpace(e){return!0===e.isVideoTexture&&e.colorSpace!==Yt}_generateTextureSample(e,t,s,i,r=this.shaderStage){return"fragment"===r?i?`textureSample( ${t}, ${t}_sampler, ${s}, ${i} )`:`textureSample( ${t}, ${t}_sampler, ${s} )`:this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,s):this.generateTextureLod(e,t,s,"0")}_generateVideoSample(e,t,s=this.shaderStage){if("fragment"===s)return`textureSampleBaseClampToEdge( ${e}, ${e}_sampler, vec2( ${t}.x, 1.0 - ${t}.y ) )`;console.error(`WebGPURenderer: THREE.VideoTexture does not support ${s} shader.`)}_generateTextureSampleLevel(e,t,s,i,r,n=this.shaderStage){return"fragment"===n&&!1===this.isUnfilterable(e)?`textureSampleLevel( ${t}, ${t}_sampler, ${s}, ${i} )`:this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,s,i):this.generateTextureLod(e,t,s,i)}generateFilteredTexture(e,t,s,i="0"){return this._include("biquadraticTexture"),`tsl_biquadraticTexture( ${t}, ${s}, i32( ${i} ) )`}generateTextureLod(e,t,s,i="0"){this._include("repeatWrapping");return`textureLoad( ${t}, tsl_repeatWrapping( ${s}, ${!0===e.isMultisampleRenderTargetTexture?`textureDimensions( ${t} )`:`textureDimensions( ${t}, 0 )`} ), i32( ${i} ) )`}generateTextureLoad(e,t,s,i,r="0u"){return i?`textureLoad( ${t}, ${s}, ${i}, ${r} )`:`textureLoad( ${t}, ${s}, ${r} )`}generateTextureStore(e,t,s,i){return`textureStore( ${t}, ${s}, ${i} )`}isUnfilterable(e){return"float"!==this.getComponentTypeFromTexture(e)||!this.isAvailable("float32Filterable")&&!0===e.isDataTexture&&e.type===Ie||!0===e.isMultisampleRenderTargetTexture}generateTexture(e,t,s,i,r=this.shaderStage){let n=null;return n=!0===e.isVideoTexture?this._generateVideoSample(t,s,r):this.isUnfilterable(e)?this.generateTextureLod(e,t,s,"0",i,r):this._generateTextureSample(e,t,s,i,r),n}generateTextureGrad(e,t,s,i,r,n=this.shaderStage){if("fragment"===n)return`textureSampleGrad( ${t}, ${t}_sampler, ${s}, ${i[0]}, ${i[1]} )`;console.error(`WebGPURenderer: THREE.TextureNode.gradient() does not support ${n} shader.`)}generateTextureCompare(e,t,s,i,r,n=this.shaderStage){if("fragment"===n)return`textureSampleCompare( ${t}, ${t}_sampler, ${s}, ${i} )`;console.error(`WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${n} shader.`)}generateTextureLevel(e,t,s,i,r,n=this.shaderStage){let o=null;return o=!0===e.isVideoTexture?this._generateVideoSample(t,s,n):this._generateTextureSampleLevel(e,t,s,i,r,n),o}generateTextureBias(e,t,s,i,r,n=this.shaderStage){if("fragment"===n)return`textureSampleBias( ${t}, ${t}_sampler, ${s}, ${i} )`;console.error(`WebGPURenderer: THREE.TextureNode.biasNode does not support ${n} shader.`)}getPropertyName(e,t=this.shaderStage){if(!0===e.isNodeVarying&&!0===e.needsInterpolation){if("vertex"===t)return`varyings.${e.name}`}else if(!0===e.isNodeUniform){const t=e.name,s=e.type;return"texture"===s||"cubeTexture"===s||"storageTexture"===s||"texture3D"===s?t:"buffer"===s||"storageBuffer"===s?`NodeBuffer_${e.id}.${t}`:e.groupNode.name+"."+t}return super.getPropertyName(e)}getOutputStructName(){return"output"}_getUniformGroupCount(e){return Object.keys(this.uniforms[e]).length}getFunctionOperator(e){const t=fF[e];return void 0!==t?(this._include(t),t):null}getStorageAccess(e){if(e.isStorageTextureNode)switch(e.access){case RA:return"read";case CA:return"write";default:return"read_write"}else switch(e.access){case NA:return"read_write";case AA:return"read";default:return"write"}}getUniformFromNode(e,t,s,i=null){const r=super.getUniformFromNode(e,t,s,i),n=this.getDataFromNode(e,s,this.globalCache);if(void 0===n.uniformGPU){let i;const o=e.groupNode,a=o.name,h=this.getBindGroupArray(a,s);if("texture"===t||"cubeTexture"===t||"storageTexture"===t||"texture3D"===t){let n=null;if("texture"===t||"storageTexture"===t?n=new _P(r.name,r.node,o,e.access?e.access:null):"cubeTexture"===t?n=new wP(r.name,r.node,o,e.access?e.access:null):"texture3D"===t&&(n=new SP(r.name,r.node,o,e.access?e.access:null)),n.store=!0===e.isStorageTextureNode,n.setVisibility(mF[s]),"fragment"===s&&!1===this.isUnfilterable(e.value)&&!1===n.store){const e=new QP(`${r.name}_sampler`,r.node,o);e.setVisibility(mF[s]),h.push(e,n),i=[e,n]}else h.push(n),i=[n]}else if("buffer"===t||"storageBuffer"===t){const r=new("storageBuffer"===t?sF:fP)(e,o);r.setVisibility(mF[s]),h.push(r),i=r}else{const e=this.uniformGroups[s]||(this.uniformGroups[s]={});let n=e[a];void 0===n&&(n=new bP(a,o),n.setVisibility(mF[s]),e[a]=n,h.push(n)),i=this.getNodeUniform(r,t),n.addUniform(i)}n.uniformGPU=i}return r}getBuiltin(e,t,s,i=this.shaderStage){const r=this.builtins[i]||(this.builtins[i]=new Map);return!1===r.has(e)&&r.set(e,{name:e,property:t,type:s}),t}hasBuiltin(e,t=this.shaderStage){return void 0!==this.builtins[t]&&this.builtins[t].has(e)}getVertexIndex(){return"vertex"===this.shaderStage?this.getBuiltin("vertex_index","vertexIndex","u32","attribute"):"vertexIndex"}buildFunctionCode(e){const t=e.layout,s=this.flowShaderNode(e),i=[];for(const e of t.inputs)i.push(e.name+" : "+this.getType(e.type));let r=`fn ${t.name}( ${i.join(", ")} ) -> ${this.getType(t.type)} {\n${s.vars}\n${s.code}\n`;return s.result&&(r+=`\treturn ${s.result};\n`),r+="\n}\n",r}getInstanceIndex(){return"vertex"===this.shaderStage?this.getBuiltin("instance_index","instanceIndex","u32","attribute"):"instanceIndex"}getInvocationLocalIndex(){return this.getBuiltin("local_invocation_index","invocationLocalIndex","u32","attribute")}getSubgroupSize(){return this.enableSubGroups(),this.getBuiltin("subgroup_size","subgroupSize","u32","attribute")}getInvocationSubgroupIndex(){return this.enableSubGroups(),this.getBuiltin("subgroup_invocation_id","invocationSubgroupIndex","u32","attribute")}getSubgroupIndex(){return this.enableSubGroups(),this.getBuiltin("subgroup_id","subgroupIndex","u32","attribute")}getDrawIndex(){return null}getFrontFacing(){return this.getBuiltin("front_facing","isFront","bool")}getFragCoord(){return this.getBuiltin("position","fragCoord","vec4")+".xy"}getFragDepth(){return"output."+this.getBuiltin("frag_depth","depth","f32","output")}isFlipY(){return!1}enableDirective(e,t=this.shaderStage){(this.directives[t]||(this.directives[t]=new Set)).add(e)}getDirectives(e){const t=[],s=this.directives[e];if(void 0!==s)for(const e of s)t.push(`enable ${e};`);return t.join("\n")}enableSubGroups(){this.enableDirective("subgroups")}enableSubgroupsF16(){this.enableDirective("subgroups-f16")}enableClipDistances(){this.enableDirective("clip_distances")}enableShaderF16(){this.enableDirective("f16")}enableDualSourceBlending(){this.enableDirective("dual_source_blending")}getBuiltins(e){const t=[],s=this.builtins[e];if(void 0!==s)for(const{name:e,property:i,type:r}of s.values())t.push(`@builtin( ${e} ) ${i} : ${r}`);return t.join(",\n\t")}getScopedArray(e,t,s,i){return!1===this.scopedArrays.has(e)&&this.scopedArrays.set(e,{name:e,scope:t,bufferType:s,bufferCount:i}),e}getScopedArrays(e){if("compute"!==e)return;const t=[];for(const{name:e,scope:s,bufferType:i,bufferCount:r}of this.scopedArrays.values()){const n=this.getType(i);t.push(`var<${s}> ${e}: array< ${n}, ${r} >;`)}return t.join("\n")}getAttributes(e){const t=[];if("compute"===e&&(this.getBuiltin("global_invocation_id","id","vec3","attribute"),this.getBuiltin("workgroup_id","workgroupId","vec3","attribute"),this.getBuiltin("local_invocation_id","localId","vec3","attribute"),this.getBuiltin("num_workgroups","numWorkgroups","vec3","attribute"),this.renderer.hasFeature("subgroups")&&(this.enableDirective("subgroups",e),this.getBuiltin("subgroup_size","subgroupSize","u32","attribute"))),"vertex"===e||"compute"===e){const e=this.getBuiltins("attribute");e&&t.push(e);const s=this.getAttributesArray();for(let e=0,i=s.length;e`)}const i=this.getBuiltins("output");return i&&t.push("\t"+i),t.join(",\n")}getStructs(e){const t=[],s=this.structs[e];for(let e=0,i=s.length;e output : ${r};\n\n`)}return t.join("\n\n")}getVar(e,t){return`var ${t} : ${this.getType(e)}`}getVars(e){const t=[],s=this.vars[e];if(void 0!==s)for(const e of s)t.push(`\t${this.getVar(e.type,e.name)};`);return`\n${t.join("\n")}\n`}getVaryings(e){const t=[];if("vertex"===e&&this.getBuiltin("position","Vertex","vec4","vertex"),"vertex"===e||"fragment"===e){const s=this.varyings,i=this.vars[e];for(let r=0;r";else if(!0===t.isDataArrayTexture||!0===t.isCompressedArrayTexture)i="texture_2d_array";else if(!0===t.isDepthTexture)i=`texture_depth${n}_2d`;else if(!0===t.isVideoTexture)i="texture_external";else if(!0===t.isData3DTexture)i="texture_3d";else if(!0===r.node.isStorageTextureNode){i=`texture_storage_2d<${aF(t)}, ${this.getStorageAccess(r.node)}>`}else{i=`texture${n}_2d<${this.getComponentTypeFromTexture(t).charAt(0)}32>`}s.push(`@binding( ${o.binding++} ) @group( ${o.group} ) var ${r.name} : ${i};`)}else if("buffer"===r.type||"storageBuffer"===r.type){const e=r.node,t=this.getType(e.bufferType),s=e.bufferCount,n=s>0?", "+s:"",a=e.isAtomic?`atomic<${t}>`:`${t}`,h=`\t${r.name} : array< ${a}${n} >\n`,u=e.isStorageBufferNode?`storage, ${this.getStorageAccess(e)}`:"uniform";i.push(this._getWGSLStructBinding("NodeBuffer_"+e.id,h,u,o.binding++,o.group))}else{const e=this.getType(this.getVectorType(r.type)),t=r.groupNode.name;(n[t]||(n[t]={index:o.binding++,id:o.group,snippets:[]})).snippets.push(`\t${r.name} : ${e}`)}}for(const e in n){const t=n[e];r.push(this._getWGSLStructBinding(e,t.snippets.join(",\n"),"uniform",t.index,t.id))}let o=s.join("\n");return o+=i.join("\n"),o+=r.join("\n"),o}buildCode(){const e=null!==this.material?{fragment:{},vertex:{}}:{compute:{}};this.sortBindingGroups();for(const t in e){const s=e[t];s.uniforms=this.getUniforms(t),s.attributes=this.getAttributes(t),s.varyings=this.getVaryings(t),s.structs=this.getStructs(t),s.vars=this.getVars(t),s.codes=this.getCodes(t),s.directives=this.getDirectives(t),s.scopedArrays=this.getScopedArrays(t);let i="// code\n\n";i+=this.flowCode[t];const r=this.flowNodes[t],n=r[r.length-1],o=n.outputNode,a=void 0!==o&&!0===o.isOutputStructNode;for(const e of r){const r=this.getFlowData(e),h=e.name;if(h&&(i.length>0&&(i+="\n"),i+=`\t// flow -> ${h}\n\t`),i+=`${r.code}\n\t`,e===n&&"compute"!==t)if(i+="// result\n\n\t","vertex"===t)i+=`varyings.Vertex = ${r.result};`;else if("fragment"===t)if(a)s.returnType=o.nodeType,i+=`return ${r.result};`;else{let e="\t@location(0) color: vec4";const t=this.getBuiltins("output");t&&(e+=",\n\t"+t),s.returnType="OutputStruct",s.structs+=this._getWGSLStruct("OutputStruct",e),s.structs+="\nvar output : OutputStruct;\n\n",i+=`output.color = ${r.result};\n\n\treturn output;`}}s.flow=i}null!==this.material?(this.vertexShader=this._getWGSLVertexCode(e.vertex),this.fragmentShader=this._getWGSLFragmentCode(e.fragment)):this.computeShader=this._getWGSLComputeCode(e.compute,(this.object.workgroupSize||[64]).join(", "))}getMethod(e,t=null){let s;return null!==t&&(s=this._getWGSLMethod(e+"_"+t)),void 0===s&&(s=this._getWGSLMethod(e)),s||e}getType(e){return yF[e]||e}isAvailable(e){let t=gF[e];return void 0===t&&("float32Filterable"===e&&(t=this.renderer.hasFeature("float32-filterable")),gF[e]=t),t}_getWGSLMethod(e){return void 0!==xF[e]&&this._include(e),bF[e]}_include(e){const t=xF[e];return t.build(this),null!==this.currentFunctionNode&&this.currentFunctionNode.includes.push(t),t}_getWGSLVertexCode(e){return`${this.getSignature()}\n// directives\n${e.directives}\n\n// uniforms\n${e.uniforms}\n\n// varyings\n${e.varyings}\nvar varyings : VaryingsStruct;\n\n// codes\n${e.codes}\n\n@vertex\nfn main( ${e.attributes} ) -> VaryingsStruct {\n\n\t// vars\n\t${e.vars}\n\n\t// flow\n\t${e.flow}\n\n\treturn varyings;\n\n}\n`}_getWGSLFragmentCode(e){return`${this.getSignature()}\n// global\n${vF}\n\n// uniforms\n${e.uniforms}\n\n// structs\n${e.structs}\n\n// codes\n${e.codes}\n\n@fragment\nfn main( ${e.varyings} ) -> ${e.returnType} {\n\n\t// vars\n\t${e.vars}\n\n\t// flow\n\t${e.flow}\n\n}\n`}_getWGSLComputeCode(e,t){return`${this.getSignature()}\n// directives\n${e.directives}\n\n// system\nvar instanceIndex : u32;\n\n// locals\n${e.scopedArrays}\n\n// uniforms\n${e.uniforms}\n\n// codes\n${e.codes}\n\n@compute @workgroup_size( ${t} )\nfn main( ${e.attributes} ) {\n\n\t// system\n\tinstanceIndex = id.x + id.y * numWorkgroups.x * u32(${t}) + id.z * numWorkgroups.x * numWorkgroups.y * u32(${t});\n\n\t// vars\n\t${e.vars}\n\n\t// flow\n\t${e.flow}\n\n}\n`}_getWGSLStruct(e,t){return`\nstruct ${e} {\n${t}\n};`}_getWGSLStructBinding(e,t,s,i=0,r=0){const n=e+"Struct";return`${this._getWGSLStruct(n,t)}\n@binding( ${i} ) @group( ${r} )\nvar<${s}> ${e} : ${n};`}}class _F{constructor(e){this.backend=e}getCurrentDepthStencilFormat(e){let t;return null!==e.depthTexture?t=this.getTextureFormatGPU(e.depthTexture):e.depth&&e.stencil?t=qN.Depth24PlusStencil8:e.depth&&(t=qN.Depth24Plus),t}getTextureFormatGPU(e){return this.backend.get(e).format}getCurrentColorFormat(e){let t;return t=null!==e.textures?this.getTextureFormatGPU(e.textures[0]):this.getPreferredCanvasFormat(),t}getCurrentColorSpace(e){return null!==e.textures?e.textures[0].colorSpace:this.backend.renderer.outputColorSpace}getPrimitiveTopology(e,t){return e.isPoints?SN:e.isLineSegments||e.isMesh&&!0===t.wireframe?MN:e.isLine?NN:e.isMesh?AN:void 0}getSampleCount(e){let t=1;return e>1&&(t=Math.pow(2,Math.floor(Math.log2(e))),2===t&&(t=4)),t}getSampleCountRenderContext(e){return null!==e.textures?this.getSampleCount(e.sampleCount):this.getSampleCount(this.backend.renderer.samples)}getPreferredCanvasFormat(){return navigator.userAgent.includes("Quest")?qN.BGRA8Unorm:navigator.gpu.getPreferredCanvasFormat()}}const wF=new Map([[Int8Array,["sint8","snorm8"]],[Uint8Array,["uint8","unorm8"]],[Int16Array,["sint16","snorm16"]],[Uint16Array,["uint16","unorm16"]],[Int32Array,["sint32","snorm32"]],[Uint32Array,["uint32","unorm32"]],[Float32Array,["float32"]]]),SF=new Map([[xn,["float16"]]]),MF=new Map([[Int32Array,"sint32"],[Int16Array,"sint32"],[Uint32Array,"uint32"],[Uint16Array,"uint32"],[Float32Array,"float32"]]);class NF{constructor(e){this.backend=e}createAttribute(e,t){const s=this._getBufferAttribute(e),i=this.backend,r=i.get(s);let n=r.buffer;if(void 0===n){const o=i.device;let a=s.array;if(!1===e.normalized&&(a.constructor===Int16Array||a.constructor===Uint16Array)){const e=new Uint32Array(a.length);for(let t=0;t1},layout:u.createPipelineLayout({bindGroupLayouts:d})};if(null===t)c.pipeline=u.createRenderPipeline(M);else{const e=new Promise((e=>{u.createRenderPipelineAsync(M).then((t=>{c.pipeline=t,e()}))}));t.push(e)}}createBundleEncoder(e){const t=this.backend,{utils:s,device:i}=t,r=s.getCurrentDepthStencilFormat(e),n={label:"renderBundleEncoder",colorFormats:[s.getCurrentColorFormat(e)],depthStencilFormat:r,sampleCount:this._getSampleCount(e)};return i.createRenderBundleEncoder(n)}createComputePipeline(e,t){const s=this.backend,i=s.device,r=s.get(e.computeProgram).module,n=s.get(e),o=[];for(const e of t){const t=s.get(e);o.push(t.layout)}n.pipeline=i.createComputePipeline({compute:r,layout:i.createPipelineLayout({bindGroupLayouts:o})})}_getBlending(e){let t,s;const i=e.blending,r=e.blendSrc,n=e.blendDst,o=e.blendEquation;if(5===i){const i=null!==e.blendSrcAlpha?e.blendSrcAlpha:r,a=null!==e.blendDstAlpha?e.blendDstAlpha:n,h=null!==e.blendEquationAlpha?e.blendEquationAlpha:o;t={srcFactor:this._getBlendFactor(r),dstFactor:this._getBlendFactor(n),operation:this._getBlendOperation(o)},s={srcFactor:this._getBlendFactor(i),dstFactor:this._getBlendFactor(a),operation:this._getBlendOperation(h)}}else{const r=(e,i,r,n)=>{t={srcFactor:e,dstFactor:i,operation:cA},s={srcFactor:r,dstFactor:n,operation:cA}};if(e.premultipliedAlpha)switch(i){case 1:r(QN,iA,QN,iA);break;case 2:r(QN,QN,QN,QN);break;case 3:r(KN,tA,KN,QN);break;case 4:r(KN,eA,KN,sA)}else switch(i){case 1:r(sA,iA,QN,iA);break;case 2:r(sA,QN,sA,QN);break;case 3:r(KN,tA,KN,QN);break;case 4:r(KN,eA,KN,eA)}}if(void 0!==t&&void 0!==s)return{color:t,alpha:s};console.error("THREE.WebGPURenderer: Invalid blending: ",i)}_getBlendFactor(e){let t;switch(e){case 200:t=KN;break;case 201:t=QN;break;case 202:t=eA;break;case 203:t=tA;break;case R:t=sA;break;case E:t=iA;break;case 208:t=rA;break;case 209:t=nA;break;case 206:t=oA;break;case 207:t=aA;break;case 210:t=hA;break;case 211:t=uA;break;case 212:t=lA;break;default:console.error("THREE.WebGPURenderer: Blend factor not supported.",e)}return t}_getStencilCompare(e){let t;const s=e.stencilFunc;switch(s){case 512:t=RN;break;case bs:t=UN;break;case 513:t=EN;break;case 515:t=IN;break;case 514:t=BN;break;case 518:t=zN;break;case 516:t=PN;break;case 517:t=FN;break;default:console.error("THREE.WebGPURenderer: Invalid stencil function.",s)}return t}_getStencilOperation(e){let t;switch(e){case ns:t=xA;break;case 0:t=bA;break;case 7681:t=vA;break;case 5386:t=TA;break;case 7682:t=_A;break;case 7683:t=wA;break;case 34055:t=SA;break;case 34056:t=MA;break;default:console.error("THREE.WebGPURenderer: Invalid stencil operation.",t)}return t}_getBlendOperation(e){let t;switch(e){case v:t=cA;break;case 101:t=dA;break;case 102:t=pA;break;case 103:t=mA;break;case 104:t=gA;break;default:console.error("THREE.WebGPUPipelineUtils: Blend equation not supported.",e)}return t}_getPrimitiveState(e,t,s){const i={},r=this.backend.utils;switch(i.topology=r.getPrimitiveTopology(e,s),null!==t.index&&!0===e.isLine&&!0!==e.isLineSegments&&(i.stripIndexFormat=t.index.array instanceof Uint16Array?jN:HN),s.side){case c:i.frontFace=DN,i.cullMode=WN;break;case d:i.frontFace=DN,i.cullMode=GN;break;case 2:i.frontFace=DN,i.cullMode=kN;break;default:console.error("THREE.WebGPUPipelineUtils: Unknown material.side value.",s.side)}return i}_getColorWriteMask(e){return!0===e.colorWrite?yA:fA}_getDepthCompare(e){let t;if(!1===e.depthTest)t=UN;else{const s=e.depthFunc;switch(s){case 0:t=RN;break;case 1:t=UN;break;case 2:t=EN;break;case 3:t=IN;break;case 4:t=BN;break;case 5:t=zN;break;case 6:t=PN;break;case 7:t=FN;break;default:console.error("THREE.WebGPUPipelineUtils: Invalid depth function.",s)}}return t}}class RF extends PP{constructor(e={}){super(e),this.isWebGPUBackend=!0,this.parameters.alpha=void 0===e.alpha||e.alpha,this.parameters.requiredLimits=void 0===e.requiredLimits?{}:e.requiredLimits,this.trackTimestamp=!0===e.trackTimestamp,this.device=null,this.context=null,this.colorBuffer=null,this.defaultRenderPassdescriptor=null,this.utils=new _F(this),this.attributeUtils=new NF(this),this.bindingUtils=new AF(this),this.pipelineUtils=new CF(this),this.textureUtils=new oF(this),this.occludedResolveCache=new Map}async init(e){await super.init(e);const t=this.parameters;let s;if(void 0===t.device){const e={powerPreference:t.powerPreference},i=await navigator.gpu.requestAdapter(e);if(null===i)throw new Error("WebGPUBackend: Unable to create WebGPU adapter.");const r=Object.values(jA),n=[];for(const e of r)i.features.has(e)&&n.push(e);const o={requiredFeatures:n,requiredLimits:t.requiredLimits};s=await i.requestDevice(o)}else s=t.device;const i=void 0!==t.context?t.context:e.domElement.getContext("webgpu");this.device=s,this.context=i;const r=t.alpha?"premultiplied":"opaque";this.trackTimestamp=this.trackTimestamp&&this.hasFeature(jA.TimestampQuery),this.context.configure({device:this.device,format:this.utils.getPreferredCanvasFormat(),usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC,alphaMode:r}),this.updateSize()}get coordinateSystem(){return Ds}async getArrayBufferAsync(e){return await this.attributeUtils.getArrayBufferAsync(e)}getContext(){return this.context}_getDefaultRenderPassDescriptor(){let e=this.defaultRenderPassdescriptor;if(null===e){const t=this.renderer;e={colorAttachments:[{view:null}],depthStencilAttachment:{view:this.textureUtils.getDepthBuffer(t.depth,t.stencil).createView()}};const s=e.colorAttachments[0];this.renderer.samples>0?s.view=this.colorBuffer.createView():s.resolveTarget=void 0,this.defaultRenderPassdescriptor=e}const t=e.colorAttachments[0];return this.renderer.samples>0?t.resolveTarget=this.context.getCurrentTexture().createView():t.view=this.context.getCurrentTexture().createView(),e}_getRenderPassDescriptor(e){const t=e.renderTarget,s=this.get(t);let i=s.descriptors;if(void 0===i||s.width!==t.width||s.height!==t.height||s.activeMipmapLevel!==t.activeMipmapLevel||s.samples!==t.samples){i={},s.descriptors=i;const e=()=>{t.removeEventListener("dispose",e),this.delete(t)};t.addEventListener("dispose",e)}const r=e.getCacheKey();let n=i[r];if(void 0===n){const o=e.textures,a=[];for(let t=0;t0&&(t.currentOcclusionQuerySet&&t.currentOcclusionQuerySet.destroy(),t.currentOcclusionQueryBuffer&&t.currentOcclusionQueryBuffer.destroy(),t.currentOcclusionQuerySet=t.occlusionQuerySet,t.currentOcclusionQueryBuffer=t.occlusionQueryBuffer,t.currentOcclusionQueryObjects=t.occlusionQueryObjects,r=s.createQuerySet({type:"occlusion",count:i}),t.occlusionQuerySet=r,t.occlusionQueryIndex=0,t.occlusionQueryObjects=new Array(i),t.lastOcclusionObject=null),n=null===e.textures?this._getDefaultRenderPassDescriptor():this._getRenderPassDescriptor(e),this.initTimestampQuery(e,n),n.occlusionQuerySet=r;const o=n.depthStencilAttachment;if(null!==e.textures){const t=n.colorAttachments;for(let s=0;s0&&t.currentPass.executeBundles(t.renderBundles),s>t.occlusionQueryIndex&&t.currentPass.endOcclusionQuery(),t.currentPass.end(),s>0){const i=8*s;let r=this.occludedResolveCache.get(i);void 0===r&&(r=this.device.createBuffer({size:i,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),this.occludedResolveCache.set(i,r));const n=this.device.createBuffer({size:i,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});t.encoder.resolveQuerySet(t.occlusionQuerySet,0,s,r,0),t.encoder.copyBufferToBuffer(r,0,n,0,i),t.occlusionQueryBuffer=n,this.resolveOccludedAsync(e)}if(this.prepareTimestampBuffer(e,t.encoder),this.device.queue.submit([t.encoder.finish()]),null!==e.textures){const t=e.textures;for(let e=0;eo?(h.x=Math.min(t.dispatchCount,o),h.y=Math.ceil(t.dispatchCount/o)):h.x=t.dispatchCount,r.dispatchWorkgroups(h.x,h.y,h.z)}finishCompute(e){const t=this.get(e);t.passEncoderGPU.end(),this.prepareTimestampBuffer(e,t.cmdEncoderGPU),this.device.queue.submit([t.cmdEncoderGPU.finish()])}draw(e,t){const{object:s,context:i,pipeline:r}=e,n=e.getBindings(),o=this.get(i),a=this.get(r).pipeline,h=o.currentSets,u=o.currentPass,l=e.getDrawParameters();if(null===l)return;h.pipeline!==a&&(u.setPipeline(a),h.pipeline=a);const c=h.bindingGroups;for(let e=0,t=n.length;e1?0:s;u.drawIndexed(t[s],i,e[s]/n,0,o)}}else if(!0===p){const{vertexCount:e,instanceCount:i,firstVertex:r}=l;u.drawIndexed(e,i,r,0,0),t.update(s,e,i)}else{const{vertexCount:e,instanceCount:i,firstVertex:r}=l;u.draw(e,i,r,0),t.update(s,e,i)}}needsRenderUpdate(e){const t=this.get(e),{object:s,material:i}=e,r=this.utils,n=r.getSampleCountRenderContext(e.context),o=r.getCurrentColorSpace(e.context),a=r.getCurrentColorFormat(e.context),h=r.getCurrentDepthStencilFormat(e.context),u=r.getPrimitiveTopology(s,i);let l=!1;return t.material===i&&t.materialVersion===i.version&&t.transparent===i.transparent&&t.blending===i.blending&&t.premultipliedAlpha===i.premultipliedAlpha&&t.blendSrc===i.blendSrc&&t.blendDst===i.blendDst&&t.blendEquation===i.blendEquation&&t.blendSrcAlpha===i.blendSrcAlpha&&t.blendDstAlpha===i.blendDstAlpha&&t.blendEquationAlpha===i.blendEquationAlpha&&t.colorWrite===i.colorWrite&&t.depthWrite===i.depthWrite&&t.depthTest===i.depthTest&&t.depthFunc===i.depthFunc&&t.stencilWrite===i.stencilWrite&&t.stencilFunc===i.stencilFunc&&t.stencilFail===i.stencilFail&&t.stencilZFail===i.stencilZFail&&t.stencilZPass===i.stencilZPass&&t.stencilFuncMask===i.stencilFuncMask&&t.stencilWriteMask===i.stencilWriteMask&&t.side===i.side&&t.alphaToCoverage===i.alphaToCoverage&&t.sampleCount===n&&t.colorSpace===o&&t.colorFormat===a&&t.depthStencilFormat===h&&t.primitiveTopology===u&&t.clippingContextCacheKey===e.clippingContext.cacheKey||(t.material=i,t.materialVersion=i.version,t.transparent=i.transparent,t.blending=i.blending,t.premultipliedAlpha=i.premultipliedAlpha,t.blendSrc=i.blendSrc,t.blendDst=i.blendDst,t.blendEquation=i.blendEquation,t.blendSrcAlpha=i.blendSrcAlpha,t.blendDstAlpha=i.blendDstAlpha,t.blendEquationAlpha=i.blendEquationAlpha,t.colorWrite=i.colorWrite,t.depthWrite=i.depthWrite,t.depthTest=i.depthTest,t.depthFunc=i.depthFunc,t.stencilWrite=i.stencilWrite,t.stencilFunc=i.stencilFunc,t.stencilFail=i.stencilFail,t.stencilZFail=i.stencilZFail,t.stencilZPass=i.stencilZPass,t.stencilFuncMask=i.stencilFuncMask,t.stencilWriteMask=i.stencilWriteMask,t.side=i.side,t.alphaToCoverage=i.alphaToCoverage,t.sampleCount=n,t.colorSpace=o,t.colorFormat=a,t.depthStencilFormat=h,t.primitiveTopology=u,t.clippingContextCacheKey=e.clippingContext.cacheKey,l=!0),l}getRenderCacheKey(e){const{object:t,material:s}=e,i=this.utils,r=e.context;return[s.transparent,s.blending,s.premultipliedAlpha,s.blendSrc,s.blendDst,s.blendEquation,s.blendSrcAlpha,s.blendDstAlpha,s.blendEquationAlpha,s.colorWrite,s.depthWrite,s.depthTest,s.depthFunc,s.stencilWrite,s.stencilFunc,s.stencilFail,s.stencilZFail,s.stencilZPass,s.stencilFuncMask,s.stencilWriteMask,s.side,i.getSampleCountRenderContext(r),i.getCurrentColorSpace(r),i.getCurrentColorFormat(r),i.getCurrentDepthStencilFormat(r),i.getPrimitiveTopology(t,s),e.clippingContext.cacheKey].join()}createSampler(e){this.textureUtils.createSampler(e)}destroySampler(e){this.textureUtils.destroySampler(e)}createDefaultTexture(e){this.textureUtils.createDefaultTexture(e)}createTexture(e,t){this.textureUtils.createTexture(e,t)}updateTexture(e,t){this.textureUtils.updateTexture(e,t)}generateMipmaps(e){this.textureUtils.generateMipmaps(e)}destroyTexture(e){this.textureUtils.destroyTexture(e)}copyTextureToBuffer(e,t,s,i,r,n){return this.textureUtils.copyTextureToBuffer(e,t,s,i,r,n)}initTimestampQuery(e,t){if(!this.trackTimestamp)return;const s=this.get(e);if(!s.timeStampQuerySet){const e=this.device.createQuerySet({type:"timestamp",count:2}),i={querySet:e,beginningOfPassWriteIndex:0,endOfPassWriteIndex:1};Object.assign(t,{timestampWrites:i}),s.timeStampQuerySet=e}}prepareTimestampBuffer(e,t){if(!this.trackTimestamp)return;const s=this.get(e),i=2*BigInt64Array.BYTES_PER_ELEMENT;void 0===s.currentTimestampQueryBuffers&&(s.currentTimestampQueryBuffers={resolveBuffer:this.device.createBuffer({label:"timestamp resolve buffer",size:i,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),resultBuffer:this.device.createBuffer({label:"timestamp result buffer",size:i,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),isMappingPending:!1});const{resolveBuffer:r,resultBuffer:n,isMappingPending:o}=s.currentTimestampQueryBuffers;!0!==o&&(t.resolveQuerySet(s.timeStampQuerySet,0,2,r,0),t.copyBufferToBuffer(r,0,n,0,i))}async resolveTimestampAsync(e,t="render"){if(!this.trackTimestamp)return;const s=this.get(e);if(void 0===s.currentTimestampQueryBuffers)return;const{resultBuffer:i,isMappingPending:r}=s.currentTimestampQueryBuffers;!0!==r&&(s.currentTimestampQueryBuffers.isMappingPending=!0,i.mapAsync(GPUMapMode.READ).then((()=>{const e=new BigUint64Array(i.getMappedRange()),r=Number(e[1]-e[0])/1e6;this.renderer.info.updateTimestamp(t,r),i.unmap(),s.currentTimestampQueryBuffers.isMappingPending=!1})))}createNodeBuilder(e,t){return new TF(e,t)}createProgram(e){this.get(e).module={module:this.device.createShaderModule({code:e.code,label:e.stage}),entryPoint:"main"}}destroyProgram(e){this.delete(e)}createRenderPipeline(e,t){this.pipelineUtils.createRenderPipeline(e,t)}createComputePipeline(e,t){this.pipelineUtils.createComputePipeline(e,t)}beginBundle(e){const t=this.get(e);t._currentPass=t.currentPass,t._currentSets=t.currentSets,t.currentSets={attributes:{},bindingGroups:[],pipeline:null,index:null},t.currentPass=this.pipelineUtils.createBundleEncoder(e)}finishBundle(e,t){const s=this.get(e),i=s.currentPass.finish();this.get(t).bundleGPU=i,s.currentSets=s._currentSets,s.currentPass=s._currentPass}addBundle(e,t){this.get(e).renderBundles.push(this.get(t).bundleGPU)}createBindings(e){this.bindingUtils.createBindings(e)}updateBindings(e){this.bindingUtils.createBindings(e)}updateBinding(e){this.bindingUtils.updateBinding(e)}createIndexAttribute(e){this.attributeUtils.createAttribute(e,GPUBufferUsage.INDEX|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST)}createAttribute(e){this.attributeUtils.createAttribute(e,GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST)}createStorageAttribute(e){this.attributeUtils.createAttribute(e,GPUBufferUsage.STORAGE|GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST)}updateAttribute(e){this.attributeUtils.updateAttribute(e)}destroyAttribute(e){this.attributeUtils.destroyAttribute(e)}updateSize(){this.colorBuffer=this.textureUtils.getColorBuffer(),this.defaultRenderPassdescriptor=null}getMaxAnisotropy(){return 16}hasFeature(e){return this.device.features.has(e)}copyTextureToTexture(e,t,s=null,i=null,r=0){let n=0,o=0,a=0,h=0,u=0,l=0,c=e.image.width,d=e.image.height;null!==s&&(h=s.x,u=s.y,l=s.z||0,c=s.width,d=s.height),null!==i&&(n=i.x,o=i.y,a=i.z||0);const p=this.device.createCommandEncoder({label:"copyTextureToTexture_"+e.id+"_"+t.id}),m=this.get(e).texture,g=this.get(t).texture;p.copyTextureToTexture({texture:m,mipLevel:r,origin:{x:h,y:u,z:l}},{texture:g,mipLevel:r,origin:{x:n,y:o,z:a}},[c,d,1]),this.device.queue.submit([p.finish()])}copyFramebufferToTexture(e,t,s){const i=this.get(t),{encoder:r,descriptor:n}=i;let o=null;o=t.renderTarget?e.isDepthTexture?this.get(t.depthTexture).texture:this.get(t.textures[0]).texture:e.isDepthTexture?this.textureUtils.getDepthBuffer(t.depth,t.stencil):this.context.getCurrentTexture();const a=this.get(e).texture;if(o.format===a.format){i.currentPass.end(),r.copyTextureToTexture({texture:o,origin:{x:s.x,y:s.y,z:0}},{texture:a},[s.z,s.w]),e.generateMipmaps&&this.textureUtils.generateMipmaps(e);for(let e=0;e(console.warn("THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend."),new JP(e)));super(new t(e),e),this.nodes.library=new BF,this.isWebGPURenderer=!0}}const PF=new pT,FF=new dN(PF);class zF{constructor(e,t=Xp(0,0,1,1)){this.renderer=e,this.outputNode=t,this.outputColorTransform=!0,this.needsUpdate=!0,PF.name="PostProcessing"}render(){this.update();const e=this.renderer,t=e.toneMapping,s=e.outputColorSpace;e.toneMapping=0,e.outputColorSpace=Jt,FF.render(e),e.toneMapping=t,e.outputColorSpace=s}update(){if(!0===this.needsUpdate){const e=this.renderer,t=e.toneMapping,s=e.outputColorSpace;FF.material.fragmentNode=!0===this.outputColorTransform?Ty(this.outputNode,t,s):this.outputNode.context({toneMapping:t,outputColorSpace:s}),FF.material.needsUpdate=!0,this.needsUpdate=!1}}async renderAsync(){this.update();const e=this.renderer,t=e.toneMapping,s=e.outputColorSpace;e.toneMapping=0,e.outputColorSpace=Jt,await FF.renderAsync(e),e.toneMapping=t,e.outputColorSpace=s}}class UF extends vi{constructor(e=1,t=1){super(),this.image={width:e,height:t},this.magFilter=Te,this.minFilter=Te,this.isStorageTexture=!0}}class OF extends ln{constructor(e,t,s=Float32Array){!1===ArrayBuffer.isView(e)&&(e=new s(e*t)),super(e,t),this.isStorageBufferAttribute=!0}}class LF extends Do{constructor(e,t,s=Float32Array){!1===ArrayBuffer.isView(e)&&(e=new s(e*t)),super(e,t),this.isStorageInstancedBufferAttribute=!0}}class VF extends tl{constructor(e){super(e),this.textures={},this.nodes={}}load(e,t,s,i){const r=new rl(this.manager);r.setPath(this.path),r.setRequestHeader(this.requestHeader),r.setWithCredentials(this.withCredentials),r.load(e,(s=>{try{t(this.parse(JSON.parse(s)))}catch(t){i?i(t):console.error(t),this.manager.itemError(e)}}),s,i)}parseNodes(e){const t={};if(void 0!==e){for(const s of e){const{uuid:e,type:i}=s;t[e]=this.createNodeFromType(i),t[e].uuid=e}const s={nodes:t,textures:this.textures};for(const i of e){i.meta=s;t[i.uuid].deserialize(i),delete i.meta}}return t}parse(e){const t=this.createNodeFromType(e.type);t.uuid=e.uuid;const s={nodes:this.parseNodes(e.nodes),textures:this.textures};return e.meta=s,t.deserialize(e),delete e.meta,t}setTextures(e){return this.textures=e,this}setNodes(e){return this.nodes=e,this}createNodeFromType(e){return void 0===this.nodes[e]?(console.error("THREE.NodeLoader: Node type not found:",e),Up()):Sp(new this.nodes[e])}}class DF extends Bl{constructor(e){super(e),this.nodes={},this.nodeMaterials={}}parse(e){const t=super.parse(e),s=this.nodes,i=e.inputNodes;for(const e in i){const r=i[e];t[e]=s[r]}return t}setNodes(e){return this.nodes=e,this}setNodeMaterials(e){return this.nodeMaterials=e,this}createMaterialFromType(e){const t=this.nodeMaterials[e];return void 0!==t?new t:super.createMaterialFromType(e)}}class kF extends zl{constructor(e){super(e),this.nodes={},this.nodeMaterials={},this._nodesJSON=null}setNodes(e){return this.nodes=e,this}setNodeMaterials(e){return this.nodeMaterials=e,this}parse(e,t){this._nodesJSON=e.nodes;const s=super.parse(e,t);return this._nodesJSON=null,s}parseNodes(e,t){if(void 0!==e){const s=new VF;return s.setNodes(this.nodes),s.setTextures(t),s.parseNodes(e)}return{}}parseMaterials(e,t){const s={};if(void 0!==e){const i=this.parseNodes(this._nodesJSON,t),r=new DF;r.setTextures(t),r.setNodes(i),r.setNodeMaterials(this.nodeMaterials);for(let t=0,i=e.length;t[method:Float getVolume]()

[method:this play]( delay )

+ delay (optional) - The delay, in seconds, at which the audio should start playing.
If [page:Audio.hasPlaybackControl hasPlaybackControl] is true, starts playback.

@@ -244,8 +245,9 @@

[method:this setPlaybackRate]( [param:Float value] )

[method:this setVolume]( [param:Float value] )

Set the volume.

-

[method:this stop]()

+

[method:this stop]( delay )

+ delay (optional) - The delay, in seconds, at which the audio should stop playing.
If [page:Audio.hasPlaybackControl hasPlaybackControl] is enabled, stops playback.

diff --git a/docs/api/en/materials/LineBasicMaterial.html b/docs/api/en/materials/LineBasicMaterial.html index 8efaf0b1be3fd4..3f24c3b601a688 100644 --- a/docs/api/en/materials/LineBasicMaterial.html +++ b/docs/api/en/materials/LineBasicMaterial.html @@ -69,7 +69,9 @@

[property:Float linewidth]

Due to limitations of the [link:https://www.khronos.org/registry/OpenGL/specs/gl/glspec46.core.pdf OpenGL Core Profile] with the [page:WebGLRenderer WebGL] renderer on most - platforms linewidth will always be `1` regardless of the set value. + platforms linewidth will always be `1` regardless of the set value.

+ + If you need wider lines, consider using [page:Line2] or [page:LineSegments2] with [page:LineMaterial].

[property:String linecap]

diff --git a/docs/api/en/math/Triangle.html b/docs/api/en/math/Triangle.html index 4e7a055f4ca1ac..4ddadd8bfb026f 100644 --- a/docs/api/en/math/Triangle.html +++ b/docs/api/en/math/Triangle.html @@ -140,6 +140,20 @@

triangle. Returns `null` if the triangle is degenerate.

+

+ [method:Vector getInterpolatedAttribute]( [param:BufferAttribute attribute], [param:Number i1], [param:Vector3 i2], [param:Number i3], [param:Vector3 barycoord], [param:Vector3 target] ) +

+

+ [page:BufferAttribute attribute] - The attribute to interpolate.
+ p1 - Index of first vertex.
+ p2 - Index of second vertex.
+ p3 - Index of third vertex.
+ barycoord - The barycoordinate value to use to interpolate.
+ [page:Vector target] — Result will be copied into this Vector.

+ + Returns the value barycentrically interpolated for the given attribute and indices. +

+

[method:Boolean intersectsBox]( [param:Box3 box] )

[page:Box3 box] - Box to check for intersection against.

diff --git a/docs/api/en/objects/BatchedMesh.html b/docs/api/en/objects/BatchedMesh.html index 417ef92361ade1..1b59384361dc47 100644 --- a/docs/api/en/objects/BatchedMesh.html +++ b/docs/api/en/objects/BatchedMesh.html @@ -167,7 +167,28 @@

[page:Integer instanceId]: The id of an instance to get the visibility state of.

-

Get whether the given instance is marked as "visible" or not.

+

Get whether the given instance is marked as "visible" or not.

+ +

+ [method:Object getGeometryRangeAt]( [param:Integer geometryId], [param:Object target] ) +

+

+ [page:Integer geometryId]: The id of the geometry to get the range of. +

+

+ [page:Object target]: Optional target object to copy the range in to. +

+

Get the range representing the subset of triangles related to the attached geometry, indicating the starting offset and count, or `null` if invalid.

+

Return an object of the form:

+ { start: Integer, count: Integer } + +

+ [method:Integer getGeometryIdAt]( [param:Integer instanceId] ) +

+

+ [page:Integer instanceId]: The id of an instance to get the geometryIndex of. +

+

Get the geometryIndex of the defined instance.

[method:undefined setColorAt]( [param:Integer instanceId], [param:Color color] ) @@ -207,6 +228,19 @@

Sets the visibility of the instance at the given index.

+

+ [method:this setGeometryIdAt]( [param:Integer instanceId], [param:Integer geometryId] ) +

+

+ [page:Integer instanceId]: The id of the instance to set the geometryIndex of. +

+

+ [page:Integer geometryId]: The geometryIndex to be use by the instance. +

+

+ Sets the geometryIndex of the instance at the given index. +

+

[method:Integer addGeometry]( [param:BufferGeometry geometry], [param:Integer reservedVertexRange], [param:Integer reservedIndexRange] )

@@ -237,6 +271,15 @@

Adds a new instance to the [name] using the geometry of the given geometryId and returns a new id referring to the new instance to be used by other functions.

+

+ [method:Integer deleteInstance]( [param:Integer instanceId] ) +

+

+ [page:Integer instanceId]: The id of an instance to remove from the [name] that was previously added via "addInstance". +

+

+ Removes an existing instance from the [name] using the given instanceId. +

[method:Integer setGeometryAt]( [param:Integer geometryId], [param:BufferGeometry geometry] ) diff --git a/docs/api/en/objects/LOD.html b/docs/api/en/objects/LOD.html index 314420e229fe16..49aec0cf64560a 100644 --- a/docs/api/en/objects/LOD.html +++ b/docs/api/en/objects/LOD.html @@ -85,6 +85,15 @@

Adds a mesh that will display at a certain distance and greater. Typically the further away the distance, the lower the detail on the mesh.

+

+ [method:Boolean removeLevel]( [param:Float distance]) +

+

+ distance - Distance of the level to delete.

+ + Removes an existing level, based on the distance from the camera. + Returns `true` when the level has been removed. Otherwise `false`. +

[method:Integer getCurrentLevel]()

Get the currently active LOD level. As index of the levels array.

diff --git a/docs/api/en/renderers/WebGLRenderer.html b/docs/api/en/renderers/WebGLRenderer.html index 8a453696ec1a10..0b085051595cde 100644 --- a/docs/api/en/renderers/WebGLRenderer.html +++ b/docs/api/en/renderers/WebGLRenderer.html @@ -75,6 +75,9 @@

[name]( [param:Object parameters] )

[link:https://www.khronos.org/opengl/wiki/Early_Fragment_Test Early Fragment Test] optimization and can cause a decrease in performance. Default is `false`. See the [example:webgl_camera_logarithmicdepthbuffer camera / logarithmicdepthbuffer] example. + + [page:Boolean reverseDepthBuffer] - whether to use a reverse depth buffer. Requires the `EXT_clip_control` extension. + This is a more faster and accurate version than logarithmic depth buffer. Default is `false`.

Properties

@@ -119,9 +122,7 @@

[property:Object capabilities]

- [page:Boolean isWebGL2]: `true` if the context in use is a WebGL2RenderingContext object.
- [page:Boolean logarithmicDepthBuffer]: `true` if the [page:parameter logarithmicDepthBuffer] - was set to true in the constructor and the context - supports the - [link:https://developer.mozilla.org/en-US/docs/Web/API/EXT_frag_depth EXT_frag_depth] extension.
+ was set to true in the constructor.
- [page:Integer maxAttributes]: The value of `gl.MAX_VERTEX_ATTRIBS`.
- [page:Integer maxCubemapSize]: The value of `gl.MAX_CUBE_MAP_TEXTURE_SIZE`. Maximum height * width of cube map @@ -145,6 +146,9 @@

[property:Object capabilities]

be used in a vertex shader.
- [page:String precision]: The shader precision currently being used by the renderer.
+ - [page:Boolean reverseDepthBuffer]: `true` if the [page:parameter reverseDepthBuffer] + was set to `true` in the constructor and the context + supports the [link:https://registry.khronos.org/webgl/extensions/EXT_clip_control/ EXT_clip_control] extension.
- [page:Boolean vertexTextures]: `true` if [property:Integer maxVertexTextures] is greater than 0 (i.e. vertex textures can be used).

diff --git a/docs/api/zh/extras/TextureUtils.html b/docs/api/zh/extras/TextureUtils.html new file mode 100644 index 00000000000000..1aec64d138bc02 --- /dev/null +++ b/docs/api/zh/extras/TextureUtils.html @@ -0,0 +1,42 @@ + + + + + + + + + +

[name]

+ +

包含纹理实用函数的类。

+ +

方法

+ +

[method:Texture contain]( [param:Texture texture], [param:Number aspect] )

+

+ 在不裁剪或拉伸纹理的情况下,将纹理在其表面内缩放到尽可能大。该方法保留了纹理的原始纵横比。类似于 CSS 中的 `object-fit: contain`。 +

+ +

[method:Texture cover]( [param:Texture texture], [param:Number aspect] )

+

+ 将纹理缩放到尽可能小的尺寸以填充表面,不留空白。该方法保留了纹理的原始纵横比。类似于 CSS 中的 `object-fit: cover`。 +

+ +

[method:Texture fill]( [param:Texture texture] )

+

+ 将纹理配置为默认转换。类似于 CSS 中的 `object-fit: fill`。 +

+ +

[method:Number getByteLength]( [param:Number width], [param:Number height], [param:Number format], [param:Number type] )

+

+ 给定纹理的宽度、高度、格式和类型。确定必须使用多少个字节来表示纹理。 +

+ +

源代码

+ +

+ [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] +

+ + diff --git a/docs/api/zh/objects/InstancedMesh.html b/docs/api/zh/objects/InstancedMesh.html index 83ea9ce4fae6aa..46d1fd31700c7d 100644 --- a/docs/api/zh/objects/InstancedMesh.html +++ b/docs/api/zh/objects/InstancedMesh.html @@ -34,7 +34,7 @@

[name]( [param:BufferGeometry geometry], [param:Material material], [param:I

属性

-

See the base [page:Mesh] class for common properties.

+

公共属性请查看基类 [page:Mesh]。

[property:Box3 boundingBox]

@@ -67,14 +67,19 @@

[property:InstancedBufferAttribute instanceMatrix]

如果你要通过 [page:.setMatrixAt]() 来修改实例数据,你必须将它的 [page:BufferAttribute.needsUpdate needsUpdate] 标识为 true 。

+

[property:DataTexture morphTexture]

+

+ 用于表示所有实例的变形权重。如果你通过 [page:.setMorphAt]() 修改了实例数据,你必须将 [page:Texture.needsUpdate needsUpdate] 标识设置为 true。 +

+

[property:Boolean isInstancedMesh]

- Read-only flag to check if a given object is of type [name]. + 用来检查对象是否属于 [name] 类型的只读标识。

方法

-

See the base [page:Mesh] class for common methods.

+

公共方法请查看基类 [page:Mesh]。

[method:undefined computeBoundingBox]()

@@ -90,18 +95,18 @@

[method:undefined computeBoundingSphere]()

[method:undefined dispose]()

- Frees the internal resources of this instance. + 释放实例的内部资源。

[method:undefined getColorAt]( [param:Integer index], [param:Color color] )

- [page:Integer index]: The index of an instance. Values have to be in the range [0, count]. + [page:Integer index]: 实例的索引。 值必须在 [0, count] 区间。

- [page:Color color]: This color object will be set to the color of the defined instance. + [page:Color color]: 传入的颜色对象将会被设置为指定的实例的颜色。

- Get the color of the defined instance. + 获取已定义实例的颜色。

[method:undefined getMatrixAt]( [param:Integer index], [param:Matrix4 matrix] )

@@ -115,16 +120,26 @@

[method:undefined getMatrixAt]( [param:Integer index], [param:Matrix4 matrix 获得已定义实例的本地变换矩阵。

+

+ [method:undefined getMorphAt]( [param:Integer index], [param:Mesh mesh] ) +

+

+ [page:Integer index]: 实例的索引。值必须在 [0, count] 区间。 +

+

+ [page:Mesh mesh]: 网格属性 [page:Mesh.morphTargetInfluences .morphTargetInfluences] 将会被填充为已定义实例的变形权重。 +

+

获取已定义实例的变形权重

+

[method:undefined setColorAt]( [param:Integer index], [param:Color color] )

- [page:Integer index]: The index of an instance. Values have to be in the range [0, count]. + [page:Integer index]: 实例的索引。值必须在 [0, count] 区间。

- [page:Color color]: The color of a single instance. + [page:Color color]: 单个实例的颜色。

- Sets the given color to the defined instance. - Make sure you set [page:.instanceColor][page:BufferAttribute.needsUpdate .needsUpdate] to true after updating all the colors. + 设置已定义实例的颜色。请确保在更新颜色后将 [page:.instanceColor][page:BufferAttribute.needsUpdate .needsUpdate] 标识设置为 true。

[method:undefined setMatrixAt]( [param:Integer index], [param:Matrix4 matrix] )

@@ -139,6 +154,19 @@

[method:undefined setMatrixAt]( [param:Integer index], [param:Matrix4 matrix 请确保在更新所有矩阵后将 [page:.instanceMatrix][page:BufferAttribute.needsUpdate .needsUpdate] 设置为true。

+

+ [method:undefined setMorphAt]( [param:Integer index], [param:Mesh mesh] ) +

+

+ [page:Integer index]: 实例的索引。值必须在 [0, count] 区间。 +

+

+ [page:Mesh mesh]: 网格属性 [page:Mesh.morphTargetInfluences .morphTargetInfluences] 包含了单个实例的变形权重。 +

+

+ 设置已定义实例的变形权重。请确保在更新所有变形数据后将 [page:.morphTexture][page:Texture.needsUpdate .needsUpdate] 设置为 true。 +

+

源代码

diff --git a/docs/examples/en/controls/DragControls.html b/docs/examples/en/controls/DragControls.html index 8671d98c049004..cb6ddd78119173 100644 --- a/docs/examples/en/controls/DragControls.html +++ b/docs/examples/en/controls/DragControls.html @@ -127,21 +127,6 @@

Methods

See the base [page:Controls] class for common methods.

-

[method:undefined connect] ()

-

- Adds the event listeners of the controls. -

- -

[method:undefined disconnect] ()

-

- Removes the event listeners of the controls. -

- -

[method:undefined dispose] ()

-

- Should be called if the controls is no longer required. -

-

Source

diff --git a/docs/examples/en/controls/TransformControls.html b/docs/examples/en/controls/TransformControls.html index 334ca36614f04c..8b826c89935d7a 100644 --- a/docs/examples/en/controls/TransformControls.html +++ b/docs/examples/en/controls/TransformControls.html @@ -7,7 +7,7 @@ - [page:Object3D] → + [page:Controls] →

[name]

@@ -41,7 +41,7 @@

[name]( [param:Camera camera], [param:HTMLDOMElement domElement] )

[page:Camera camera]: The camera of the rendered scene.

- [page:HTMLDOMElement domElement]: The HTML element used for event listeners. + [page:HTMLDOMElement domElement]: The HTML element used for event listeners. (optional)

Creates a new instance of [name]. @@ -73,7 +73,7 @@

objectChange

Properties

-

See the base [page:Object3D] class for common properties.

+

See the base [page:Controls] class for common properties.

[property:String axis]

@@ -85,32 +85,16 @@

[property:Camera camera]

The camera of the rendered scene.

-

[property:HTMLDOMElement domElement]

-

- The HTMLDOMElement used to listen for mouse / touch events. This must be passed in the constructor; changing it here will - not set up new event listeners. -

-

[property:Boolean dragging]

Whether or not dragging is currently performed. Read-only property.

-

[property:Boolean enabled]

-

- Whether or not the controls are enabled. -

-

[property:String mode]

The current transformation mode. Possible values are "translate", "rotate" and "scale". Default is `translate`.

-

[property:Object3D object]

-

- The 3D object being controlled. -

-

[property:Number rotationSnap]

By default, 3D objects are continuously rotated. If you set this property to a numeric value (radians), you can define in which @@ -150,7 +134,7 @@

[property:Number translationSnap]

Methods

-

See the base [page:Object3D] class for common methods.

+

See the base [page:Controls] class for common methods.

[method:TransformControls attach] ( [param:Object3D object] )

@@ -167,9 +151,10 @@

[method:TransformControls detach] ()

Removes the current 3D object from the controls and makes the helper UI invisible.

-

[method:undefined dispose] ()

+

[method:Object3D getHelper] ()

- Should be called if the controls is no longer required. + Returns the visual representation of the controls. Add the helper to your scene to visually transform the attached + 3D object.

[method:Raycaster getRaycaster] ()

diff --git a/docs/examples/en/geometries/SDFGeometryGenerator.html b/docs/examples/en/geometries/SDFGeometryGenerator.html deleted file mode 100644 index a7c256c10e3b3a..00000000000000 --- a/docs/examples/en/geometries/SDFGeometryGenerator.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - -

[name]

- -

- [name] generates instances of [page:BufferGeometry] from a Signed Distance Function
- Uses Mikola Lysenko's Isosurface -

- -

Import

- -

- [name] is an add-on, and must be imported explicitly. - See [link:#manual/introduction/Installation Installation / Addons]. -

- - - import { SDFGeometryGenerator } from 'three/addons/geometries/SDFGeometryGenerator.js'; - - -

Code Example

- - - const generator = new SDFGeometryGenerator( renderer ); - const sdf = 'float dist( vec3 p ){ return length(p) - 0.5; }' // glsl - const geometry = generator.generate( 64, sdf, 1 ); // ~> THREE.BufferGeometry - - -

Examples

- -

[example:webgl_geometry_sdf geometry / sdf ]

- -

Constructor

- -

[name]( [param:WebGLRenderer renderer] )

- -

- [page:WebGLRenderer renderer] -- The renderer used to render the scene.
-

- -

Methods

- -

[method:BufferGeometry generate]( [param:Int resolution], [param:String distanceField], [param:Int bounds] )

- -

- resolution - Int [ mandatory ] Amount of 'voxels' used for triangulation. Must be power of 2.
Gets heavy after 256, most machines won't be able to process over 512. Defaults to 64. -

-

- distanceField - String [ mandatory ] String with glsl distance function. Name of function must be 'dist', with a vec3 argument. ( see code above ). Defaults to a sphere distance. -

-

- bounds - Int [ optional ] Bounds in which signed distance field will be evaluated. Defaults to 1. -

- - -

Source

- -

- [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/SDFGeometry.js examples/jsm/geometries/SDFGeometryGenerator.js] -

- - diff --git a/docs/examples/en/geometries/TeapotGeometry.html b/docs/examples/en/geometries/TeapotGeometry.html index 4d2e8050b4bdfa..03668f86f3ba56 100644 --- a/docs/examples/en/geometries/TeapotGeometry.html +++ b/docs/examples/en/geometries/TeapotGeometry.html @@ -60,8 +60,7 @@

Methods

Source

- [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/TeapotGeometry.js - examples/jsm/geometries/TeapotGeometry.js] + [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/TeapotGeometry.js examples/jsm/geometries/TeapotGeometry.js]

diff --git a/docs/examples/en/lines/Line2.html b/docs/examples/en/lines/Line2.html new file mode 100644 index 00000000000000..41c484d2a7690a --- /dev/null +++ b/docs/examples/en/lines/Line2.html @@ -0,0 +1,65 @@ + + + + + + + + + + [page:Object3D] → [page:Mesh] → [page:LineSegments2] → + +

[name]

+ +

+ A polyline drawn between vertices. +

+ +

+ This adds functionality beyond [page:Line], like arbitrary line width and changing width to be in world units. + It extends [page:LineSegments2], simplifying constructing segments from a chain of points. +

+ +

Import

+ +

+ [name] is an add-on, and therefore must be imported explicitly. + See [link:#manual/introduction/Installation Installation / Addons]. +

+ + + import { Line2 } from 'three/addons/lines/Line2.js'; + + +

Examples

+ +

+ [example:webgl_lines_fat WebGL / lines / fat ]
+ [example:webgl_lines_fat_raycasting WebGL / lines / fat / raycasting ]
+ [example:webgpu_lines_fat WebGPU / lines / fat / raycasting ] +

+ +

Constructor

+ +

[name]( [param:LineGeometry geometry], [param:LineMaterial material] )

+

+ [page:LineGeometry geometry] — (optional) Pair(s) of vertices representing each line segment.
+ [page:Material material] — (optional) Material for the line. Default is a [page:LineMaterial] with random color. +

+ +

Properties

+

See the base [page:LineSegments2] class for common properties.

+ +

[property:Boolean isLine2]

+

Read-only flag to check if a given object is of type [name].

+ +

Methods

+

See the base [page:LineSegments2] class for common methods.

+ +

Source

+ +

+ [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/lines/Line2.js examples/jsm/lines/Line2.js] +

+ + diff --git a/docs/examples/en/lines/LineGeometry.html b/docs/examples/en/lines/LineGeometry.html new file mode 100644 index 00000000000000..d1a3ff370e036d --- /dev/null +++ b/docs/examples/en/lines/LineGeometry.html @@ -0,0 +1,84 @@ + + + + + + + + + + [page:BufferGeometry] → [page:InstancedBufferGeometry] → [page:LineSegmentsGeometry] → + +

[name]

+ +

+ A chain of vertices, forming a polyline. +

+ +

+ This is used in [page:Line2] to describe the shape. +

+ +

Import

+ +

+ [name] is an add-on, and therefore must be imported explicitly. + See [link:#manual/introduction/Installation Installation / Addons]. +

+ + + import { LineGeometry } from 'three/addons/lines/LineGeometry.js'; + + +

Examples

+ +

+ [example:webgl_lines_fat WebGL / lines / fat ]
+ [example:webgl_lines_fat_raycasting WebGL / lines / fat / raycasting ]
+ [example:webgpu_lines_fat WebGPU / lines / fat / raycasting ] +

+ +

Constructor

+ +

[name]()

+

+ Creates a new geometry. + Call [page:LineGeometry.setPositions setPositions] to add segments. +

+ +

Properties

+

See the base [page:LineSegmentsGeometry] class for common properties.

+ +

[property:Boolean isLineGeometry]

+

Read-only flag to check if a given object is of type [name].

+ +

Methods

+

See the base [page:LineSegmentsGeometry] class for common methods.

+ +

[method:this fromLine]( [param:Line line] )

+

+ Copy the vertex positions of a [page:Line] object into this geometry. + Assumes the source geometry is not using indices. +

+ +

[method:this setColors]( [param:Array array] )

+

+ Replace the per-vertex colors. + Every triple describes a line vertex: `[r1, g1, b1]`. + The array can be an `Array` or `Float32Array`. +

+ +

[method:this setPositions]( [param:Array array] )

+

+ Replace the vertex positions with a new set. + The array can be an `Array` or `Float32Array`. + The length must be a multiple of three. +

+ +

Source

+ +

+ [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/lines/LineGeometry.js examples/jsm/lines/LineGeometry.js] +

+ + diff --git a/docs/examples/en/lines/LineMaterial.html b/docs/examples/en/lines/LineMaterial.html new file mode 100644 index 00000000000000..d988ad641df6d6 --- /dev/null +++ b/docs/examples/en/lines/LineMaterial.html @@ -0,0 +1,92 @@ + + + + + + + + + + [page:Material] → [page:ShaderMaterial] → + +

[name]

+ +

+ A material for drawing wireframe-style geometries. + Unlike [page:LineBasicMaterial], it supports arbitrary line widths and allows using world units instead of screen space units. + This material is used with [page:LineSegments2] and [page:Line2]. +

+ +

+ Lines are always rendered with round caps and round joints. +

+ +

Examples

+

+ [example:webgl_lines_fat WebGL / lines / fat ]
+ [example:webgl_lines_fat_raycasting WebGL / lines / fat / raycasting ]
+ [example:webgl_lines_fat_wireframe WebGL / lines / fat / wireframe ]
+ [example:webgpu_lines_fat WebGPU / lines / fat / raycasting ] +

+ +

Constructor

+

[name]( [param:Object parameters] )

+ +

+ [page:Object parameters] - (optional) an object with one or more properties defining the material's appearance. + Any property of the material (including any property inherited from [page:ShaderMaterial]) can be passed in here. +

+ +

+ The exception is the property [page:Hexadecimal color], which can be passed in as a number or hexadecimal string and is `0xffffff` (white) by default. + [page:Color.set]( color ) is called internally. +

+ +

Properties

+

See the base [page:ShaderMaterial] class for common properties.

+ +

[property:Color color]

+

[page:Color] of the material, by default set to white (0xffffff).

+ +

[property:Boolean dashed]

+

Whether the line is dashed, or solid. Default is `false`.

+ +

[property:number dashOffset]

+

Where in the dash cycle the dash starts. Default is `0`.

+ +

[property:number dashScale]

+

The scale of the dashes and gaps. Default is `1`.

+ +

[property:number dashSize]

+

The size of the dash. Default is `1`.

+ +

[property:number gapSize]

+

The size of the gap. Default is `1`.

+ +

[property:Float linewidth]

+

Controls line thickness. Default is `1`.

+ +

[property:Vector2 resolution]

+

+ The size of the viewport, in screen pixels. + This must be kept updated to make screen-space rendering accurate. + The [page:LineSegments2.onBeforeRender] callback performs the update for visible objects. + Default is `[1, 1]`. +

+ +

[property:Boolean worldUnits]

+

+ Whether the material's sizes (width, dash gaps) are in world units. + Default is `false` (screen space units.) +

+ +

Methods

+

See the base [page:ShaderMaterial] class for common methods.

+ +

Source

+ +

+ [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/lines/LineMaterial.js examples/jsm/lines/LineMaterial.js] +

+ + diff --git a/docs/examples/en/lines/LineSegments2.html b/docs/examples/en/lines/LineSegments2.html new file mode 100644 index 00000000000000..ae32f9d8d2f17c --- /dev/null +++ b/docs/examples/en/lines/LineSegments2.html @@ -0,0 +1,69 @@ + + + + + + + + + + [page:Object3D] → [page:Mesh] → + +

[name]

+ +

+ A series of lines drawn between pairs of vertices. +

+ +

+ This adds functionality beyond [page:LineSegments], like arbitrary line width and changing width to be in world units. + The [page:Line2] extends this object, forming a polyline instead of individual segments. +

+ +

Import

+ +

+ [name] is an add-on, and therefore must be imported explicitly. + See [link:#manual/introduction/Installation Installation / Addons]. +

+ + + import { LineSegments2 } from 'three/addons/lines/LineSegments2.js'; + + +

Example

+ +

[example:webgl_lines_fat_raycasting WebGL / lines / fat / raycasting ]

+ +

Constructor

+ +

[name]( [param:LineSegmentsGeometry geometry], [param:LineMaterial material] )

+

+ [page:LineSegmentsGeometry geometry] — (optional) Pair(s) of vertices representing each line segment.
+ [page:Material material] — (optional) Material for the line. Default is a [page:LineMaterial] with random color. +

+ +

Properties

+

See the base [page:Mesh] class for common properties.

+ +

[property:Boolean isLineSegments2]

+

Read-only flag to check if a given object is of type [name].

+ +

Methods

+

See the base [page:Mesh] class for common methods.

+ +

[method:undefined onBeforeRender]( [param:WebGLRenderer renderer] )

+

+ Called by the framework to update the material's resolution property, needed for screen-scaled widths. +

+

+ If your object is not visible to a camera (e.g. by [page:Object3D.layers layers] or [page:Object3D.visible visible],) you must call this manually whenever the viewport changes. +

+ +

Source

+ +

+ [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/lines/LineSegments2.js examples/jsm/lines/LineSegments2.js] +

+ + diff --git a/docs/examples/en/lines/LineSegmentsGeometry.html b/docs/examples/en/lines/LineSegmentsGeometry.html new file mode 100644 index 00000000000000..56e81af1859ec7 --- /dev/null +++ b/docs/examples/en/lines/LineSegmentsGeometry.html @@ -0,0 +1,103 @@ + + + + + + + + + + [page:BufferGeometry] → [page:InstancedBufferGeometry] → + +

[name]

+ +

+ A series of vertex pairs, forming line segments. +

+ +

+ This is used in [page:LineSegments2] to describe the shape. +

+ +

Import

+ +

+ [name] is an add-on, and therefore must be imported explicitly. + See [link:#manual/introduction/Installation Installation / Addons]. +

+ + + import { LineSegmentsGeometry } from 'three/addons/lines/LineSegmentsGeometry.js'; + + +

Example

+ +

[example:webgl_lines_fat_raycasting WebGL / lines / fat / raycasting ]

+ +

Constructor

+ +

[name]()

+

+ Creates a new geometry. + Call [page:LineSegmentsGeometry.setPositions setPositions] to add segments. +

+ +

Properties

+

See the base [page:InstancedBufferGeometry] class for common properties.

+ +

[property:Boolean isLineSegmentsGeometry]

+

Read-only flag to check if a given object is of type [name].

+ +

Methods

+

See the base [page:Mesh] class for common methods.

+ +

[method:this fromEdgesGeometry]( [param:EdgesGeometry geometry] )

+

+ Copy the vertex positions of an edge geometry into this geometry. +

+ +

[method:this fromLineSegments]( [param:LineSegments lineSegments] )

+

+ Copy the vertex positions of a [page:LineSegments] object into this geometry. + Assumes the source geometry is not using indices. +

+ +

[method:this fromMesh]( [param:Mesh mesh] )

+

+ Copy the vertex positions of a mesh object into this geometry. +

+ +

[method:this fromWireframeGeometry]( [param:WireframeGeometry geometry] )

+

+ Copy the vertex positions of a wireframe geometry into this geometry. +

+ +

[method:this setColors]( [param:Array array] )

+

+ Replace the per-vertex colors. + Every sixtuple describes a segment: `[r1, g1, b1, r2, g2, b2]`. + The array can be an `Array` or `Float32Array`. +

+ +

[method:this setPositions]( [param:Array array] )

+

+ Replace the vertex positions with a new set. + The array can be an `Array` or `Float32Array`. + The length must be a multiple of six. +

+

+ See also [page:LineSegmentsGeometry.positions positions]. +

+ +

[method:undefined toJSON]()

+

+ Unimplemented. +

+ +

Source

+ +

+ [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/lines/LineSegmentsGeometry.js examples/jsm/lines/LineSegmentsGeometry.js] +

+ + diff --git a/docs/examples/ko/controls/MapControls.html b/docs/examples/ko/controls/MapControls.html new file mode 100644 index 00000000000000..51963bd66cdcaf --- /dev/null +++ b/docs/examples/ko/controls/MapControls.html @@ -0,0 +1,122 @@ + + + + + + + + + + + + [page:OrbitControls] → + +

[name]

+ +

+ [name]은 지도 위에서 조망자의 시각으로 카메라를 이동하기 위해 설계되었습니다. + 이 클래스는 [page:OrbitControls]와 같은 구현을 공유하지만 특정한 마우스/터치 상호작용 프리셋을 사용하고 기본적으로 화면 공간 패닝을 비활성화합니다. +

+ +

가져오기

+ +

+ [name]은 애드온으로서 명시적으로 가져와야 합니다. + [link:#manual/introduction/Installation 설치 / 애드온]을 참조하십시오. +

+ + + import { MapControls } from 'three/addons/controls/MapControls.js'; + + +

코드 예제

+ + + const renderer = new THREE.WebGLRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + document.body.appendChild( renderer.domElement ); + + const scene = new THREE.Scene(); + + const camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.set( 0, 20, 100 ); + + const controls = new MapControls( camera, renderer.domElement ); + controls.enableDamping = true; + + function animate() { + + requestAnimationFrame( animate ); + + // controls.enableDamping 또는 controls.autoRotate가 true로 설정된 경우 필수 + controls.update(); + + renderer.render( scene, camera ); + + } + + +

예제

+ +

[example:misc_controls_map misc / controls / map ]

+ +

생성자

+ +

[name]( [param:Camera object], [param:HTMLDOMElement domElement] )

+

+ [page:Camera object]: (필수) 제어할 카메라입니다. 카메라는 다른 객체의 자식이어서는 안 되며, 그 객체가 스케인 자체가 아니라면 됩니다.

+ + [page:HTMLDOMElement domElement]: 이벤트 리스너에 사용되는 HTML 요소입니다. +

+ +

이벤트

+ +

공통 이벤트를 보기 위해 기본 [page:OrbitControls] 클래스를 참조하십시오.

+ +

속성

+ +

공통 속성을 보기 위해 기본 [page:OrbitControls] 클래스를 참조하십시오.

+ +

+ [property:Object mouseButtons]

+

+ 이 객체에는 컨트롤에 의해 사용되는 마우스 동작에 대한 참조가 포함되어 있습니다. + +controls.mouseButtons = { + LEFT: THREE.MOUSE.PAN, + MIDDLE: THREE.MOUSE.DOLLY, + RIGHT: THREE.MOUSE.ROTATE +} + +

+ +

[property:Boolean screenSpacePanning]

+

+ 패닝 시 카메라 위치가 어떻게 이동되는지 정의합니다. 만약 true이면, 카메라는 화면 공간에서 패닝합니다. + 그렇지 않으면, 카메라는 카메라의 위 방향에 수직인 평면에서 패닝합니다. + 기본값은 `false`입니다. +

+ +

[property:Object touches]

+

+ 이 객체에는 컨트롤에 의해 사용되는 터치 동작에 대한 참조가 포함되어 있습니다. + +controls.touches = { + ONE: THREE.TOUCH.PAN, + TWO: THREE.TOUCH.DOLLY_ROTATE +} + +

+ +

메서드

+ +

공통 메서드를 보기 위해 기본 [page:OrbitControls] 클래스를 참조하십시오.

+ +

소스

+ +

+ [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/MapControls.js examples/jsm/controls/MapControls.js] +

+ + + \ No newline at end of file diff --git a/docs/examples/ko/webxr/XREstimatedLight.html b/docs/examples/ko/webxr/XREstimatedLight.html new file mode 100644 index 00000000000000..0f55ff1c1282f1 --- /dev/null +++ b/docs/examples/ko/webxr/XREstimatedLight.html @@ -0,0 +1,117 @@ + + + + + + + + + + + + [page:Group] → + +

[name]

+ +

+ XREstimatedLight은 WebXR의 빛 추정 기능을 사용하여 광도계(light probe), 방향광(directional light) 그리고 (선택적으로) 환경 맵(environment + map)을 생성하여 사용자의 현실 세계의 환경과 조명을 모델링합니다.
+ WebXR가 빛과 환경 추정을 업데이트할 때, XREstimatedLight는 자동으로 광도계, 방향광, 그리고 환경 맵을 업데이트합니다.

+ + WebXR 세션을 생성할 때 `light-estimation`을 선택적 또는 필수 기능으로 지정하는 것이 중요합니다. 그렇지 않으면 빛 추정 기능은 작동하지 않습니다.

+ + 브라우저 호환성 정보는 여기를 참조하십시오. 이는 아직 WebXR의 실험적 기능입니다. 여기

+ + 이를 사용하려면, /examples 디렉토리 내의 모든 파일과 마찬가지로, HTML에 별도로 파일을 포함해야 합니다. +

+ +

가져오기

+ +

+ [name]은 애드온이므로 명시적으로 가져와야 합니다. + [link:#manual/introduction/Installation 설치 / 애드온]을 참조하십시오. +

+ + + import { XREstimatedLight } from 'three/addons/webxr/XREstimatedLight.js'; + + +

코드 예제

+ + + renderer.xr.enabled = true; + + // XREstimatedLight를 초기 시점에 장면에 추가하지 마세요. + // AR 세션이 시작할 때까지 추정된 조명값이 없기 때문입니다. + const xrLight = new XREstimatedLight( renderer ); + + xrLight.addEventListener( 'estimationstart' , () => { + + scene.add( xrLight ); + + if ( xrLight.environment ) { + + scene.environment = xrLight.environment; + + } + + } ); + + xrLight.addEventListener( 'estimationend', () => { + + scene.remove( xrLight ); + + scene.environment = null; + + } ); + + // 조명 추정 기능을 작동하도록 하려면 'light-estimation'을 선택적 또는 필수 기능으로 포함해야 합니다. + document.body.appendChild( XRButton.createButton( renderer, { + optionalFeatures: [ 'light-estimation' ] + } ) ); + + +

예제

+ +

[example:webxr_ar_lighting webxr / light estimation]

+ +

생성자

+ +

[name]( [param:WebGLRenderer renderer], [param:Boolean environmentEstimation] )

+

+ [page:WebGLRenderer renderer]: (필수) 장면을 렌더링하는 렌더러. 주로 WebXRManager와 상호작용하는 데 사용됩니다.

+ + environmentEstimation: `true`로 설정하면 WebXR을 사용하여 환경 맵을 추정합니다. +

+ +

이벤트

+ +

estimationstart

+

+ 추정된 조명값이 업데이트 시작할 때 발생합니다. +

+ +

estimationend

+

+ 추정된 조명값이 업데이트 중지할 때 발생합니다. +

+ +

속성

+ +

[property:Texture environment]

+

+ WebXR에 의해 추정된 환경 맵입니다. 이는 environmentEstimation이 `true`로 설정된 경우에만 사용할 수 있습니다.

+ + 이는 [page:Scene.environment], [page:MeshStandardMaterial.envMap], 또는 [page:Scene.background]로 사용할 수 있습니다. +

+ +

소스

+ +

+ [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/webxr/XREstimatedLight.js + examples/jsm/webxr/XREstimatedLight.js] +

+ + + \ No newline at end of file diff --git a/docs/examples/zh/controls/DragControls.html b/docs/examples/zh/controls/DragControls.html index e0795737498230..b3051c45a53f56 100644 --- a/docs/examples/zh/controls/DragControls.html +++ b/docs/examples/zh/controls/DragControls.html @@ -129,21 +129,6 @@

方法

共有方法请参见其基类[page:Controls]。

-

[method:undefined connect] ()

-

- 添加控制器的事件监听。 -

- -

[method:undefined disconnect] ()

-

- 移除控制器的事件监听。 -

- -

[method:undefined dispose] ()

-

- 若不再需要该控制器,则应当调用此函数。 -

-

源代码

diff --git a/docs/examples/zh/controls/OrbitControls.html b/docs/examples/zh/controls/OrbitControls.html index 9e611a278ce096..2d1fd24fdfd2c4 100644 --- a/docs/examples/zh/controls/OrbitControls.html +++ b/docs/examples/zh/controls/OrbitControls.html @@ -7,6 +7,8 @@ + [page:Controls] → +

轨道控制器([name])

@@ -67,7 +69,7 @@

[name]( [param:Camera object], [param:HTMLDOMElement domElement] )

[page:Camera object]: (必须)将要被控制的相机。该相机不允许是其他任何对象的子级,除非该对象是场景自身。

- [page:HTMLDOMElement domElement]: 用于事件监听的HTML元素。 + [page:HTMLDOMElement domElement]: 用于事件监听的HTML元素。(可选)

Events

@@ -89,12 +91,13 @@

end

属性

+

共有属性请参见其基类[page:Controls]。

+

[property:Boolean autoRotate]

将其设为true,以自动围绕目标旋转。
请注意,如果它被启用,你必须在你的动画循环里调用[page:.update]()。 - Set to true to automatically rotate around the target.
Note that if this is enabled, you must call [page:.update] - () in your animation loop. If you want the auto-rotate speed to be independent of the frame rate (the refresh rate of the display), you must pass the time `deltaTime`, in seconds, to [page:.update](). + 如果希望自动旋转速度与帧速率(显示器的刷新率)无关,则必须将时间 `deltaTime`(以秒为单位)传递给 [page:.update]()。

[property:Float autoRotateSpeed]

@@ -110,16 +113,6 @@

请注意,要使得这一值生效,你必须在你的动画循环里调用[page:.update]()。

-

[property:HTMLDOMElement domElement]

-

- 该 HTMLDOMElement 用于监听鼠标/触摸事件,该属性必须在构造函数中传入。在此处改变它将不会设置新的事件监听。 -

- -

[property:Boolean enabled]

-

- 当设置为false时,控制器将不会响应用户的操作。默认值为true。 -

-

[property:Boolean enableDamping]

将其设置为true以启用阻尼(惯性),这将给控制器带来重量感。默认值为false。
@@ -177,6 +170,11 @@

[property:Float maxPolarAngle]

你能够垂直旋转的角度的上限,范围是0到Math.PI,其默认值为Math.PI。

+

[property:Float maxTargetRadius]

+

+ 你能够让目标移动离 [page:.cursor] 有多远,其默认值为Infinity。 +

+

[property:Float maxZoom]

你能够将相机缩小多少(仅适用于[page:OrthographicCamera]),其默认值为Infinity。 @@ -197,6 +195,11 @@

[property:Float minPolarAngle]

你能够垂直旋转的角度的下限,范围是0到Math.PI,其默认值为0。

+

[property:Float minTargetRadius]

+

+ 你能够让目标移动离 [page:.cursor] 有多近,其默认值为0。 +

+

[property:Float minZoom]

你能够将相机放大多少(仅适用于[page:OrthographicCamera]),其默认值为0。 @@ -215,11 +218,6 @@

-

[property:Camera object]

-

- 正被控制的摄像机。 -

-

[property:Float panSpeed]

位移的速度,其默认值为1。 @@ -253,6 +251,11 @@

[property:Vector3 target]

它可以在任何时候被手动更新,以更改控制器的焦点。

+

[property:Vector3 cursor]

+

+ 被 [page:.minTargetRadius] 和 [page:.maxTargetRadius] 限制的焦点。可随时手动更新以更改 [page:.target] 的兴趣中心。 +

+

[property:Object touches]

该对象包含由控件所使用的触摸操作的引用。 @@ -276,15 +279,12 @@

[property:Float zoomSpeed]

[property:Boolean zoomToCursor]

- Setting this property to `true` allows to zoom to the cursor's position. Default is `false`. + 将此属性设置为 `true` 可以缩放至光标位置。默认值为 `false`。

-

Methods

+

方法

-

[method:undefined dispose] ()

-

- 移除所有的事件监听。 -

+

共有方法请参见其基类[page:Controls]。

[method:radians getAzimuthalAngle] ()

@@ -298,7 +298,7 @@

[method:radians getPolarAngle] ()

[method:Float getDistance] ()

- Returns the distance from the camera to the target. + 返回从相机到目标的距离。

[method:undefined listenToKeyEvents] ( [param:HTMLDOMElement domElement] )

@@ -323,11 +323,7 @@

[method:undefined stopListenToKeyEvents] ()

[method:Boolean update] ( [param:Number deltaTime] )

- 更新控制器。必须在摄像机的变换发生任何手动改变后调用, - 或如果[page:.autoRotate]或[page:.enableDamping]被设置时,在update循环里调用。 - Update the controls. Must be called after any manual changes to the camera's transform, - or in the update loop if [page:.autoRotate] or [page:.enableDamping] are set. `deltaTime`, in seconds, is optional, - and is only required if you want the auto-rotate speed to be independent of the frame rate (the refresh rate of the display). + 更新控制器。必须在摄像机的变换发生任何手动改变后调用,或如果[page:.autoRotate]或[page:.enableDamping]被设置时,在update循环里调用。`deltaTime` 以秒为单位,是可选的,并且仅当您希望自动旋转速度独立于帧速率(显示器的刷新率)时才是必需的。

源代码

diff --git a/docs/examples/zh/controls/PointerLockControls.html b/docs/examples/zh/controls/PointerLockControls.html index cd9814fe7d6981..08429e2c131d27 100644 --- a/docs/examples/zh/controls/PointerLockControls.html +++ b/docs/examples/zh/controls/PointerLockControls.html @@ -102,6 +102,11 @@

[property:Float minPolarAngle]

摄像机的俯仰角下限限制。范围为0到Math.PI弧度之间。默认值为0。

+

[property:Float pointerSpeed]

+

+ 指针移动对相机旋转的影响程度的乘数。默认值为1。 +

+

方法

共有方法请参见其基类[page:Controls]。

diff --git a/docs/examples/zh/controls/TrackballControls.html b/docs/examples/zh/controls/TrackballControls.html index 64a013505ed5aa..ac4ff0bb0de291 100644 --- a/docs/examples/zh/controls/TrackballControls.html +++ b/docs/examples/zh/controls/TrackballControls.html @@ -7,7 +7,7 @@ - [page:EventDispatcher] → + [page:Controls] →

轨迹球控制器([name])

@@ -41,7 +41,7 @@

[name]( [param:Camera camera], [param:HTMLDOMElement domElement] )

[page:Camera camera]: 渲染场景的摄像机。

- [page:HTMLDOMElement domElement]: 用于事件监听的HTML元素。 + [page:HTMLDOMElement domElement]: 用于事件监听的HTML元素。(可选)

创建一个新的 [name] 实例。 @@ -67,21 +67,13 @@

end

属性

-

[property:HTMLDOMElement domElement]

-

- 该 HTMLDOMElement 用于监听鼠标/触摸事件,该属性必须在构造函数中传入。在此处改变它将不会设置新的事件监听。 -

+

共有属性请参见其基类[page:Controls]。

[property:Number dynamicDampingFactor]

设置阻尼的强度。仅在[page:.staticMoving staticMoving]设为*false*时考虑。默认为*0.2*。

-

[property:Boolean enabled]

-

- 是否启用控制器。 -

-

[property:Array keys]

该数组包含用于控制交互的按键代码。 @@ -139,11 +131,6 @@

[property:Boolean noZoom]

是否禁用缩放,默认为*false*。

-

[property:Camera object]

-

- 正被控制的摄像机。 -

-

[property:Number panSpeed]

平移的速度,其默认值为*0.3*。 @@ -170,6 +157,11 @@

[property:Boolean staticMoving]

阻尼是否被禁用。默认为*false*。

+

[property:Vector3 target]

+

+ 控件的焦点。 +

+

[property:Number zoomSpeed]

缩放的速度,其默认值为*1.2*。 @@ -177,46 +169,18 @@

[property:Number zoomSpeed]

方法

-

[method:undefined checkDistances] ()

-

- 确保控制器位于 [minDistance, maxDistance] 范围内。由[page:.update update]()调用。 -

- -

[method:undefined dispose] ()

-

- 若不再需要该控制器,则应当调用此函数。 -

+

共有方法请参见其基类[page:Controls]。

[method:undefined handleResize] ()

若应用程序窗口大小发生改变,则应当调用此函数。

-

[method:undefined panCamera] ()

-

- 如有必要,执行平移。由[page:.update update]()调用。 -

-

[method:undefined reset] ()

重置控制器到初始状态。

-

[method:undefined rotateCamera] ()

-

- 如有必要,旋转相机。由[page:.update update]()调用。 -

- -

[method:undefined update] ()

-

- 更新控制器,常被用在动画循环中。 -

- -

[method:undefined zoomCamera] ()

-

- 如有必要,执行缩放。由[page:.update update]()调用。 -

-

源代码

diff --git a/docs/examples/zh/controls/TransformControls.html b/docs/examples/zh/controls/TransformControls.html index be66b519f224e4..7083adc6fdf19b 100644 --- a/docs/examples/zh/controls/TransformControls.html +++ b/docs/examples/zh/controls/TransformControls.html @@ -7,7 +7,7 @@ - [page:Object3D] → + [page:Controls] →

变换控制器([name])

@@ -41,7 +41,7 @@

[name]( [param:Camera camera], [param:HTMLDOMElement domElement] )

[page:Camera camera]: 被控制的摄像机。

- [page:HTMLDOMElement domElement]: 用于事件监听的HTML元素。 + [page:HTMLDOMElement domElement]: 用于事件监听的HTML元素。(可选)

创建一个新的 [name] 实例。 @@ -73,7 +73,7 @@

objectChange

属性

-

共有属性请参见其基类[page:Object3D]。

+

共有属性请参见其基类[page:Controls]。

[property:String axis]

@@ -85,31 +85,16 @@

[property:Camera camera]

渲染场景的摄像机。

-

[property:HTMLDOMElement domElement]

-

- 该 HTMLDOMElement 用于监听鼠标/触摸事件,该属性必须在构造函数中传入。在此处改变它将不会设置新的事件监听。 -

-

[property:Boolean dragging]

当前是否正在拖动。只读属性。

-

[property:Boolean enabled]

-

- 是否启用控制器。默认为*true*。 -

-

[property:String mode]

当前的变换模式。可能的值包括"translate"、"rotate" 和 "scale"。默认为*translate*。

-

[property:Object3D object]

-

- 正在被控制的3D对象。 -

-

[property:Number rotationSnap]

默认情况下,3D对象是可以被连续旋转的。如果你将该值设为一个数值(弧度),则你将可以定义每次旋转3D对象时的步幅。 @@ -149,7 +134,7 @@

[property:Number translationSnap]

方法

-

共有方法请参见其基类[page:Object3D]。

+

共有方法请参见其基类[page:Controls]。

[method:TransformControls attach] ( [param:Object3D object] )

@@ -166,9 +151,9 @@

[method:TransformControls detach] ()

从控制器中移除当前3D对象,并确保控制器UI是不可见的。

-

[method:undefined dispose] ()

+

[method:Object3D getHelper] ()

- 若不再需要该控制器,则应当调用此函数。 + 返回控件的视觉表示。将辅助对象添加到场景中,以直观地变换附着的3D对象。

[method:Raycaster getRaycaster] ()

@@ -182,6 +167,11 @@

[method:String getMode] ()

返回变换模式。

+ +

[method:undefined reset] ()

+

+ 将对象的位置、旋转和缩放重置为当前变换开始时的状态。 +

[method:undefined setMode] ( [param:String mode] )

diff --git a/docs/examples/zh/geometries/SDFGeometryGenerator.html b/docs/examples/zh/geometries/SDFGeometryGenerator.html deleted file mode 100644 index 94672f8524b595..00000000000000 --- a/docs/examples/zh/geometries/SDFGeometryGenerator.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - -

SDF几何体生成器([name])

- -

- [name] 从有符号距离函数 生成 [page:BufferGeometry] 实例。
- 使用 Mikola Lysenko 的等值面。 -

- -

导入

- -

- [name] 是一个附加组件,必须显式导入。请参阅 [link:#manual/introduction/Installation Installation / Addons]. -

- - - import { SDFGeometryGenerator } from 'three/addons/geometries/SDFGeometryGenerator.js'; - - -

代码示例

- - - const generator = new SDFGeometryGenerator( renderer ); - const sdf = 'float dist( vec3 p ){ return length(p) - 0.5; }' // glsl - const geometry = generator.generate( 64, sdf, 1 ); // ~> THREE.BufferGeometry - - -

例子

- -

[example:webgl_geometry_sdf geometry / sdf ]

- -

构造函数

- -

[name]( [param:WebGLRenderer renderer] )

- -

- [page:WebGLRenderer renderer] -- 用于渲染场景的渲染器。
-

- -

方法

- -

[method:BufferGeometry generate]( [param:Int resolution], [param:String distanceField], [param:Int bounds] )

- -

- resolution - Int [必填项] 用于三角测量的“体素”数量。必须是 2 的幂。256 之后会变得很重,大多数机器将无法处理超过 512 的数据。默认为 64。 -

-

- distanceField - String [必填项] 具有 glsl 距离函数的字符串。函数名称必须是“dist”,带有 vec3 参数。(参见上面的代码)。默认为球体距离。 -

-

- bounds - Int [可选] 将评估有符号距离字段的边界。默认为 1。 -

- - -

源代码

- -

- [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/SDFGeometry.js examples/jsm/geometries/SDFGeometryGenerator.js] -

- - - diff --git a/docs/examples/zh/geometries/TeapotGeometry.html b/docs/examples/zh/geometries/TeapotGeometry.html index 15f8bca1b7a32f..b5ff451e009cb9 100644 --- a/docs/examples/zh/geometries/TeapotGeometry.html +++ b/docs/examples/zh/geometries/TeapotGeometry.html @@ -63,8 +63,7 @@

方法

源代码

- [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/TeapotGeometry.js - examples/jsm/geometries/TeapotGeometry.js] + [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/TeapotGeometry.js examples/jsm/geometries/TeapotGeometry.js]

diff --git a/docs/index.html b/docs/index.html index 892c35685b248e..43e7148c934ac5 100644 --- a/docs/index.html +++ b/docs/index.html @@ -538,17 +538,23 @@

three.js

const oldIframe = iframe; iframe = oldIframe.cloneNode(); + iframe.style.display = 'none'; + if ( hash && titles[ splitHash[ 0 ] ] ) { + iframe.onload = function () { + + iframe.style.display = 'unset'; + + }; + iframe.src = splitHash[ 0 ] + '.html' + splitHash[ 1 ]; subtitle = titles[ splitHash[ 0 ] ] + splitHash[ 1 ] + ' – '; - iframe.style.display = 'unset'; } else { iframe.src = ''; subtitle = ''; - iframe.style.display = 'none'; } diff --git a/docs/list.json b/docs/list.json index 86141e3326621f..81426149a26793 100644 --- a/docs/list.json +++ b/docs/list.json @@ -346,7 +346,6 @@ "ConvexGeometry": "examples/en/geometries/ConvexGeometry", "DecalGeometry": "examples/en/geometries/DecalGeometry", "ParametricGeometry": "examples/en/geometries/ParametricGeometry", - "SDFGeometryGenerator": "examples/en/geometries/SDFGeometryGenerator", "TeapotGeometry": "examples/en/geometries/TeapotGeometry", "TextGeometry": "examples/en/geometries/TextGeometry" }, @@ -363,6 +362,14 @@ "LightProbeGenerator": "examples/en/lights/LightProbeGenerator" }, + "Lines": { + "Line2": "examples/en/lines/Line2", + "LineGeometry": "examples/en/lines/LineGeometry", + "LineMaterial": "examples/en/lines/LineMaterial", + "LineSegments2": "examples/en/lines/LineSegments2", + "LineSegmentsGeometry": "examples/en/lines/LineSegmentsGeometry" + }, + "Loaders": { "3DMLoader": "examples/en/loaders/3DMLoader", "DRACOLoader": "examples/en/loaders/DRACOLoader", @@ -434,7 +441,7 @@ "SceneUtils": "examples/en/utils/SceneUtils", "SkeletonUtils": "examples/en/utils/SkeletonUtils" }, - + "WebXR": { "XREstimatedLight": "examples/en/webxr/XREstimatedLight" } @@ -859,7 +866,8 @@ "Earcut": "api/zh/extras/Earcut", "ImageUtils": "api/zh/extras/ImageUtils", "PMREMGenerator": "api/zh/extras/PMREMGenerator", - "ShapeUtils": "api/zh/extras/ShapeUtils" + "ShapeUtils": "api/zh/extras/ShapeUtils", + "TextureUtils": "api/zh/extras/TextureUtils" }, "附件 / 核心": { @@ -1100,8 +1108,7 @@ "DecalGeometry": "examples/zh/geometries/DecalGeometry", "ParametricGeometry": "examples/zh/geometries/ParametricGeometry", "TeapotGeometry": "examples/zh/geometries/TeapotGeometry", - "TextGeometry": "examples/zh/geometries/TextGeometry", - "SDFGeometryGenerator": "examples/zh/geometries/SDFGeometryGenerator" + "TextGeometry": "examples/zh/geometries/TextGeometry" }, "辅助对象": { @@ -1362,12 +1369,16 @@ "DragControls": "examples/ko/controls/DragControls", "FirstPersonControls": "examples/ko/controls/FirstPersonControls", "FlyControls": "examples/ko/controls/FlyControls", + "MapControls": "examples/ko/controls/MapControls", "OrbitControls": "examples/ko/controls/OrbitControls", "PointerLockControls": "examples/ko/controls/PointerLockControls", "TrackballControls": "examples/ko/controls/TrackballControls", "TransformControls": "examples/ko/controls/TransformControls" - } + }, + "WebXR": { + "XREstimatedLight": "examples/ko/webxr/XREstimatedLight" + } } }, diff --git a/docs/manual/ar/introduction/How-to-create-VR-content.html b/docs/manual/ar/introduction/How-to-create-VR-content.html index 85f45c3b386e5a..f4264174f92a2c 100644 --- a/docs/manual/ar/introduction/How-to-create-VR-content.html +++ b/docs/manual/ar/introduction/How-to-create-VR-content.html @@ -59,15 +59,15 @@

الخطوات التالية

ألق نظرة على أحد أمثلة WebVR الرسمية لرؤية سير العمل.

- [example:webxr_vr_ballshooter WebXR / VR / ballshooter]
- [example:webxr_vr_cubes WebXR / VR / cubes]
- [example:webxr_vr_dragging WebXR / VR / dragging]
- [example:webxr_vr_paint WebXR / VR / paint]
+ [example:webxr_xr_ballshooter WebXR / XR / ballshooter]
+ [example:webxr_xr_cubes WebXR / XR / cubes]
+ [example:webxr_xr_dragging WebXR / XR / dragging]
+ [example:webxr_xr_paint WebXR / XR / paint]
+ [example:webxr_xr_sculpt WebXR / XR / sculpt]
[example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]
[example:webxr_vr_panorama WebXR / VR / panorama]
[example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]
[example:webxr_vr_sandbox WebXR / VR / sandbox]
- [example:webxr_vr_sculpt WebXR / VR / sculpt]
[example:webxr_vr_video WebXR / VR / video]

diff --git a/docs/manual/ar/introduction/Libraries-and-Plugins.html b/docs/manual/ar/introduction/Libraries-and-Plugins.html index 44c7eca01c9004..743b874692f4cc 100644 --- a/docs/manual/ar/introduction/Libraries-and-Plugins.html +++ b/docs/manual/ar/introduction/Libraries-and-Plugins.html @@ -107,6 +107,7 @@

الأغلفة والأطُر (Wrappers and Frameworks)

  • [link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.
  • [link:https://needle.tools/ Needle Engine]
  • [link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.
  • +
  • [link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.
  • diff --git a/docs/manual/en/introduction/How-to-create-VR-content.html b/docs/manual/en/introduction/How-to-create-VR-content.html index c27063612bc0ce..9b76b9e8e3468e 100644 --- a/docs/manual/en/introduction/How-to-create-VR-content.html +++ b/docs/manual/en/introduction/How-to-create-VR-content.html @@ -64,15 +64,15 @@

    Next Steps

    Have a look at one of the official WebVR examples to see this workflow in action.

    - [example:webxr_vr_ballshooter WebXR / VR / ballshooter]
    - [example:webxr_vr_cubes WebXR / VR / cubes]
    - [example:webxr_vr_dragging WebXR / VR / dragging]
    - [example:webxr_vr_paint WebXR / VR / paint]
    + [example:webxr_xr_ballshooter WebXR / XR / ballshooter]
    + [example:webxr_xr_cubes WebXR / XR / cubes]
    + [example:webxr_xr_dragging WebXR / XR / dragging]
    + [example:webxr_xr_paint WebXR / XR / paint]
    + [example:webxr_xr_sculpt WebXR / XR / sculpt]
    [example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]
    [example:webxr_vr_panorama WebXR / VR / panorama]
    [example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]
    [example:webxr_vr_sandbox WebXR / VR / sandbox]
    - [example:webxr_vr_sculpt WebXR / VR / sculpt]
    [example:webxr_vr_video WebXR / VR / video]

    diff --git a/docs/manual/en/introduction/How-to-update-things.html b/docs/manual/en/introduction/How-to-update-things.html index 7a28ac5bcfd17f..61e7372f642eaa 100644 --- a/docs/manual/en/introduction/How-to-update-things.html +++ b/docs/manual/en/introduction/How-to-update-things.html @@ -62,7 +62,7 @@

    BufferGeometry

    const geometry = new THREE.BufferGeometry(); // attributes -const positions = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point +const positions = new Float32Array( MAX_POINTS * 3 ); // 3 floats (x, y and z) per point geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); // draw range diff --git a/docs/manual/en/introduction/Libraries-and-Plugins.html b/docs/manual/en/introduction/Libraries-and-Plugins.html index 84beff181027e6..7342dd23f0c512 100644 --- a/docs/manual/en/introduction/Libraries-and-Plugins.html +++ b/docs/manual/en/introduction/Libraries-and-Plugins.html @@ -111,6 +111,7 @@

    Wrappers and Frameworks

  • [link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.
  • [link:https://needle.tools/ Needle Engine]
  • [link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.
  • +
  • [link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.
  • diff --git a/docs/manual/fr/introduction/How-to-create-VR-content.html b/docs/manual/fr/introduction/How-to-create-VR-content.html index bad2a211ede43a..d846cd1d2b730f 100644 --- a/docs/manual/fr/introduction/How-to-create-VR-content.html +++ b/docs/manual/fr/introduction/How-to-create-VR-content.html @@ -64,15 +64,15 @@

    Étapes Suivantes

    Jetez un coup d'oeil à un des exemples officiels WebVR pour voir le workflow en action.

    - [example:webxr_vr_ballshooter WebXR / VR / ballshooter]
    - [example:webxr_vr_cubes WebXR / VR / cubes]
    - [example:webxr_vr_dragging WebXR / VR / dragging]
    - [example:webxr_vr_paint WebXR / VR / paint]
    + [example:webxr_xr_ballshooter WebXR / XR / ballshooter]
    + [example:webxr_xr_cubes WebXR / XR / cubes]
    + [example:webxr_xr_dragging WebXR / XR / dragging]
    + [example:webxr_xr_paint WebXR / XR / paint]
    + [example:webxr_xr_sculpt WebXR / XR / sculpt]
    [example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]
    [example:webxr_vr_panorama WebXR / VR / panorama]
    [example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]
    [example:webxr_vr_sandbox WebXR / VR / sandbox]
    - [example:webxr_vr_sculpt WebXR / VR / sculpt]
    [example:webxr_vr_video WebXR / VR / video]

    diff --git a/docs/manual/fr/introduction/How-to-update-things.html b/docs/manual/fr/introduction/How-to-update-things.html index 544e0074f2190b..5937b7eaff78ed 100644 --- a/docs/manual/fr/introduction/How-to-update-things.html +++ b/docs/manual/fr/introduction/How-to-update-things.html @@ -95,22 +95,23 @@

    BufferGeometry

    }

    - If you want to change the number of points rendered after the first render, do this: + Si vous voulez changer le nombre de points rendus après le premier rendu, faites ainsi :

    line.geometry.setDrawRange( 0, newValue );

    - If you want to change the position data values after the first render, you need to - set the needsUpdate flag like so: + Si vous voulez changer la valeur des données de position après le premier rendu, vous devez + régler le flag needsUpdate ainsi :

    positionAttribute.needsUpdate = true; // required after the first render

    - If you change the position data values after the initial render, you may need to recompute - bounding volumes so other features of the engine like view frustum culling or helpers properly work. + Si vous changez les valeurs de la donnée de position après le premier rendu, vous devez + recalculer les volumes englobants de telle sorte que les autres fonctionnalités du moteur comme + le frustrum culling ou les helpers le prenne en compte correctement.

    line.geometry.computeBoundingBox(); @@ -118,10 +119,10 @@

    BufferGeometry

    - [link:https://jsfiddle.net/t4m85pLr/1/ Here is a fiddle] showing an animated line which you can adapt to your use case. + [link:https://jsfiddle.net/t4m85pLr/1/ Voici un fiddle] montrant une ligne animée, que vous pouvez adapter comme vous le souhaitez.

    -

    Examples

    +

    Exemples

    [example:webgl_custom_attributes WebGL / custom / attributes]
    @@ -130,11 +131,11 @@

    Examples

    -

    Materiaux

    +

    Matériaux

    Toutes les valeurs uniformes peuvent être changées librement(e.g. couleurs, textures, opacité, etc), les valeurs sont envoyées aux shaders à chaque frame.

    -

    De plus, les paramètresen relation avec GLstate peuvent changer à tout moment (depthTest, blending, polygonOffset, etc).

    +

    De plus, les paramètres en relation avec GLstate peuvent changer à tout moment (depthTest, blending, polygonOffset, etc).

    Les propriétés suivantes ne peuvent pas être changées facilement durant l'exécution (une fois que le matériau a été rendu au moins une fois):

      diff --git a/docs/manual/fr/introduction/How-to-use-post-processing.html b/docs/manual/fr/introduction/How-to-use-post-processing.html index 1e5c9254668eea..f31877d72edcc0 100644 --- a/docs/manual/fr/introduction/How-to-use-post-processing.html +++ b/docs/manual/fr/introduction/How-to-use-post-processing.html @@ -88,11 +88,11 @@

      Effets Intégrés

      [link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm/postprocessing postprocessing].

      -

      Effets Customisés

      +

      Effets Personnalisés

      - Parfois vous voulez écrire un shader de post-processing customisé et l'inclure dans les effets (passes) de post-processing. Dans ce scénario, - vous pouvez utiliser `ShaderPass`. Après avoir importé le fichier et votre shader customisé, vous pouvez utiliser le code suivant pour mettre en place l'effet (pass). + Parfois vous voulez écrire un shader de post-processing personnalisé et l'inclure dans les effets (passes) de post-processing. Dans ce scénario, + vous pouvez utiliser `ShaderPass`. Après avoir importé le fichier et votre shader personnalisé, vous pouvez utiliser le code suivant pour mettre en place l'effet (pass).

      @@ -106,8 +106,8 @@

      Effets Customisés

      - Ce repository fournit un fichier appelé [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/shaders/CopyShader.js CopyShader] qui est - une bonne base de code pour créer votre propose shader customisé. `CopyShader` copie simplement le contenu de l'image du buffer de l'[page:EffectComposer] + Ce dépôt fournit un fichier appelé [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/shaders/CopyShader.js CopyShader] qui est + une bonne base de code pour créer votre propose shader personnalisé. `CopyShader` copie simplement le contenu de l'image du buffer de l'[page:EffectComposer] à son buffer d'écriture sans y appliquer aucun effet.

      diff --git a/docs/manual/fr/introduction/Libraries-and-Plugins.html b/docs/manual/fr/introduction/Libraries-and-Plugins.html index c3d9d5b3c21aa0..07bb7a5641a4ef 100644 --- a/docs/manual/fr/introduction/Libraries-and-Plugins.html +++ b/docs/manual/fr/introduction/Libraries-and-Plugins.html @@ -37,7 +37,7 @@

      Postprocessing

    • [link:https://github.com/vanruesc/postprocessing postprocessing]
    -

    Intersections et Performance de Raycast

    +

    Intersections et lancers de rayon

    • [link:https://github.com/gkjohnson/three-mesh-bvh three-mesh-bvh]
    • @@ -91,7 +91,7 @@

      Cinématique inverse

    • [link:https://github.com/gkjohnson/closed-chain-ik-js closed-chain-ik]
    -

    Jeu IA

    +

    Jeu et IA

    • [link:https://mugen87.github.io/yuka/ yuka]
    • @@ -103,13 +103,14 @@

      Wrappers et Frameworks

      • [link:https://aframe.io/ A-Frame]
      • -
      • [link:https://lume.io/ Lume] - HTML elements for 3D graphics built on Three.
      • -
      • [link:https://github.com/pmndrs/react-three-fiber react-three-fiber] - React components for 3D graphics built on Three.
      • -
      • [link:https://threepipe.org/ threepipe] - A versatile 3D viewer framework using three.js for rendering.
      • +
      • [link:https://lume.io/ Lume] - Éléments HTML pour interface 3D, basé sur Three.
      • +
      • [link:https://github.com/pmndrs/react-three-fiber react-three-fiber] - Composants React pour interface 3D, basé sur Three.
      • +
      • [link:https://threepipe.org/ threepipe] - Un framework de visualisation 3D polyvalent utilisant Three pour le rendu.
      • [link:https://github.com/ecsyjs/ecsy-three ECSY]
      • -
      • [link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.
      • +
      • [link:https://threlte.xyz/ Threlte] - Des composants Svelte pour interface 3D, basé sur Three.
      • [link:https://needle.tools/ Needle Engine]
      • -
      • [link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.
      • +
      • [link:https://tresjs.org/ tresjs] - Des composants Vue pour interface 3D, basé sur Three.
      • +
      • [link:https://giro3d.org Giro3D] - Un framework polyvalent basé sur Three pour la visualisation et l'interaction avec des données géospatiales 2D, 2.5D et 3D.
      diff --git a/docs/manual/it/introduction/How-to-create-VR-content.html b/docs/manual/it/introduction/How-to-create-VR-content.html index e54f2478fdd5e7..9737690beb7836 100644 --- a/docs/manual/it/introduction/How-to-create-VR-content.html +++ b/docs/manual/it/introduction/How-to-create-VR-content.html @@ -62,15 +62,15 @@

      Prossimi passi

      Dai un'occhiata ad uno degli esempi ufficiali di WebVR per vedere questo flusso di lavoro in azione.

      - [example:webxr_vr_ballshooter WebXR / VR / ballshooter]
      - [example:webxr_vr_cubes WebXR / VR / cubes]
      - [example:webxr_vr_dragging WebXR / VR / dragging]
      - [example:webxr_vr_paint WebXR / VR / paint]
      + [example:webxr_xr_ballshooter WebXR / XR / ballshooter]
      + [example:webxr_xr_cubes WebXR / XR / cubes]
      + [example:webxr_xr_dragging WebXR / XR / dragging]
      + [example:webxr_xr_paint WebXR / XR / paint]
      + [example:webxr_xr_sculpt WebXR / XR / sculpt]
      [example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]
      [example:webxr_vr_panorama WebXR / VR / panorama]
      [example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]
      [example:webxr_vr_sandbox WebXR / VR / sandbox]
      - [example:webxr_vr_sculpt WebXR / VR / sculpt]
      [example:webxr_vr_video WebXR / VR / video]

      diff --git a/docs/manual/it/introduction/Libraries-and-Plugins.html b/docs/manual/it/introduction/Libraries-and-Plugins.html index 35a747b50128f6..0ed081f3ba72e2 100644 --- a/docs/manual/it/introduction/Libraries-and-Plugins.html +++ b/docs/manual/it/introduction/Libraries-and-Plugins.html @@ -110,6 +110,7 @@

      Wrappers e Frameworks

    • [link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.
    • [link:https://needle.tools/ Needle Engine]
    • [link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.
    • +
    • [link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.
    diff --git a/docs/manual/ja/introduction/How-to-create-VR-content.html b/docs/manual/ja/introduction/How-to-create-VR-content.html index 9fd2dd351530df..859511bbdb6f6d 100644 --- a/docs/manual/ja/introduction/How-to-create-VR-content.html +++ b/docs/manual/ja/introduction/How-to-create-VR-content.html @@ -58,15 +58,15 @@

    Next Steps

    このワークフローを実際に見るために、公式のWebVRの例を見てみましょう。

    - [example:webxr_vr_ballshooter WebXR / VR / ballshooter]
    - [example:webxr_vr_cubes WebXR / VR / cubes]
    - [example:webxr_vr_dragging WebXR / VR / dragging]
    - [example:webxr_vr_paint WebXR / VR / paint]
    + [example:webxr_xr_ballshooter WebXR / XR / ballshooter]
    + [example:webxr_xr_cubes WebXR / XR / cubes]
    + [example:webxr_xr_dragging WebXR / XR / dragging]
    + [example:webxr_xr_paint WebXR / XR / paint]
    + [example:webxr_xr_sculpt WebXR / XR / sculpt]
    [example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]
    [example:webxr_vr_panorama WebXR / VR / panorama]
    [example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]
    [example:webxr_vr_sandbox WebXR / VR / sandbox]
    - [example:webxr_vr_sculpt WebXR / VR / sculpt]
    [example:webxr_vr_video WebXR / VR / video]

    diff --git a/docs/manual/ja/introduction/Libraries-and-Plugins.html b/docs/manual/ja/introduction/Libraries-and-Plugins.html index dac20124c856d9..593678c94db9dc 100644 --- a/docs/manual/ja/introduction/Libraries-and-Plugins.html +++ b/docs/manual/ja/introduction/Libraries-and-Plugins.html @@ -103,6 +103,7 @@

    Wrappers and Frameworks

  • [link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.
  • [link:https://needle.tools/ Needle Engine]
  • [link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.
  • +
  • [link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.
  • diff --git a/docs/manual/ko/introduction/Drawing-lines.html b/docs/manual/ko/introduction/Drawing-lines.html index 454c23b0045289..36142f4cf7b101 100644 --- a/docs/manual/ko/introduction/Drawing-lines.html +++ b/docs/manual/ko/introduction/Drawing-lines.html @@ -47,7 +47,7 @@

    선 그리기([name])

    const geometry = new THREE.BufferGeometry().setFromPoints( points ); -

    선은 연속된 꼭짓점 쌍 사이에 그려지고 첫 번재와 마지막 꼭짓점에는 그려지지 않습니다. (선은 닫혀있지 않습니다.)

    +

    선은 연속된 꼭짓점 쌍 사이에 그려지고 첫 번째와 마지막 꼭짓점에는 그려지지 않습니다. (선은 닫혀있지 않습니다.)

    이제 두 선을 그리기 위한 점과 재질이 있으니, 합쳐서 선을 만들 수 있습니다.

    @@ -64,4 +64,4 @@

    선 그리기([name])

    - \ No newline at end of file + diff --git a/docs/manual/ko/introduction/How-to-create-VR-content.html b/docs/manual/ko/introduction/How-to-create-VR-content.html index 2534d9d5e19a3e..32ecf7374ee9b4 100644 --- a/docs/manual/ko/introduction/How-to-create-VR-content.html +++ b/docs/manual/ko/introduction/How-to-create-VR-content.html @@ -62,15 +62,15 @@

    다음 절차

    실행을 위한 작업 절차와 관련된 공식 WebVR 예제를 확인하세요.

    - [example:webxr_vr_ballshooter WebXR / VR / ballshooter]
    - [example:webxr_vr_cubes WebXR / VR / cubes]
    - [example:webxr_vr_dragging WebXR / VR / dragging]
    - [example:webxr_vr_paint WebXR / VR / paint]
    + [example:webxr_xr_ballshooter WebXR / XR / ballshooter]
    + [example:webxr_xr_cubes WebXR / XR / cubes]
    + [example:webxr_xr_dragging WebXR / XR / dragging]
    + [example:webxr_xr_paint WebXR / XR / paint]
    + [example:webxr_xr_sculpt WebXR / XR / sculpt]
    [example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]
    [example:webxr_vr_panorama WebXR / VR / panorama]
    [example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]
    [example:webxr_vr_sandbox WebXR / VR / sandbox]
    - [example:webxr_vr_sculpt WebXR / VR / sculpt]
    [example:webxr_vr_video WebXR / VR / video]

    diff --git a/docs/manual/pt-br/introduction/How-to-create-VR-content.html b/docs/manual/pt-br/introduction/How-to-create-VR-content.html index 1fe33be277a179..adf249e6c7df95 100644 --- a/docs/manual/pt-br/introduction/How-to-create-VR-content.html +++ b/docs/manual/pt-br/introduction/How-to-create-VR-content.html @@ -64,15 +64,15 @@

    Próximos Passos

    Dê uma olhada em um dos exemplos oficiais de WebVR para ver esse workflow em ação

    - [example:webxr_vr_ballshooter WebXR / VR / ballshooter]
    - [example:webxr_vr_cubes WebXR / VR / cubes]
    - [example:webxr_vr_dragging WebXR / VR / dragging]
    - [example:webxr_vr_paint WebXR / VR / paint]
    + [example:webxr_xr_ballshooter WebXR / XR / ballshooter]
    + [example:webxr_xr_cubes WebXR / XR / cubes]
    + [example:webxr_xr_dragging WebXR / XR / dragging]
    + [example:webxr_xr_paint WebXR / XR / paint]
    + [example:webxr_xr_sculpt WebXR / XR / sculpt]
    [example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]
    [example:webxr_vr_panorama WebXR / VR / panorama]
    [example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]
    [example:webxr_vr_sandbox WebXR / VR / sandbox]
    - [example:webxr_vr_sculpt WebXR / VR / sculpt]
    [example:webxr_vr_video WebXR / VR / video]

    diff --git a/docs/manual/pt-br/introduction/Libraries-and-Plugins.html b/docs/manual/pt-br/introduction/Libraries-and-Plugins.html index 90ef230cdf846f..6e0fab2a1421cf 100644 --- a/docs/manual/pt-br/introduction/Libraries-and-Plugins.html +++ b/docs/manual/pt-br/introduction/Libraries-and-Plugins.html @@ -110,6 +110,7 @@

    Wrappers e Frameworks

  • [link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.
  • [link:https://needle.tools/ Needle Engine]
  • [link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.
  • +
  • [link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.
  • diff --git a/docs/manual/ru/introduction/Libraries-and-Plugins.html b/docs/manual/ru/introduction/Libraries-and-Plugins.html index 9ed45fa94e8a56..3b706b953b6aaa 100644 --- a/docs/manual/ru/introduction/Libraries-and-Plugins.html +++ b/docs/manual/ru/introduction/Libraries-and-Plugins.html @@ -109,6 +109,7 @@

    Обертки и фреймворки

  • [link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.
  • [link:https://needle.tools/ Needle Engine]
  • [link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.
  • +
  • [link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.
  • diff --git a/docs/manual/zh/introduction/How-to-create-VR-content.html b/docs/manual/zh/introduction/How-to-create-VR-content.html index 37d6c3c7b5c5a5..730bbe0d57fff7 100644 --- a/docs/manual/zh/introduction/How-to-create-VR-content.html +++ b/docs/manual/zh/introduction/How-to-create-VR-content.html @@ -64,15 +64,15 @@

    接下来的步骤

    请查看官方示例中与WebVR相关的示例,了解这一工作流程的实际使用、运行情况。

    - [example:webxr_vr_ballshooter WebXR / VR / ballshooter]
    - [example:webxr_vr_cubes WebXR / VR / cubes]
    - [example:webxr_vr_dragging WebXR / VR / dragging]
    - [example:webxr_vr_paint WebXR / VR / paint]
    + [example:webxr_xr_ballshooter WebXR / XR / ballshooter]
    + [example:webxr_xr_cubes WebXR / XR / cubes]
    + [example:webxr_xr_dragging WebXR / XR / dragging]
    + [example:webxr_xr_paint WebXR / XR / paint]
    + [example:webxr_xr_sculpt WebXR / XR / sculpt]
    [example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]
    [example:webxr_vr_panorama WebXR / VR / panorama]
    [example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]
    [example:webxr_vr_sandbox WebXR / VR / sandbox]
    - [example:webxr_vr_sculpt WebXR / VR / sculpt]
    [example:webxr_vr_video WebXR / VR / video]

    diff --git a/docs/manual/zh/introduction/Libraries-and-Plugins.html b/docs/manual/zh/introduction/Libraries-and-Plugins.html index 4a20d8cdf25723..e022958eb95e32 100644 --- a/docs/manual/zh/introduction/Libraries-and-Plugins.html +++ b/docs/manual/zh/introduction/Libraries-and-Plugins.html @@ -106,6 +106,7 @@

    封装器和框架(Wrappers and Frameworks)

  • [link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.
  • [link:https://needle.tools/ Needle Engine]
  • [link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.
  • +
  • [link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.
  • diff --git a/docs/page.css b/docs/page.css index 641915d7ce6c21..192705002f35a0 100644 --- a/docs/page.css +++ b/docs/page.css @@ -122,6 +122,10 @@ summary { margin-bottom: 16px; } +summary:hover { + cursor: pointer; +} + p { padding-right: 16px; } diff --git a/editor/js/Viewport.js b/editor/js/Viewport.js index 3b04fc8b4f91c1..334288367b1511 100644 --- a/editor/js/Viewport.js +++ b/editor/js/Viewport.js @@ -142,7 +142,7 @@ function Viewport( editor ) { } ); - sceneHelpers.add( transformControls ); + sceneHelpers.add( transformControls.getHelper() ); // diff --git a/examples/files.json b/examples/files.json index 31f706f8f73475..99aa8b5d01225f 100644 --- a/examples/files.json +++ b/examples/files.json @@ -34,7 +34,6 @@ "webgl_geometry_extrude_splines", "webgl_geometry_minecraft", "webgl_geometry_nurbs", - "webgl_geometry_sdf", "webgl_geometry_shapes", "webgl_geometry_spline_editor", "webgl_geometry_teapot", @@ -114,7 +113,6 @@ "webgl_loader_ply", "webgl_loader_stl", "webgl_loader_svg", - "webgl_loader_tilt", "webgl_loader_texture_dds", "webgl_loader_texture_exr", "webgl_loader_texture_ultrahdr", @@ -254,7 +252,6 @@ "webgl_buffergeometry", "webgl_buffergeometry_attributes_integer", "webgl_buffergeometry_attributes_none", - "webgl_buffergeometry_compression", "webgl_buffergeometry_custom_attributes_particles", "webgl_buffergeometry_drawrange", "webgl_buffergeometry_glbufferattribute", @@ -302,6 +299,8 @@ "webgl_performance" ], "webgpu (wip)": [ + "webgpu_animation_retargeting", + "webgpu_animation_retargeting_readyplayer", "webgpu_backdrop", "webgpu_backdrop_area", "webgpu_backdrop_water", @@ -315,8 +314,10 @@ "webgpu_compute_particles_rain", "webgpu_compute_particles_snow", "webgpu_compute_points", + "webgpu_compute_sort_bitonic", "webgpu_compute_texture", "webgpu_compute_texture_pingpong", + "webgpu_compute_water", "webgpu_cubemap_adjustments", "webgpu_cubemap_dynamic", "webgpu_cubemap_mix", @@ -329,7 +330,9 @@ "webgpu_instance_points", "webgpu_instance_uniform", "webgpu_instancing_morph", + "webgpu_lensflares", "webgpu_lightprobe", + "webgpu_lightprobe_cubecamera", "webgpu_lights_custom", "webgpu_lights_ies_spotlight", "webgpu_lights_phong", @@ -345,6 +348,7 @@ "webgpu_loader_gltf_transmission", "webgpu_loader_materialx", "webgpu_materials", + "webgpu_materials_arrays", "webgpu_materials_basic", "webgpu_materials_displacementmap", "webgpu_materials_envmaps", @@ -357,6 +361,7 @@ "webgpu_materialx_noise", "webgpu_mesh_batch", "webgpu_mirror", + "webgpu_modifier_curve", "webgpu_morphtargets", "webgpu_morphtargets_face", "webgpu_mrt", @@ -399,6 +404,7 @@ "webgpu_shadertoy", "webgpu_shadowmap", "webgpu_shadowmap_opacity", + "webgpu_shadowmap_vsm", "webgpu_skinning", "webgpu_skinning_instancing", "webgpu_skinning_points", @@ -410,6 +416,7 @@ "webgpu_textures_2d-array_compressed", "webgpu_textures_anisotropy", "webgpu_textures_partialupdate", + "webgpu_tonemapping", "webgpu_tsl_angular_slicing", "webgpu_tsl_coffee_smoke", "webgpu_tsl_compute_attractors_particles", @@ -422,6 +429,7 @@ "webgpu_tsl_raging_sea", "webgpu_tsl_transpiler", "webgpu_tsl_vfx_flames", + "webgpu_tsl_vfx_linkedparticles", "webgpu_tsl_vfx_tornado", "webgpu_video_panorama", "webgpu_volume_cloud", diff --git a/examples/jsm/Addons.js b/examples/jsm/Addons.js index 6941a5553a9ee5..81a0a1d6a8a01a 100644 --- a/examples/jsm/Addons.js +++ b/examples/jsm/Addons.js @@ -124,7 +124,6 @@ export * from './loaders/TDSLoader.js'; export * from './loaders/TGALoader.js'; export * from './loaders/TIFFLoader.js'; export * from './loaders/TTFLoader.js'; -export * from './loaders/TiltLoader.js'; export * from './loaders/USDZLoader.js'; export * from './loaders/VOXLoader.js'; export * from './loaders/VRMLLoader.js'; @@ -172,9 +171,6 @@ export * from './objects/ShadowMesh.js'; export * from './objects/Sky.js'; export * from './objects/Water.js'; export { Water as Water2 } from './objects/Water2.js'; -export * from './objects/SkyMesh.js'; -export * from './objects/WaterMesh.js'; -export { WaterMesh as Water2Mesh } from './objects/Water2Mesh.js'; export * from './physics/AmmoPhysics.js'; export * from './physics/RapierPhysics.js'; @@ -271,11 +267,9 @@ export * from './textures/FlakesTexture.js'; export * as BufferGeometryUtils from './utils/BufferGeometryUtils.js'; export * as CameraUtils from './utils/CameraUtils.js'; -export * from './utils/GPUStatsPanel.js'; export * as GeometryCompressionUtils from './utils/GeometryCompressionUtils.js'; export * as GeometryUtils from './utils/GeometryUtils.js'; export * from './utils/LDrawUtils.js'; -export * from './utils/PackedPhongMaterial.js'; export * as SceneUtils from './utils/SceneUtils.js'; export * from './utils/ShadowMapViewer.js'; export * as SkeletonUtils from './utils/SkeletonUtils.js'; diff --git a/examples/jsm/controls/TrackballControls.js b/examples/jsm/controls/TrackballControls.js index dec8248f6bf514..eebf91004d66ff 100644 --- a/examples/jsm/controls/TrackballControls.js +++ b/examples/jsm/controls/TrackballControls.js @@ -618,23 +618,43 @@ function onKeyDown( event ) { function onMouseDown( event ) { - if ( this.state === _STATE.NONE ) { + let mouseAction; - switch ( event.button ) { + switch ( event.button ) { - case this.mouseButtons.LEFT: - this.state = _STATE.ROTATE; - break; + case 0: + mouseAction = this.mouseButtons.LEFT; + break; + + case 1: + mouseAction = this.mouseButtons.MIDDLE; + break; - case this.mouseButtons.MIDDLE: - this.state = _STATE.ZOOM; - break; + case 2: + mouseAction = this.mouseButtons.RIGHT; + break; - case this.mouseButtons.RIGHT: - this.state = _STATE.PAN; - break; + default: + mouseAction = - 1; - } + } + + switch ( mouseAction ) { + + case MOUSE.DOLLY: + this.state = _STATE.ZOOM; + break; + + case MOUSE.ROTATE: + this.state = _STATE.ROTATE; + break; + + case MOUSE.PAN: + this.state = _STATE.PAN; + break; + + default: + this.state = _STATE.NONE; } diff --git a/examples/jsm/controls/TransformControls.js b/examples/jsm/controls/TransformControls.js index 38ee44ae6f322a..78dafca81304b0 100644 --- a/examples/jsm/controls/TransformControls.js +++ b/examples/jsm/controls/TransformControls.js @@ -1,6 +1,7 @@ import { BoxGeometry, BufferGeometry, + Controls, CylinderGeometry, DoubleSide, Euler, @@ -36,32 +37,22 @@ const _mouseDownEvent = { type: 'mouseDown', mode: null }; const _mouseUpEvent = { type: 'mouseUp', mode: null }; const _objectChangeEvent = { type: 'objectChange' }; -class TransformControls extends Object3D { +class TransformControls extends Controls { - constructor( camera, domElement ) { + constructor( camera, domElement = null ) { - super(); - - if ( domElement === undefined ) { - - console.warn( 'THREE.TransformControls: The second parameter "domElement" is now mandatory.' ); - domElement = document; + super( undefined, domElement ); - } + const root = new TransformControlsRoot( this ); + this._root = root; - this.isTransformControls = true; + const gizmo = new TransformControlsGizmo(); + this._gizmo = gizmo; + root.add( gizmo ); - this.visible = false; - this.domElement = domElement; - this.domElement.style.touchAction = 'none'; // disable touch scroll - - const _gizmo = new TransformControlsGizmo(); - this._gizmo = _gizmo; - this.add( _gizmo ); - - const _plane = new TransformControlsPlane(); - this._plane = _plane; - this.add( _plane ); + const plane = new TransformControlsPlane(); + this._plane = plane; + root.add( plane ); const scope = this; @@ -83,8 +74,8 @@ class TransformControls extends Object3D { if ( propValue !== value ) { propValue = value; - _plane[ propName ] = value; - _gizmo[ propName ] = value; + plane[ propName ] = value; + gizmo[ propName ] = value; scope.dispatchEvent( { type: propName + '-changed', value: value } ); scope.dispatchEvent( _changeEvent ); @@ -96,8 +87,8 @@ class TransformControls extends Object3D { } ); scope[ propName ] = defaultValue; - _plane[ propName ] = defaultValue; - _gizmo[ propName ] = defaultValue; + plane[ propName ] = defaultValue; + gizmo[ propName ] = defaultValue; } @@ -172,50 +163,38 @@ class TransformControls extends Object3D { this._onPointerMove = onPointerMove.bind( this ); this._onPointerUp = onPointerUp.bind( this ); - this.domElement.addEventListener( 'pointerdown', this._onPointerDown ); - this.domElement.addEventListener( 'pointermove', this._onPointerHover ); - this.domElement.addEventListener( 'pointerup', this._onPointerUp ); - - } - - // updateMatrixWorld updates key transformation variables - updateMatrixWorld( force ) { - - if ( this.object !== undefined ) { + if ( domElement !== null ) { - this.object.updateMatrixWorld(); - - if ( this.object.parent === null ) { - - console.error( 'TransformControls: The attached 3D object must be a part of the scene graph.' ); - - } else { + this.connect(); - this.object.parent.matrixWorld.decompose( this._parentPosition, this._parentQuaternion, this._parentScale ); + } - } + } - this.object.matrixWorld.decompose( this.worldPosition, this.worldQuaternion, this._worldScale ); + connect() { - this._parentQuaternionInv.copy( this._parentQuaternion ).invert(); - this._worldQuaternionInv.copy( this.worldQuaternion ).invert(); + this.domElement.addEventListener( 'pointerdown', this._onPointerDown ); + this.domElement.addEventListener( 'pointermove', this._onPointerHover ); + this.domElement.addEventListener( 'pointerup', this._onPointerUp ); - } + this.domElement.style.touchAction = 'none'; // disable touch scroll - this.camera.updateMatrixWorld(); - this.camera.matrixWorld.decompose( this.cameraPosition, this.cameraQuaternion, this._cameraScale ); + } - if ( this.camera.isOrthographicCamera ) { + disconnect() { - this.camera.getWorldDirection( this.eye ).negate(); + this.domElement.removeEventListener( 'pointerdown', this._onPointerDown ); + this.domElement.removeEventListener( 'pointermove', this._onPointerHover ); + this.domElement.removeEventListener( 'pointermove', this._onPointerMove ); + this.domElement.removeEventListener( 'pointerup', this._onPointerUp ); - } else { + this.domElement.style.touchAction = 'auto'; - this.eye.copy( this.cameraPosition ).sub( this.worldPosition ).normalize(); + } - } + getHelper() { - super.updateMatrixWorld( force ); + return this._root; } @@ -555,10 +534,7 @@ class TransformControls extends Object3D { dispose() { - this.domElement.removeEventListener( 'pointerdown', this._onPointerDown ); - this.domElement.removeEventListener( 'pointermove', this._onPointerHover ); - this.domElement.removeEventListener( 'pointermove', this._onPointerMove ); - this.domElement.removeEventListener( 'pointerup', this._onPointerUp ); + this.disconnect(); this.traverse( function ( child ) { @@ -573,7 +549,7 @@ class TransformControls extends Object3D { attach( object ) { this.object = object; - this.visible = true; + this._root.visible = true; return this; @@ -583,9 +559,10 @@ class TransformControls extends Object3D { detach() { this.object = undefined; - this.visible = false; this.axis = null; + this._root.visible = false; + return this; } @@ -778,6 +755,64 @@ const _v1 = new Vector3(); const _v2 = new Vector3(); const _v3 = new Vector3(); +class TransformControlsRoot extends Object3D { + + constructor( controls ) { + + super(); + + this.isTransformControlsRoot = true; + + this.controls = controls; + this.visible = false; + + } + + // updateMatrixWorld updates key transformation variables + updateMatrixWorld( force ) { + + const controls = this.controls; + + if ( controls.object !== undefined ) { + + controls.object.updateMatrixWorld(); + + if ( controls.object.parent === null ) { + + console.error( 'TransformControls: The attached 3D object must be a part of the scene graph.' ); + + } else { + + controls.object.parent.matrixWorld.decompose( controls._parentPosition, controls._parentQuaternion, controls._parentScale ); + + } + + controls.object.matrixWorld.decompose( controls.worldPosition, controls.worldQuaternion, controls._worldScale ); + + controls._parentQuaternionInv.copy( controls._parentQuaternion ).invert(); + controls._worldQuaternionInv.copy( controls.worldQuaternion ).invert(); + + } + + controls.camera.updateMatrixWorld(); + controls.camera.matrixWorld.decompose( controls.cameraPosition, controls.cameraQuaternion, controls._cameraScale ); + + if ( controls.camera.isOrthographicCamera ) { + + controls.camera.getWorldDirection( controls.eye ).negate(); + + } else { + + controls.eye.copy( controls.cameraPosition ).sub( controls.worldPosition ).normalize(); + + } + + super.updateMatrixWorld( force ); + + } + +} + class TransformControlsGizmo extends Object3D { constructor() { diff --git a/examples/jsm/exporters/DRACOExporter.js b/examples/jsm/exporters/DRACOExporter.js index 85a2e15adc4d6d..4b0a1a396e184a 100644 --- a/examples/jsm/exporters/DRACOExporter.js +++ b/examples/jsm/exporters/DRACOExporter.js @@ -1,4 +1,4 @@ -import { Color } from 'three'; +import { Color, ColorManagement, SRGBColorSpace } from 'three'; /** * Export draco compressed files from threejs geometry objects. @@ -227,7 +227,9 @@ function createVertexColorSRGBArray( attribute ) { for ( let i = 0, il = count; i < il; i ++ ) { - _color.fromBufferAttribute( attribute, i ).convertLinearToSRGB(); + _color.fromBufferAttribute( attribute, i ); + + ColorManagement.fromWorkingColorSpace( _color, SRGBColorSpace ); array[ i * itemSize ] = _color.r; array[ i * itemSize + 1 ] = _color.g; diff --git a/examples/jsm/exporters/EXRExporter.js b/examples/jsm/exporters/EXRExporter.js index bd1d8202d2d83d..950e2d1641490d 100644 --- a/examples/jsm/exporters/EXRExporter.js +++ b/examples/jsm/exporters/EXRExporter.js @@ -21,20 +21,20 @@ const ZIP_COMPRESSION = 3; class EXRExporter { - parse( arg1, arg2, arg3 ) { + async parse( arg1, arg2, arg3 ) { - if ( ! arg1 || ! ( arg1.isWebGLRenderer || arg1.isDataTexture ) ) { + if ( ! arg1 || ! ( arg1.isWebGLRenderer || arg1.isWebGPURenderer || arg1.isDataTexture ) ) { throw Error( 'EXRExporter.parse: Unsupported first parameter, expected instance of WebGLRenderer or DataTexture.' ); - } else if ( arg1.isWebGLRenderer ) { + } else if ( arg1.isWebGLRenderer || arg1.isWebGPURenderer ) { const renderer = arg1, renderTarget = arg2, options = arg3; supportedRTT( renderTarget ); const info = buildInfoRTT( renderTarget, options ), - dataBuffer = getPixelData( renderer, renderTarget, info ), + dataBuffer = await getPixelData( renderer, renderTarget, info ), rawContentBuffer = reorganizeDataBuffer( dataBuffer, info ), chunks = compressData( rawContentBuffer, info ); @@ -61,7 +61,7 @@ class EXRExporter { function supportedRTT( renderTarget ) { - if ( ! renderTarget || ! renderTarget.isWebGLRenderTarget ) { + if ( ! renderTarget || ! renderTarget.isRenderTarget ) { throw Error( 'EXRExporter.parse: Unsupported second parameter, expected instance of WebGLRenderTarget.' ); @@ -189,22 +189,30 @@ function buildInfoDT( texture, options = {} ) { } -function getPixelData( renderer, rtt, info ) { +async function getPixelData( renderer, rtt, info ) { let dataBuffer; - if ( info.type === FloatType ) { + if ( renderer.isWebGLRenderer ) { - dataBuffer = new Float32Array( info.width * info.height * info.numInputChannels ); + if ( info.type === FloatType ) { + + dataBuffer = new Float32Array( info.width * info.height * info.numInputChannels ); + + } else { + + dataBuffer = new Uint16Array( info.width * info.height * info.numInputChannels ); + + } + + await renderer.readRenderTargetPixelsAsync( rtt, 0, 0, info.width, info.height, dataBuffer ); } else { - dataBuffer = new Uint16Array( info.width * info.height * info.numInputChannels ); + dataBuffer = await renderer.readRenderTargetPixelsAsync( rtt, 0, 0, info.width, info.height ); } - renderer.readRenderTargetPixels( rtt, 0, 0, info.width, info.height, dataBuffer ); - return dataBuffer; } diff --git a/examples/jsm/exporters/KTX2Exporter.js b/examples/jsm/exporters/KTX2Exporter.js index bfc24d8dda08b2..e5b086a24529c4 100644 --- a/examples/jsm/exporters/KTX2Exporter.js +++ b/examples/jsm/exporters/KTX2Exporter.js @@ -111,7 +111,7 @@ const ERROR_COLOR_SPACE = 'THREE.KTX2Exporter: Supported color spaces are SRGBCo export class KTX2Exporter { - parse( arg1, arg2 ) { + async parse( arg1, arg2 ) { let texture; @@ -119,9 +119,9 @@ export class KTX2Exporter { texture = arg1; - } else if ( arg1.isWebGLRenderer && arg2.isWebGLRenderTarget ) { + } else if ( ( arg1.isWebGLRenderer || arg1.isWebGPURenderer ) && arg2.isRenderTarget ) { - texture = toDataTexture( arg1, arg2 ); + texture = await toDataTexture( arg1, arg2 ); } else { @@ -235,32 +235,40 @@ export class KTX2Exporter { } -function toDataTexture( renderer, rtt ) { +async function toDataTexture( renderer, rtt ) { const channelCount = getChannelCount( rtt.texture ); let view; - if ( rtt.texture.type === FloatType ) { + if ( renderer.isWebGLRenderer ) { - view = new Float32Array( rtt.width * rtt.height * channelCount ); + if ( rtt.texture.type === FloatType ) { - } else if ( rtt.texture.type === HalfFloatType ) { + view = new Float32Array( rtt.width * rtt.height * channelCount ); - view = new Uint16Array( rtt.width * rtt.height * channelCount ); + } else if ( rtt.texture.type === HalfFloatType ) { - } else if ( rtt.texture.type === UnsignedByteType ) { + view = new Uint16Array( rtt.width * rtt.height * channelCount ); - view = new Uint8Array( rtt.width * rtt.height * channelCount ); + } else if ( rtt.texture.type === UnsignedByteType ) { + + view = new Uint8Array( rtt.width * rtt.height * channelCount ); + + } else { + + throw new Error( ERROR_TYPE ); + + } + + await renderer.readRenderTargetPixelsAsync( rtt, 0, 0, rtt.width, rtt.height, view ); } else { - throw new Error( ERROR_TYPE ); + view = await renderer.readRenderTargetPixelsAsync( rtt, 0, 0, rtt.width, rtt.height ); } - renderer.readRenderTargetPixels( rtt, 0, 0, rtt.width, rtt.height, view ); - return new DataTexture( view, rtt.width, rtt.height, rtt.texture.format, rtt.texture.type ); } diff --git a/examples/jsm/exporters/OBJExporter.js b/examples/jsm/exporters/OBJExporter.js index 63a483e2b7c2e7..c49662700b9a1b 100644 --- a/examples/jsm/exporters/OBJExporter.js +++ b/examples/jsm/exporters/OBJExporter.js @@ -1,6 +1,8 @@ import { Color, + ColorManagement, Matrix3, + SRGBColorSpace, Vector2, Vector3 } from 'three'; @@ -226,7 +228,9 @@ class OBJExporter { if ( colors !== undefined ) { - color.fromBufferAttribute( colors, i ).convertLinearToSRGB(); + color.fromBufferAttribute( colors, i ); + + ColorManagement.fromWorkingColorSpace( color, SRGBColorSpace ); output += ' ' + color.r + ' ' + color.g + ' ' + color.b; diff --git a/examples/jsm/exporters/PLYExporter.js b/examples/jsm/exporters/PLYExporter.js index 2e46a8c45b5358..b96bb999e6c743 100644 --- a/examples/jsm/exporters/PLYExporter.js +++ b/examples/jsm/exporters/PLYExporter.js @@ -1,7 +1,9 @@ import { Matrix3, Vector3, - Color + Color, + ColorManagement, + SRGBColorSpace } from 'three'; /** @@ -302,9 +304,9 @@ class PLYExporter { if ( colors != null ) { - tempColor - .fromBufferAttribute( colors, i ) - .convertLinearToSRGB(); + tempColor.fromBufferAttribute( colors, i ); + + ColorManagement.fromWorkingColorSpace( tempColor, SRGBColorSpace ); output.setUint8( vOffset, Math.floor( tempColor.r * 255 ) ); vOffset += 1; @@ -461,9 +463,9 @@ class PLYExporter { if ( colors != null ) { - tempColor - .fromBufferAttribute( colors, i ) - .convertLinearToSRGB(); + tempColor.fromBufferAttribute( colors, i ); + + ColorManagement.fromWorkingColorSpace( tempColor, SRGBColorSpace ); line += ' ' + Math.floor( tempColor.r * 255 ) + ' ' + diff --git a/examples/jsm/geometries/DecalGeometry.js b/examples/jsm/geometries/DecalGeometry.js index 5e712f23c65bf0..d5782ac2a0b531 100644 --- a/examples/jsm/geometries/DecalGeometry.js +++ b/examples/jsm/geometries/DecalGeometry.js @@ -1,6 +1,7 @@ import { BufferGeometry, Float32BufferAttribute, + Matrix3, Matrix4, Vector3 } from 'three'; @@ -36,6 +37,8 @@ class DecalGeometry extends BufferGeometry { const plane = new Vector3(); + const normalMatrix = new Matrix3().getNormalMatrix( mesh.matrixWorld ); + // this matrix represents the transformation of the decal projector const projectorMatrix = new Matrix4(); @@ -146,7 +149,7 @@ class DecalGeometry extends BufferGeometry { vertex.applyMatrix4( mesh.matrixWorld ); vertex.applyMatrix4( projectorMatrixInverse ); - normal.transformDirection( mesh.matrixWorld ); + normal.applyNormalMatrix( normalMatrix ); decalVertices.push( new DecalVertex( vertex.clone(), normal.clone() ) ); diff --git a/examples/jsm/geometries/InstancedPointsGeometry.js b/examples/jsm/geometries/InstancedPointsGeometry.js index 081ab6b81af176..1238ad88391542 100644 --- a/examples/jsm/geometries/InstancedPointsGeometry.js +++ b/examples/jsm/geometries/InstancedPointsGeometry.js @@ -20,7 +20,7 @@ class InstancedPointsGeometry extends InstancedBufferGeometry { this.type = 'InstancedPointsGeometry'; const positions = [ - 1, 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ]; - const uvs = [ - 1, 1, 1, 1, - 1, - 1, 1, - 1 ]; + const uvs = [ 0, 1, 1, 1, 0, 0, 1, 0 ]; const index = [ 0, 2, 1, 2, 3, 1 ]; this.setIndex( index ); diff --git a/examples/jsm/geometries/SDFGeometryGenerator.js b/examples/jsm/geometries/SDFGeometryGenerator.js deleted file mode 100644 index e80c9a39ab1422..00000000000000 --- a/examples/jsm/geometries/SDFGeometryGenerator.js +++ /dev/null @@ -1,144 +0,0 @@ -/** - * @author santiago / @glitch_life - * wrapper of https://www.npmjs.com/package/isosurface by https://github.com/mikolalysenko - * - * Returns BufferGeometry from SDF - */ - -import { - BufferAttribute, - BufferGeometry, - FloatType, - Mesh, - OrthographicCamera, - PlaneGeometry, - Scene, - ShaderMaterial, - Vector2, - WebGLRenderTarget -} from 'three'; - -import { surfaceNet } from './../libs/surfaceNet.js'; - -class SDFGeometryGenerator { - - constructor( renderer ) { - - this.renderer = renderer; - - } - - generate( res = 64, distFunc = 'float dist( vec3 p ){ return length(p) - 0.5; }', bounds = 1 ) { - - let w, h; - if ( res == 8 ) [ w, h ] = [ 32, 16 ]; - else if ( res == 16 ) [ w, h ] = [ 64, 64 ]; - else if ( res == 32 ) [ w, h ] = [ 256, 128 ]; - else if ( res == 64 ) [ w, h ] = [ 512, 512 ]; - else if ( res == 128 ) [ w, h ] = [ 2048, 1024 ]; - else if ( res == 256 ) [ w, h ] = [ 4096, 4096 ]; - else if ( res == 512 ) [ w, h ] = [ 16384, 8096 ]; - else if ( res == 1024 ) [ w, h ] = [ 32768, 32768 ]; - else throw new Error( 'THREE.SDFGeometryGenerator: Resolution must be in range 8 < res < 1024 and must be ^2' ); - - const maxTexSize = this.renderer.capabilities.maxTextureSize; - - if ( w > maxTexSize || h > maxTexSize ) throw new Error( 'THREE.SDFGeometryGenerator: Your device does not support this resolution ( ' + res + ' ), decrease [res] param.' ); - - const [ tilesX, tilesY ] = [ ( w / res ), ( h / res ) ]; - - const sdfCompute = ` - varying vec2 vUv; - uniform float tileNum; - uniform float bounds; - [#dist#] - void main() { gl_FragColor=vec4( ( dist( vec3( vUv, tileNum ) * 2.0 * bounds - vec3( bounds ) ) < 0.00001 ) ? 1.0 : 0.0 ); } - `; - - const sdfRT = this.computeSDF( w, h, tilesX, tilesY, bounds, sdfCompute.replace( '[#dist#]', distFunc ) ); - - const read = new Float32Array( w * h * 4 ); - this.renderer.readRenderTargetPixels( sdfRT, 0, 0, w, h, read ); - sdfRT.dispose(); - - // - - const mesh = surfaceNet( [ res, res, res ], ( x, y, z ) => { - - x = ( x + bounds ) * ( res / ( bounds * 2 ) ); - y = ( y + bounds ) * ( res / ( bounds * 2 ) ); - z = ( z + bounds ) * ( res / ( bounds * 2 ) ); - let p = ( x + ( z % tilesX ) * res ) + y * w + ( Math.floor( z / tilesX ) * res * w ); - p *= 4; - return ( read[ p + 3 ] > 0 ) ? - 0.000000001 : 1; - - }, [[ - bounds, - bounds, - bounds ], [ bounds, bounds, bounds ]] ); - - const ps = [], ids = []; - const geometry = new BufferGeometry(); - mesh.positions.forEach( p => { - - ps.push( p[ 0 ], p[ 1 ], p[ 2 ] ); - - } ); - mesh.cells.forEach( p => ids.push( p[ 0 ], p[ 1 ], p[ 2 ] ) ); - geometry.setAttribute( 'position', new BufferAttribute( new Float32Array( ps ), 3 ) ); - geometry.setIndex( ids ); - - return geometry; - - } - - computeSDF( width, height, tilesX, tilesY, bounds, shader ) { - - const rt = new WebGLRenderTarget( width, height, { type: FloatType } ); - const scn = new Scene(); - const cam = new OrthographicCamera(); - const tiles = tilesX * tilesY; - let currentTile = 0; - - Object.assign( cam, { left: width / - 2, right: width / 2, top: height / 2, bottom: height / - 2 } ).updateProjectionMatrix(); - cam.position.z = 2; - - const tileSize = width / tilesX; - const geometry = new PlaneGeometry( tileSize, tileSize ); - - while ( currentTile ++ < tiles ) { - - const c = currentTile - 1; - const [ px, py ] = [ ( tileSize ) / 2 + ( c % tilesX ) * ( tileSize ) - width / 2, ( tileSize ) / 2 + Math.floor( c / tilesX ) * ( tileSize ) - height / 2 ]; - const compPlane = new Mesh( geometry, new ShaderMaterial( { - uniforms: { - res: { value: new Vector2( width, height ) }, - tileNum: { value: c / ( tilesX * tilesY - 1 ) }, - bounds: { value: bounds } - }, - vertexShader: 'varying vec2 vUv;void main(){vUv=uv;gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0);}', - fragmentShader: shader - } ) ); - compPlane.position.set( px, py, 0 ); - scn.add( compPlane ); - - } - - this.renderer.setRenderTarget( rt ); - this.renderer.render( scn, cam ); - this.renderer.setRenderTarget( null ); - - // - - geometry.dispose(); - - scn.traverse( function ( object ) { - - if ( object.material !== undefined ) object.material.dispose(); - - } ); - - return rt; - - } - -} - -export { SDFGeometryGenerator }; diff --git a/examples/jsm/helpers/LightProbeHelper.js b/examples/jsm/helpers/LightProbeHelper.js index e8d1356fc20e24..d6fff3ef1732a1 100644 --- a/examples/jsm/helpers/LightProbeHelper.js +++ b/examples/jsm/helpers/LightProbeHelper.js @@ -6,7 +6,7 @@ import { class LightProbeHelper extends Mesh { - constructor( lightProbe, size ) { + constructor( lightProbe, size = 1 ) { const material = new ShaderMaterial( { diff --git a/examples/jsm/helpers/LightProbeHelperGPU.js b/examples/jsm/helpers/LightProbeHelperGPU.js new file mode 100644 index 00000000000000..c44df32acb1d2f --- /dev/null +++ b/examples/jsm/helpers/LightProbeHelperGPU.js @@ -0,0 +1,65 @@ +import { + Mesh, + NodeMaterial, + SphereGeometry +} from 'three'; +import { float, Fn, getShIrradianceAt, normalWorld, uniformArray, uniform, vec4 } from 'three/tsl'; + +class LightProbeHelper extends Mesh { + + constructor( lightProbe, size = 1 ) { + + const sh = uniformArray( lightProbe.sh.coefficients ); + const intensity = uniform( lightProbe.intensity ); + + const RECIPROCAL_PI = float( 1 / Math.PI ); + + const fragmentNode = Fn( () => { + + const irradiance = getShIrradianceAt( normalWorld, sh ); + + const outgoingLight = RECIPROCAL_PI.mul( irradiance ).mul( intensity ); + + return vec4( outgoingLight, 1.0 ); + + } )(); + + const material = new NodeMaterial(); + material.fragmentNode = fragmentNode; + + const geometry = new SphereGeometry( 1, 32, 16 ); + + super( geometry, material ); + + this.lightProbe = lightProbe; + this.size = size; + this.type = 'LightProbeHelper'; + + this._intensity = intensity; + this._sh = sh; + + this.onBeforeRender(); + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + + onBeforeRender() { + + this.position.copy( this.lightProbe.position ); + + this.scale.set( 1, 1, 1 ).multiplyScalar( this.size ); + + this._intensity.value = this.lightProbe.intensity; + this._sh.array = this.lightProbe.sh.coefficients; + + } + +} + +export { LightProbeHelper }; diff --git a/examples/jsm/libs/basis/basis_transcoder.js b/examples/jsm/libs/basis/basis_transcoder.js index 9e285ddc9515bd..6f02a4ac8504ea 100644 --- a/examples/jsm/libs/basis/basis_transcoder.js +++ b/examples/jsm/libs/basis/basis_transcoder.js @@ -1,21 +1,19 @@ -var BASIS = (function() { - var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; - if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename; +var BASIS = (() => { + var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined; + if (typeof __filename != 'undefined') _scriptName ||= __filename; return ( -function(BASIS) { - BASIS = BASIS || {}; +function(moduleArg = {}) { + var moduleRtn; -var Module=typeof BASIS!=="undefined"?BASIS:{};var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise(function(resolve,reject){readyPromiseResolve=resolve;readyPromiseReject=reject});var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string";ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;var nodeFS;var nodePath;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require("path").dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=function shell_read(filename,binary){if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);return nodeFS["readFileSync"](filename,binary?null:"utf8")};readBinary=function readBinary(filename){var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);process["on"]("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process["on"]("unhandledRejection",abort);quit_=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){read_=function shell_read(f){return read(f)}}readBinary=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){arguments_=scriptArgs}else if(typeof arguments!="undefined"){arguments_=arguments}if(typeof quit==="function"){quit_=function(status){quit(status)}}if(typeof print!=="undefined"){if(typeof console==="undefined")console={};console.log=print;console.warn=console.error=typeof printErr!=="undefined"?printErr:print}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!=="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var tempRet0=0;var setTempRet0=function(value){tempRet0=value};var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime;if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(typeof WebAssembly!=="object"){abort("no native wasm support detected")}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(heap,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heap[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heap.subarray&&UTF8Decoder){return UTF8Decoder.decode(heap.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;function UTF16ToString(ptr,maxBytesToRead){var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder){return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr))}else{var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str}}function stringToUTF16(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}function lengthBytesUTF16(str){return str.length*2}function UTF32ToString(ptr,maxBytesToRead){var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str}function stringToUTF32(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr}function lengthBytesUTF32(str){var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len}function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}function hasPrefix(str,prefix){return String.prototype.startsWith?str.startsWith(prefix):str.indexOf(prefix)===0}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return hasPrefix(filename,dataURIPrefix)}var fileURIPrefix="file://";function isFileURI(filename){return hasPrefix(filename,fileURIPrefix)}var wasmBinaryFile="basis_transcoder.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"&&!isFileURI(wasmBinaryFile)){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return Promise.resolve().then(getBinary)}function createWasm(){var info={"a":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;wasmMemory=Module["asm"]["K"];updateGlobalBufferAndViews(wasmMemory.buffer);wasmTable=Module["asm"]["L"];removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&!isFileURI(wasmBinaryFile)&&typeof fetch==="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(receiveInstantiatedSource)})})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync().catch(readyPromiseReject);return{}}function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback(Module);continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){wasmTable.get(func)()}else{wasmTable.get(func)(callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var structRegistrations={};function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function simpleReadValueFromPointer(pointer){return this["fromWireType"](HEAPU32[pointer>>2])}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return"_"+name}else{return name}}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return new Function("body","return function "+name+"() {\n"+' "use strict";'+" return body.apply(this, arguments);\n"+"};\n")(body)}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return this.name+": "+this.message}};return errorClass}var InternalError=undefined;function throwInternalError(message){throw new InternalError(message)}function whenDependentTypesAreResolved(myTypes,dependentTypes,getTypeConverters){myTypes.forEach(function(type){typeDependencies[type]=dependentTypes});function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i>shift])},destructorFunction:null})}function ClassHandle_isAliasOf(other){if(!(this instanceof ClassHandle)){return false}if(!(other instanceof ClassHandle)){return false}var leftClass=this.$$.ptrType.registeredClass;var left=this.$$.ptr;var rightClass=other.$$.ptrType.registeredClass;var right=other.$$.ptr;while(leftClass.baseClass){left=leftClass.upcast(left);leftClass=leftClass.baseClass}while(rightClass.baseClass){right=rightClass.upcast(right);rightClass=rightClass.baseClass}return leftClass===rightClass&&left===right}function shallowCopyInternalPointer(o){return{count:o.count,deleteScheduled:o.deleteScheduled,preservePointerOnDelete:o.preservePointerOnDelete,ptr:o.ptr,ptrType:o.ptrType,smartPtr:o.smartPtr,smartPtrType:o.smartPtrType}}function throwInstanceAlreadyDeleted(obj){function getInstanceTypeName(handle){return handle.$$.ptrType.registeredClass.name}throwBindingError(getInstanceTypeName(obj)+" instance already deleted")}var finalizationGroup=false;function detachFinalizer(handle){}function runDestructor($$){if($$.smartPtr){$$.smartPtrType.rawDestructor($$.smartPtr)}else{$$.ptrType.registeredClass.rawDestructor($$.ptr)}}function releaseClassHandle($$){$$.count.value-=1;var toDelete=0===$$.count.value;if(toDelete){runDestructor($$)}}function attachFinalizer(handle){if("undefined"===typeof FinalizationGroup){attachFinalizer=function(handle){return handle};return handle}finalizationGroup=new FinalizationGroup(function(iter){for(var result=iter.next();!result.done;result=iter.next()){var $$=result.value;if(!$$.ptr){console.warn("object already deleted: "+$$.ptr)}else{releaseClassHandle($$)}}});attachFinalizer=function(handle){finalizationGroup.register(handle,handle.$$,handle.$$);return handle};detachFinalizer=function(handle){finalizationGroup.unregister(handle.$$)};return attachFinalizer(handle)}function ClassHandle_clone(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.preservePointerOnDelete){this.$$.count.value+=1;return this}else{var clone=attachFinalizer(Object.create(Object.getPrototypeOf(this),{$$:{value:shallowCopyInternalPointer(this.$$)}}));clone.$$.count.value+=1;clone.$$.deleteScheduled=false;return clone}}function ClassHandle_delete(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}detachFinalizer(this);releaseClassHandle(this.$$);if(!this.$$.preservePointerOnDelete){this.$$.smartPtr=undefined;this.$$.ptr=undefined}}function ClassHandle_isDeleted(){return!this.$$.ptr}var delayFunction=undefined;var deletionQueue=[];function flushPendingDeletes(){while(deletionQueue.length){var obj=deletionQueue.pop();obj.$$.deleteScheduled=false;obj["delete"]()}}function ClassHandle_deleteLater(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}deletionQueue.push(this);if(deletionQueue.length===1&&delayFunction){delayFunction(flushPendingDeletes)}this.$$.deleteScheduled=true;return this}function init_ClassHandle(){ClassHandle.prototype["isAliasOf"]=ClassHandle_isAliasOf;ClassHandle.prototype["clone"]=ClassHandle_clone;ClassHandle.prototype["delete"]=ClassHandle_delete;ClassHandle.prototype["isDeleted"]=ClassHandle_isDeleted;ClassHandle.prototype["deleteLater"]=ClassHandle_deleteLater}function ClassHandle(){}var registeredPointers={};function ensureOverloadTable(proto,methodName,humanName){if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(){if(!proto[methodName].overloadTable.hasOwnProperty(arguments.length)){throwBindingError("Function '"+humanName+"' called with an invalid number of arguments ("+arguments.length+") - expects one of ("+proto[methodName].overloadTable+")!")}return proto[methodName].overloadTable[arguments.length].apply(this,arguments)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}}function exposePublicSymbol(name,value,numArguments){if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError("Cannot register public name '"+name+"' twice")}ensureOverloadTable(Module,name,name);if(Module.hasOwnProperty(numArguments)){throwBindingError("Cannot register multiple overloads of a function with the same number of arguments ("+numArguments+")!")}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;if(undefined!==numArguments){Module[name].numArguments=numArguments}}}function RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast){this.name=name;this.constructor=constructor;this.instancePrototype=instancePrototype;this.rawDestructor=rawDestructor;this.baseClass=baseClass;this.getActualType=getActualType;this.upcast=upcast;this.downcast=downcast;this.pureVirtualFunctions=[]}function upcastPointer(ptr,ptrClass,desiredClass){while(ptrClass!==desiredClass){if(!ptrClass.upcast){throwBindingError("Expected null or instance of "+desiredClass.name+", got an instance of "+ptrClass.name)}ptr=ptrClass.upcast(ptr);ptrClass=ptrClass.baseClass}return ptr}function constNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}return 0}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function genericPointerToWireType(destructors,handle){var ptr;if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}if(this.isSmartPointer){ptr=this.rawConstructor();if(destructors!==null){destructors.push(this.rawDestructor,ptr)}return ptr}else{return 0}}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}if(!this.isConst&&handle.$$.ptrType.isConst){throwBindingError("Cannot convert argument of type "+(handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name)+" to parameter type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);if(this.isSmartPointer){if(undefined===handle.$$.smartPtr){throwBindingError("Passing raw pointer to smart pointer is illegal")}switch(this.sharingPolicy){case 0:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{throwBindingError("Cannot convert argument of type "+(handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name)+" to parameter type "+this.name)}break;case 1:ptr=handle.$$.smartPtr;break;case 2:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{var clonedHandle=handle["clone"]();ptr=this.rawShare(ptr,__emval_register(function(){clonedHandle["delete"]()}));if(destructors!==null){destructors.push(this.rawDestructor,ptr)}}break;default:throwBindingError("Unsupporting sharing policy")}}return ptr}function nonConstNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}return 0}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}if(handle.$$.ptrType.isConst){throwBindingError("Cannot convert argument of type "+handle.$$.ptrType.name+" to parameter type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function RegisteredPointer_getPointee(ptr){if(this.rawGetPointee){ptr=this.rawGetPointee(ptr)}return ptr}function RegisteredPointer_destructor(ptr){if(this.rawDestructor){this.rawDestructor(ptr)}}function RegisteredPointer_deleteObject(handle){if(handle!==null){handle["delete"]()}}function downcastPointer(ptr,ptrClass,desiredClass){if(ptrClass===desiredClass){return ptr}if(undefined===desiredClass.baseClass){return null}var rv=downcastPointer(ptr,ptrClass,desiredClass.baseClass);if(rv===null){return null}return desiredClass.downcast(rv)}function getInheritedInstanceCount(){return Object.keys(registeredInstances).length}function getLiveInheritedInstances(){var rv=[];for(var k in registeredInstances){if(registeredInstances.hasOwnProperty(k)){rv.push(registeredInstances[k])}}return rv}function setDelayFunction(fn){delayFunction=fn;if(deletionQueue.length&&delayFunction){delayFunction(flushPendingDeletes)}}function init_embind(){Module["getInheritedInstanceCount"]=getInheritedInstanceCount;Module["getLiveInheritedInstances"]=getLiveInheritedInstances;Module["flushPendingDeletes"]=flushPendingDeletes;Module["setDelayFunction"]=setDelayFunction}var registeredInstances={};function getBasestPointer(class_,ptr){if(ptr===undefined){throwBindingError("ptr should not be undefined")}while(class_.baseClass){ptr=class_.upcast(ptr);class_=class_.baseClass}return ptr}function getInheritedInstance(class_,ptr){ptr=getBasestPointer(class_,ptr);return registeredInstances[ptr]}function makeClassHandle(prototype,record){if(!record.ptrType||!record.ptr){throwInternalError("makeClassHandle requires ptr and ptrType")}var hasSmartPtrType=!!record.smartPtrType;var hasSmartPtr=!!record.smartPtr;if(hasSmartPtrType!==hasSmartPtr){throwInternalError("Both smartPtrType and smartPtr must be specified")}record.count={value:1};return attachFinalizer(Object.create(prototype,{$$:{value:record}}))}function RegisteredPointer_fromWireType(ptr){var rawPointer=this.getPointee(ptr);if(!rawPointer){this.destructor(ptr);return null}var registeredInstance=getInheritedInstance(this.registeredClass,rawPointer);if(undefined!==registeredInstance){if(0===registeredInstance.$$.count.value){registeredInstance.$$.ptr=rawPointer;registeredInstance.$$.smartPtr=ptr;return registeredInstance["clone"]()}else{var rv=registeredInstance["clone"]();this.destructor(ptr);return rv}}function makeDefaultHandle(){if(this.isSmartPointer){return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:rawPointer,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this,ptr:ptr})}}var actualType=this.registeredClass.getActualType(rawPointer);var registeredPointerRecord=registeredPointers[actualType];if(!registeredPointerRecord){return makeDefaultHandle.call(this)}var toType;if(this.isConst){toType=registeredPointerRecord.constPointerType}else{toType=registeredPointerRecord.pointerType}var dp=downcastPointer(rawPointer,this.registeredClass,toType.registeredClass);if(dp===null){return makeDefaultHandle.call(this)}if(this.isSmartPointer){return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp})}}function init_RegisteredPointer(){RegisteredPointer.prototype.getPointee=RegisteredPointer_getPointee;RegisteredPointer.prototype.destructor=RegisteredPointer_destructor;RegisteredPointer.prototype["argPackAdvance"]=8;RegisteredPointer.prototype["readValueFromPointer"]=simpleReadValueFromPointer;RegisteredPointer.prototype["deleteObject"]=RegisteredPointer_deleteObject;RegisteredPointer.prototype["fromWireType"]=RegisteredPointer_fromWireType}function RegisteredPointer(name,registeredClass,isReference,isConst,isSmartPointer,pointeeType,sharingPolicy,rawGetPointee,rawConstructor,rawShare,rawDestructor){this.name=name;this.registeredClass=registeredClass;this.isReference=isReference;this.isConst=isConst;this.isSmartPointer=isSmartPointer;this.pointeeType=pointeeType;this.sharingPolicy=sharingPolicy;this.rawGetPointee=rawGetPointee;this.rawConstructor=rawConstructor;this.rawShare=rawShare;this.rawDestructor=rawDestructor;if(!isSmartPointer&®isteredClass.baseClass===undefined){if(isConst){this["toWireType"]=constNoSmartPtrRawPointerToWireType;this.destructorFunction=null}else{this["toWireType"]=nonConstNoSmartPtrRawPointerToWireType;this.destructorFunction=null}}else{this["toWireType"]=genericPointerToWireType}}function replacePublicSymbol(name,value,numArguments){if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}}function dynCallLegacy(sig,ptr,args){if(args&&args.length){return Module["dynCall_"+sig].apply(null,[ptr].concat(args))}return Module["dynCall_"+sig].call(null,ptr)}function dynCall(sig,ptr,args){if(sig.indexOf("j")!=-1){return dynCallLegacy(sig,ptr,args)}return wasmTable.get(ptr).apply(null,args)}function getDynCaller(sig,ptr){assert(sig.indexOf("j")>=0,"getDynCaller should only be called with i64 sigs");var argCache=[];return function(){argCache.length=arguments.length;for(var i=0;i>2)+i])}return array}function __embind_register_class_constructor(rawClassType,argCount,rawArgTypesAddr,invokerSignature,invoker,rawConstructor){assert(argCount>0);var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);invoker=embind__requireFunction(invokerSignature,invoker);var args=[rawConstructor];var destructors=[];whenDependentTypesAreResolved([],[rawClassType],function(classType){classType=classType[0];var humanName="constructor "+classType.name;if(undefined===classType.registeredClass.constructor_body){classType.registeredClass.constructor_body=[]}if(undefined!==classType.registeredClass.constructor_body[argCount-1]){throw new BindingError("Cannot register multiple constructors with identical number of parameters ("+(argCount-1)+") for class '"+classType.name+"'! Overload resolution is currently only performed using the parameter count, not actual type info!")}classType.registeredClass.constructor_body[argCount-1]=function unboundTypeHandler(){throwUnboundTypeError("Cannot construct "+classType.name+" due to unbound types",rawArgTypes)};whenDependentTypesAreResolved([],rawArgTypes,function(argTypes){classType.registeredClass.constructor_body[argCount-1]=function constructor_body(){if(arguments.length!==argCount-1){throwBindingError(humanName+" called with "+arguments.length+" arguments, expected "+(argCount-1))}destructors.length=0;args.length=argCount;for(var i=1;i0?", ":"")+argsListWired}invokerFnBody+=(returns?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i4&&0===--emval_handle_array[handle].refcount){emval_handle_array[handle]=undefined;emval_free_list.push(handle)}}function count_emval_handles(){var count=0;for(var i=5;i>1])};case 2:return function(pointer){var heap=signed?HEAP32:HEAPU32;return this["fromWireType"](heap[pointer>>2])};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_enum(rawType,name,size,isSigned){var shift=getShiftFromSize(size);name=readLatin1String(name);function ctor(){}ctor.values={};registerType(rawType,{name:name,constructor:ctor,"fromWireType":function(c){return this.constructor.values[c]},"toWireType":function(destructors,c){return c.value},"argPackAdvance":8,"readValueFromPointer":enumReadValueFromPointer(name,shift,isSigned),destructorFunction:null});exposePublicSymbol(name,ctor)}function requireRegisteredType(rawType,humanName){var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl}function __embind_register_enum_value(rawEnumType,name,enumValue){var enumType=requireRegisteredType(rawEnumType,"enum");name=readLatin1String(name);var Enum=enumType.constructor;var Value=Object.create(enumType.constructor.prototype,{value:{value:enumValue},constructor:{value:createNamedFunction(enumType.name+"_"+name,function(){})}});Enum.values[enumValue]=Value;Enum[name]=Value}function _embind_repr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function __embind_register_function(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn){var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,function(){throwUnboundTypeError("Cannot call "+name+" due to unbound types",argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,function(argTypes){var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn),argCount-1);return[]})}function integerReadValueFromPointer(name,shift,signed){switch(shift){case 0:return signed?function readS8FromPointer(pointer){return HEAP8[pointer]}:function readU8FromPointer(pointer){return HEAPU8[pointer]};case 1:return signed?function readS16FromPointer(pointer){return HEAP16[pointer>>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=function(value){return value};if(minRange===0){var bitshift=32-8*size;fromWireType=function(value){return value<>>bitshift}}var isUnsignedType=name.indexOf("unsigned")!=-1;registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}if(valuemaxRange){throw new TypeError('Passing a number "'+_embind_repr(value)+'" from JS side to C/C++ side to an argument of type "'+name+'", which is outside the valid range ['+minRange+", "+maxRange+"]!")}return isUnsignedType?value>>>0:value|0},"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var str;if(stdStringIsUTF8){var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i;if(i==length||HEAPU8[currentBytePtr]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr+4,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+4+i]=charCode}}else{for(var i=0;i>2];var HEAP=getHeap();var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||HEAP[currentBytePtr>>shift]==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},"toWireType":function(destructors,value){if(!(typeof value==="string")){throwBindingError("Cannot pass non-string to C++ string type "+name)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length>>shift;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_value_object(rawType,name,constructorSignature,rawConstructor,destructorSignature,rawDestructor){structRegistrations[rawType]={name:readLatin1String(name),rawConstructor:embind__requireFunction(constructorSignature,rawConstructor),rawDestructor:embind__requireFunction(destructorSignature,rawDestructor),fields:[]}}function __embind_register_value_object_field(structType,fieldName,getterReturnType,getterSignature,getter,getterContext,setterArgumentType,setterSignature,setter,setterContext){structRegistrations[structType].fields.push({fieldName:readLatin1String(fieldName),getterReturnType:getterReturnType,getter:embind__requireFunction(getterSignature,getter),getterContext:getterContext,setterArgumentType:setterArgumentType,setter:embind__requireFunction(setterSignature,setter),setterContext:setterContext})}function __embind_register_void(rawType,name){name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":function(){return undefined},"toWireType":function(destructors,o){return undefined}})}function requireHandle(handle){if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handle_array[handle].value}function __emval_as(handle,returnType,destructorsRef){handle=requireHandle(handle);returnType=requireRegisteredType(returnType,"emval::as");var destructors=[];var rd=__emval_register(destructors);HEAP32[destructorsRef>>2]=rd;return returnType["toWireType"](destructors,handle)}var emval_symbols={};function getStringOrSymbol(address){var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}else{return symbol}}var emval_methodCallers=[];function __emval_call_void_method(caller,handle,methodName,args){caller=emval_methodCallers[caller];handle=requireHandle(handle);methodName=getStringOrSymbol(methodName);caller(handle,methodName,null,args)}function emval_get_global(){if(typeof globalThis==="object"){return globalThis}return function(){return Function}()("return this")()}function __emval_get_global(name){if(name===0){return __emval_register(emval_get_global())}else{name=getStringOrSymbol(name);return __emval_register(emval_get_global()[name])}}function __emval_addMethodCaller(caller){var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id}function __emval_lookupTypes(argCount,argTypes){var a=new Array(argCount);for(var i=0;i>2)+i],"parameter "+i)}return a}function __emval_get_method_caller(argCount,argTypes){var types=__emval_lookupTypes(argCount,argTypes);var retType=types[0];var signatureName=retType.name+"_$"+types.slice(1).map(function(t){return t.name}).join("_")+"$";var params=["retType"];var args=[retType];var argsList="";for(var i=0;i4){emval_handle_array[handle].refcount+=1}}function craftEmvalAllocator(argCount){var argsList="";for(var i=0;i>> 2) + "+i+'], "parameter '+i+'");\n'+"var arg"+i+" = argType"+i+".readValueFromPointer(args);\n"+"args += argType"+i+"['argPackAdvance'];\n"}functionBody+="var obj = new constructor("+argsList+");\n"+"return __emval_register(obj);\n"+"}\n";return new Function("requireRegisteredType","Module","__emval_register",functionBody)(requireRegisteredType,Module,__emval_register)}var emval_newers={};function __emval_new(handle,argCount,argTypes,args){handle=requireHandle(handle);var newer=emval_newers[argCount];if(!newer){newer=craftEmvalAllocator(argCount);emval_newers[argCount]=newer}return newer(handle,argTypes,args)}function __emval_new_cstring(v){return __emval_register(getStringOrSymbol(v))}function __emval_run_destructors(handle){var destructors=emval_handle_array[handle].value;runDestructors(destructors);__emval_decref(handle)}function _abort(){abort()}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function _emscripten_get_heap_size(){return HEAPU8.length}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){requestedSize=requestedSize>>>0;var oldSize=_emscripten_get_heap_size();var maxHeapSize=2147483648;if(requestedSize>maxHeapSize){return false}var minHeapSize=16777216;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(minHeapSize,requestedSize,overGrownHeapSize),65536));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}var SYSCALLS={mappings:{},buffers:[null,[],[]],printChar:function(stream,curr){var buffer=SYSCALLS.buffers[stream];if(curr===0||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer,0));buffer.length=0}else{buffer.push(curr)}},varargs:undefined,get:function(){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},get64:function(low,high){return low}};function _fd_close(fd){return 0}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){}function _fd_write(fd,iov,iovcnt,pnum){var num=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];for(var j=0;j>2]=num;return 0}function _setTempRet0($i){setTempRet0($i|0)}InternalError=Module["InternalError"]=extendError(Error,"InternalError");embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");init_ClassHandle();init_RegisteredPointer();init_embind();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");init_emval();__ATINIT__.push({func:function(){___wasm_call_ctors()}});var asmLibraryArg={"t":__embind_finalize_value_object,"I":__embind_register_bool,"x":__embind_register_class,"w":__embind_register_class_constructor,"d":__embind_register_class_function,"k":__embind_register_constant,"H":__embind_register_emval,"n":__embind_register_enum,"a":__embind_register_enum_value,"A":__embind_register_float,"i":__embind_register_function,"j":__embind_register_integer,"h":__embind_register_memory_view,"B":__embind_register_std_string,"v":__embind_register_std_wstring,"u":__embind_register_value_object,"c":__embind_register_value_object_field,"J":__embind_register_void,"m":__emval_as,"s":__emval_call_void_method,"b":__emval_decref,"y":__emval_get_global,"p":__emval_get_method_caller,"r":__emval_get_module_property,"e":__emval_get_property,"g":__emval_incref,"q":__emval_new,"f":__emval_new_cstring,"l":__emval_run_destructors,"o":_abort,"E":_emscripten_memcpy_big,"F":_emscripten_resize_heap,"G":_fd_close,"C":_fd_seek,"z":_fd_write,"D":_setTempRet0};var asm=createWasm();var ___wasm_call_ctors=Module["___wasm_call_ctors"]=function(){return(___wasm_call_ctors=Module["___wasm_call_ctors"]=Module["asm"]["M"]).apply(null,arguments)};var _malloc=Module["_malloc"]=function(){return(_malloc=Module["_malloc"]=Module["asm"]["N"]).apply(null,arguments)};var _free=Module["_free"]=function(){return(_free=Module["_free"]=Module["asm"]["O"]).apply(null,arguments)};var ___getTypeName=Module["___getTypeName"]=function(){return(___getTypeName=Module["___getTypeName"]=Module["asm"]["P"]).apply(null,arguments)};var ___embind_register_native_and_builtin_types=Module["___embind_register_native_and_builtin_types"]=function(){return(___embind_register_native_and_builtin_types=Module["___embind_register_native_and_builtin_types"]=Module["asm"]["Q"]).apply(null,arguments)};var dynCall_jiji=Module["dynCall_jiji"]=function(){return(dynCall_jiji=Module["dynCall_jiji"]=Module["asm"]["R"]).apply(null,arguments)};var calledRun;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(args){args=args||arguments_;if(runDependencies>0){return}preRun();if(runDependencies>0)return;function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}noExitRuntime=true;run(); +var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){}var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");scriptDirectory=__dirname+"/";readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);var ret=fs.readFileSync(filename);return ret};readAsync=(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return new Promise((resolve,reject)=>{fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)reject(err);else resolve(binary?data.buffer:data)})})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptName){scriptDirectory=_scriptName}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=url=>{if(isFileURI(url)){return new Promise((reject,resolve)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){resolve(xhr.response)}reject(xhr.status)};xhr.onerror=reject;xhr.send(null)})}return fetch(url,{credentials:"same-origin"}).then(response=>{if(response.ok){return response.arrayBuffer()}return Promise.reject(new Error(response.status+" : "+response.url))})}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var wasmMemory;var ABORT=false;var EXITSTATUS;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var __ATPRERUN__=[];var __ATINIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);var isFileURI=filename=>filename.startsWith("file://");function findWasmBinary(){var f="basis_transcoder.wasm";if(!isDataURI(f)){return locateFile(f)}return f}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary){return readAsync(binaryFile).then(response=>new Uint8Array(response),()=>getBinarySync(binaryFile))}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return{a:wasmImports}}function createWasm(){var info=getWasmImports();function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["L"];updateMemoryViews();wasmTable=wasmExports["P"];addOnInit(wasmExports["M"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}if(!wasmBinaryFile)wasmBinaryFile=findWasmBinary();instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var noExitRuntime=Module["noExitRuntime"]||true;class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>2]=type}get_type(){return HEAPU32[this.ptr+4>>2]}set_destructor(destructor){HEAPU32[this.ptr+8>>2]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>2]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12]=caught}get_caught(){return HEAP8[this.ptr+12]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13]=rethrown}get_rethrown(){return HEAP8[this.ptr+13]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>2]}get_exception_ptr(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return HEAPU32[this.excPtr>>2]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}var exceptionLast=0;var uncaughtExceptionCount=0;var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast};var __abort_js=()=>{abort("")};var structRegistrations={};var runDestructors=destructors=>{while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}};function readPointer(pointer){return this["fromWireType"](HEAPU32[pointer>>2])}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var InternalError;var throwInternalError=message=>{throw new InternalError(message)};var whenDependentTypesAreResolved=(myTypes,dependentTypes,getTypeConverters)=>{myTypes.forEach(function(type){typeDependencies[type]=dependentTypes});function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i{if(registeredTypes.hasOwnProperty(dt)){typeConverters[i]=registeredTypes[dt]}else{unregisteredTypes.push(dt);if(!awaitingDependencies.hasOwnProperty(dt)){awaitingDependencies[dt]=[]}awaitingDependencies[dt].push(()=>{typeConverters[i]=registeredTypes[dt];++registered;if(registered===unregisteredTypes.length){onComplete(typeConverters)}})}});if(0===unregisteredTypes.length){onComplete(typeConverters)}};var __embind_finalize_value_object=structType=>{var reg=structRegistrations[structType];delete structRegistrations[structType];var rawConstructor=reg.rawConstructor;var rawDestructor=reg.rawDestructor;var fieldRecords=reg.fields;var fieldTypes=fieldRecords.map(field=>field.getterReturnType).concat(fieldRecords.map(field=>field.setterArgumentType));whenDependentTypesAreResolved([structType],fieldTypes,fieldTypes=>{var fields={};fieldRecords.forEach((field,i)=>{var fieldName=field.fieldName;var getterReturnType=fieldTypes[i];var getter=field.getter;var getterContext=field.getterContext;var setterArgumentType=fieldTypes[i+fieldRecords.length];var setter=field.setter;var setterContext=field.setterContext;fields[fieldName]={read:ptr=>getterReturnType["fromWireType"](getter(getterContext,ptr)),write:(ptr,o)=>{var destructors=[];setter(setterContext,ptr,setterArgumentType["toWireType"](destructors,o));runDestructors(destructors)}}});return[{name:reg.name,fromWireType:ptr=>{var rv={};for(var i in fields){rv[i]=fields[i].read(ptr)}rawDestructor(ptr);return rv},toWireType:(destructors,o)=>{for(var fieldName in fields){if(!(fieldName in o)){throw new TypeError(`Missing field: "${fieldName}"`)}}var ptr=rawConstructor();for(fieldName in fields){fields[fieldName].write(ptr,o[fieldName])}if(destructors!==null){destructors.push(rawDestructor,ptr)}return ptr},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction:rawDestructor}]})};var __embind_register_bigint=(primitiveType,name,size,minRange,maxRange)=>{};var embind_init_charCodes=()=>{var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes};var embind_charCodes;var readLatin1String=ptr=>{var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret};var BindingError;var throwBindingError=message=>{throw new BindingError(message)};function sharedRegisterType(rawType,registeredInstance,options={}){var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function registerType(rawType,registeredInstance,options={}){if(!("argPackAdvance"in registeredInstance)){throw new TypeError("registerType registeredInstance requires argPackAdvance")}return sharedRegisterType(rawType,registeredInstance,options)}var GenericWireTypeSize=8;var __embind_register_bool=(rawType,name,trueValue,falseValue)=>{name=readLatin1String(name);registerType(rawType,{name:name,fromWireType:function(wt){return!!wt},toWireType:function(destructors,o){return o?trueValue:falseValue},argPackAdvance:GenericWireTypeSize,readValueFromPointer:function(pointer){return this["fromWireType"](HEAPU8[pointer])},destructorFunction:null})};var shallowCopyInternalPointer=o=>({count:o.count,deleteScheduled:o.deleteScheduled,preservePointerOnDelete:o.preservePointerOnDelete,ptr:o.ptr,ptrType:o.ptrType,smartPtr:o.smartPtr,smartPtrType:o.smartPtrType});var throwInstanceAlreadyDeleted=obj=>{function getInstanceTypeName(handle){return handle.$$.ptrType.registeredClass.name}throwBindingError(getInstanceTypeName(obj)+" instance already deleted")};var finalizationRegistry=false;var detachFinalizer=handle=>{};var runDestructor=$$=>{if($$.smartPtr){$$.smartPtrType.rawDestructor($$.smartPtr)}else{$$.ptrType.registeredClass.rawDestructor($$.ptr)}};var releaseClassHandle=$$=>{$$.count.value-=1;var toDelete=0===$$.count.value;if(toDelete){runDestructor($$)}};var downcastPointer=(ptr,ptrClass,desiredClass)=>{if(ptrClass===desiredClass){return ptr}if(undefined===desiredClass.baseClass){return null}var rv=downcastPointer(ptr,ptrClass,desiredClass.baseClass);if(rv===null){return null}return desiredClass.downcast(rv)};var registeredPointers={};var getInheritedInstanceCount=()=>Object.keys(registeredInstances).length;var getLiveInheritedInstances=()=>{var rv=[];for(var k in registeredInstances){if(registeredInstances.hasOwnProperty(k)){rv.push(registeredInstances[k])}}return rv};var deletionQueue=[];var flushPendingDeletes=()=>{while(deletionQueue.length){var obj=deletionQueue.pop();obj.$$.deleteScheduled=false;obj["delete"]()}};var delayFunction;var setDelayFunction=fn=>{delayFunction=fn;if(deletionQueue.length&&delayFunction){delayFunction(flushPendingDeletes)}};var init_embind=()=>{Module["getInheritedInstanceCount"]=getInheritedInstanceCount;Module["getLiveInheritedInstances"]=getLiveInheritedInstances;Module["flushPendingDeletes"]=flushPendingDeletes;Module["setDelayFunction"]=setDelayFunction};var registeredInstances={};var getBasestPointer=(class_,ptr)=>{if(ptr===undefined){throwBindingError("ptr should not be undefined")}while(class_.baseClass){ptr=class_.upcast(ptr);class_=class_.baseClass}return ptr};var getInheritedInstance=(class_,ptr)=>{ptr=getBasestPointer(class_,ptr);return registeredInstances[ptr]};var makeClassHandle=(prototype,record)=>{if(!record.ptrType||!record.ptr){throwInternalError("makeClassHandle requires ptr and ptrType")}var hasSmartPtrType=!!record.smartPtrType;var hasSmartPtr=!!record.smartPtr;if(hasSmartPtrType!==hasSmartPtr){throwInternalError("Both smartPtrType and smartPtr must be specified")}record.count={value:1};return attachFinalizer(Object.create(prototype,{$$:{value:record,writable:true}}))};function RegisteredPointer_fromWireType(ptr){var rawPointer=this.getPointee(ptr);if(!rawPointer){this.destructor(ptr);return null}var registeredInstance=getInheritedInstance(this.registeredClass,rawPointer);if(undefined!==registeredInstance){if(0===registeredInstance.$$.count.value){registeredInstance.$$.ptr=rawPointer;registeredInstance.$$.smartPtr=ptr;return registeredInstance["clone"]()}else{var rv=registeredInstance["clone"]();this.destructor(ptr);return rv}}function makeDefaultHandle(){if(this.isSmartPointer){return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:rawPointer,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this,ptr:ptr})}}var actualType=this.registeredClass.getActualType(rawPointer);var registeredPointerRecord=registeredPointers[actualType];if(!registeredPointerRecord){return makeDefaultHandle.call(this)}var toType;if(this.isConst){toType=registeredPointerRecord.constPointerType}else{toType=registeredPointerRecord.pointerType}var dp=downcastPointer(rawPointer,this.registeredClass,toType.registeredClass);if(dp===null){return makeDefaultHandle.call(this)}if(this.isSmartPointer){return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp})}}var attachFinalizer=handle=>{if("undefined"===typeof FinalizationRegistry){attachFinalizer=handle=>handle;return handle}finalizationRegistry=new FinalizationRegistry(info=>{releaseClassHandle(info.$$)});attachFinalizer=handle=>{var $$=handle.$$;var hasSmartPtr=!!$$.smartPtr;if(hasSmartPtr){var info={$$:$$};finalizationRegistry.register(handle,info,handle)}return handle};detachFinalizer=handle=>finalizationRegistry.unregister(handle);return attachFinalizer(handle)};var init_ClassHandle=()=>{Object.assign(ClassHandle.prototype,{isAliasOf(other){if(!(this instanceof ClassHandle)){return false}if(!(other instanceof ClassHandle)){return false}var leftClass=this.$$.ptrType.registeredClass;var left=this.$$.ptr;other.$$=other.$$;var rightClass=other.$$.ptrType.registeredClass;var right=other.$$.ptr;while(leftClass.baseClass){left=leftClass.upcast(left);leftClass=leftClass.baseClass}while(rightClass.baseClass){right=rightClass.upcast(right);rightClass=rightClass.baseClass}return leftClass===rightClass&&left===right},clone(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.preservePointerOnDelete){this.$$.count.value+=1;return this}else{var clone=attachFinalizer(Object.create(Object.getPrototypeOf(this),{$$:{value:shallowCopyInternalPointer(this.$$)}}));clone.$$.count.value+=1;clone.$$.deleteScheduled=false;return clone}},delete(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}detachFinalizer(this);releaseClassHandle(this.$$);if(!this.$$.preservePointerOnDelete){this.$$.smartPtr=undefined;this.$$.ptr=undefined}},isDeleted(){return!this.$$.ptr},deleteLater(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}deletionQueue.push(this);if(deletionQueue.length===1&&delayFunction){delayFunction(flushPendingDeletes)}this.$$.deleteScheduled=true;return this}})};function ClassHandle(){}var createNamedFunction=(name,body)=>Object.defineProperty(body,"name",{value:name});var ensureOverloadTable=(proto,methodName,humanName)=>{if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(...args){if(!proto[methodName].overloadTable.hasOwnProperty(args.length)){throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${args.length}) - expects one of (${proto[methodName].overloadTable})!`)}return proto[methodName].overloadTable[args.length].apply(this,args)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}};var exposePublicSymbol=(name,value,numArguments)=>{if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError(`Cannot register public name '${name}' twice`)}ensureOverloadTable(Module,name,name);if(Module.hasOwnProperty(numArguments)){throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`)}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;if(undefined!==numArguments){Module[name].numArguments=numArguments}}};var char_0=48;var char_9=57;var makeLegalFunctionName=name=>{if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return`_${name}`}return name};function RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast){this.name=name;this.constructor=constructor;this.instancePrototype=instancePrototype;this.rawDestructor=rawDestructor;this.baseClass=baseClass;this.getActualType=getActualType;this.upcast=upcast;this.downcast=downcast;this.pureVirtualFunctions=[]}var upcastPointer=(ptr,ptrClass,desiredClass)=>{while(ptrClass!==desiredClass){if(!ptrClass.upcast){throwBindingError(`Expected null or instance of ${desiredClass.name}, got an instance of ${ptrClass.name}`)}ptr=ptrClass.upcast(ptr);ptrClass=ptrClass.baseClass}return ptr};function constNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function genericPointerToWireType(destructors,handle){var ptr;if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}if(this.isSmartPointer){ptr=this.rawConstructor();if(destructors!==null){destructors.push(this.rawDestructor,ptr)}return ptr}else{return 0}}if(!handle||!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(!this.isConst&&handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);if(this.isSmartPointer){if(undefined===handle.$$.smartPtr){throwBindingError("Passing raw pointer to smart pointer is illegal")}switch(this.sharingPolicy){case 0:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}break;case 1:ptr=handle.$$.smartPtr;break;case 2:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{var clonedHandle=handle["clone"]();ptr=this.rawShare(ptr,Emval.toHandle(()=>clonedHandle["delete"]()));if(destructors!==null){destructors.push(this.rawDestructor,ptr)}}break;default:throwBindingError("Unsupporting sharing policy")}}return ptr}function nonConstNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}var init_RegisteredPointer=()=>{Object.assign(RegisteredPointer.prototype,{getPointee(ptr){if(this.rawGetPointee){ptr=this.rawGetPointee(ptr)}return ptr},destructor(ptr){this.rawDestructor?.(ptr)},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,fromWireType:RegisteredPointer_fromWireType})};function RegisteredPointer(name,registeredClass,isReference,isConst,isSmartPointer,pointeeType,sharingPolicy,rawGetPointee,rawConstructor,rawShare,rawDestructor){this.name=name;this.registeredClass=registeredClass;this.isReference=isReference;this.isConst=isConst;this.isSmartPointer=isSmartPointer;this.pointeeType=pointeeType;this.sharingPolicy=sharingPolicy;this.rawGetPointee=rawGetPointee;this.rawConstructor=rawConstructor;this.rawShare=rawShare;this.rawDestructor=rawDestructor;if(!isSmartPointer&®isteredClass.baseClass===undefined){if(isConst){this["toWireType"]=constNoSmartPtrRawPointerToWireType;this.destructorFunction=null}else{this["toWireType"]=nonConstNoSmartPtrRawPointerToWireType;this.destructorFunction=null}}else{this["toWireType"]=genericPointerToWireType}}var replacePublicSymbol=(name,value,numArguments)=>{if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistent public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var dynCallLegacy=(sig,ptr,args)=>{sig=sig.replace(/p/g,"i");var f=Module["dynCall_"+sig];return f(ptr,...args)};var wasmTableMirror=[];var wasmTable;var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func};var dynCall=(sig,ptr,args=[])=>{if(sig.includes("j")){return dynCallLegacy(sig,ptr,args)}var rtn=getWasmTableEntry(ptr)(...args);return rtn};var getDynCaller=(sig,ptr)=>(...args)=>dynCall(sig,ptr,args);var embind__requireFunction=(signature,rawFunction)=>{signature=readLatin1String(signature);function makeDynCaller(){if(signature.includes("j")){return getDynCaller(signature,rawFunction)}return getWasmTableEntry(rawFunction)}var fp=makeDynCaller();if(typeof fp!="function"){throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`)}return fp};var extendError=(baseErrorType,errorName)=>{var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return`${this.name}: ${this.message}`}};return errorClass};var UnboundTypeError;var getTypeName=type=>{var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv};var throwUnboundTypeError=(message,types)=>{var unboundTypes=[];var seen={};function visit(type){if(seen[type]){return}if(registeredTypes[type]){return}if(typeDependencies[type]){typeDependencies[type].forEach(visit);return}unboundTypes.push(type);seen[type]=true}types.forEach(visit);throw new UnboundTypeError(`${message}: `+unboundTypes.map(getTypeName).join([", "]))};var __embind_register_class=(rawType,rawPointerType,rawConstPointerType,baseClassRawType,getActualTypeSignature,getActualType,upcastSignature,upcast,downcastSignature,downcast,name,destructorSignature,rawDestructor)=>{name=readLatin1String(name);getActualType=embind__requireFunction(getActualTypeSignature,getActualType);upcast&&=embind__requireFunction(upcastSignature,upcast);downcast&&=embind__requireFunction(downcastSignature,downcast);rawDestructor=embind__requireFunction(destructorSignature,rawDestructor);var legalFunctionName=makeLegalFunctionName(name);exposePublicSymbol(legalFunctionName,function(){throwUnboundTypeError(`Cannot construct ${name} due to unbound types`,[baseClassRawType])});whenDependentTypesAreResolved([rawType,rawPointerType,rawConstPointerType],baseClassRawType?[baseClassRawType]:[],base=>{base=base[0];var baseClass;var basePrototype;if(baseClassRawType){baseClass=base.registeredClass;basePrototype=baseClass.instancePrototype}else{basePrototype=ClassHandle.prototype}var constructor=createNamedFunction(name,function(...args){if(Object.getPrototypeOf(this)!==instancePrototype){throw new BindingError("Use 'new' to construct "+name)}if(undefined===registeredClass.constructor_body){throw new BindingError(name+" has no accessible constructor")}var body=registeredClass.constructor_body[args.length];if(undefined===body){throw new BindingError(`Tried to invoke ctor of ${name} with invalid number of parameters (${args.length}) - expected (${Object.keys(registeredClass.constructor_body).toString()}) parameters instead!`)}return body.apply(this,args)});var instancePrototype=Object.create(basePrototype,{constructor:{value:constructor}});constructor.prototype=instancePrototype;var registeredClass=new RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast);if(registeredClass.baseClass){registeredClass.baseClass.__derivedClasses??=[];registeredClass.baseClass.__derivedClasses.push(registeredClass)}var referenceConverter=new RegisteredPointer(name,registeredClass,true,false,false);var pointerConverter=new RegisteredPointer(name+"*",registeredClass,false,false,false);var constPointerConverter=new RegisteredPointer(name+" const*",registeredClass,false,true,false);registeredPointers[rawType]={pointerType:pointerConverter,constPointerType:constPointerConverter};replacePublicSymbol(legalFunctionName,constructor);return[referenceConverter,pointerConverter,constPointerConverter]})};var heap32VectorToArray=(count,firstElement)=>{var array=[];for(var i=0;i>2])}return array};function usesDestructorStack(argTypes){for(var i=1;i0?", ":"")+argsListWired}invokerFnBody+=(returns||isAsync?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i{var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);invoker=embind__requireFunction(invokerSignature,invoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`constructor ${classType.name}`;if(undefined===classType.registeredClass.constructor_body){classType.registeredClass.constructor_body=[]}if(undefined!==classType.registeredClass.constructor_body[argCount-1]){throw new BindingError(`Cannot register multiple constructors with identical number of parameters (${argCount-1}) for class '${classType.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`)}classType.registeredClass.constructor_body[argCount-1]=()=>{throwUnboundTypeError(`Cannot construct ${classType.name} due to unbound types`,rawArgTypes)};whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{argTypes.splice(1,0,null);classType.registeredClass.constructor_body[argCount-1]=craftInvokerFunction(humanName,argTypes,null,invoker,rawConstructor);return[]});return[]})};var getFunctionName=signature=>{signature=signature.trim();const argsIndex=signature.indexOf("(");if(argsIndex!==-1){return signature.substr(0,argsIndex)}else{return signature}};var __embind_register_class_function=(rawClassType,methodName,argCount,rawArgTypesAddr,invokerSignature,rawInvoker,context,isPureVirtual,isAsync)=>{var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);methodName=readLatin1String(methodName);methodName=getFunctionName(methodName);rawInvoker=embind__requireFunction(invokerSignature,rawInvoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`${classType.name}.${methodName}`;if(methodName.startsWith("@@")){methodName=Symbol[methodName.substring(2)]}if(isPureVirtual){classType.registeredClass.pureVirtualFunctions.push(methodName)}function unboundTypesHandler(){throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`,rawArgTypes)}var proto=classType.registeredClass.instancePrototype;var method=proto[methodName];if(undefined===method||undefined===method.overloadTable&&method.className!==classType.name&&method.argCount===argCount-2){unboundTypesHandler.argCount=argCount-2;unboundTypesHandler.className=classType.name;proto[methodName]=unboundTypesHandler}else{ensureOverloadTable(proto,methodName,humanName);proto[methodName].overloadTable[argCount-2]=unboundTypesHandler}whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{var memberFunction=craftInvokerFunction(humanName,argTypes,classType,rawInvoker,context,isAsync);if(undefined===proto[methodName].overloadTable){memberFunction.argCount=argCount-2;proto[methodName]=memberFunction}else{proto[methodName].overloadTable[argCount-2]=memberFunction}return[]});return[]})};var __embind_register_constant=(name,type,value)=>{name=readLatin1String(name);whenDependentTypesAreResolved([],[type],type=>{type=type[0];Module[name]=type["fromWireType"](value);return[]})};var emval_freelist=[];var emval_handles=[];var __emval_decref=handle=>{if(handle>9&&0===--emval_handles[handle+1]){emval_handles[handle]=undefined;emval_freelist.push(handle)}};var count_emval_handles=()=>emval_handles.length/2-5-emval_freelist.length;var init_emval=()=>{emval_handles.push(0,1,undefined,1,null,1,true,1,false,1);Module["count_emval_handles"]=count_emval_handles};var Emval={toValue:handle=>{if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handles[handle]},toHandle:value=>{switch(value){case undefined:return 2;case null:return 4;case true:return 6;case false:return 8;default:{const handle=emval_freelist.pop()||emval_handles.length;emval_handles[handle]=value;emval_handles[handle+1]=1;return handle}}}};var EmValType={name:"emscripten::val",fromWireType:handle=>{var rv=Emval.toValue(handle);__emval_decref(handle);return rv},toWireType:(destructors,value)=>Emval.toHandle(value),argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction:null};var __embind_register_emval=rawType=>registerType(rawType,EmValType);var enumReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?function(pointer){return this["fromWireType"](HEAP8[pointer])}:function(pointer){return this["fromWireType"](HEAPU8[pointer])};case 2:return signed?function(pointer){return this["fromWireType"](HEAP16[pointer>>1])}:function(pointer){return this["fromWireType"](HEAPU16[pointer>>1])};case 4:return signed?function(pointer){return this["fromWireType"](HEAP32[pointer>>2])}:function(pointer){return this["fromWireType"](HEAPU32[pointer>>2])};default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};var __embind_register_enum=(rawType,name,size,isSigned)=>{name=readLatin1String(name);function ctor(){}ctor.values={};registerType(rawType,{name:name,constructor:ctor,fromWireType:function(c){return this.constructor.values[c]},toWireType:(destructors,c)=>c.value,argPackAdvance:GenericWireTypeSize,readValueFromPointer:enumReadValueFromPointer(name,size,isSigned),destructorFunction:null});exposePublicSymbol(name,ctor)};var requireRegisteredType=(rawType,humanName)=>{var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(`${humanName} has unknown type ${getTypeName(rawType)}`)}return impl};var __embind_register_enum_value=(rawEnumType,name,enumValue)=>{var enumType=requireRegisteredType(rawEnumType,"enum");name=readLatin1String(name);var Enum=enumType.constructor;var Value=Object.create(enumType.constructor.prototype,{value:{value:enumValue},constructor:{value:createNamedFunction(`${enumType.name}_${name}`,function(){})}});Enum.values[enumValue]=Value;Enum[name]=Value};var embindRepr=v=>{if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}};var floatReadValueFromPointer=(name,width)=>{switch(width){case 4:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 8:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError(`invalid float width (${width}): ${name}`)}};var __embind_register_float=(rawType,name,size)=>{name=readLatin1String(name);registerType(rawType,{name:name,fromWireType:value=>value,toWireType:(destructors,value)=>value,argPackAdvance:GenericWireTypeSize,readValueFromPointer:floatReadValueFromPointer(name,size),destructorFunction:null})};var __embind_register_function=(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn,isAsync)=>{var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);name=getFunctionName(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,function(){throwUnboundTypeError(`Cannot call ${name} due to unbound types`,argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,argTypes=>{var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn,isAsync),argCount-1);return[]})};var integerReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?pointer=>HEAP8[pointer]:pointer=>HEAPU8[pointer];case 2:return signed?pointer=>HEAP16[pointer>>1]:pointer=>HEAPU16[pointer>>1];case 4:return signed?pointer=>HEAP32[pointer>>2]:pointer=>HEAPU32[pointer>>2];default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};var __embind_register_integer=(primitiveType,name,size,minRange,maxRange)=>{name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var fromWireType=value=>value;if(minRange===0){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift}var isUnsignedType=name.includes("unsigned");var checkAssertions=(value,toTypeName)=>{};var toWireType;if(isUnsignedType){toWireType=function(destructors,value){checkAssertions(value,this.name);return value>>>0}}else{toWireType=function(destructors,value){checkAssertions(value,this.name);return value}}registerType(primitiveType,{name:name,fromWireType:fromWireType,toWireType:toWireType,argPackAdvance:GenericWireTypeSize,readValueFromPointer:integerReadValueFromPointer(name,size,minRange!==0),destructorFunction:null})};var __embind_register_memory_view=(rawType,dataTypeIndex,name)=>{var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){var size=HEAPU32[handle>>2];var data=HEAPU32[handle+4>>2];return new TA(HEAP8.buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,fromWireType:decodeMemoryView,argPackAdvance:GenericWireTypeSize,readValueFromPointer:decodeMemoryView},{ignoreDuplicateRegistrations:true})};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx,maxBytesToRead)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var __embind_register_std_string=(rawType,name)=>{name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,fromWireType(value){var length=HEAPU32[value>>2];var payload=value+4;var str;if(stdStringIsUTF8){var decodeStartPtr=payload;for(var i=0;i<=length;++i){var currentBytePtr=payload+i;if(i==length||HEAPU8[currentBytePtr]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+i]=charCode}}else{for(var i=0;i{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr};var lengthBytesUTF16=str=>str.length*2;var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr};var lengthBytesUTF32=str=>{var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len};var __embind_register_std_wstring=(rawType,charSize,name)=>{name=readLatin1String(name);var decodeString,encodeString,readCharAt,lengthBytesUTF;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16;readCharAt=pointer=>HEAPU16[pointer>>1]}else if(charSize===4){decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32;readCharAt=pointer=>HEAPU32[pointer>>2]}registerType(rawType,{name:name,fromWireType:value=>{var length=HEAPU32[value>>2];var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||readCharAt(currentBytePtr)==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},toWireType:(destructors,value)=>{if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length/charSize;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction(ptr){_free(ptr)}})};var __embind_register_value_object=(rawType,name,constructorSignature,rawConstructor,destructorSignature,rawDestructor)=>{structRegistrations[rawType]={name:readLatin1String(name),rawConstructor:embind__requireFunction(constructorSignature,rawConstructor),rawDestructor:embind__requireFunction(destructorSignature,rawDestructor),fields:[]}};var __embind_register_value_object_field=(structType,fieldName,getterReturnType,getterSignature,getter,getterContext,setterArgumentType,setterSignature,setter,setterContext)=>{structRegistrations[structType].fields.push({fieldName:readLatin1String(fieldName),getterReturnType:getterReturnType,getter:embind__requireFunction(getterSignature,getter),getterContext:getterContext,setterArgumentType:setterArgumentType,setter:embind__requireFunction(setterSignature,setter),setterContext:setterContext})};var __embind_register_void=(rawType,name)=>{name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,argPackAdvance:0,fromWireType:()=>undefined,toWireType:(destructors,o)=>undefined})};var __emscripten_memcpy_js=(dest,src,num)=>HEAPU8.copyWithin(dest,src,src+num);var emval_returnValue=(returnType,destructorsRef,handle)=>{var destructors=[];var result=returnType["toWireType"](destructors,handle);if(destructors.length){HEAPU32[destructorsRef>>2]=Emval.toHandle(destructors)}return result};var __emval_as=(handle,returnType,destructorsRef)=>{handle=Emval.toValue(handle);returnType=requireRegisteredType(returnType,"emval::as");return emval_returnValue(returnType,destructorsRef,handle)};var emval_methodCallers=[];var __emval_call=(caller,handle,destructorsRef,args)=>{caller=emval_methodCallers[caller];handle=Emval.toValue(handle);return caller(null,handle,destructorsRef,args)};var emval_symbols={};var getStringOrSymbol=address=>{var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}return symbol};var __emval_call_method=(caller,objHandle,methodName,destructorsRef,args)=>{caller=emval_methodCallers[caller];objHandle=Emval.toValue(objHandle);methodName=getStringOrSymbol(methodName);return caller(objHandle,objHandle[methodName],destructorsRef,args)};var emval_get_global=()=>{if(typeof globalThis=="object"){return globalThis}return function(){return Function}()("return this")()};var __emval_get_global=name=>{if(name===0){return Emval.toHandle(emval_get_global())}else{name=getStringOrSymbol(name);return Emval.toHandle(emval_get_global()[name])}};var emval_addMethodCaller=caller=>{var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id};var emval_lookupTypes=(argCount,argTypes)=>{var a=new Array(argCount);for(var i=0;i>2],"parameter "+i)}return a};var reflectConstruct=Reflect.construct;var __emval_get_method_caller=(argCount,argTypes,kind)=>{var types=emval_lookupTypes(argCount,argTypes);var retType=types.shift();argCount--;var functionBody=`return function (obj, func, destructorsRef, args) {\n`;var offset=0;var argsList=[];if(kind===0){argsList.push("obj")}var params=["retType"];var args=[retType];for(var i=0;it.name).join(", ")}) => ${retType.name}>`;return emval_addMethodCaller(createNamedFunction(functionName,invokerFunction))};var __emval_get_module_property=name=>{name=getStringOrSymbol(name);return Emval.toHandle(Module[name])};var __emval_get_property=(handle,key)=>{handle=Emval.toValue(handle);key=Emval.toValue(key);return Emval.toHandle(handle[key])};var __emval_incref=handle=>{if(handle>9){emval_handles[handle+1]+=1}};var __emval_new_cstring=v=>Emval.toHandle(getStringOrSymbol(v));var __emval_run_destructors=handle=>{var destructors=Emval.toValue(handle);runDestructors(destructors);__emval_decref(handle)};var getHeapMax=()=>2147483648;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var _fd_close=fd=>52;var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);return 70}var printCharBuffers=[null,[],[]];var printChar=(stream,curr)=>{var buffer=printCharBuffers[stream];if(curr===0||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer,0));buffer.length=0}else{buffer.push(curr)}};var _fd_write=(fd,iov,iovcnt,pnum)=>{var num=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;for(var j=0;j>2]=num;return 0};InternalError=Module["InternalError"]=class InternalError extends Error{constructor(message){super(message);this.name="InternalError"}};embind_init_charCodes();BindingError=Module["BindingError"]=class BindingError extends Error{constructor(message){super(message);this.name="BindingError"}};init_ClassHandle();init_embind();init_RegisteredPointer();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");init_emval();var wasmImports={K:___cxa_throw,G:__abort_js,s:__embind_finalize_value_object,C:__embind_register_bigint,I:__embind_register_bool,w:__embind_register_class,v:__embind_register_class_constructor,d:__embind_register_class_function,m:__embind_register_constant,H:__embind_register_emval,o:__embind_register_enum,a:__embind_register_enum_value,A:__embind_register_float,i:__embind_register_function,l:__embind_register_integer,f:__embind_register_memory_view,z:__embind_register_std_string,u:__embind_register_std_wstring,t:__embind_register_value_object,c:__embind_register_value_object_field,J:__embind_register_void,F:__emscripten_memcpy_js,n:__emval_as,q:__emval_call,p:__emval_call_method,b:__emval_decref,x:__emval_get_global,j:__emval_get_method_caller,r:__emval_get_module_property,g:__emval_get_property,k:__emval_incref,h:__emval_new_cstring,e:__emval_run_destructors,D:_emscripten_resize_heap,E:_fd_close,B:_fd_seek,y:_fd_write};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["M"])();var ___getTypeName=a0=>(___getTypeName=wasmExports["N"])(a0);var _malloc=a0=>(_malloc=wasmExports["O"])(a0);var _free=a0=>(_free=wasmExports["Q"])(a0);var ___cxa_is_pointer_type=a0=>(___cxa_is_pointer_type=wasmExports["R"])(a0);var dynCall_jiji=Module["dynCall_jiji"]=(a0,a1,a2,a3,a4)=>(dynCall_jiji=Module["dynCall_jiji"]=wasmExports["S"])(a0,a1,a2,a3,a4);var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve(Module);Module["onRuntimeInitialized"]?.();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run();moduleRtn=readyPromise; - return BASIS.ready + return moduleRtn; } ); })(); if (typeof exports === 'object' && typeof module === 'object') module.exports = BASIS; else if (typeof define === 'function' && define['amd']) - define([], function() { return BASIS; }); -else if (typeof exports === 'object') - exports["BASIS"] = BASIS; + define([], () => BASIS); diff --git a/examples/jsm/libs/basis/basis_transcoder.wasm b/examples/jsm/libs/basis/basis_transcoder.wasm index 4b9c3437170cf2..bc646825614381 100644 Binary files a/examples/jsm/libs/basis/basis_transcoder.wasm and b/examples/jsm/libs/basis/basis_transcoder.wasm differ diff --git a/examples/jsm/libs/ktx-parse.module.js b/examples/jsm/libs/ktx-parse.module.js index c1d66bc7462119..3593d4378b02e0 100644 --- a/examples/jsm/libs/ktx-parse.module.js +++ b/examples/jsm/libs/ktx-parse.module.js @@ -1 +1 @@ -const t=0,e=1,n=2,i=3,s=0,a=0,r=2,o=0,l=1,f=160,U=161,c=162,h=163,_=0,p=1,g=0,y=1,x=2,u=3,b=4,d=5,m=6,w=7,D=8,B=9,L=10,A=11,k=12,v=13,S=14,I=15,O=16,T=17,V=18,E=0,F=1,P=2,C=3,z=4,M=5,W=6,N=7,H=8,K=9,X=10,j=11,R=0,Y=1,q=2,G=13,J=14,Q=15,Z=128,$=64,tt=32,et=16,nt=0,it=1,st=2,at=3,rt=4,ot=5,lt=6,ft=7,Ut=8,ct=9,ht=10,_t=13,pt=14,gt=15,yt=16,xt=17,ut=20,bt=21,dt=22,mt=23,wt=24,Dt=27,Bt=28,Lt=29,At=30,kt=31,vt=34,St=35,It=36,Ot=37,Tt=38,Vt=41,Et=42,Ft=43,Pt=44,Ct=45,zt=48,Mt=49,Wt=50,Nt=58,Ht=59,Kt=62,Xt=63,jt=64,Rt=65,Yt=68,qt=69,Gt=70,Jt=71,Qt=74,Zt=75,$t=76,te=77,ee=78,ne=81,ie=82,se=83,ae=84,re=85,oe=88,le=89,fe=90,Ue=91,ce=92,he=95,_e=96,pe=97,ge=98,ye=99,xe=100,ue=101,be=102,de=103,me=104,we=105,De=106,Be=107,Le=108,Ae=109,ke=110,ve=111,Se=112,Ie=113,Oe=114,Te=115,Ve=116,Ee=117,Fe=118,Pe=119,Ce=120,ze=121,Me=122,We=123,Ne=124,He=125,Ke=126,Xe=127,je=128,Re=129,Ye=130,qe=131,Ge=132,Je=133,Qe=134,Ze=135,$e=136,tn=137,en=138,nn=139,sn=140,an=141,rn=142,on=143,ln=144,fn=145,Un=146,cn=147,hn=148,_n=149,pn=150,gn=151,yn=152,xn=153,un=154,bn=155,dn=156,mn=157,wn=158,Dn=159,Bn=160,Ln=161,An=162,kn=163,vn=164,Sn=165,In=166,On=167,Tn=168,Vn=169,En=170,Fn=171,Pn=172,Cn=173,zn=174,Mn=175,Wn=176,Nn=177,Hn=178,Kn=179,Xn=180,jn=181,Rn=182,Yn=183,qn=184,Gn=1000156007,Jn=1000156008,Qn=1000156009,Zn=1000156010,$n=1000156011,ti=1000156017,ei=1000156018,ni=1000156019,ii=1000156020,si=1000156021,ai=1000054e3,ri=1000054001,oi=1000054002,li=1000054003,fi=1000054004,Ui=1000054005,ci=1000054006,hi=1000054007,_i=1000066e3,pi=1000066001,gi=1000066002,yi=1000066003,xi=1000066004,ui=1000066005,bi=1000066006,di=1000066007,mi=1000066008,wi=1000066009,Di=1000066010,Bi=1000066011,Li=1000066012,Ai=1000066013,ki=100034e4,vi=1000340001;class Si{constructor(){this.vkFormat=0,this.typeSize=1,this.pixelWidth=0,this.pixelHeight=0,this.pixelDepth=0,this.layerCount=0,this.faceCount=1,this.supercompressionScheme=0,this.levels=[],this.dataFormatDescriptor=[{vendorId:0,descriptorType:0,descriptorBlockSize:0,versionNumber:2,colorModel:0,colorPrimaries:1,transferFunction:2,flags:0,texelBlockDimension:[0,0,0,0],bytesPlane:[0,0,0,0,0,0,0,0],samples:[]}],this.keyValue={},this.globalData=null}}class Ii{constructor(t,e,n,i){this._dataView=new DataView(t.buffer,t.byteOffset+e,n),this._littleEndian=i,this._offset=0}_nextUint8(){const t=this._dataView.getUint8(this._offset);return this._offset+=1,t}_nextUint16(){const t=this._dataView.getUint16(this._offset,this._littleEndian);return this._offset+=2,t}_nextUint32(){const t=this._dataView.getUint32(this._offset,this._littleEndian);return this._offset+=4,t}_nextUint64(){const t=this._dataView.getUint32(this._offset,this._littleEndian)+2**32*this._dataView.getUint32(this._offset+4,this._littleEndian);return this._offset+=8,t}_nextInt32(){const t=this._dataView.getInt32(this._offset,this._littleEndian);return this._offset+=4,t}_skip(t){return this._offset+=t,this}_scan(t,e=0){const n=this._offset;let i=0;for(;this._dataView.getUint8(this._offset)!==e&&i0?c+a.byteLength:0;h%8&&(h+=8-h%8);const _=[],p=new DataView(new ArrayBuffer(3*t.levels.length*8));let g=(h||c+a.byteLength)+n.byteLength;for(let e=0;e0?h:0),!0),x.setBigUint64(60,BigInt(n.byteLength),!0),new Uint8Array(Fi([new Uint8Array(Ti).buffer,y,p.buffer,o,a,h>0?new ArrayBuffer(h-(c+a.byteLength)):new ArrayBuffer(0),n,..._]))}export{Q as KHR_DF_CHANNEL_RGBSDA_ALPHA,q as KHR_DF_CHANNEL_RGBSDA_BLUE,J as KHR_DF_CHANNEL_RGBSDA_DEPTH,Y as KHR_DF_CHANNEL_RGBSDA_GREEN,R as KHR_DF_CHANNEL_RGBSDA_RED,G as KHR_DF_CHANNEL_RGBSDA_STENCIL,p as KHR_DF_FLAG_ALPHA_PREMULTIPLIED,_ as KHR_DF_FLAG_ALPHA_STRAIGHT,s as KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT,c as KHR_DF_MODEL_ASTC,f as KHR_DF_MODEL_ETC1,h as KHR_DF_MODEL_ETC1S,U as KHR_DF_MODEL_ETC2,l as KHR_DF_MODEL_RGBSDA,o as KHR_DF_MODEL_UNSPECIFIED,W as KHR_DF_PRIMARIES_ACES,N as KHR_DF_PRIMARIES_ACESCC,j as KHR_DF_PRIMARIES_ADOBERGB,z as KHR_DF_PRIMARIES_BT2020,P as KHR_DF_PRIMARIES_BT601_EBU,C as KHR_DF_PRIMARIES_BT601_SMPTE,F as KHR_DF_PRIMARIES_BT709,M as KHR_DF_PRIMARIES_CIEXYZ,X as KHR_DF_PRIMARIES_DISPLAYP3,H as KHR_DF_PRIMARIES_NTSC1953,K as KHR_DF_PRIMARIES_PAL525,E as KHR_DF_PRIMARIES_UNSPECIFIED,tt as KHR_DF_SAMPLE_DATATYPE_EXPONENT,Z as KHR_DF_SAMPLE_DATATYPE_FLOAT,et as KHR_DF_SAMPLE_DATATYPE_LINEAR,$ as KHR_DF_SAMPLE_DATATYPE_SIGNED,O as KHR_DF_TRANSFER_ACESCC,T as KHR_DF_TRANSFER_ACESCCT,V as KHR_DF_TRANSFER_ADOBERGB,w as KHR_DF_TRANSFER_BT1886,k as KHR_DF_TRANSFER_DCIP3,B as KHR_DF_TRANSFER_HLG_EOTF,D as KHR_DF_TRANSFER_HLG_OETF,u as KHR_DF_TRANSFER_ITU,y as KHR_DF_TRANSFER_LINEAR,b as KHR_DF_TRANSFER_NTSC,S as KHR_DF_TRANSFER_PAL625_EOTF,v as KHR_DF_TRANSFER_PAL_OETF,L as KHR_DF_TRANSFER_PQ_EOTF,A as KHR_DF_TRANSFER_PQ_OETF,d as KHR_DF_TRANSFER_SLOG,m as KHR_DF_TRANSFER_SLOG2,x as KHR_DF_TRANSFER_SRGB,I as KHR_DF_TRANSFER_ST240,g as KHR_DF_TRANSFER_UNSPECIFIED,a as KHR_DF_VENDORID_KHRONOS,r as KHR_DF_VERSION,e as KHR_SUPERCOMPRESSION_BASISLZ,t as KHR_SUPERCOMPRESSION_NONE,i as KHR_SUPERCOMPRESSION_ZLIB,n as KHR_SUPERCOMPRESSION_ZSTD,Si as KTX2Container,Ut as VK_FORMAT_A1R5G5B5_UNORM_PACK16,qt as VK_FORMAT_A2B10G10R10_SINT_PACK32,Rt as VK_FORMAT_A2B10G10R10_SNORM_PACK32,Yt as VK_FORMAT_A2B10G10R10_UINT_PACK32,jt as VK_FORMAT_A2B10G10R10_UNORM_PACK32,Xt as VK_FORMAT_A2R10G10B10_SINT_PACK32,Ht as VK_FORMAT_A2R10G10B10_SNORM_PACK32,Kt as VK_FORMAT_A2R10G10B10_UINT_PACK32,Nt as VK_FORMAT_A2R10G10B10_UNORM_PACK32,vi as VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT,ki as VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT,Bi as VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT,Xn as VK_FORMAT_ASTC_10x10_SRGB_BLOCK,Kn as VK_FORMAT_ASTC_10x10_UNORM_BLOCK,mi as VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT,zn as VK_FORMAT_ASTC_10x5_SRGB_BLOCK,Cn as VK_FORMAT_ASTC_10x5_UNORM_BLOCK,wi as VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT,Wn as VK_FORMAT_ASTC_10x6_SRGB_BLOCK,Mn as VK_FORMAT_ASTC_10x6_UNORM_BLOCK,Di as VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT,Hn as VK_FORMAT_ASTC_10x8_SRGB_BLOCK,Nn as VK_FORMAT_ASTC_10x8_UNORM_BLOCK,Li as VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT,Rn as VK_FORMAT_ASTC_12x10_SRGB_BLOCK,jn as VK_FORMAT_ASTC_12x10_UNORM_BLOCK,Ai as VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT,qn as VK_FORMAT_ASTC_12x12_SRGB_BLOCK,Yn as VK_FORMAT_ASTC_12x12_UNORM_BLOCK,_i as VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT,wn as VK_FORMAT_ASTC_4x4_SRGB_BLOCK,mn as VK_FORMAT_ASTC_4x4_UNORM_BLOCK,pi as VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT,Bn as VK_FORMAT_ASTC_5x4_SRGB_BLOCK,Dn as VK_FORMAT_ASTC_5x4_UNORM_BLOCK,gi as VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT,An as VK_FORMAT_ASTC_5x5_SRGB_BLOCK,Ln as VK_FORMAT_ASTC_5x5_UNORM_BLOCK,yi as VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT,vn as VK_FORMAT_ASTC_6x5_SRGB_BLOCK,kn as VK_FORMAT_ASTC_6x5_UNORM_BLOCK,xi as VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT,In as VK_FORMAT_ASTC_6x6_SRGB_BLOCK,Sn as VK_FORMAT_ASTC_6x6_UNORM_BLOCK,ui as VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT,Tn as VK_FORMAT_ASTC_8x5_SRGB_BLOCK,On as VK_FORMAT_ASTC_8x5_UNORM_BLOCK,bi as VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT,En as VK_FORMAT_ASTC_8x6_SRGB_BLOCK,Vn as VK_FORMAT_ASTC_8x6_UNORM_BLOCK,di as VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT,Pn as VK_FORMAT_ASTC_8x8_SRGB_BLOCK,Fn as VK_FORMAT_ASTC_8x8_UNORM_BLOCK,Me as VK_FORMAT_B10G11R11_UFLOAT_PACK32,$n as VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,si as VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,at as VK_FORMAT_B4G4R4A4_UNORM_PACK16,ft as VK_FORMAT_B5G5R5A1_UNORM_PACK16,ot as VK_FORMAT_B5G6R5_UNORM_PACK16,Mt as VK_FORMAT_B8G8R8A8_SINT,Ct as VK_FORMAT_B8G8R8A8_SNORM,Wt as VK_FORMAT_B8G8R8A8_SRGB,zt as VK_FORMAT_B8G8R8A8_UINT,Pt as VK_FORMAT_B8G8R8A8_UNORM,St as VK_FORMAT_B8G8R8_SINT,kt as VK_FORMAT_B8G8R8_SNORM,It as VK_FORMAT_B8G8R8_SRGB,vt as VK_FORMAT_B8G8R8_UINT,At as VK_FORMAT_B8G8R8_UNORM,Qe as VK_FORMAT_BC1_RGBA_SRGB_BLOCK,Je as VK_FORMAT_BC1_RGBA_UNORM_BLOCK,Ge as VK_FORMAT_BC1_RGB_SRGB_BLOCK,qe as VK_FORMAT_BC1_RGB_UNORM_BLOCK,$e as VK_FORMAT_BC2_SRGB_BLOCK,Ze as VK_FORMAT_BC2_UNORM_BLOCK,en as VK_FORMAT_BC3_SRGB_BLOCK,tn as VK_FORMAT_BC3_UNORM_BLOCK,sn as VK_FORMAT_BC4_SNORM_BLOCK,nn as VK_FORMAT_BC4_UNORM_BLOCK,rn as VK_FORMAT_BC5_SNORM_BLOCK,an as VK_FORMAT_BC5_UNORM_BLOCK,ln as VK_FORMAT_BC6H_SFLOAT_BLOCK,on as VK_FORMAT_BC6H_UFLOAT_BLOCK,Un as VK_FORMAT_BC7_SRGB_BLOCK,fn as VK_FORMAT_BC7_UNORM_BLOCK,Ne as VK_FORMAT_D16_UNORM,je as VK_FORMAT_D16_UNORM_S8_UINT,Re as VK_FORMAT_D24_UNORM_S8_UINT,Ke as VK_FORMAT_D32_SFLOAT,Ye as VK_FORMAT_D32_SFLOAT_S8_UINT,We as VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,dn as VK_FORMAT_EAC_R11G11_SNORM_BLOCK,bn as VK_FORMAT_EAC_R11G11_UNORM_BLOCK,un as VK_FORMAT_EAC_R11_SNORM_BLOCK,xn as VK_FORMAT_EAC_R11_UNORM_BLOCK,pn as VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,_n as VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,yn as VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,gn as VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,hn as VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,cn as VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,Zn as VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,ii as VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,fi as VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG,ai as VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG,Ui as VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG,ri as VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG,ci as VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG,oi as VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG,hi as VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG,li as VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG,Qn as VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,Jn as VK_FORMAT_R10X6G10X6_UNORM_2PACK16,Gn as VK_FORMAT_R10X6_UNORM_PACK16,ni as VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,ei as VK_FORMAT_R12X4G12X4_UNORM_2PACK16,ti as VK_FORMAT_R12X4_UNORM_PACK16,pe as VK_FORMAT_R16G16B16A16_SFLOAT,_e as VK_FORMAT_R16G16B16A16_SINT,ce as VK_FORMAT_R16G16B16A16_SNORM,he as VK_FORMAT_R16G16B16A16_UINT,Ue as VK_FORMAT_R16G16B16A16_UNORM,fe as VK_FORMAT_R16G16B16_SFLOAT,le as VK_FORMAT_R16G16B16_SINT,re as VK_FORMAT_R16G16B16_SNORM,oe as VK_FORMAT_R16G16B16_UINT,ae as VK_FORMAT_R16G16B16_UNORM,se as VK_FORMAT_R16G16_SFLOAT,ie as VK_FORMAT_R16G16_SINT,ee as VK_FORMAT_R16G16_SNORM,ne as VK_FORMAT_R16G16_UINT,te as VK_FORMAT_R16G16_UNORM,$t as VK_FORMAT_R16_SFLOAT,Zt as VK_FORMAT_R16_SINT,Jt as VK_FORMAT_R16_SNORM,Qt as VK_FORMAT_R16_UINT,Gt as VK_FORMAT_R16_UNORM,Ae as VK_FORMAT_R32G32B32A32_SFLOAT,Le as VK_FORMAT_R32G32B32A32_SINT,Be as VK_FORMAT_R32G32B32A32_UINT,De as VK_FORMAT_R32G32B32_SFLOAT,we as VK_FORMAT_R32G32B32_SINT,me as VK_FORMAT_R32G32B32_UINT,de as VK_FORMAT_R32G32_SFLOAT,be as VK_FORMAT_R32G32_SINT,ue as VK_FORMAT_R32G32_UINT,xe as VK_FORMAT_R32_SFLOAT,ye as VK_FORMAT_R32_SINT,ge as VK_FORMAT_R32_UINT,st as VK_FORMAT_R4G4B4A4_UNORM_PACK16,it as VK_FORMAT_R4G4_UNORM_PACK8,lt as VK_FORMAT_R5G5B5A1_UNORM_PACK16,rt as VK_FORMAT_R5G6B5_UNORM_PACK16,ze as VK_FORMAT_R64G64B64A64_SFLOAT,Ce as VK_FORMAT_R64G64B64A64_SINT,Pe as VK_FORMAT_R64G64B64A64_UINT,Fe as VK_FORMAT_R64G64B64_SFLOAT,Ee as VK_FORMAT_R64G64B64_SINT,Ve as VK_FORMAT_R64G64B64_UINT,Te as VK_FORMAT_R64G64_SFLOAT,Oe as VK_FORMAT_R64G64_SINT,Ie as VK_FORMAT_R64G64_UINT,Se as VK_FORMAT_R64_SFLOAT,ve as VK_FORMAT_R64_SINT,ke as VK_FORMAT_R64_UINT,Et as VK_FORMAT_R8G8B8A8_SINT,Tt as VK_FORMAT_R8G8B8A8_SNORM,Ft as VK_FORMAT_R8G8B8A8_SRGB,Vt as VK_FORMAT_R8G8B8A8_UINT,Ot as VK_FORMAT_R8G8B8A8_UNORM,Bt as VK_FORMAT_R8G8B8_SINT,wt as VK_FORMAT_R8G8B8_SNORM,Lt as VK_FORMAT_R8G8B8_SRGB,Dt as VK_FORMAT_R8G8B8_UINT,mt as VK_FORMAT_R8G8B8_UNORM,bt as VK_FORMAT_R8G8_SINT,xt as VK_FORMAT_R8G8_SNORM,dt as VK_FORMAT_R8G8_SRGB,ut as VK_FORMAT_R8G8_UINT,yt as VK_FORMAT_R8G8_UNORM,pt as VK_FORMAT_R8_SINT,ht as VK_FORMAT_R8_SNORM,gt as VK_FORMAT_R8_SRGB,_t as VK_FORMAT_R8_UINT,ct as VK_FORMAT_R8_UNORM,Xe as VK_FORMAT_S8_UINT,nt as VK_FORMAT_UNDEFINED,He as VK_FORMAT_X8_D24_UNORM_PACK32,Pi as read,Mi as write}; +const t=0,e=1,n=2,i=3,s=0,a=0,r=2,o=0,l=1,f=160,h=161,U=162,c=163,_=166,p=0,g=1,y=0,x=1,u=2,b=3,d=4,w=5,m=6,D=7,B=8,L=9,v=10,A=11,k=12,V=13,I=14,S=15,F=16,O=17,E=18,T=0,C=1,M=2,P=3,z=4,W=5,H=6,N=7,K=8,X=9,R=10,Y=11,j=0,q=1,G=2,J=13,Q=14,Z=15,$=128,tt=64,et=32,nt=16,it=0,st=1,at=2,rt=3,ot=4,lt=5,ft=6,ht=7,Ut=8,ct=9,_t=10,pt=13,gt=14,yt=15,xt=16,ut=17,bt=20,dt=21,wt=22,mt=23,Dt=24,Bt=27,Lt=28,vt=29,At=30,kt=31,Vt=34,It=35,St=36,Ft=37,Ot=38,Et=41,Tt=42,Ct=43,Mt=44,Pt=45,zt=48,Wt=49,Ht=50,Nt=58,Kt=59,Xt=62,Rt=63,Yt=64,jt=65,qt=68,Gt=69,Jt=70,Qt=71,Zt=74,$t=75,te=76,ee=77,ne=78,ie=81,se=82,ae=83,re=84,oe=85,le=88,fe=89,he=90,Ue=91,ce=92,_e=95,pe=96,ge=97,ye=98,xe=99,ue=100,be=101,de=102,we=103,me=104,De=105,Be=106,Le=107,ve=108,Ae=109,ke=110,Ve=111,Ie=112,Se=113,Fe=114,Oe=115,Ee=116,Te=117,Ce=118,Me=119,Pe=120,ze=121,We=122,He=123,Ne=124,Ke=125,Xe=126,Re=127,Ye=128,je=129,qe=130,Ge=131,Je=132,Qe=133,Ze=134,$e=135,tn=136,en=137,nn=138,sn=139,an=140,rn=141,on=142,ln=143,fn=144,hn=145,Un=146,cn=147,_n=148,pn=149,gn=150,yn=151,xn=152,un=153,bn=154,dn=155,wn=156,mn=157,Dn=158,Bn=159,Ln=160,vn=161,An=162,kn=163,Vn=164,In=165,Sn=166,Fn=167,On=168,En=169,Tn=170,Cn=171,Mn=172,Pn=173,zn=174,Wn=175,Hn=176,Nn=177,Kn=178,Xn=179,Rn=180,Yn=181,jn=182,qn=183,Gn=184,Jn=1000156007,Qn=1000156008,Zn=1000156009,$n=1000156010,ti=1000156011,ei=1000156017,ni=1000156018,ii=1000156019,si=1000156020,ai=1000156021,ri=1000054e3,oi=1000054001,li=1000054002,fi=1000054003,hi=1000054004,Ui=1000054005,ci=1000054006,_i=1000054007,pi=1000066e3,gi=1000066001,yi=1000066002,xi=1000066003,ui=1000066004,bi=1000066005,di=1000066006,wi=1000066007,mi=1000066008,Di=1000066009,Bi=1000066010,Li=1000066011,vi=1000066012,Ai=1000066013,ki=100034e4,Vi=1000340001;class Ii{constructor(){this.vkFormat=0,this.typeSize=1,this.pixelWidth=0,this.pixelHeight=0,this.pixelDepth=0,this.layerCount=0,this.faceCount=1,this.supercompressionScheme=0,this.levels=[],this.dataFormatDescriptor=[{vendorId:0,descriptorType:0,descriptorBlockSize:0,versionNumber:2,colorModel:0,colorPrimaries:1,transferFunction:2,flags:0,texelBlockDimension:[0,0,0,0],bytesPlane:[0,0,0,0,0,0,0,0],samples:[]}],this.keyValue={},this.globalData=null}}class Si{constructor(t,e,n,i){this._dataView=void 0,this._littleEndian=void 0,this._offset=void 0,this._dataView=new DataView(t.buffer,t.byteOffset+e,n),this._littleEndian=i,this._offset=0}_nextUint8(){const t=this._dataView.getUint8(this._offset);return this._offset+=1,t}_nextUint16(){const t=this._dataView.getUint16(this._offset,this._littleEndian);return this._offset+=2,t}_nextUint32(){const t=this._dataView.getUint32(this._offset,this._littleEndian);return this._offset+=4,t}_nextUint64(){const t=this._dataView.getUint32(this._offset,this._littleEndian)+2**32*this._dataView.getUint32(this._offset+4,this._littleEndian);return this._offset+=8,t}_nextInt32(){const t=this._dataView.getInt32(this._offset,this._littleEndian);return this._offset+=4,t}_nextUint8Array(t){const e=new Uint8Array(this._dataView.buffer,this._dataView.byteOffset+this._offset,t);return this._offset+=t,e}_skip(t){return this._offset+=t,this}_scan(t,e){void 0===e&&(e=0);const n=this._offset;let i=0;for(;this._dataView.getUint8(this._offset)!==e&&i0?U+a.byteLength:0;c%8&&(c+=8-c%8);const _=[],p=new DataView(new ArrayBuffer(3*t.levels.length*8)),g=new Uint32Array(t.levels.length);let y=0;0===t.supercompressionScheme&&(y=function(t,e){const n=Math.max(t,4),i=Math.min(t,4);let s=n;for(;s%i!=0;)s+=n;return s}(function(t){return t.levels[0].levelData.byteLength/function(t,e){let n=1;const i=[t.pixelWidth,t.pixelHeight,t.pixelDepth],s=function(t){const[e,n,i]=t.dataFormatDescriptor[0].texelBlockDimension;return[e+1,n+1,i+1]}(t);for(let t=0;t<3;t++)if(i[t]>0){const e=Math.ceil(Math.floor(i[t]*Math.pow(2,-0))/s[t]);n*=Math.max(1,e)}return t.layerCount>0&&(n*=t.layerCount),t.faceCount>0&&(n*=t.faceCount),n}(t)}(t)));let x=(c||U+a.byteLength)+n.byteLength;for(let e=t.levels.length-1;e>=0;e--){if(x%y){const t=Mi(x,y);_.push(new Uint8Array(t)),x+=t}const n=t.levels[e];_.push(n.levelData),g[e]=x,x+=n.levelData.byteLength}for(let e=0;e0?c:0),!0),b.setBigUint64(60,BigInt(n.byteLength),!0),new Uint8Array(Ci([new Uint8Array(Oi).buffer,u,p.buffer,o,a,c>0?new ArrayBuffer(c-(U+a.byteLength)):new ArrayBuffer(0),n,..._]))}export{Z as KHR_DF_CHANNEL_RGBSDA_ALPHA,G as KHR_DF_CHANNEL_RGBSDA_BLUE,Q as KHR_DF_CHANNEL_RGBSDA_DEPTH,q as KHR_DF_CHANNEL_RGBSDA_GREEN,j as KHR_DF_CHANNEL_RGBSDA_RED,J as KHR_DF_CHANNEL_RGBSDA_STENCIL,g as KHR_DF_FLAG_ALPHA_PREMULTIPLIED,p as KHR_DF_FLAG_ALPHA_STRAIGHT,s as KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT,U as KHR_DF_MODEL_ASTC,f as KHR_DF_MODEL_ETC1,c as KHR_DF_MODEL_ETC1S,h as KHR_DF_MODEL_ETC2,l as KHR_DF_MODEL_RGBSDA,_ as KHR_DF_MODEL_UASTC,o as KHR_DF_MODEL_UNSPECIFIED,H as KHR_DF_PRIMARIES_ACES,N as KHR_DF_PRIMARIES_ACESCC,Y as KHR_DF_PRIMARIES_ADOBERGB,z as KHR_DF_PRIMARIES_BT2020,M as KHR_DF_PRIMARIES_BT601_EBU,P as KHR_DF_PRIMARIES_BT601_SMPTE,C as KHR_DF_PRIMARIES_BT709,W as KHR_DF_PRIMARIES_CIEXYZ,R as KHR_DF_PRIMARIES_DISPLAYP3,K as KHR_DF_PRIMARIES_NTSC1953,X as KHR_DF_PRIMARIES_PAL525,T as KHR_DF_PRIMARIES_UNSPECIFIED,et as KHR_DF_SAMPLE_DATATYPE_EXPONENT,$ as KHR_DF_SAMPLE_DATATYPE_FLOAT,nt as KHR_DF_SAMPLE_DATATYPE_LINEAR,tt as KHR_DF_SAMPLE_DATATYPE_SIGNED,F as KHR_DF_TRANSFER_ACESCC,O as KHR_DF_TRANSFER_ACESCCT,E as KHR_DF_TRANSFER_ADOBERGB,D as KHR_DF_TRANSFER_BT1886,k as KHR_DF_TRANSFER_DCIP3,L as KHR_DF_TRANSFER_HLG_EOTF,B as KHR_DF_TRANSFER_HLG_OETF,b as KHR_DF_TRANSFER_ITU,x as KHR_DF_TRANSFER_LINEAR,d as KHR_DF_TRANSFER_NTSC,I as KHR_DF_TRANSFER_PAL625_EOTF,V as KHR_DF_TRANSFER_PAL_OETF,v as KHR_DF_TRANSFER_PQ_EOTF,A as KHR_DF_TRANSFER_PQ_OETF,w as KHR_DF_TRANSFER_SLOG,m as KHR_DF_TRANSFER_SLOG2,u as KHR_DF_TRANSFER_SRGB,S as KHR_DF_TRANSFER_ST240,y as KHR_DF_TRANSFER_UNSPECIFIED,a as KHR_DF_VENDORID_KHRONOS,r as KHR_DF_VERSION,e as KHR_SUPERCOMPRESSION_BASISLZ,t as KHR_SUPERCOMPRESSION_NONE,i as KHR_SUPERCOMPRESSION_ZLIB,n as KHR_SUPERCOMPRESSION_ZSTD,Ii as KTX2Container,Ut as VK_FORMAT_A1R5G5B5_UNORM_PACK16,Gt as VK_FORMAT_A2B10G10R10_SINT_PACK32,jt as VK_FORMAT_A2B10G10R10_SNORM_PACK32,qt as VK_FORMAT_A2B10G10R10_UINT_PACK32,Yt as VK_FORMAT_A2B10G10R10_UNORM_PACK32,Rt as VK_FORMAT_A2R10G10B10_SINT_PACK32,Kt as VK_FORMAT_A2R10G10B10_SNORM_PACK32,Xt as VK_FORMAT_A2R10G10B10_UINT_PACK32,Nt as VK_FORMAT_A2R10G10B10_UNORM_PACK32,Vi as VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT,ki as VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT,Li as VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT,Rn as VK_FORMAT_ASTC_10x10_SRGB_BLOCK,Xn as VK_FORMAT_ASTC_10x10_UNORM_BLOCK,mi as VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT,zn as VK_FORMAT_ASTC_10x5_SRGB_BLOCK,Pn as VK_FORMAT_ASTC_10x5_UNORM_BLOCK,Di as VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT,Hn as VK_FORMAT_ASTC_10x6_SRGB_BLOCK,Wn as VK_FORMAT_ASTC_10x6_UNORM_BLOCK,Bi as VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT,Kn as VK_FORMAT_ASTC_10x8_SRGB_BLOCK,Nn as VK_FORMAT_ASTC_10x8_UNORM_BLOCK,vi as VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT,jn as VK_FORMAT_ASTC_12x10_SRGB_BLOCK,Yn as VK_FORMAT_ASTC_12x10_UNORM_BLOCK,Ai as VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT,Gn as VK_FORMAT_ASTC_12x12_SRGB_BLOCK,qn as VK_FORMAT_ASTC_12x12_UNORM_BLOCK,pi as VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT,Dn as VK_FORMAT_ASTC_4x4_SRGB_BLOCK,mn as VK_FORMAT_ASTC_4x4_UNORM_BLOCK,gi as VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT,Ln as VK_FORMAT_ASTC_5x4_SRGB_BLOCK,Bn as VK_FORMAT_ASTC_5x4_UNORM_BLOCK,yi as VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT,An as VK_FORMAT_ASTC_5x5_SRGB_BLOCK,vn as VK_FORMAT_ASTC_5x5_UNORM_BLOCK,xi as VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT,Vn as VK_FORMAT_ASTC_6x5_SRGB_BLOCK,kn as VK_FORMAT_ASTC_6x5_UNORM_BLOCK,ui as VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT,Sn as VK_FORMAT_ASTC_6x6_SRGB_BLOCK,In as VK_FORMAT_ASTC_6x6_UNORM_BLOCK,bi as VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT,On as VK_FORMAT_ASTC_8x5_SRGB_BLOCK,Fn as VK_FORMAT_ASTC_8x5_UNORM_BLOCK,di as VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT,Tn as VK_FORMAT_ASTC_8x6_SRGB_BLOCK,En as VK_FORMAT_ASTC_8x6_UNORM_BLOCK,wi as VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT,Mn as VK_FORMAT_ASTC_8x8_SRGB_BLOCK,Cn as VK_FORMAT_ASTC_8x8_UNORM_BLOCK,We as VK_FORMAT_B10G11R11_UFLOAT_PACK32,ti as VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,ai as VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,rt as VK_FORMAT_B4G4R4A4_UNORM_PACK16,ht as VK_FORMAT_B5G5R5A1_UNORM_PACK16,lt as VK_FORMAT_B5G6R5_UNORM_PACK16,Wt as VK_FORMAT_B8G8R8A8_SINT,Pt as VK_FORMAT_B8G8R8A8_SNORM,Ht as VK_FORMAT_B8G8R8A8_SRGB,zt as VK_FORMAT_B8G8R8A8_UINT,Mt as VK_FORMAT_B8G8R8A8_UNORM,It as VK_FORMAT_B8G8R8_SINT,kt as VK_FORMAT_B8G8R8_SNORM,St as VK_FORMAT_B8G8R8_SRGB,Vt as VK_FORMAT_B8G8R8_UINT,At as VK_FORMAT_B8G8R8_UNORM,Ze as VK_FORMAT_BC1_RGBA_SRGB_BLOCK,Qe as VK_FORMAT_BC1_RGBA_UNORM_BLOCK,Je as VK_FORMAT_BC1_RGB_SRGB_BLOCK,Ge as VK_FORMAT_BC1_RGB_UNORM_BLOCK,tn as VK_FORMAT_BC2_SRGB_BLOCK,$e as VK_FORMAT_BC2_UNORM_BLOCK,nn as VK_FORMAT_BC3_SRGB_BLOCK,en as VK_FORMAT_BC3_UNORM_BLOCK,an as VK_FORMAT_BC4_SNORM_BLOCK,sn as VK_FORMAT_BC4_UNORM_BLOCK,on as VK_FORMAT_BC5_SNORM_BLOCK,rn as VK_FORMAT_BC5_UNORM_BLOCK,fn as VK_FORMAT_BC6H_SFLOAT_BLOCK,ln as VK_FORMAT_BC6H_UFLOAT_BLOCK,Un as VK_FORMAT_BC7_SRGB_BLOCK,hn as VK_FORMAT_BC7_UNORM_BLOCK,Ne as VK_FORMAT_D16_UNORM,Ye as VK_FORMAT_D16_UNORM_S8_UINT,je as VK_FORMAT_D24_UNORM_S8_UINT,Xe as VK_FORMAT_D32_SFLOAT,qe as VK_FORMAT_D32_SFLOAT_S8_UINT,He as VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,wn as VK_FORMAT_EAC_R11G11_SNORM_BLOCK,dn as VK_FORMAT_EAC_R11G11_UNORM_BLOCK,bn as VK_FORMAT_EAC_R11_SNORM_BLOCK,un as VK_FORMAT_EAC_R11_UNORM_BLOCK,gn as VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,pn as VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,xn as VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,yn as VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,_n as VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,cn as VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,$n as VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,si as VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,hi as VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG,ri as VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG,Ui as VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG,oi as VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG,ci as VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG,li as VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG,_i as VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG,fi as VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG,Zn as VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,Qn as VK_FORMAT_R10X6G10X6_UNORM_2PACK16,Jn as VK_FORMAT_R10X6_UNORM_PACK16,ii as VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,ni as VK_FORMAT_R12X4G12X4_UNORM_2PACK16,ei as VK_FORMAT_R12X4_UNORM_PACK16,ge as VK_FORMAT_R16G16B16A16_SFLOAT,pe as VK_FORMAT_R16G16B16A16_SINT,ce as VK_FORMAT_R16G16B16A16_SNORM,_e as VK_FORMAT_R16G16B16A16_UINT,Ue as VK_FORMAT_R16G16B16A16_UNORM,he as VK_FORMAT_R16G16B16_SFLOAT,fe as VK_FORMAT_R16G16B16_SINT,oe as VK_FORMAT_R16G16B16_SNORM,le as VK_FORMAT_R16G16B16_UINT,re as VK_FORMAT_R16G16B16_UNORM,ae as VK_FORMAT_R16G16_SFLOAT,se as VK_FORMAT_R16G16_SINT,ne as VK_FORMAT_R16G16_SNORM,ie as VK_FORMAT_R16G16_UINT,ee as VK_FORMAT_R16G16_UNORM,te as VK_FORMAT_R16_SFLOAT,$t as VK_FORMAT_R16_SINT,Qt as VK_FORMAT_R16_SNORM,Zt as VK_FORMAT_R16_UINT,Jt as VK_FORMAT_R16_UNORM,Ae as VK_FORMAT_R32G32B32A32_SFLOAT,ve as VK_FORMAT_R32G32B32A32_SINT,Le as VK_FORMAT_R32G32B32A32_UINT,Be as VK_FORMAT_R32G32B32_SFLOAT,De as VK_FORMAT_R32G32B32_SINT,me as VK_FORMAT_R32G32B32_UINT,we as VK_FORMAT_R32G32_SFLOAT,de as VK_FORMAT_R32G32_SINT,be as VK_FORMAT_R32G32_UINT,ue as VK_FORMAT_R32_SFLOAT,xe as VK_FORMAT_R32_SINT,ye as VK_FORMAT_R32_UINT,at as VK_FORMAT_R4G4B4A4_UNORM_PACK16,st as VK_FORMAT_R4G4_UNORM_PACK8,ft as VK_FORMAT_R5G5B5A1_UNORM_PACK16,ot as VK_FORMAT_R5G6B5_UNORM_PACK16,ze as VK_FORMAT_R64G64B64A64_SFLOAT,Pe as VK_FORMAT_R64G64B64A64_SINT,Me as VK_FORMAT_R64G64B64A64_UINT,Ce as VK_FORMAT_R64G64B64_SFLOAT,Te as VK_FORMAT_R64G64B64_SINT,Ee as VK_FORMAT_R64G64B64_UINT,Oe as VK_FORMAT_R64G64_SFLOAT,Fe as VK_FORMAT_R64G64_SINT,Se as VK_FORMAT_R64G64_UINT,Ie as VK_FORMAT_R64_SFLOAT,Ve as VK_FORMAT_R64_SINT,ke as VK_FORMAT_R64_UINT,Tt as VK_FORMAT_R8G8B8A8_SINT,Ot as VK_FORMAT_R8G8B8A8_SNORM,Ct as VK_FORMAT_R8G8B8A8_SRGB,Et as VK_FORMAT_R8G8B8A8_UINT,Ft as VK_FORMAT_R8G8B8A8_UNORM,Lt as VK_FORMAT_R8G8B8_SINT,Dt as VK_FORMAT_R8G8B8_SNORM,vt as VK_FORMAT_R8G8B8_SRGB,Bt as VK_FORMAT_R8G8B8_UINT,mt as VK_FORMAT_R8G8B8_UNORM,dt as VK_FORMAT_R8G8_SINT,ut as VK_FORMAT_R8G8_SNORM,wt as VK_FORMAT_R8G8_SRGB,bt as VK_FORMAT_R8G8_UINT,xt as VK_FORMAT_R8G8_UNORM,gt as VK_FORMAT_R8_SINT,_t as VK_FORMAT_R8_SNORM,yt as VK_FORMAT_R8_SRGB,pt as VK_FORMAT_R8_UINT,ct as VK_FORMAT_R8_UNORM,Re as VK_FORMAT_S8_UINT,it as VK_FORMAT_UNDEFINED,Ke as VK_FORMAT_X8_D24_UNORM_PACK32,Pi as read,Wi as write}; diff --git a/examples/jsm/lights/LightProbeGenerator.js b/examples/jsm/lights/LightProbeGenerator.js index 4bd9896c8cd3fd..692c7c219518c7 100644 --- a/examples/jsm/lights/LightProbeGenerator.js +++ b/examples/jsm/lights/LightProbeGenerator.js @@ -7,7 +7,8 @@ import { SRGBColorSpace, NoColorSpace, HalfFloatType, - DataUtils + DataUtils, + WebGLCoordinateSystem } from 'three'; class LightProbeGenerator { @@ -126,7 +127,9 @@ class LightProbeGenerator { } - static fromCubeRenderTarget( renderer, cubeRenderTarget ) { + static async fromCubeRenderTarget( renderer, cubeRenderTarget ) { + + const flip = renderer.coordinateSystem === WebGLCoordinateSystem ? -1 : 1; // The renderTarget must be set to RGBA in order to make readRenderTargetPixels works let totalWeight = 0; @@ -143,12 +146,11 @@ class LightProbeGenerator { const shCoefficients = sh.coefficients; const dataType = cubeRenderTarget.texture.type; + const imageWidth = cubeRenderTarget.width; // assumed to be square - for ( let faceIndex = 0; faceIndex < 6; faceIndex ++ ) { - - const imageWidth = cubeRenderTarget.width; // assumed to be square + let data; - let data; + if ( renderer.isWebGLRenderer ) { if ( dataType === HalfFloatType ) { @@ -162,7 +164,19 @@ class LightProbeGenerator { } - renderer.readRenderTargetPixels( cubeRenderTarget, 0, 0, imageWidth, imageWidth, data, faceIndex ); + } + + for ( let faceIndex = 0; faceIndex < 6; faceIndex ++ ) { + + if ( renderer.isWebGLRenderer ) { + + await renderer.readRenderTargetPixelsAsync( cubeRenderTarget, 0, 0, imageWidth, imageWidth, data, faceIndex ); + + } else { + + data = await renderer.readRenderTargetPixelsAsync( cubeRenderTarget, 0, 0, imageWidth, imageWidth, 0, faceIndex ); + + } const pixelSize = 2 / imageWidth; @@ -194,15 +208,15 @@ class LightProbeGenerator { const pixelIndex = i / 4; - const col = - 1 + ( pixelIndex % imageWidth + 0.5 ) * pixelSize; + const col = ( 1 - ( pixelIndex % imageWidth + 0.5 ) * pixelSize ) * flip; const row = 1 - ( Math.floor( pixelIndex / imageWidth ) + 0.5 ) * pixelSize; switch ( faceIndex ) { - case 0: coord.set( 1, row, - col ); break; + case 0: coord.set( - 1 * flip, row, col * flip ); break; - case 1: coord.set( - 1, row, col ); break; + case 1: coord.set( 1 * flip, row, - col * flip ); break; case 2: coord.set( col, 1, - row ); break; diff --git a/examples/jsm/loaders/ColladaLoader.js b/examples/jsm/loaders/ColladaLoader.js index f3497f33e7d7e8..dbff500338a2e7 100644 --- a/examples/jsm/loaders/ColladaLoader.js +++ b/examples/jsm/loaders/ColladaLoader.js @@ -5,6 +5,7 @@ import { BufferGeometry, ClampToEdgeWrapping, Color, + ColorManagement, DirectionalLight, DoubleSide, FileLoader, @@ -1681,9 +1682,9 @@ class ColladaLoader extends Loader { } - material.color.convertSRGBToLinear(); - if ( material.specular ) material.specular.convertSRGBToLinear(); - if ( material.emissive ) material.emissive.convertSRGBToLinear(); + ColorManagement.toWorkingColorSpace( material.color, SRGBColorSpace ); + if ( material.specular ) ColorManagement.toWorkingColorSpace( material.specular, SRGBColorSpace ); + if ( material.emissive ) ColorManagement.toWorkingColorSpace( material.emissive, SRGBColorSpace ); // @@ -2019,7 +2020,8 @@ class ColladaLoader extends Loader { case 'color': const array = parseFloats( child.textContent ); - data.color = new Color().fromArray( array ).convertSRGBToLinear(); + data.color = new Color().fromArray( array ); + ColorManagement.toWorkingColorSpace( data.color, SRGBColorSpace ); break; case 'falloff_angle': @@ -2548,8 +2550,9 @@ class ColladaLoader extends Loader { tempColor.setRGB( array[ startIndex + 0 ], array[ startIndex + 1 ], - array[ startIndex + 2 ] - ).convertSRGBToLinear(); + array[ startIndex + 2 ], + SRGBColorSpace + ); array[ startIndex + 0 ] = tempColor.r; array[ startIndex + 1 ] = tempColor.g; diff --git a/examples/jsm/loaders/DRACOLoader.js b/examples/jsm/loaders/DRACOLoader.js index 07a4e83898dbbc..ca111d71274d95 100644 --- a/examples/jsm/loaders/DRACOLoader.js +++ b/examples/jsm/loaders/DRACOLoader.js @@ -2,6 +2,7 @@ import { BufferAttribute, BufferGeometry, Color, + ColorManagement, FileLoader, Loader, LinearSRGBColorSpace, @@ -235,7 +236,8 @@ class DRACOLoader extends Loader { for ( let i = 0, il = attribute.count; i < il; i ++ ) { - _color.fromBufferAttribute( attribute, i ).convertSRGBToLinear(); + _color.fromBufferAttribute( attribute, i ); + ColorManagement.toWorkingColorSpace( _color, SRGBColorSpace ); attribute.setXYZ( i, _color.r, _color.g, _color.b ); } diff --git a/examples/jsm/loaders/FBXLoader.js b/examples/jsm/loaders/FBXLoader.js index ee2890e85ca395..bc8d49a7290720 100644 --- a/examples/jsm/loaders/FBXLoader.js +++ b/examples/jsm/loaders/FBXLoader.js @@ -5,6 +5,7 @@ import { BufferGeometry, ClampToEdgeWrapping, Color, + ColorManagement, DirectionalLight, EquirectangularReflectionMapping, Euler, @@ -23,13 +24,14 @@ import { MeshPhongMaterial, NumberKeyframeTrack, Object3D, - OrthographicCamera, PerspectiveCamera, PointLight, PropertyBinding, Quaternion, QuaternionKeyframeTrack, RepeatWrapping, + SRGBColorSpace, + ShapeUtils, Skeleton, SkinnedMesh, SpotLight, @@ -39,10 +41,9 @@ import { Vector2, Vector3, Vector4, - VectorKeyframeTrack, - SRGBColorSpace, - ShapeUtils + VectorKeyframeTrack } from 'three'; + import * as fflate from '../libs/fflate.module.js'; import { NURBSCurve } from '../curves/NURBSCurve.js'; @@ -538,12 +539,12 @@ class FBXTreeParser { if ( materialNode.Diffuse ) { - parameters.color = new Color().fromArray( materialNode.Diffuse.value ).convertSRGBToLinear(); + parameters.color = ColorManagement.toWorkingColorSpace( new Color().fromArray( materialNode.Diffuse.value ), SRGBColorSpace ); } else if ( materialNode.DiffuseColor && ( materialNode.DiffuseColor.type === 'Color' || materialNode.DiffuseColor.type === 'ColorRGB' ) ) { // The blender exporter exports diffuse here instead of in materialNode.Diffuse - parameters.color = new Color().fromArray( materialNode.DiffuseColor.value ).convertSRGBToLinear(); + parameters.color = ColorManagement.toWorkingColorSpace( new Color().fromArray( materialNode.DiffuseColor.value ), SRGBColorSpace ); } @@ -555,12 +556,12 @@ class FBXTreeParser { if ( materialNode.Emissive ) { - parameters.emissive = new Color().fromArray( materialNode.Emissive.value ).convertSRGBToLinear(); + parameters.emissive = ColorManagement.toWorkingColorSpace( new Color().fromArray( materialNode.Emissive.value ), SRGBColorSpace ); } else if ( materialNode.EmissiveColor && ( materialNode.EmissiveColor.type === 'Color' || materialNode.EmissiveColor.type === 'ColorRGB' ) ) { // The blender exporter exports emissive color here instead of in materialNode.Emissive - parameters.emissive = new Color().fromArray( materialNode.EmissiveColor.value ).convertSRGBToLinear(); + parameters.emissive = ColorManagement.toWorkingColorSpace( new Color().fromArray( materialNode.EmissiveColor.value ), SRGBColorSpace ); } @@ -596,12 +597,12 @@ class FBXTreeParser { if ( materialNode.Specular ) { - parameters.specular = new Color().fromArray( materialNode.Specular.value ).convertSRGBToLinear(); + parameters.specular = ColorManagement.toWorkingColorSpace( new Color().fromArray( materialNode.Specular.value ), SRGBColorSpace ); } else if ( materialNode.SpecularColor && materialNode.SpecularColor.type === 'Color' ) { // The blender exporter exports specular color here instead of in materialNode.Specular - parameters.specular = new Color().fromArray( materialNode.SpecularColor.value ).convertSRGBToLinear(); + parameters.specular = ColorManagement.toWorkingColorSpace( new Color().fromArray( materialNode.SpecularColor.value ), SRGBColorSpace ); } @@ -1094,7 +1095,8 @@ class FBXTreeParser { break; case 1: // Orthographic - model = new OrthographicCamera( - width / 2, width / 2, height / 2, - height / 2, nearClippingPlane, farClippingPlane ); + console.warn( 'THREE.FBXLoader: Orthographic cameras not supported yet.' ); + model = new Object3D(); break; default: @@ -1151,7 +1153,7 @@ class FBXTreeParser { if ( lightAttribute.Color !== undefined ) { - color = new Color().fromArray( lightAttribute.Color.value ).convertSRGBToLinear(); + color = ColorManagement.toWorkingColorSpace( new Color().fromArray( lightAttribute.Color.value ), SRGBColorSpace ); } @@ -1329,7 +1331,7 @@ class FBXTreeParser { if ( 'InheritType' in modelNode ) transformData.inheritType = parseInt( modelNode.InheritType.value ); if ( 'RotationOrder' in modelNode ) transformData.eulerOrder = getEulerOrder( modelNode.RotationOrder.value ); - else transformData.eulerOrder = 'ZYX'; + else transformData.eulerOrder = getEulerOrder( 0 ); if ( 'Lcl_Translation' in modelNode ) transformData.translation = modelNode.Lcl_Translation.value; @@ -1477,7 +1479,7 @@ class FBXTreeParser { if ( r !== 0 || g !== 0 || b !== 0 ) { - const color = new Color( r, g, b ).convertSRGBToLinear(); + const color = new Color().setRGB( r, g, b, SRGBColorSpace ); sceneGraph.add( new AmbientLight( color, 1 ) ); } @@ -2319,7 +2321,9 @@ class GeometryParser { for ( let i = 0, c = new Color(); i < buffer.length; i += 4 ) { - c.fromArray( buffer, i ).convertSRGBToLinear().toArray( buffer, i ); + c.fromArray( buffer, i ); + ColorManagement.toWorkingColorSpace( c, SRGBColorSpace ); + c.toArray( buffer, i ); } @@ -2809,10 +2813,13 @@ class AnimationParser { } + // For Maya models using "Joint Orient", Euler order only applies to rotation, not pre/post-rotations + const defaultEulerOrder = getEulerOrder( 0 ); + if ( preRotation !== undefined ) { preRotation = preRotation.map( MathUtils.degToRad ); - preRotation.push( eulerOrder ); + preRotation.push( defaultEulerOrder ); preRotation = new Euler().fromArray( preRotation ); preRotation = new Quaternion().setFromEuler( preRotation ); @@ -2822,7 +2829,7 @@ class AnimationParser { if ( postRotation !== undefined ) { postRotation = postRotation.map( MathUtils.degToRad ); - postRotation.push( eulerOrder ); + postRotation.push( defaultEulerOrder ); postRotation = new Euler().fromArray( postRotation ); postRotation = new Quaternion().setFromEuler( postRotation ).invert(); @@ -4134,10 +4141,13 @@ function generateTransform( transformData ) { if ( transformData.translation ) lTranslationM.setPosition( tempVec.fromArray( transformData.translation ) ); + // For Maya models using "Joint Orient", Euler order only applies to rotation, not pre/post-rotations + const defaultEulerOrder = getEulerOrder( 0 ); + if ( transformData.preRotation ) { const array = transformData.preRotation.map( MathUtils.degToRad ); - array.push( transformData.eulerOrder || Euler.DEFAULT_ORDER ); + array.push( defaultEulerOrder ); lPreRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) ); } @@ -4145,7 +4155,7 @@ function generateTransform( transformData ) { if ( transformData.rotation ) { const array = transformData.rotation.map( MathUtils.degToRad ); - array.push( transformData.eulerOrder || Euler.DEFAULT_ORDER ); + array.push( transformData.eulerOrder || defaultEulerOrder ); lRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) ); } @@ -4153,7 +4163,7 @@ function generateTransform( transformData ) { if ( transformData.postRotation ) { const array = transformData.postRotation.map( MathUtils.degToRad ); - array.push( transformData.eulerOrder || Euler.DEFAULT_ORDER ); + array.push( defaultEulerOrder ); lPostRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) ); lPostRotationM.invert(); diff --git a/examples/jsm/loaders/GLTFLoader.js b/examples/jsm/loaders/GLTFLoader.js index 27170277e22c03..e39cbcb9233e31 100644 --- a/examples/jsm/loaders/GLTFLoader.js +++ b/examples/jsm/loaders/GLTFLoader.js @@ -267,16 +267,6 @@ class GLTFLoader extends Loader { } - setDDSLoader() { - - throw new Error( - - 'THREE.GLTFLoader: "MSFT_texture_dds" no longer supported. Please update to "KHR_texture_basisu".' - - ); - - } - setKTX2Loader( ktx2Loader ) { this.ktx2Loader = ktx2Loader; @@ -3153,6 +3143,9 @@ class GLTFParser { } + // Ignore normalized since we copy from sparse + bufferAttribute.normalized = false; + for ( let i = 0, il = sparseIndices.length; i < il; i ++ ) { const index = sparseIndices[ i ]; @@ -3165,6 +3158,8 @@ class GLTFParser { } + bufferAttribute.normalized = normalized; + } return bufferAttribute; diff --git a/examples/jsm/loaders/KTX2Loader.js b/examples/jsm/loaders/KTX2Loader.js index 95649b9bd691c0..d402f44af27afc 100644 --- a/examples/jsm/loaders/KTX2Loader.js +++ b/examples/jsm/loaders/KTX2Loader.js @@ -9,6 +9,7 @@ * References: * - KTX: http://github.khronos.org/KTX-Specification/ * - DFD: https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.html#basicdescriptor + * - BasisU HDR: https://github.com/BinomialLLC/basis_universal/wiki/UASTC-HDR-Texture-Specification-v1.0 */ import { @@ -63,6 +64,7 @@ import { VK_FORMAT_R8G8_UNORM, VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_R8G8B8A8_UNORM, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT, VK_FORMAT_ASTC_6x6_SRGB_BLOCK, VK_FORMAT_ASTC_6x6_UNORM_BLOCK, KHR_DF_PRIMARIES_UNSPECIFIED, @@ -251,7 +253,7 @@ class KTX2Loader extends Loader { loader.load( url, ( buffer ) => { - this.parse( buffer, onLoad, onError); + this.parse( buffer, onLoad, onError ); }, onProgress, onError ); @@ -269,15 +271,15 @@ class KTX2Loader extends Loader { // again from this thread. if ( _taskCache.has( buffer ) ) { - const cachedTask = _taskCache.get( buffer ); + const cachedTask = _taskCache.get( buffer ); - return cachedTask.promise.then( onLoad ).catch( onError ); + return cachedTask.promise.then( onLoad ).catch( onError ); } this._createTexture( buffer ) - .then( ( texture ) => onLoad ? onLoad( texture ) : null ) - .catch( onError ); + .then( ( texture ) => onLoad ? onLoad( texture ) : null ) + .catch( onError ); } @@ -730,8 +732,7 @@ KTX2Loader.BasisWorker = function () { }; -// -// Parsing for non-Basis textures. These textures are may have supercompression +// Parsing for non-Basis textures. These textures may have supercompression // like Zstd, but they do not require transcoding. const UNCOMPRESSED_FORMATS = new Set( [ RGBAFormat, RGFormat, RedFormat ] ); @@ -753,6 +754,7 @@ const FORMAT_MAP = { [ VK_FORMAT_R8_SRGB ]: RedFormat, [ VK_FORMAT_R8_UNORM ]: RedFormat, + [ VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT ]: RGBA_ASTC_4x4_Format, [ VK_FORMAT_ASTC_6x6_SRGB_BLOCK ]: RGBA_ASTC_6x6_Format, [ VK_FORMAT_ASTC_6x6_UNORM_BLOCK ]: RGBA_ASTC_6x6_Format, @@ -775,6 +777,7 @@ const TYPE_MAP = { [ VK_FORMAT_R8_SRGB ]: UnsignedByteType, [ VK_FORMAT_R8_UNORM ]: UnsignedByteType, + [ VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT ]: HalfFloatType, [ VK_FORMAT_ASTC_6x6_SRGB_BLOCK ]: UnsignedByteType, [ VK_FORMAT_ASTC_6x6_UNORM_BLOCK ]: UnsignedByteType, diff --git a/examples/jsm/loaders/MTLLoader.js b/examples/jsm/loaders/MTLLoader.js index f277c973536ea4..41d7663d967650 100644 --- a/examples/jsm/loaders/MTLLoader.js +++ b/examples/jsm/loaders/MTLLoader.js @@ -1,5 +1,6 @@ import { Color, + ColorManagement, DefaultLoadingManager, FileLoader, FrontSide, @@ -384,21 +385,21 @@ class MaterialCreator { // Diffuse color (color under white light) using RGB values - params.color = new Color().fromArray( value ).convertSRGBToLinear(); + params.color = ColorManagement.toWorkingColorSpace( new Color().fromArray( value ), SRGBColorSpace ); break; case 'ks': // Specular color (color when light is reflected from shiny surface) using RGB values - params.specular = new Color().fromArray( value ).convertSRGBToLinear(); + params.specular = ColorManagement.toWorkingColorSpace( new Color().fromArray( value ), SRGBColorSpace ); break; case 'ke': // Emissive using RGB values - params.emissive = new Color().fromArray( value ).convertSRGBToLinear(); + params.emissive = ColorManagement.toWorkingColorSpace( new Color().fromArray( value ), SRGBColorSpace ); break; diff --git a/examples/jsm/loaders/MaterialXLoader.js b/examples/jsm/loaders/MaterialXLoader.js index 051438732d6047..371e357e804438 100644 --- a/examples/jsm/loaders/MaterialXLoader.js +++ b/examples/jsm/loaders/MaterialXLoader.js @@ -7,7 +7,7 @@ import { add, sub, mul, div, mod, abs, sign, floor, ceil, round, pow, sin, cos, tan, asin, acos, atan2, sqrt, exp, clamp, min, max, normalize, length, dot, cross, normalMap, remap, smoothstep, luminance, mx_rgbtohsv, mx_hsvtorgb, - mix, + mix, split, mx_ramplr, mx_ramptb, mx_splitlr, mx_splittb, mx_fractal_noise_float, mx_noise_float, mx_cell_noise_float, mx_worley_noise_float, mx_transform_uv, @@ -44,6 +44,10 @@ const mx_power = ( in1, in2 = float( 1 ) ) => pow( in1, in2 ); const mx_atan2 = ( in1 = float( 0 ), in2 = float( 1 ) ) => atan2( in1, in2 ); const mx_timer = () => timerLocal(); const mx_frame = () => frameId; +const mx_invert = ( in1, amount = float( 1 ) ) => sub( amount, in1 ); + +const separate = ( in1, channel ) => split( in1, channel.at( - 1 ) ); +const extract = ( in1, index ) => in1.element( index ); const MXElements = [ @@ -75,6 +79,7 @@ const MXElements = [ new MXElement( 'magnitude', length, [ 'in1', 'in2' ] ), new MXElement( 'dotproduct', dot, [ 'in1', 'in2' ] ), new MXElement( 'crossproduct', cross, [ 'in' ] ), + new MXElement( 'invert', mx_invert, [ 'in', 'amount' ] ), //new MtlXElement( 'transformpoint', ... ), //new MtlXElement( 'transformvector', ... ), //new MtlXElement( 'transformnormal', ... ), @@ -127,10 +132,10 @@ const MXElements = [ new MXElement( 'contrast', mx_contrast, [ 'in', 'amount', 'pivot' ] ), //new MtlXElement( 'hsvadjust', ... ), new MXElement( 'saturate', saturation, [ 'in', 'amount' ] ), - //new MtlXElement( 'extract', ... ), - //new MtlXElement( 'separate2', ... ), - //new MtlXElement( 'separate3', ... ), - //new MtlXElement( 'separate4', ... ) + new MXElement( 'extract', extract, [ 'in', 'index' ] ), + new MXElement( 'separate2', separate, [ 'in' ] ), + new MXElement( 'separate3', separate, [ 'in' ] ), + new MXElement( 'separate4', separate, [ 'in' ] ), new MXElement( 'time', mx_timer ), new MXElement( 'frame', mx_frame ) @@ -369,11 +374,11 @@ class MaterialXNode { } - getNode() { + getNode( out = null ) { let node = this.node; - if ( node !== null ) { + if ( node !== null && out === null ) { return node; @@ -391,7 +396,13 @@ class MaterialXNode { } else if ( this.hasReference ) { - node = this.materialX.getMaterialXNode( this.referencePath ).getNode(); + if ( this.element === 'output' && this.output && out === null ) { + + out = this.output; + + } + + node = this.materialX.getMaterialXNode( this.referencePath ).getNode( out ); } else { @@ -474,7 +485,15 @@ class MaterialXNode { const nodeElement = MtlXLibrary[ element ]; - node = nodeElement.nodeFunc( ...this.getNodesByNames( ...nodeElement.params ) ); + if ( out !== null ) { + + node = nodeElement.nodeFunc( ...this.getNodesByNames( ...nodeElement.params ), out ); + + } else { + + node = nodeElement.nodeFunc( ...this.getNodesByNames( ...nodeElement.params ) ); + + } } @@ -542,7 +561,7 @@ class MaterialXNode { const child = this.getChildByName( name ); - return child ? child.getNode() : undefined; + return child ? child.getNode( child.output ) : undefined; } diff --git a/examples/jsm/loaders/OBJLoader.js b/examples/jsm/loaders/OBJLoader.js index 7792458abce807..c6bc16c12c8414 100644 --- a/examples/jsm/loaders/OBJLoader.js +++ b/examples/jsm/loaders/OBJLoader.js @@ -12,7 +12,8 @@ import { Points, PointsMaterial, Vector3, - Color + Color, + SRGBColorSpace } from 'three'; // o object_name | g group_name @@ -534,8 +535,9 @@ class OBJLoader extends Loader { _color.setRGB( parseFloat( data[ 4 ] ), parseFloat( data[ 5 ] ), - parseFloat( data[ 6 ] ) - ).convertSRGBToLinear(); + parseFloat( data[ 6 ] ), + SRGBColorSpace + ); state.colors.push( _color.r, _color.g, _color.b ); diff --git a/examples/jsm/loaders/PCDLoader.js b/examples/jsm/loaders/PCDLoader.js index 49f7c8334f9e1a..8cd6edbabc9df3 100644 --- a/examples/jsm/loaders/PCDLoader.js +++ b/examples/jsm/loaders/PCDLoader.js @@ -6,7 +6,8 @@ import { Int32BufferAttribute, Loader, Points, - PointsMaterial + PointsMaterial, + SRGBColorSpace } from 'three'; class PCDLoader extends Loader { @@ -279,7 +280,7 @@ class PCDLoader extends Loader { const g = ( ( rgb >> 8 ) & 0x0000ff ) / 255; const b = ( ( rgb >> 0 ) & 0x0000ff ) / 255; - c.set( r, g, b ).convertSRGBToLinear(); + c.setRGB( r, g, b, SRGBColorSpace ); color.push( c.r, c.g, c.b ); @@ -346,7 +347,7 @@ class PCDLoader extends Loader { const g = dataview.getUint8( ( PCDheader.points * offset.rgb ) + PCDheader.size[ rgbIndex ] * i + 1 ) / 255.0; const b = dataview.getUint8( ( PCDheader.points * offset.rgb ) + PCDheader.size[ rgbIndex ] * i + 0 ) / 255.0; - c.set( r, g, b ).convertSRGBToLinear(); + c.setRGB( r, g, b, SRGBColorSpace ); color.push( c.r, c.g, c.b ); @@ -404,7 +405,7 @@ class PCDLoader extends Loader { const g = dataview.getUint8( row + offset.rgb + 1 ) / 255.0; const b = dataview.getUint8( row + offset.rgb + 0 ) / 255.0; - c.set( r, g, b ).convertSRGBToLinear(); + c.setRGB( r, g, b, SRGBColorSpace ); color.push( c.r, c.g, c.b ); diff --git a/examples/jsm/loaders/PDBLoader.js b/examples/jsm/loaders/PDBLoader.js index bb24a5510d86e3..2be3aa2b688d6a 100644 --- a/examples/jsm/loaders/PDBLoader.js +++ b/examples/jsm/loaders/PDBLoader.js @@ -3,7 +3,8 @@ import { FileLoader, Float32BufferAttribute, Loader, - Color + Color, + SRGBColorSpace } from 'three'; class PDBLoader extends Loader { @@ -131,7 +132,7 @@ class PDBLoader extends Loader { const g = atom[ 3 ][ 1 ] / 255; const b = atom[ 3 ][ 2 ] / 255; - c.set( r, g, b ).convertSRGBToLinear(); + c.setRGB( r, g, b, SRGBColorSpace ); colorsAtoms.push( c.r, c.g, c.b ); diff --git a/examples/jsm/loaders/PLYLoader.js b/examples/jsm/loaders/PLYLoader.js index 3834bfbfd36984..2e83745d7cf1c3 100644 --- a/examples/jsm/loaders/PLYLoader.js +++ b/examples/jsm/loaders/PLYLoader.js @@ -3,7 +3,8 @@ import { FileLoader, Float32BufferAttribute, Loader, - Color + Color, + SRGBColorSpace } from 'three'; /** @@ -468,8 +469,9 @@ class PLYLoader extends Loader { _color.setRGB( element[ cacheEntry.attrR ] / 255.0, element[ cacheEntry.attrG ] / 255.0, - element[ cacheEntry.attrB ] / 255.0 - ).convertSRGBToLinear(); + element[ cacheEntry.attrB ] / 255.0, + SRGBColorSpace + ); buffer.colors.push( _color.r, _color.g, _color.b ); @@ -516,8 +518,9 @@ class PLYLoader extends Loader { _color.setRGB( element[ cacheEntry.attrR ] / 255.0, element[ cacheEntry.attrG ] / 255.0, - element[ cacheEntry.attrB ] / 255.0 - ).convertSRGBToLinear(); + element[ cacheEntry.attrB ] / 255.0, + SRGBColorSpace + ); buffer.faceVertexColors.push( _color.r, _color.g, _color.b ); buffer.faceVertexColors.push( _color.r, _color.g, _color.b ); buffer.faceVertexColors.push( _color.r, _color.g, _color.b ); diff --git a/examples/jsm/loaders/STLLoader.js b/examples/jsm/loaders/STLLoader.js index 75d4f84586b83c..b94b8069555cdf 100644 --- a/examples/jsm/loaders/STLLoader.js +++ b/examples/jsm/loaders/STLLoader.js @@ -5,7 +5,8 @@ import { FileLoader, Float32BufferAttribute, Loader, - Vector3 + Vector3, + SRGBColorSpace } from 'three'; /** @@ -242,7 +243,7 @@ class STLLoader extends Loader { if ( hasColors ) { - color.set( r, g, b ).convertSRGBToLinear(); + color.setRGB( r, g, b, SRGBColorSpace ); colors[ componentIdx ] = color.r; colors[ componentIdx + 1 ] = color.g; diff --git a/examples/jsm/loaders/TiltLoader.js b/examples/jsm/loaders/TiltLoader.js deleted file mode 100644 index b8e6a8d935eceb..00000000000000 --- a/examples/jsm/loaders/TiltLoader.js +++ /dev/null @@ -1,520 +0,0 @@ -import { - BufferAttribute, - BufferGeometry, - Color, - DoubleSide, - FileLoader, - Group, - Loader, - Mesh, - MeshBasicMaterial, - RawShaderMaterial, - TextureLoader, - Quaternion, - Vector3 -} from 'three'; -import * as fflate from '../libs/fflate.module.js'; - -class TiltLoader extends Loader { - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setResponseType( 'arraybuffer' ); - loader.setWithCredentials( this.withCredentials ); - - loader.load( url, function ( buffer ) { - - try { - - onLoad( scope.parse( buffer ) ); - - } catch ( e ) { - - if ( onError ) { - - onError( e ); - - } else { - - console.error( e ); - - } - - scope.manager.itemError( url ); - - } - - }, onProgress, onError ); - - } - - parse( buffer ) { - - const group = new Group(); - // https://docs.google.com/document/d/11ZsHozYn9FnWG7y3s3WAyKIACfbfwb4PbaS8cZ_xjvo/edit# - - const zip = fflate.unzipSync( new Uint8Array( buffer.slice( 16 ) ) ); - - /* - const thumbnail = zip[ 'thumbnail.png' ].buffer; - const img = document.createElement( 'img' ); - img.src = URL.createObjectURL( new Blob( [ thumbnail ] ) ); - document.body.appendChild( img ); - */ - - const metadata = JSON.parse( fflate.strFromU8( zip[ 'metadata.json' ] ) ); - - /* - const blob = new Blob( [ zip[ 'data.sketch' ].buffer ], { type: 'application/octet-stream' } ); - window.open( URL.createObjectURL( blob ) ); - */ - - const data = new DataView( zip[ 'data.sketch' ].buffer ); - - const num_strokes = data.getInt32( 16, true ); - - const brushes = {}; - - let offset = 20; - - for ( let i = 0; i < num_strokes; i ++ ) { - - const brush_index = data.getInt32( offset, true ); - - const brush_color = [ - data.getFloat32( offset + 4, true ), - data.getFloat32( offset + 8, true ), - data.getFloat32( offset + 12, true ), - data.getFloat32( offset + 16, true ) - ]; - const brush_size = data.getFloat32( offset + 20, true ); - const stroke_mask = data.getUint32( offset + 24, true ); - const controlpoint_mask = data.getUint32( offset + 28, true ); - - let offset_stroke_mask = 0; - let offset_controlpoint_mask = 0; - - for ( let j = 0; j < 4; j ++ ) { - - // TOFIX: I don't understand these masks yet - - const byte = 1 << j; - if ( ( stroke_mask & byte ) > 0 ) offset_stroke_mask += 4; - if ( ( controlpoint_mask & byte ) > 0 ) offset_controlpoint_mask += 4; - - } - - // console.log( { brush_index, brush_color, brush_size, stroke_mask, controlpoint_mask } ); - // console.log( offset_stroke_mask, offset_controlpoint_mask ); - - offset = offset + 28 + offset_stroke_mask + 4; // TOFIX: This is wrong - - const num_control_points = data.getInt32( offset, true ); - - // console.log( { num_control_points } ); - - const positions = new Float32Array( num_control_points * 3 ); - const quaternions = new Float32Array( num_control_points * 4 ); - - offset = offset + 4; - - for ( let j = 0, k = 0; j < positions.length; j += 3, k += 4 ) { - - positions[ j + 0 ] = data.getFloat32( offset + 0, true ); - positions[ j + 1 ] = data.getFloat32( offset + 4, true ); - positions[ j + 2 ] = data.getFloat32( offset + 8, true ); - - quaternions[ k + 0 ] = data.getFloat32( offset + 12, true ); - quaternions[ k + 1 ] = data.getFloat32( offset + 16, true ); - quaternions[ k + 2 ] = data.getFloat32( offset + 20, true ); - quaternions[ k + 3 ] = data.getFloat32( offset + 24, true ); - - offset = offset + 28 + offset_controlpoint_mask; // TOFIX: This is wrong - - } - - if ( brush_index in brushes === false ) { - - brushes[ brush_index ] = []; - - } - - brushes[ brush_index ].push( [ positions, quaternions, brush_size, brush_color ] ); - - } - - for ( const brush_index in brushes ) { - - const geometry = new StrokeGeometry( brushes[ brush_index ] ); - const material = getMaterial( metadata.BrushIndex[ brush_index ] ); - - group.add( new Mesh( geometry, material ) ); - - } - - return group; - - } - -} - -class StrokeGeometry extends BufferGeometry { - - constructor( strokes ) { - - super(); - - const vertices = []; - const colors = []; - const uvs = []; - - const position = new Vector3(); - const prevPosition = new Vector3(); - - const quaternion = new Quaternion(); - const prevQuaternion = new Quaternion(); - - const vector1 = new Vector3(); - const vector2 = new Vector3(); - const vector3 = new Vector3(); - const vector4 = new Vector3(); - - const color = new Color(); - - // size = size / 2; - - for ( const k in strokes ) { - - const stroke = strokes[ k ]; - const positions = stroke[ 0 ]; - const quaternions = stroke[ 1 ]; - const size = stroke[ 2 ]; - const rgba = stroke[ 3 ]; - const alpha = stroke[ 3 ][ 3 ]; - - color.fromArray( rgba ).convertSRGBToLinear(); - - prevPosition.fromArray( positions, 0 ); - prevQuaternion.fromArray( quaternions, 0 ); - - for ( let i = 3, j = 4, l = positions.length; i < l; i += 3, j += 4 ) { - - position.fromArray( positions, i ); - quaternion.fromArray( quaternions, j ); - - vector1.set( - size, 0, 0 ); - vector1.applyQuaternion( quaternion ); - vector1.add( position ); - - vector2.set( size, 0, 0 ); - vector2.applyQuaternion( quaternion ); - vector2.add( position ); - - vector3.set( size, 0, 0 ); - vector3.applyQuaternion( prevQuaternion ); - vector3.add( prevPosition ); - - vector4.set( - size, 0, 0 ); - vector4.applyQuaternion( prevQuaternion ); - vector4.add( prevPosition ); - - vertices.push( vector1.x, vector1.y, - vector1.z ); - vertices.push( vector2.x, vector2.y, - vector2.z ); - vertices.push( vector4.x, vector4.y, - vector4.z ); - - vertices.push( vector2.x, vector2.y, - vector2.z ); - vertices.push( vector3.x, vector3.y, - vector3.z ); - vertices.push( vector4.x, vector4.y, - vector4.z ); - - prevPosition.copy( position ); - prevQuaternion.copy( quaternion ); - - colors.push( ...color, alpha ); - colors.push( ...color, alpha ); - colors.push( ...color, alpha ); - - colors.push( ...color, alpha ); - colors.push( ...color, alpha ); - colors.push( ...color, alpha ); - - const p1 = i / l; - const p2 = ( i - 3 ) / l; - - uvs.push( p1, 0 ); - uvs.push( p1, 1 ); - uvs.push( p2, 0 ); - - uvs.push( p1, 1 ); - uvs.push( p2, 1 ); - uvs.push( p2, 0 ); - - } - - } - - this.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) ); - this.setAttribute( 'color', new BufferAttribute( new Float32Array( colors ), 4 ) ); - this.setAttribute( 'uv', new BufferAttribute( new Float32Array( uvs ), 2 ) ); - - } - -} - -const BRUSH_LIST_ARRAY = { - '89d104cd-d012-426b-b5b3-bbaee63ac43c': 'Bubbles', - '700f3aa8-9a7c-2384-8b8a-ea028905dd8c': 'CelVinyl', - '0f0ff7b2-a677-45eb-a7d6-0cd7206f4816': 'ChromaticWave', - '1161af82-50cf-47db-9706-0c3576d43c43': 'CoarseBristles', - '79168f10-6961-464a-8be1-57ed364c5600': 'CoarseBristlesSingleSided', - '1caa6d7d-f015-3f54-3a4b-8b5354d39f81': 'Comet', - 'c8313697-2563-47fc-832e-290f4c04b901': 'DiamondHull', - '4391aaaa-df73-4396-9e33-31e4e4930b27': 'Disco', - 'd1d991f2-e7a0-4cf1-b328-f57e915e6260': 'DotMarker', - '6a1cf9f9-032c-45ec-9b1d-a6680bee30f7': 'Dots', - '0d3889f3-3ede-470c-8af4-f44813306126': 'DoubleTaperedFlat', - '0d3889f3-3ede-470c-8af4-de4813306126': 'DoubleTaperedMarker', - 'd0262945-853c-4481-9cbd-88586bed93cb': 'DuctTape', - '3ca16e2f-bdcd-4da2-8631-dcef342f40f1': 'DuctTapeSingleSided', - 'f6e85de3-6dcc-4e7f-87fd-cee8c3d25d51': 'Electricity', - '02ffb866-7fb2-4d15-b761-1012cefb1360': 'Embers', - 'cb92b597-94ca-4255-b017-0e3f42f12f9e': 'Fire', - '2d35bcf0-e4d8-452c-97b1-3311be063130': 'Flat', - '55303bc4-c749-4a72-98d9-d23e68e76e18': 'FlatDeprecated', - '280c0a7a-aad8-416c-a7d2-df63d129ca70': 'FlatSingleSided', - 'cf019139-d41c-4eb0-a1d0-5cf54b0a42f3': 'Highlighter', - '6a1cf9f9-032c-45ec-9b6e-a6680bee32e9': 'HyperGrid', - 'dce872c2-7b49-4684-b59b-c45387949c5c': 'Hypercolor', - 'e8ef32b1-baa8-460a-9c2c-9cf8506794f5': 'HypercolorSingleSided', - '2f212815-f4d3-c1a4-681a-feeaf9c6dc37': 'Icing', - 'f5c336cf-5108-4b40-ade9-c687504385ab': 'Ink', - 'c0012095-3ffd-4040-8ee1-fc180d346eaa': 'InkSingleSided', - '4a76a27a-44d8-4bfe-9a8c-713749a499b0': 'Leaves', - 'ea19de07-d0c0-4484-9198-18489a3c1487': 'LeavesSingleSided', - '2241cd32-8ba2-48a5-9ee7-2caef7e9ed62': 'Light', - '4391aaaa-df81-4396-9e33-31e4e4930b27': 'LightWire', - 'd381e0f5-3def-4a0d-8853-31e9200bcbda': 'Lofted', - '429ed64a-4e97-4466-84d3-145a861ef684': 'Marker', - '79348357-432d-4746-8e29-0e25c112e3aa': 'MatteHull', - 'b2ffef01-eaaa-4ab5-aa64-95a2c4f5dbc6': 'NeonPulse', - 'f72ec0e7-a844-4e38-82e3-140c44772699': 'OilPaint', - 'c515dad7-4393-4681-81ad-162ef052241b': 'OilPaintSingleSided', - 'f1114e2e-eb8d-4fde-915a-6e653b54e9f5': 'Paper', - '759f1ebd-20cd-4720-8d41-234e0da63716': 'PaperSingleSided', - 'e0abbc80-0f80-e854-4970-8924a0863dcc': 'Petal', - 'c33714d1-b2f9-412e-bd50-1884c9d46336': 'Plasma', - 'ad1ad437-76e2-450d-a23a-e17f8310b960': 'Rainbow', - 'faaa4d44-fcfb-4177-96be-753ac0421ba3': 'ShinyHull', - '70d79cca-b159-4f35-990c-f02193947fe8': 'Smoke', - 'd902ed8b-d0d1-476c-a8de-878a79e3a34c': 'Snow', - 'accb32f5-4509-454f-93f8-1df3fd31df1b': 'SoftHighlighter', - 'cf7f0059-7aeb-53a4-2b67-c83d863a9ffa': 'Spikes', - '8dc4a70c-d558-4efd-a5ed-d4e860f40dc3': 'Splatter', - '7a1c8107-50c5-4b70-9a39-421576d6617e': 'SplatterSingleSided', - '0eb4db27-3f82-408d-b5a1-19ebd7d5b711': 'Stars', - '44bb800a-fbc3-4592-8426-94ecb05ddec3': 'Streamers', - '0077f88c-d93a-42f3-b59b-b31c50cdb414': 'Taffy', - 'b468c1fb-f254-41ed-8ec9-57030bc5660c': 'TaperedFlat', - 'c8ccb53d-ae13-45ef-8afb-b730d81394eb': 'TaperedFlatSingleSided', - 'd90c6ad8-af0f-4b54-b422-e0f92abe1b3c': 'TaperedMarker', - '1a26b8c0-8a07-4f8a-9fac-d2ef36e0cad0': 'TaperedMarker_Flat', - '75b32cf0-fdd6-4d89-a64b-e2a00b247b0f': 'ThickPaint', - 'fdf0326a-c0d1-4fed-b101-9db0ff6d071f': 'ThickPaintSingleSided', - '4391385a-df73-4396-9e33-31e4e4930b27': 'Toon', - 'a8fea537-da7c-4d4b-817f-24f074725d6d': 'UnlitHull', - 'd229d335-c334-495a-a801-660ac8a87360': 'VelvetInk', - '10201aa3-ebc2-42d8-84b7-2e63f6eeb8ab': 'Waveform', - 'b67c0e81-ce6d-40a8-aeb0-ef036b081aa3': 'WetPaint', - 'dea67637-cd1a-27e4-c9b1-52f4bbcb84e5': 'WetPaintSingleSided', - '5347acf0-a8e2-47b6-8346-30c70719d763': 'WigglyGraphite', - 'e814fef1-97fd-7194-4a2f-50c2bb918be2': 'WigglyGraphiteSingleSided', - '4391385a-cf83-4396-9e33-31e4e4930b27': 'Wire' -}; - -const common = { - - 'colors': { - - 'BloomColor': ` - vec3 BloomColor(vec3 color, float gain) { - // Guarantee that there's at least a little bit of all 3 channels. - // This makes fully-saturated strokes (which only have 2 non-zero - // color channels) eventually clip to white rather than to a secondary. - float cmin = length(color.rgb) * .05; - color.rgb = max(color.rgb, vec3(cmin, cmin, cmin)); - // If we try to remove this pow() from .a, it brightens up - // pressure-sensitive strokes; looks better as-is. - color = pow(color, vec3(2.2)); - color.rgb *= 2. * exp(gain * 10.); - return color; - } - `, - - 'LinearToSrgb': ` - vec3 LinearToSrgb(vec3 color) { - // Approximation http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html - vec3 linearColor = color.rgb; - vec3 S1 = sqrt(linearColor); - vec3 S2 = sqrt(S1); - vec3 S3 = sqrt(S2); - color.rgb = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * linearColor; - return color; - } - `, - - 'hsv': ` - // uniform sampler2D lookupTex; - vec4 lookup(vec4 textureColor) { - return textureColor; - } - - vec3 lookup(vec3 textureColor) { - return textureColor; - } - - vec3 hsv2rgb( vec3 hsv ) { - vec3 rgb = clamp( abs(mod(hsv.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 ); - return hsv.z * mix( vec3(1.0), rgb, hsv.y); - } - - vec3 rgb2hsv( vec3 rgb ) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(rgb.bg, K.wz), vec4(rgb.gb, K.xy), step(rgb.b, rgb.g)); - vec4 q = mix(vec4(p.xyw, rgb.r), vec4(rgb.r, p.yzx), step(p.x, rgb.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); - } - `, - - 'SrgbToLinear': ` - vec3 SrgbToLinear(vec3 color) { - // Approximation http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html - vec3 sRGB = color.rgb; - color.rgb = sRGB * (sRGB * (sRGB * 0.305306011 + 0.682171111) + 0.012522878); - return color; - } - ` - - } - -}; - -let shaders = null; - -function getShaders() { - - if ( shaders === null ) { - - const loader = new TextureLoader().setPath( './textures/tiltbrush/' ); - - shaders = { - 'Light': { - uniforms: { - mainTex: { value: loader.load( 'Light.webp' ) }, - alphaTest: { value: 0.067 }, - emission_gain: { value: 0.45 }, - alpha: { value: 1 }, - }, - vertexShader: ` - precision highp float; - precision highp int; - - attribute vec2 uv; - attribute vec4 color; - attribute vec3 position; - - uniform mat4 modelMatrix; - uniform mat4 modelViewMatrix; - uniform mat4 projectionMatrix; - uniform mat4 viewMatrix; - uniform mat3 normalMatrix; - uniform vec3 cameraPosition; - - varying vec2 vUv; - varying vec3 vColor; - - ${ common.colors.LinearToSrgb } - ${ common.colors.hsv } - - void main() { - - vUv = uv; - - vColor = lookup(color.rgb); - - vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); - - gl_Position = projectionMatrix * mvPosition; - - } - `, - fragmentShader: ` - precision highp float; - precision highp int; - - uniform float emission_gain; - - uniform sampler2D mainTex; - uniform float alphaTest; - - varying vec2 vUv; - varying vec3 vColor; - - ${ common.colors.BloomColor } - ${ common.colors.SrgbToLinear } - - void main(){ - vec4 col = texture2D(mainTex, vUv); - vec3 color = vColor; - color = BloomColor(color, emission_gain); - color = color * col.rgb; - color = color * col.a; - color = SrgbToLinear(color); - gl_FragColor = vec4(color, 1.0); - } - `, - side: 2, - transparent: true, - depthFunc: 2, - depthWrite: true, - depthTest: false, - blending: 5, - blendDst: 201, - blendDstAlpha: 201, - blendEquation: 100, - blendEquationAlpha: 100, - blendSrc: 201, - blendSrcAlpha: 201, - } - - }; - - } - - return shaders; - -} - -function getMaterial( GUID ) { - - const name = BRUSH_LIST_ARRAY[ GUID ]; - - switch ( name ) { - - case 'Light': - return new RawShaderMaterial( getShaders().Light ); - - default: - return new MeshBasicMaterial( { vertexColors: true, side: DoubleSide } ); - - } - -} - -export { TiltLoader }; diff --git a/examples/jsm/loaders/VRMLLoader.js b/examples/jsm/loaders/VRMLLoader.js index fc5098a72171c5..e8e6022d2eca72 100644 --- a/examples/jsm/loaders/VRMLLoader.js +++ b/examples/jsm/loaders/VRMLLoader.js @@ -5,6 +5,7 @@ import { BufferGeometry, ClampToEdgeWrapping, Color, + ColorManagement, ConeGeometry, CylinderGeometry, DataTexture, @@ -918,8 +919,7 @@ class VRMLLoader extends Loader { } else { - skyMaterial.color.setRGB( skyColor[ 0 ], skyColor[ 1 ], skyColor[ 2 ] ); - skyMaterial.color.convertSRGBToLinear(); + skyMaterial.color.setRGB( skyColor[ 0 ], skyColor[ 1 ], skyColor[ 2 ], SRGBColorSpace ); } @@ -1240,13 +1240,11 @@ class VRMLLoader extends Loader { break; case 'diffuseColor': - materialData.diffuseColor = new Color( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] ); - materialData.diffuseColor.convertSRGBToLinear(); + materialData.diffuseColor = new Color().setRGB( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ], SRGBColorSpace ); break; case 'emissiveColor': - materialData.emissiveColor = new Color( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] ); - materialData.emissiveColor.convertSRGBToLinear(); + materialData.emissiveColor = new Color().setRGB( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ], SRGBColorSpace ); break; case 'shininess': @@ -1254,8 +1252,7 @@ class VRMLLoader extends Loader { break; case 'specularColor': - materialData.specularColor = new Color( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] ); - materialData.specularColor.convertSRGBToLinear(); + materialData.specularColor = new Color().setRGB( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ], SRGBColorSpace ); break; case 'transparency': @@ -3111,7 +3108,8 @@ class VRMLLoader extends Loader { for ( let i = 0; i < attribute.count; i ++ ) { color.fromBufferAttribute( attribute, i ); - color.convertSRGBToLinear(); + + ColorManagement.toWorkingColorSpace( color, SRGBColorSpace ); attribute.setXYZ( i, color.r, color.g, color.b ); @@ -3216,7 +3214,9 @@ class VRMLLoader extends Loader { const colorA = colors[ thresholdIndexA ]; const colorB = colors[ thresholdIndexB ]; - color.copy( colorA ).lerp( colorB, t ).convertSRGBToLinear(); + color.copy( colorA ).lerp( colorB, t ); + + ColorManagement.toWorkingColorSpace( color, SRGBColorSpace ); colorAttribute.setXYZ( index, color.r, color.g, color.b ); diff --git a/examples/jsm/loaders/VTKLoader.js b/examples/jsm/loaders/VTKLoader.js index 05fac6a29ebc01..d6fe8ba7b23dcf 100644 --- a/examples/jsm/loaders/VTKLoader.js +++ b/examples/jsm/loaders/VTKLoader.js @@ -4,7 +4,8 @@ import { Color, FileLoader, Float32BufferAttribute, - Loader + Loader, + SRGBColorSpace } from 'three'; import * as fflate from '../libs/fflate.module.js'; @@ -211,7 +212,7 @@ class VTKLoader extends Loader { const g = parseFloat( result[ 2 ] ); const b = parseFloat( result[ 3 ] ); - color.set( r, g, b ).convertSRGBToLinear(); + color.setRGB( r, g, b, SRGBColorSpace ); colors.push( color.r, color.g, color.b ); @@ -325,7 +326,7 @@ class VTKLoader extends Loader { const g = colors[ 3 * i + 1 ]; const b = colors[ 3 * i + 2 ]; - color.set( r, g, b ).convertSRGBToLinear(); + color.setRGB( r, g, b, SRGBColorSpace ); newColors.push( color.r, color.g, color.b ); newColors.push( color.r, color.g, color.b ); diff --git a/examples/jsm/loaders/XYZLoader.js b/examples/jsm/loaders/XYZLoader.js index 40d5519da560ca..9d94c5e863e936 100644 --- a/examples/jsm/loaders/XYZLoader.js +++ b/examples/jsm/loaders/XYZLoader.js @@ -3,7 +3,8 @@ import { Color, FileLoader, Float32BufferAttribute, - Loader + Loader, + SRGBColorSpace } from 'three'; class XYZLoader extends Loader { @@ -80,7 +81,7 @@ class XYZLoader extends Loader { const g = parseFloat( lineValues[ 4 ] ) / 255; const b = parseFloat( lineValues[ 5 ] ) / 255; - color.set( r, g, b ).convertSRGBToLinear(); + color.setRGB( r, g, b, SRGBColorSpace ); colors.push( color.r, color.g, color.b ); diff --git a/examples/jsm/misc/Timer.js b/examples/jsm/misc/Timer.js index 36ff8a7b7202d5..1a541ec8ecb044 100644 --- a/examples/jsm/misc/Timer.js +++ b/examples/jsm/misc/Timer.js @@ -115,7 +115,7 @@ class FixedTimer extends Timer { function now() { - return ( typeof performance === 'undefined' ? Date : performance ).now(); + return performance.now(); } diff --git a/examples/jsm/modifiers/CurveModifierGPU.js b/examples/jsm/modifiers/CurveModifierGPU.js new file mode 100644 index 00000000000000..b561bff9e27db9 --- /dev/null +++ b/examples/jsm/modifiers/CurveModifierGPU.js @@ -0,0 +1,233 @@ +// Original src: https://github.com/zz85/threejs-path-flow +const CHANNELS = 4; +const TEXTURE_WIDTH = 1024; +const TEXTURE_HEIGHT = 4; + +import { + DataTexture, + DataUtils, + RGBAFormat, + HalfFloatType, + RepeatWrapping, + Mesh, + InstancedMesh, + LinearFilter +} from 'three'; + +import { modelWorldMatrix, normalLocal, vec2, vec3, vec4, mat3, varyingProperty, texture, reference, Fn, select, positionLocal } from 'three/tsl'; + +/** + * Make a new DataTexture to store the descriptions of the curves. + * + * @param { number } numberOfCurves the number of curves needed to be described by this texture. + */ +export function initSplineTexture( numberOfCurves = 1 ) { + + const dataArray = new Uint16Array( TEXTURE_WIDTH * TEXTURE_HEIGHT * numberOfCurves * CHANNELS ); + const dataTexture = new DataTexture( + dataArray, + TEXTURE_WIDTH, + TEXTURE_HEIGHT * numberOfCurves, + RGBAFormat, + HalfFloatType + ); + + dataTexture.wrapS = RepeatWrapping; + dataTexture.wrapY = RepeatWrapping; + dataTexture.magFilter = LinearFilter; + dataTexture.minFilter = LinearFilter; + dataTexture.needsUpdate = true; + + return dataTexture; + +} + +/** + * Write the curve description to the data texture + * + * @param { DataTexture } texture The DataTexture to write to + * @param { Curve } splineCurve The curve to describe + * @param { number } offset Which curve slot to write to + */ +export function updateSplineTexture( texture, splineCurve, offset = 0 ) { + + const numberOfPoints = Math.floor( TEXTURE_WIDTH * ( TEXTURE_HEIGHT / 4 ) ); + splineCurve.arcLengthDivisions = numberOfPoints / 2; + splineCurve.updateArcLengths(); + const points = splineCurve.getSpacedPoints( numberOfPoints ); + const frenetFrames = splineCurve.computeFrenetFrames( numberOfPoints, true ); + + for ( let i = 0; i < numberOfPoints; i ++ ) { + + const rowOffset = Math.floor( i / TEXTURE_WIDTH ); + const rowIndex = i % TEXTURE_WIDTH; + + let pt = points[ i ]; + setTextureValue( texture, rowIndex, pt.x, pt.y, pt.z, 0 + rowOffset + ( TEXTURE_HEIGHT * offset ) ); + pt = frenetFrames.tangents[ i ]; + setTextureValue( texture, rowIndex, pt.x, pt.y, pt.z, 1 + rowOffset + ( TEXTURE_HEIGHT * offset ) ); + pt = frenetFrames.normals[ i ]; + setTextureValue( texture, rowIndex, pt.x, pt.y, pt.z, 2 + rowOffset + ( TEXTURE_HEIGHT * offset ) ); + pt = frenetFrames.binormals[ i ]; + setTextureValue( texture, rowIndex, pt.x, pt.y, pt.z, 3 + rowOffset + ( TEXTURE_HEIGHT * offset ) ); + + } + + texture.needsUpdate = true; + +} + + +function setTextureValue( texture, index, x, y, z, o ) { + + const image = texture.image; + const { data } = image; + const i = CHANNELS * TEXTURE_WIDTH * o; // Row Offset + + data[ index * CHANNELS + i + 0 ] = DataUtils.toHalfFloat( x ); + data[ index * CHANNELS + i + 1 ] = DataUtils.toHalfFloat( y ); + data[ index * CHANNELS + i + 2 ] = DataUtils.toHalfFloat( z ); + data[ index * CHANNELS + i + 3 ] = DataUtils.toHalfFloat( 1 ); + +} + +/** + * Create a new set of uniforms for describing the curve modifier + * + * @param { DataTexture } Texture which holds the curve description + */ +export function getUniforms( splineTexture ) { + + return { + spineTexture: splineTexture, + pathOffset: 0, // time of path curve + pathSegment: 1, // fractional length of path + spineOffset: 161, + spineLength: 400, + flow: 1, // int + }; + +} + +export function modifyShader( material, uniforms, numberOfCurves ) { + + const spineTexture = uniforms.spineTexture; + + const pathOffset = reference( 'pathOffset', 'float', uniforms ); + const pathSegment = reference( 'pathSegment', 'float', uniforms ); + const spineOffset = reference( 'spineOffset', 'float', uniforms ); + const spineLength = reference( 'spineLength', 'float', uniforms ); + const flow = reference( 'flow', 'float', uniforms ); + + material.positionNode = Fn( () => { + + const textureStacks = TEXTURE_HEIGHT / 4; + const textureScale = TEXTURE_HEIGHT * numberOfCurves; + + const worldPos = modelWorldMatrix.mul( vec4( positionLocal, 1 ) ).toVar(); + + const bend = flow.greaterThan( 0 ).toVar(); + const xWeight = select( bend, 0, 1 ).toVar(); + + const spinePortion = select( bend, worldPos.x.add( spineOffset ).div( spineLength ), 0 ); + const mt = spinePortion.mul( pathSegment ).add( pathOffset ).mul( textureStacks ).toVar(); + + mt.assign( mt.mod( textureStacks ) ); + + const rowOffset = mt.floor().toVar(); + + const spinePos = texture( spineTexture, vec2( mt, rowOffset.add( 0.5 ).div( textureScale ) ) ).xyz; + + const a = texture( spineTexture, vec2( mt, rowOffset.add( 1.5 ).div( textureScale ) ) ).xyz; + const b = texture( spineTexture, vec2( mt, rowOffset.add( 2.5 ).div( textureScale ) ) ).xyz; + const c = texture( spineTexture, vec2( mt, rowOffset.add( 3.5 ).div( textureScale ) ) ).xyz; + + const basis = mat3( a, b, c ).toVar(); + + varyingProperty( 'vec3', 'curveNormal' ).assign( basis.mul( normalLocal ) ); + + return basis.mul( vec3( worldPos.x.mul( xWeight ), worldPos.y, worldPos.z ) ).add( spinePos ); + + } )(); + + material.normalNode = varyingProperty( 'vec3', 'curveNormal' ); + +} + +/** + * A helper class for making meshes bend aroudn curves + */ +export class Flow { + + /** + * @param {Mesh} mesh The mesh to clone and modify to bend around the curve + * @param {number} numberOfCurves The amount of space that should preallocated for additional curves + */ + constructor( mesh, numberOfCurves = 1 ) { + + const obj3D = mesh.clone(); + const splineTexure = initSplineTexture( numberOfCurves ); + const uniforms = getUniforms( splineTexure ); + + obj3D.traverse( function ( child ) { + + if ( + child instanceof Mesh || + child instanceof InstancedMesh + ) { + + if ( Array.isArray( child.material ) ) { + + const materials = []; + + for ( const material of child.material ) { + + const newMaterial = material.clone(); + modifyShader( newMaterial, uniforms, numberOfCurves ); + materials.push( newMaterial ); + + } + + child.material = materials; + + } else { + + child.material = child.material.clone(); + modifyShader( child.material, uniforms, numberOfCurves ); + + } + + } + + } ); + + this.curveArray = new Array( numberOfCurves ); + this.curveLengthArray = new Array( numberOfCurves ); + + this.object3D = obj3D; + this.splineTexure = splineTexure; + this.uniforms = uniforms; + + } + + updateCurve( index, curve ) { + + if ( index >= this.curveArray.length ) throw Error( 'Index out of range for Flow' ); + + const curveLength = curve.getLength(); + + this.uniforms.spineLength = curveLength; + this.curveLengthArray[ index ] = curveLength; + this.curveArray[ index ] = curve; + + updateSplineTexture( this.splineTexure, curve, index ); + + } + + moveAlongCurve( amount ) { + + this.uniforms.pathOffset += amount; + + } + +} diff --git a/examples/jsm/objects/LensflareMesh.js b/examples/jsm/objects/LensflareMesh.js new file mode 100644 index 00000000000000..0fc9bd7ab9b47c --- /dev/null +++ b/examples/jsm/objects/LensflareMesh.js @@ -0,0 +1,322 @@ +import { + AdditiveBlending, + Box2, + BufferGeometry, + Color, + FramebufferTexture, + InterleavedBuffer, + InterleavedBufferAttribute, + Mesh, + MeshBasicNodeMaterial, + NodeMaterial, + UnsignedByteType, + Vector2, + Vector3, + Vector4 } from 'three'; + +import { texture, textureLoad, uv, ivec2, vec2, vec4, positionGeometry, reference, varyingProperty, materialReference, Fn, Node } from 'three/tsl'; + +class LensflareMesh extends Mesh { + + constructor() { + + super( LensflareMesh.Geometry, new MeshBasicNodeMaterial( { opacity: 0, transparent: true } ) ); + + this.isLensflare = true; + + this.type = 'LensflareMesh'; + this.frustumCulled = false; + this.renderOrder = Infinity; + + // + + const positionView = new Vector3(); + + // textures + + const tempMap = new FramebufferTexture( 16, 16 ); + const occlusionMap = new FramebufferTexture( 16, 16 ); + + let currentType = UnsignedByteType; + + const geometry = LensflareMesh.Geometry; + + // values for shared material uniforms + + const sharedValues = { + scale: new Vector2(), + positionScreen: new Vector3() + }; + + // materials + + const scale = reference( 'scale', 'vec2', sharedValues ); + const screenPosition = reference( 'positionScreen', 'vec3', sharedValues ); + + const vertexNode = vec4( positionGeometry.xy.mul( scale ).add( screenPosition.xy ), screenPosition.z, 1.0 ); + + const material1a = new NodeMaterial(); + + material1a.depthTest = true; + material1a.depthWrite = false; + material1a.transparent = false; + material1a.fog = false; + material1a.type = 'Lensflare-1a'; + + material1a.vertexNode = vertexNode; + material1a.fragmentNode = vec4( 1.0, 0.0, 1.0, 1.0 ); + + const material1b = new NodeMaterial(); + + material1b.depthTest = false; + material1b.depthWrite = false; + material1b.transparent = false; + material1b.fog = false; + material1b.type = 'Lensflare-1b'; + + material1b.vertexNode = vertexNode; + material1b.fragmentNode = texture( tempMap, vec2( uv().flipY() ) ); + + // the following object is used for occlusionMap generation + + const mesh1 = new Mesh( geometry, material1a ); + + // + + const elements = []; + const elementMeshes = []; + + const material2 = new NodeMaterial(); + + material2.transparent = true; + material2.blending = AdditiveBlending; + material2.depthWrite = false; + material2.depthTest = false; + material2.fog = false; + material2.type = 'Lensflare-2'; + + material2.screenPosition = new Vector3(); + material2.scale = new Vector2(); + material2.occlusionMap = occlusionMap; + + material2.vertexNode = Fn( ( { material } ) => { + + const scale = materialReference( 'scale', 'vec2' ); + const screenPosition = materialReference( 'screenPosition', 'vec3' ); + + const occlusionMap = material.occlusionMap; + + const pos = positionGeometry.xy.toVar(); + + const visibility = textureLoad( occlusionMap, ivec2( 2, 2 ) ).toVar(); + visibility.addAssign( textureLoad( occlusionMap, ivec2( 8, 2 ) ) ); + visibility.addAssign( textureLoad( occlusionMap, ivec2( 14, 2 ) ) ); + visibility.addAssign( textureLoad( occlusionMap, ivec2( 14, 8 ) ) ); + visibility.addAssign( textureLoad( occlusionMap, ivec2( 14, 14 ) ) ); + visibility.addAssign( textureLoad( occlusionMap, ivec2( 8, 14 ) ) ); + visibility.addAssign( textureLoad( occlusionMap, ivec2( 2, 14 ) ) ); + visibility.addAssign( textureLoad( occlusionMap, ivec2( 2, 8 ) ) ); + visibility.addAssign( textureLoad( occlusionMap, ivec2( 8, 8 ) ) ); + + const vVisibility = varyingProperty( 'float', 'vVisibility' ); + + vVisibility.assign( visibility.r.div( 9.0 ) ); + vVisibility.mulAssign( visibility.g.div( 9.0 ).oneMinus() ); + vVisibility.mulAssign( visibility.b.div( 9.0 ) ); + + return vec4( ( pos.mul( scale ).add( screenPosition.xy ).xy ), screenPosition.z, 1.0 ); + + } )(); + + material2.fragmentNode = Fn( () => { + + const color = reference( 'color', 'color' ); + const map = reference( 'map', 'texture' ); + + const vVisibility = varyingProperty( 'float', 'vVisibility' ); + + const output = map.toVar(); + + output.a.mulAssign( vVisibility ); + output.rgb.mulAssign( color ); + + return output; + + } )(); + + + this.addElement = function ( element ) { + + elements.push( element ); + + }; + + // + + const positionScreen = sharedValues.positionScreen; + const screenPositionPixels = new Vector4( 0, 0, 16, 16 ); + const validArea = new Box2(); + const viewport = new Vector4(); + + // dummy node for renderer.renderObject() + const lightsNode = new Node(); + + this.onBeforeRender = ( renderer, scene, camera ) => { + + renderer.getViewport( viewport ); + + viewport.multiplyScalar( window.devicePixelRatio ); + + const renderTarget = renderer.getRenderTarget(); + const type = ( renderTarget !== null ) ? renderTarget.texture.type : UnsignedByteType; + + if ( currentType !== type ) { + + tempMap.dispose(); + occlusionMap.dispose(); + + tempMap.type = occlusionMap.type = type; + + currentType = type; + + } + + const invAspect = viewport.w / viewport.z; + const halfViewportWidth = viewport.z / 2.0; + const halfViewportHeight = viewport.w / 2.0; + + const size = 16 / viewport.w; + + sharedValues.scale.set( size * invAspect, size ); + + validArea.min.set( viewport.x, viewport.y ); + validArea.max.set( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) ); + + // calculate position in screen space + + positionView.setFromMatrixPosition( this.matrixWorld ); + positionView.applyMatrix4( camera.matrixWorldInverse ); + + if ( positionView.z > 0 ) return; // lensflare is behind the camera + + positionScreen.copy( positionView ).applyMatrix4( camera.projectionMatrix ); + + // horizontal and vertical coordinate of the lower left corner of the pixels to copy + + screenPositionPixels.x = viewport.x + ( positionScreen.x * halfViewportWidth ) + halfViewportWidth - 8; + screenPositionPixels.y = viewport.y - ( positionScreen.y * halfViewportHeight ) + halfViewportHeight - 8; + + // screen cull + + if ( validArea.containsPoint( screenPositionPixels ) ) { + + // save current RGB to temp texture + + renderer.copyFramebufferToTexture( tempMap, screenPositionPixels ); + + // render pink quad + + renderer.renderObject( mesh1, scene, camera, geometry, material1a, null, lightsNode ); + + // copy result to occlusionMap + + renderer.copyFramebufferToTexture( occlusionMap, screenPositionPixels ); + + // restore graphics + + renderer.renderObject( mesh1, scene, camera, geometry, material1b, null, lightsNode ); + + // render elements + + const vecX = - positionScreen.x * 2; + const vecY = - positionScreen.y * 2; + + for ( let i = 0, l = elements.length; i < l; i ++ ) { + + const element = elements[ i ]; + + let mesh2 = elementMeshes[ i ]; + + if ( mesh2 === undefined ) { + + mesh2 = elementMeshes[ i ] = new Mesh( geometry, material2 ); + + mesh2.color = element.color.convertSRGBToLinear(); + mesh2.map = element.texture; + + } + + material2.screenPosition.x = positionScreen.x + vecX * element.distance; + material2.screenPosition.y = positionScreen.y - vecY * element.distance; + material2.screenPosition.z = positionScreen.z; + + const size = element.size / viewport.w; + + material2.scale.set( size * invAspect, size ); + + renderer.renderObject( mesh2, scene, camera, geometry, material2, null, lightsNode ); + + } + + } + + }; + + this.dispose = function () { + + material1a.dispose(); + material1b.dispose(); + material2.dispose(); + + tempMap.dispose(); + occlusionMap.dispose(); + + for ( let i = 0, l = elements.length; i < l; i ++ ) { + + elements[ i ].texture.dispose(); + + } + + }; + + } + +} + +// + +class LensflareElement { + + constructor( texture, size = 1, distance = 0, color = new Color( 0xffffff ) ) { + + this.texture = texture; + this.size = size; + this.distance = distance; + this.color = color; + + } + +} + +LensflareMesh.Geometry = ( function () { + + const geometry = new BufferGeometry(); + + const float32Array = new Float32Array( [ + - 1, - 1, 0, 0, 0, + 1, - 1, 0, 1, 0, + 1, 1, 0, 1, 1, + - 1, 1, 0, 0, 1 + ] ); + + const interleavedBuffer = new InterleavedBuffer( float32Array, 5 ); + + geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] ); + geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) ); + geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) ); + + return geometry; + +} )(); + +export { LensflareMesh, LensflareElement }; diff --git a/examples/jsm/objects/SkyMesh.js b/examples/jsm/objects/SkyMesh.js index 6d0287d3839a0a..ad54769f8d67f4 100644 --- a/examples/jsm/objects/SkyMesh.js +++ b/examples/jsm/objects/SkyMesh.js @@ -2,10 +2,9 @@ import { BackSide, BoxGeometry, Mesh, - NodeMaterial, Vector3 } from 'three'; -import { float, Fn, vec3, acos, add, mul, clamp, cos, dot, exp, max, mix, modelViewProjection, normalize, positionWorld, pow, smoothstep, sub, varying, varyingProperty, vec4, uniform, cameraPosition } from 'three/tsl'; +import { Fn, NodeMaterial, float, vec3, acos, add, mul, clamp, cos, dot, exp, max, mix, modelViewProjection, normalize, positionWorld, pow, smoothstep, sub, varying, varyingProperty, vec4, uniform, cameraPosition } from 'three/tsl'; /** * Based on "A Practical Analytic Model for Daylight" diff --git a/examples/jsm/objects/Water2Mesh.js b/examples/jsm/objects/Water2Mesh.js index 29092ff2a16190..752008b3b8ebd6 100644 --- a/examples/jsm/objects/Water2Mesh.js +++ b/examples/jsm/objects/Water2Mesh.js @@ -1,11 +1,10 @@ import { Color, Mesh, - NodeMaterial, Vector2, Vector3 } from 'three'; -import { vec2, viewportSafeUV, viewportSharedTexture, reflector, pow, float, abs, texture, uniform, TempNode, NodeUpdateType, vec4, Fn, cameraPosition, positionWorld, uv, mix, vec3, normalize, max, dot, viewportUV } from 'three/tsl'; +import { Fn, NodeMaterial, NodeUpdateType, TempNode, vec2, viewportSafeUV, viewportSharedTexture, reflector, pow, float, abs, texture, uniform, vec4, cameraPosition, positionWorld, uv, mix, vec3, normalize, max, dot, screenUV } from 'three/tsl'; /** * References: @@ -141,7 +140,7 @@ class WaterNode extends TempNode { this.waterBody.add( reflectionSampler.target ); reflectionSampler.uvNode = reflectionSampler.uvNode.add( offset ); - const refractorUV = viewportUV.add( offset ); + const refractorUV = screenUV.add( offset ); const refractionSampler = viewportSharedTexture( viewportSafeUV( refractorUV ) ); // calculate final uv coords diff --git a/examples/jsm/objects/WaterMesh.js b/examples/jsm/objects/WaterMesh.js index 47f59dd18768b5..3e8dd31dfff85c 100644 --- a/examples/jsm/objects/WaterMesh.js +++ b/examples/jsm/objects/WaterMesh.js @@ -1,10 +1,9 @@ import { Color, Mesh, - NodeMaterial, Vector3 } from 'three'; -import { add, cameraPosition, div, normalize, positionWorld, sub, timerLocal, Fn, texture, vec2, vec3, vec4, max, dot, reflect, pow, length, float, uniform, reflector, mul, mix } from 'three/tsl'; +import { Fn, NodeMaterial, add, cameraPosition, div, normalize, positionWorld, sub, timerLocal, texture, vec2, vec3, vec4, max, dot, reflect, pow, length, float, uniform, reflector, mul, mix } from 'three/tsl'; /** * Work based on : diff --git a/examples/jsm/physics/JoltPhysics.js b/examples/jsm/physics/JoltPhysics.js index 4e2010e7a8a82a..133f7b56fb03d3 100644 --- a/examples/jsm/physics/JoltPhysics.js +++ b/examples/jsm/physics/JoltPhysics.js @@ -61,7 +61,7 @@ async function JoltPhysics() { if ( Jolt === null ) { - const { default: initJolt } = await import( JOLT_PATH ); + const { default: initJolt } = await import( `${JOLT_PATH}` ); Jolt = await initJolt(); } diff --git a/examples/jsm/physics/RapierPhysics.js b/examples/jsm/physics/RapierPhysics.js index 20ed2af8a817c4..e31ca9fcc1b784 100644 --- a/examples/jsm/physics/RapierPhysics.js +++ b/examples/jsm/physics/RapierPhysics.js @@ -58,7 +58,7 @@ async function RapierPhysics() { if ( RAPIER === null ) { - RAPIER = await import( RAPIER_PATH ); + RAPIER = await import( `${RAPIER_PATH}` ); await RAPIER.init(); } diff --git a/examples/jsm/transpiler/GLSLDecoder.js b/examples/jsm/transpiler/GLSLDecoder.js index 57bacb997022f9..5359e41f10607b 100644 --- a/examples/jsm/transpiler/GLSLDecoder.js +++ b/examples/jsm/transpiler/GLSLDecoder.js @@ -226,7 +226,7 @@ class GLSLDecoder { this._currentFunction = null; - this.addPolyfill( 'gl_FragCoord', 'vec3 gl_FragCoord = vec3( viewportCoordinate.x, viewportCoordinate.y.oneMinus(), viewportCoordinate.z );' ); + this.addPolyfill( 'gl_FragCoord', 'vec3 gl_FragCoord = vec3( screenCoordinate.x, screenCoordinate.y.oneMinus(), screenCoordinate.z );' ); } diff --git a/examples/jsm/transpiler/ShaderToyDecoder.js b/examples/jsm/transpiler/ShaderToyDecoder.js index 76e4ede44a011a..c640559a10525a 100644 --- a/examples/jsm/transpiler/ShaderToyDecoder.js +++ b/examples/jsm/transpiler/ShaderToyDecoder.js @@ -8,8 +8,8 @@ class ShaderToyDecoder extends GLSLDecoder { super(); this.addPolyfill( 'iTime', 'float iTime = timerGlobal();' ); - this.addPolyfill( 'iResolution', 'vec2 iResolution = viewportResolution;' ); - this.addPolyfill( 'fragCoord', 'vec3 fragCoord = vec3( viewportCoordinate.x, viewportResolution.y - viewportCoordinate.y, viewportCoordinate.z );' ); + this.addPolyfill( 'iResolution', 'vec2 iResolution = screenSize;' ); + this.addPolyfill( 'fragCoord', 'vec3 fragCoord = vec3( screenCoordinate.x, screenSize.y - screenCoordinate.y, screenCoordinate.z );' ); } diff --git a/examples/jsm/utils/GPUStatsPanel.js b/examples/jsm/utils/GPUStatsPanel.js deleted file mode 100644 index 8f74800ad58f8f..00000000000000 --- a/examples/jsm/utils/GPUStatsPanel.js +++ /dev/null @@ -1,95 +0,0 @@ -import Stats from '../libs/stats.module.js'; - -// https://www.khronos.org/registry/webgl/extensions/EXT_disjoint_timer_query_webgl2/ -export class GPUStatsPanel extends Stats.Panel { - - constructor( context, name = 'GPU MS' ) { - - super( name, '#f90', '#210' ); - - const extension = context.getExtension( 'EXT_disjoint_timer_query_webgl2' ); - - if ( extension === null ) { - - console.warn( 'GPUStatsPanel: disjoint_time_query extension not available.' ); - - } - - this.context = context; - this.extension = extension; - this.maxTime = 30; - this.activeQueries = 0; - - this.startQuery = function () { - - const gl = this.context; - const ext = this.extension; - - if ( ext === null ) { - - return; - - } - - // create the query object - const query = gl.createQuery(); - gl.beginQuery( ext.TIME_ELAPSED_EXT, query ); - - this.activeQueries ++; - - const checkQuery = () => { - - // check if the query is available and valid - - const available = gl.getQueryParameter( query, gl.QUERY_RESULT_AVAILABLE ); - const disjoint = gl.getParameter( ext.GPU_DISJOINT_EXT ); - const ns = gl.getQueryParameter( query, gl.QUERY_RESULT ); - - const ms = ns * 1e-6; - - if ( available ) { - - // update the display if it is valid - if ( ! disjoint ) { - - this.update( ms, this.maxTime ); - - } - - gl.deleteQuery( query ); - - this.activeQueries --; - - - } else if ( gl.isContextLost() === false ) { - - // otherwise try again the next frame - requestAnimationFrame( checkQuery ); - - } - - }; - - requestAnimationFrame( checkQuery ); - - }; - - this.endQuery = function () { - - // finish the query measurement - const ext = this.extension; - const gl = this.context; - - if ( ext === null ) { - - return; - - } - - gl.endQuery( ext.TIME_ELAPSED_EXT ); - - }; - - } - -} diff --git a/examples/jsm/utils/GeometryCompressionUtils.js b/examples/jsm/utils/GeometryCompressionUtils.js index 0be91d568c15bf..31bbaf9718faae 100644 --- a/examples/jsm/utils/GeometryCompressionUtils.js +++ b/examples/jsm/utils/GeometryCompressionUtils.js @@ -11,27 +11,19 @@ import { Matrix4, Vector3 } from 'three'; -import { PackedPhongMaterial } from './PackedPhongMaterial.js'; /** - * Make the input mesh.geometry's normal attribute encoded and compressed by 3 different methods. - * Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the normal data. + * Make the input geometry's normal attribute encoded and compressed by 3 different methods. * - * @param {THREE.Mesh} mesh + * @param {THREE.BufferGeometry} geometry * @param {String} encodeMethod "DEFAULT" || "OCT1Byte" || "OCT2Byte" || "ANGLES" * */ -function compressNormals( mesh, encodeMethod ) { +function compressNormals( geometry, encodeMethod ) { - if ( ! mesh.geometry ) { - - console.error( 'Mesh must contain geometry. ' ); - - } - - const normal = mesh.geometry.attributes.normal; + const normal = geometry.attributes.normal; if ( ! normal ) { @@ -66,8 +58,8 @@ function compressNormals( mesh, encodeMethod ) { } - mesh.geometry.setAttribute( 'normal', new BufferAttribute( result, 3, true ) ); - mesh.geometry.attributes.normal.bytes = result.length * 1; + geometry.setAttribute( 'normal', new BufferAttribute( result, 3, true ) ); + geometry.attributes.normal.bytes = result.length * 1; } else if ( encodeMethod == 'OCT1Byte' ) { @@ -88,8 +80,8 @@ function compressNormals( mesh, encodeMethod ) { } - mesh.geometry.setAttribute( 'normal', new BufferAttribute( result, 2, true ) ); - mesh.geometry.attributes.normal.bytes = result.length * 1; + geometry.setAttribute( 'normal', new BufferAttribute( result, 2, true ) ); + geometry.attributes.normal.bytes = result.length * 1; } else if ( encodeMethod == 'OCT2Byte' ) { @@ -104,8 +96,8 @@ function compressNormals( mesh, encodeMethod ) { } - mesh.geometry.setAttribute( 'normal', new BufferAttribute( result, 2, true ) ); - mesh.geometry.attributes.normal.bytes = result.length * 2; + geometry.setAttribute( 'normal', new BufferAttribute( result, 2, true ) ); + geometry.attributes.normal.bytes = result.length * 2; } else if ( encodeMethod == 'ANGLES' ) { @@ -120,8 +112,8 @@ function compressNormals( mesh, encodeMethod ) { } - mesh.geometry.setAttribute( 'normal', new BufferAttribute( result, 2, true ) ); - mesh.geometry.attributes.normal.bytes = result.length * 2; + geometry.setAttribute( 'normal', new BufferAttribute( result, 2, true ) ); + geometry.attributes.normal.bytes = result.length * 2; } else { @@ -129,60 +121,22 @@ function compressNormals( mesh, encodeMethod ) { } - mesh.geometry.attributes.normal.needsUpdate = true; - mesh.geometry.attributes.normal.isPacked = true; - mesh.geometry.attributes.normal.packingMethod = encodeMethod; - - // modify material - if ( ! ( mesh.material instanceof PackedPhongMaterial ) ) { - - mesh.material = new PackedPhongMaterial().copy( mesh.material ); - - } - - if ( encodeMethod == 'ANGLES' ) { - - mesh.material.defines.USE_PACKED_NORMAL = 0; - - } - - if ( encodeMethod == 'OCT1Byte' ) { - - mesh.material.defines.USE_PACKED_NORMAL = 1; - - } - - if ( encodeMethod == 'OCT2Byte' ) { - - mesh.material.defines.USE_PACKED_NORMAL = 1; - - } - - if ( encodeMethod == 'DEFAULT' ) { - - mesh.material.defines.USE_PACKED_NORMAL = 2; - - } + geometry.attributes.normal.needsUpdate = true; + geometry.attributes.normal.isPacked = true; + geometry.attributes.normal.packingMethod = encodeMethod; } /** - * Make the input mesh.geometry's position attribute encoded and compressed. - * Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the position data. + * Make the input geometry's position attribute encoded and compressed. * - * @param {THREE.Mesh} mesh + * @param {THREE.BufferGeometry} geometry * */ -function compressPositions( mesh ) { +function compressPositions( geometry ) { - if ( ! mesh.geometry ) { - - console.error( 'Mesh must contain geometry. ' ); - - } - - const position = mesh.geometry.attributes.position; + const position = geometry.attributes.position; if ( ! position ) { @@ -204,47 +158,27 @@ function compressPositions( mesh ) { const result = quantizedEncode( array, encodingBytes ); const quantized = result.quantized; - const decodeMat = result.decodeMat; // IMPORTANT: calculate original geometry bounding info first, before updating packed positions - if ( mesh.geometry.boundingBox == null ) mesh.geometry.computeBoundingBox(); - if ( mesh.geometry.boundingSphere == null ) mesh.geometry.computeBoundingSphere(); + if ( geometry.boundingBox == null ) geometry.computeBoundingBox(); + if ( geometry.boundingSphere == null ) geometry.computeBoundingSphere(); - mesh.geometry.setAttribute( 'position', new BufferAttribute( quantized, 3 ) ); - mesh.geometry.attributes.position.isPacked = true; - mesh.geometry.attributes.position.needsUpdate = true; - mesh.geometry.attributes.position.bytes = quantized.length * encodingBytes; - - // modify material - if ( ! ( mesh.material instanceof PackedPhongMaterial ) ) { - - mesh.material = new PackedPhongMaterial().copy( mesh.material ); - - } - - mesh.material.defines.USE_PACKED_POSITION = 0; - - mesh.material.uniforms.quantizeMatPos.value = decodeMat; - mesh.material.uniforms.quantizeMatPos.needsUpdate = true; + geometry.setAttribute( 'position', new BufferAttribute( quantized, 3 ) ); + geometry.attributes.position.isPacked = true; + geometry.attributes.position.needsUpdate = true; + geometry.attributes.position.bytes = quantized.length * encodingBytes; } /** - * Make the input mesh.geometry's uv attribute encoded and compressed. - * Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the uv data. + * Make the input geometry's uv attribute encoded and compressed. * - * @param {THREE.Mesh} mesh + * @param {THREE.BufferGeometry} geometry * */ -function compressUvs( mesh ) { +function compressUvs( geometry ) { - if ( ! mesh.geometry ) { - - console.error( 'Mesh must contain geometry property. ' ); - - } - - const uvs = mesh.geometry.attributes.uv; + const uvs = geometry.attributes.uv; if ( ! uvs ) { @@ -281,39 +215,20 @@ function compressUvs( mesh ) { } - mesh.geometry.setAttribute( 'uv', new BufferAttribute( result, 2, true ) ); - mesh.geometry.attributes.uv.isPacked = true; - mesh.geometry.attributes.uv.needsUpdate = true; - mesh.geometry.attributes.uv.bytes = result.length * 2; - - if ( ! ( mesh.material instanceof PackedPhongMaterial ) ) { - - mesh.material = new PackedPhongMaterial().copy( mesh.material ); - - } - - mesh.material.defines.USE_PACKED_UV = 0; + geometry.setAttribute( 'uv', new BufferAttribute( result, 2, true ) ); + geometry.attributes.uv.isPacked = true; + geometry.attributes.uv.needsUpdate = true; + geometry.attributes.uv.bytes = result.length * 2; } else { // use quantized encoding method result = quantizedEncodeUV( array, 2 ); - mesh.geometry.setAttribute( 'uv', new BufferAttribute( result.quantized, 2 ) ); - mesh.geometry.attributes.uv.isPacked = true; - mesh.geometry.attributes.uv.needsUpdate = true; - mesh.geometry.attributes.uv.bytes = result.quantized.length * 2; - - if ( ! ( mesh.material instanceof PackedPhongMaterial ) ) { - - mesh.material = new PackedPhongMaterial().copy( mesh.material ); - - } - - mesh.material.defines.USE_PACKED_UV = 1; - - mesh.material.uniforms.quantizeMatUV.value = result.decodeMat; - mesh.material.uniforms.quantizeMatUV.needsUpdate = true; + geometry.setAttribute( 'uv', new BufferAttribute( result.quantized, 2 ) ); + geometry.attributes.uv.isPacked = true; + geometry.attributes.uv.needsUpdate = true; + geometry.attributes.uv.bytes = result.quantized.length * 2; } diff --git a/examples/jsm/utils/PackedPhongMaterial.js b/examples/jsm/utils/PackedPhongMaterial.js deleted file mode 100644 index f71aab8e2d8c6b..00000000000000 --- a/examples/jsm/utils/PackedPhongMaterial.js +++ /dev/null @@ -1,178 +0,0 @@ - -/** - * `PackedPhongMaterial` inherited from THREE.MeshPhongMaterial - * - * @param {Object} parameters - */ -import { - MeshPhongMaterial, - ShaderChunk, - ShaderLib, - UniformsUtils, -} from 'three'; - -class PackedPhongMaterial extends MeshPhongMaterial { - - constructor( parameters ) { - - super(); - - this.defines = {}; - this.type = 'PackedPhongMaterial'; - this.uniforms = UniformsUtils.merge( [ - - ShaderLib.phong.uniforms, - - { - quantizeMatPos: { value: null }, - quantizeMatUV: { value: null } - } - - ] ); - - this.vertexShader = [ - '#define PHONG', - - 'varying vec3 vViewPosition;', - - ShaderChunk.common, - ShaderChunk.uv_pars_vertex, - ShaderChunk.displacementmap_pars_vertex, - ShaderChunk.envmap_pars_vertex, - ShaderChunk.color_pars_vertex, - ShaderChunk.fog_pars_vertex, - ShaderChunk.normal_pars_vertex, - ShaderChunk.morphtarget_pars_vertex, - ShaderChunk.skinning_pars_vertex, - ShaderChunk.shadowmap_pars_vertex, - ShaderChunk.logdepthbuf_pars_vertex, - ShaderChunk.clipping_planes_pars_vertex, - - `#ifdef USE_PACKED_NORMAL - #if USE_PACKED_NORMAL == 0 - vec3 decodeNormal(vec3 packedNormal) - { - float x = packedNormal.x * 2.0 - 1.0; - float y = packedNormal.y * 2.0 - 1.0; - vec2 scth = vec2(sin(x * PI), cos(x * PI)); - vec2 scphi = vec2(sqrt(1.0 - y * y), y); - return normalize( vec3(scth.y * scphi.x, scth.x * scphi.x, scphi.y) ); - } - #endif - - #if USE_PACKED_NORMAL == 1 - vec3 decodeNormal(vec3 packedNormal) - { - vec3 v = vec3(packedNormal.xy, 1.0 - abs(packedNormal.x) - abs(packedNormal.y)); - if (v.z < 0.0) - { - v.xy = (1.0 - abs(v.yx)) * vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0); - } - return normalize(v); - } - #endif - - #if USE_PACKED_NORMAL == 2 - vec3 decodeNormal(vec3 packedNormal) - { - vec3 v = (packedNormal * 2.0) - 1.0; - return normalize(v); - } - #endif - #endif`, - - `#ifdef USE_PACKED_POSITION - #if USE_PACKED_POSITION == 0 - uniform mat4 quantizeMatPos; - #endif - #endif`, - - `#ifdef USE_PACKED_UV - #if USE_PACKED_UV == 1 - uniform mat3 quantizeMatUV; - #endif - #endif`, - - `#ifdef USE_PACKED_UV - #if USE_PACKED_UV == 0 - vec2 decodeUV(vec2 packedUV) - { - vec2 uv = (packedUV * 2.0) - 1.0; - return uv; - } - #endif - - #if USE_PACKED_UV == 1 - vec2 decodeUV(vec2 packedUV) - { - vec2 uv = ( vec3(packedUV, 1.0) * quantizeMatUV ).xy; - return uv; - } - #endif - #endif`, - - 'void main() {', - - ShaderChunk.uv_vertex, - - `#ifdef USE_MAP - #ifdef USE_PACKED_UV - vMapUv = decodeUV(vMapUv); - #endif - #endif`, - - ShaderChunk.color_vertex, - ShaderChunk.morphcolor_vertex, - - ShaderChunk.beginnormal_vertex, - - `#ifdef USE_PACKED_NORMAL - objectNormal = decodeNormal(objectNormal); - #endif - - #ifdef USE_TANGENT - vec3 objectTangent = vec3( tangent.xyz ); - #endif - `, - - ShaderChunk.morphnormal_vertex, - ShaderChunk.skinbase_vertex, - ShaderChunk.skinnormal_vertex, - ShaderChunk.defaultnormal_vertex, - ShaderChunk.normal_vertex, - - ShaderChunk.begin_vertex, - - `#ifdef USE_PACKED_POSITION - #if USE_PACKED_POSITION == 0 - transformed = ( vec4(transformed, 1.0) * quantizeMatPos ).xyz; - #endif - #endif`, - - ShaderChunk.morphtarget_vertex, - ShaderChunk.skinning_vertex, - ShaderChunk.displacementmap_vertex, - ShaderChunk.project_vertex, - ShaderChunk.logdepthbuf_vertex, - ShaderChunk.clipping_planes_vertex, - - 'vViewPosition = - mvPosition.xyz;', - - ShaderChunk.worldpos_vertex, - ShaderChunk.envmap_vertex, - ShaderChunk.shadowmap_vertex, - ShaderChunk.fog_vertex, - - '}', - ].join( '\n' ); - - // Use the original MeshPhongMaterial's fragmentShader. - this.fragmentShader = ShaderLib.phong.fragmentShader; - - this.setValues( parameters ); - - } - -} - -export { PackedPhongMaterial }; diff --git a/examples/jsm/utils/ShadowMapViewer.js b/examples/jsm/utils/ShadowMapViewer.js index 53b928249dc079..ff36f70848c62a 100644 --- a/examples/jsm/utils/ShadowMapViewer.js +++ b/examples/jsm/utils/ShadowMapViewer.js @@ -1,13 +1,12 @@ import { DoubleSide, - LinearFilter, + CanvasTexture, Mesh, MeshBasicMaterial, OrthographicCamera, PlaneGeometry, Scene, ShaderMaterial, - Texture, UniformsUtils } from 'three'; import { UnpackDepthRGBAShader } from '../shaders/UnpackDepthRGBAShader.js'; @@ -93,13 +92,9 @@ class ShadowMapViewer { context.fillStyle = 'rgba( 255, 0, 0, 1 )'; context.fillText( light.name, 0, 20 ); - const labelTexture = new Texture( labelCanvas ); - labelTexture.magFilter = LinearFilter; - labelTexture.minFilter = LinearFilter; - labelTexture.needsUpdate = true; + const labelTexture = new CanvasTexture( labelCanvas ); - const labelMaterial = new MeshBasicMaterial( { map: labelTexture, side: DoubleSide } ); - labelMaterial.transparent = true; + const labelMaterial = new MeshBasicMaterial( { map: labelTexture, side: DoubleSide, transparent: true } ); const labelPlane = new PlaneGeometry( labelCanvas.width, labelCanvas.height ); labelMesh = new Mesh( labelPlane, labelMaterial ); diff --git a/examples/jsm/utils/ShadowMapViewerGPU.js b/examples/jsm/utils/ShadowMapViewerGPU.js new file mode 100644 index 00000000000000..ff8caa3054c833 --- /dev/null +++ b/examples/jsm/utils/ShadowMapViewerGPU.js @@ -0,0 +1,201 @@ +import { + DoubleSide, + CanvasTexture, + Mesh, + MeshBasicMaterial, + NodeMaterial, + OrthographicCamera, + PlaneGeometry, + Scene, + Texture +} from 'three'; +import { texture } from 'three/tsl'; + +/** + * This is a helper for visualising a given light's shadow map. + * It works for shadow casting lights: DirectionalLight and SpotLight. + * It renders out the shadow map and displays it on a HUD. + * + * Example usage: + * 1) Import ShadowMapViewer into your app. + * + * 2) Create a shadow casting light and name it optionally: + * let light = new DirectionalLight( 0xffffff, 1 ); + * light.castShadow = true; + * light.name = 'Sun'; + * + * 3) Create a shadow map viewer for that light and set its size and position optionally: + * let shadowMapViewer = new ShadowMapViewer( light ); + * shadowMapViewer.size.set( 128, 128 ); //width, height default: 256, 256 + * shadowMapViewer.position.set( 10, 10 ); //x, y in pixel default: 0, 0 (top left corner) + * + * 4) Render the shadow map viewer in your render loop: + * shadowMapViewer.render( renderer ); + * + * 5) Optionally: Update the shadow map viewer on window resize: + * shadowMapViewer.updateForWindowResize(); + * + * 6) If you set the position or size members directly, you need to call shadowMapViewer.update(); + */ + +class ShadowMapViewer { + + constructor( light ) { + + //- Internals + const scope = this; + const doRenderLabel = ( light.name !== undefined && light.name !== '' ); + let currentAutoClear; + + //Holds the initial position and dimension of the HUD + const frame = { + x: 10, + y: 10, + width: 256, + height: 256 + }; + + const camera = new OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 10 ); + camera.position.set( 0, 0, 2 ); + const scene = new Scene(); + + //HUD for shadow map + + const material = new NodeMaterial(); + + const shadowMapUniform = texture( new Texture() ); + material.fragmentNode = shadowMapUniform; + + const plane = new PlaneGeometry( frame.width, frame.height ); + const mesh = new Mesh( plane, material ); + + scene.add( mesh ); + + //Label for light's name + let labelCanvas, labelMesh; + + if ( doRenderLabel ) { + + labelCanvas = document.createElement( 'canvas' ); + + const context = labelCanvas.getContext( '2d' ); + context.font = 'Bold 20px Arial'; + + const labelWidth = context.measureText( light.name ).width; + labelCanvas.width = labelWidth; + labelCanvas.height = 25; //25 to account for g, p, etc. + + context.font = 'Bold 20px Arial'; + context.fillStyle = 'rgba( 255, 0, 0, 1 )'; + context.fillText( light.name, 0, 20 ); + + const labelTexture = new CanvasTexture( labelCanvas ); + + const labelMaterial = new MeshBasicMaterial( { map: labelTexture, side: DoubleSide, transparent: true } ); + + const labelPlane = new PlaneGeometry( labelCanvas.width, labelCanvas.height ); + labelMesh = new Mesh( labelPlane, labelMaterial ); + + scene.add( labelMesh ); + + } + + function resetPosition() { + + scope.position.set( scope.position.x, scope.position.y ); + + } + + //- API + // Set to false to disable displaying this shadow map + this.enabled = true; + + // Set the size of the displayed shadow map on the HUD + this.size = { + width: frame.width, + height: frame.height, + set: function ( width, height ) { + + this.width = width; + this.height = height; + + mesh.scale.set( this.width / frame.width, this.height / frame.height, 1 ); + + //Reset the position as it is off when we scale stuff + resetPosition(); + + } + }; + + // Set the position of the displayed shadow map on the HUD + this.position = { + x: frame.x, + y: frame.y, + set: function ( x, y ) { + + this.x = x; + this.y = y; + + const width = scope.size.width; + const height = scope.size.height; + + mesh.position.set( - window.innerWidth / 2 + width / 2 + this.x, window.innerHeight / 2 - height / 2 - this.y, 0 ); + + if ( doRenderLabel ) labelMesh.position.set( mesh.position.x, mesh.position.y - scope.size.height / 2 + labelCanvas.height / 2, 0 ); + + } + }; + + this.render = function ( renderer ) { + + if ( this.enabled ) { + + //Because a light's .shadowMap is only initialised after the first render pass + //we have to make sure the correct map is sent into the shader, otherwise we + //always end up with the scene's first added shadow casting light's shadowMap + //in the shader + //See: https://github.com/mrdoob/three.js/issues/5932 + shadowMapUniform.value = light.shadow.map.texture; + + currentAutoClear = renderer.autoClear; + renderer.autoClear = false; // To allow render overlay + renderer.clearDepth(); + renderer.render( scene, camera ); + renderer.autoClear = currentAutoClear; + + } + + }; + + this.updateForWindowResize = function () { + + if ( this.enabled ) { + + camera.left = window.innerWidth / - 2; + camera.right = window.innerWidth / 2; + camera.top = window.innerHeight / 2; + camera.bottom = window.innerHeight / - 2; + camera.updateProjectionMatrix(); + + this.update(); + + } + + }; + + this.update = function () { + + this.position.set( this.position.x, this.position.y ); + this.size.set( this.size.width, this.size.height ); + + }; + + //Force an update to set position/size + this.update(); + + } + +} + + +export { ShadowMapViewer }; diff --git a/examples/jsm/utils/SkeletonUtils.js b/examples/jsm/utils/SkeletonUtils.js index 1f25e4cbbc9a00..a4fd9922d4de26 100644 --- a/examples/jsm/utils/SkeletonUtils.js +++ b/examples/jsm/utils/SkeletonUtils.js @@ -9,28 +9,37 @@ import { VectorKeyframeTrack } from 'three'; +function getBoneName( bone, options ) { + + if ( options.getBoneName !== undefined ) { + + return options.getBoneName( bone ); + + } + + return options.names[ bone.name ]; + +} function retarget( target, source, options = {} ) { - const pos = new Vector3(), - quat = new Quaternion(), + const quat = new Quaternion(), scale = new Vector3(), - bindBoneMatrix = new Matrix4(), relativeMatrix = new Matrix4(), globalMatrix = new Matrix4(); - options.preserveMatrix = options.preserveMatrix !== undefined ? options.preserveMatrix : true; - options.preservePosition = options.preservePosition !== undefined ? options.preservePosition : true; - options.preserveHipPosition = options.preserveHipPosition !== undefined ? options.preserveHipPosition : false; + options.preserveBoneMatrix = options.preserveBoneMatrix !== undefined ? options.preserveBoneMatrix : true; + options.preserveBonePositions = options.preserveBonePositions !== undefined ? options.preserveBonePositions : true; options.useTargetMatrix = options.useTargetMatrix !== undefined ? options.useTargetMatrix : false; options.hip = options.hip !== undefined ? options.hip : 'hip'; + options.hipInfluence = options.hipInfluence !== undefined ? options.hipInfluence : new Vector3( 1, 1, 1 ); + options.scale = options.scale !== undefined ? options.scale : 1; options.names = options.names || {}; const sourceBones = source.isObject3D ? source.skeleton.bones : getBones( source ), bones = target.isObject3D ? target.skeleton.bones : getBones( target ); - let bindBones, - bone, name, boneTo, + let bone, name, boneTo, bonesPosition; // reset bones @@ -42,11 +51,11 @@ function retarget( target, source, options = {} ) { } else { options.useTargetMatrix = true; - options.preserveMatrix = false; + options.preserveBoneMatrix = false; } - if ( options.preservePosition ) { + if ( options.preserveBonePositions ) { bonesPosition = []; @@ -58,7 +67,7 @@ function retarget( target, source, options = {} ) { } - if ( options.preserveMatrix ) { + if ( options.preserveBoneMatrix ) { // reset matrix @@ -76,35 +85,10 @@ function retarget( target, source, options = {} ) { } - if ( options.offsets ) { - - bindBones = []; - - for ( let i = 0; i < bones.length; ++ i ) { - - bone = bones[ i ]; - name = options.names[ bone.name ] || bone.name; - - if ( options.offsets[ name ] ) { - - bone.matrix.multiply( options.offsets[ name ] ); - - bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); - - bone.updateMatrixWorld(); - - } - - bindBones.push( bone.matrixWorld.clone() ); - - } - - } - for ( let i = 0; i < bones.length; ++ i ) { bone = bones[ i ]; - name = options.names[ bone.name ] || bone.name; + name = getBoneName( bone, options ); boneTo = getBoneByName( name, sourceBones ); @@ -136,10 +120,15 @@ function retarget( target, source, options = {} ) { if ( target.isObject3D ) { - const boneIndex = bones.indexOf( bone ), - wBindMatrix = bindBones ? bindBones[ boneIndex ] : bindBoneMatrix.copy( target.skeleton.boneInverses[ boneIndex ] ).invert(); + if ( options.localOffsets ) { + + if ( options.localOffsets[ bone.name ] ) { - globalMatrix.multiply( wBindMatrix ); + globalMatrix.multiply( options.localOffsets[ bone.name ] ); + + } + + } } @@ -147,20 +136,30 @@ function retarget( target, source, options = {} ) { } - if ( bone.parent && bone.parent.isBone ) { + if ( name === options.hip ) { - bone.matrix.copy( bone.parent.matrixWorld ).invert(); - bone.matrix.multiply( globalMatrix ); + globalMatrix.elements[ 12 ] *= options.scale * options.hipInfluence.x; + globalMatrix.elements[ 13 ] *= options.scale * options.hipInfluence.y; + globalMatrix.elements[ 14 ] *= options.scale * options.hipInfluence.z; - } else { + if ( options.hipPosition !== undefined ) { - bone.matrix.copy( globalMatrix ); + globalMatrix.elements[ 12 ] += options.hipPosition.x * options.scale; + globalMatrix.elements[ 13 ] += options.hipPosition.y * options.scale; + globalMatrix.elements[ 14 ] += options.hipPosition.z * options.scale; + + } } - if ( options.preserveHipPosition && name === options.hip ) { + if ( bone.parent ) { - bone.matrix.setPosition( pos.set( 0, bone.position.y, 0 ) ); + bone.matrix.copy( bone.parent.matrixWorld ).invert(); + bone.matrix.multiply( globalMatrix ); + + } else { + + bone.matrix.copy( globalMatrix ); } @@ -170,12 +169,12 @@ function retarget( target, source, options = {} ) { } - if ( options.preservePosition ) { + if ( options.preserveBonePositions ) { for ( let i = 0; i < bones.length; ++ i ) { bone = bones[ i ]; - name = options.names[ bone.name ] || bone.name; + name = getBoneName( bone, options ) || bone.name; if ( name !== options.hip ) { @@ -187,7 +186,7 @@ function retarget( target, source, options = {} ) { } - if ( options.preserveMatrix ) { + if ( options.preserveBoneMatrix ) { // restore matrix @@ -200,6 +199,7 @@ function retarget( target, source, options = {} ) { function retargetClip( target, source, clip, options = {} ) { options.useFirstFramePosition = options.useFirstFramePosition !== undefined ? options.useFirstFramePosition : false; + // Calculate the fps from the source clip based on the track with the most frames, unless fps is already provided. options.fps = options.fps !== undefined ? options.fps : ( Math.max( ...clip.tracks.map( track => track.times.length ) ) / clip.duration ); options.names = options.names || []; @@ -216,30 +216,48 @@ function retargetClip( target, source, clip, options = {} ) { mixer = new AnimationMixer( source ), bones = getBones( target.skeleton ), boneDatas = []; + let positionOffset, bone, boneTo, boneData, name; mixer.clipAction( clip ).play(); - mixer.update( 0 ); + + // trim + + let start = 0, end = numFrames; + + if ( options.trim !== undefined ) { + + start = Math.round( options.trim[ 0 ] * options.fps ); + end = Math.min( Math.round( options.trim[ 1 ] * options.fps ), numFrames ) - start; + + mixer.update( options.trim[ 0 ] ); + + } else { + + mixer.update( 0 ); + + } source.updateMatrixWorld(); - for ( let i = 0; i < numFrames; ++ i ) { + // + + for ( let frame = 0; frame < end; ++ frame ) { - const time = i * delta; + const time = frame * delta; retarget( target, source, options ); for ( let j = 0; j < bones.length; ++ j ) { - name = options.names[ bones[ j ].name ] || bones[ j ].name; - + bone = bones[ j ]; + name = getBoneName( bone, options ) || bone.name; boneTo = getBoneByName( name, source.skeleton ); if ( boneTo ) { - bone = bones[ j ]; boneData = boneDatas[ j ] = boneDatas[ j ] || { bone: bone }; if ( options.hip === name ) { @@ -247,15 +265,15 @@ function retargetClip( target, source, clip, options = {} ) { if ( ! boneData.pos ) { boneData.pos = { - times: new Float32Array( numFrames ), - values: new Float32Array( numFrames * 3 ) + times: new Float32Array( end ), + values: new Float32Array( end * 3 ) }; } if ( options.useFirstFramePosition ) { - if ( i === 0 ) { + if ( frame === 0 ) { positionOffset = bone.position.clone(); @@ -265,30 +283,30 @@ function retargetClip( target, source, clip, options = {} ) { } - boneData.pos.times[ i ] = time; + boneData.pos.times[ frame ] = time; - bone.position.toArray( boneData.pos.values, i * 3 ); + bone.position.toArray( boneData.pos.values, frame * 3 ); } if ( ! boneData.quat ) { boneData.quat = { - times: new Float32Array( numFrames ), - values: new Float32Array( numFrames * 4 ) + times: new Float32Array( end ), + values: new Float32Array( end * 4 ) }; } - boneData.quat.times[ i ] = time; + boneData.quat.times[ frame ] = time; - bone.quaternion.toArray( boneData.quat.values, i * 4 ); + bone.quaternion.toArray( boneData.quat.values, frame * 4 ); } } - if ( i === numFrames - 2 ) { + if ( frame === end - 2 ) { // last mixer update before final loop iteration // make sure we do not go over or equal to clip duration diff --git a/examples/jsm/utils/TextureUtils.js b/examples/jsm/utils/TextureUtils.js index 0f944e5ffde10f..625c7354dc870b 100644 --- a/examples/jsm/utils/TextureUtils.js +++ b/examples/jsm/utils/TextureUtils.js @@ -83,6 +83,7 @@ export function decompress( texture, maxTextureSize = Infinity, renderer = null readableTexture.magFilter = texture.magFilter; readableTexture.wrapS = texture.wrapS; readableTexture.wrapT = texture.wrapT; + readableTexture.colorSpace = texture.colorSpace; readableTexture.name = texture.name; if ( _renderer ) { diff --git a/examples/jsm/utils/TextureUtilsGPU.js b/examples/jsm/utils/TextureUtilsGPU.js new file mode 100644 index 00000000000000..9c44273c9530e3 --- /dev/null +++ b/examples/jsm/utils/TextureUtilsGPU.js @@ -0,0 +1,63 @@ +import { + QuadMesh, + NodeMaterial, + WebGPURenderer, + CanvasTexture +} from 'three'; +import { texture, uv } from 'three/tsl'; + +let _renderer; +const _quadMesh = /*@__PURE__*/ new QuadMesh(); + +export async function decompress( blitTexture, maxTextureSize = Infinity, renderer = null ) { + + if ( renderer === null ) { + + renderer = _renderer = new WebGPURenderer(); + await renderer.init(); + + } + + const material = new NodeMaterial(); + material.fragmentNode = texture( blitTexture ).uv( uv().flipY() ); + + const width = Math.min( blitTexture.image.width, maxTextureSize ); + const height = Math.min( blitTexture.image.height, maxTextureSize ); + + const currentOutputColorSpace = renderer.outputColorSpace; + + renderer.setSize( width, height ); + renderer.outputColorSpace = blitTexture.colorSpace; + + _quadMesh.material = material; + _quadMesh.render( renderer ); + + renderer.outputColorSpace = currentOutputColorSpace; + + const canvas = document.createElement( 'canvas' ); + const context = canvas.getContext( '2d' ); + + canvas.width = width; + canvas.height = height; + + context.drawImage( renderer.domElement, 0, 0, width, height ); + + const readableTexture = new CanvasTexture( canvas ); + + readableTexture.minFilter = blitTexture.minFilter; + readableTexture.magFilter = blitTexture.magFilter; + readableTexture.wrapS = blitTexture.wrapS; + readableTexture.wrapT = blitTexture.wrapT; + readableTexture.colorSpace = blitTexture.colorSpace; + readableTexture.name = blitTexture.name; + + if ( _renderer !== null ) { + + _renderer.dispose(); + _renderer = null; + + } + + return readableTexture; + +} diff --git a/examples/jsm/webxr/XRControllerModelFactory.js b/examples/jsm/webxr/XRControllerModelFactory.js index b888406cf70c4d..8f13ff1bf97d27 100644 --- a/examples/jsm/webxr/XRControllerModelFactory.js +++ b/examples/jsm/webxr/XRControllerModelFactory.js @@ -239,7 +239,7 @@ class XRControllerModelFactory { const xrInputSource = event.data; - if ( xrInputSource.targetRayMode !== 'tracked-pointer' || ! xrInputSource.gamepad ) return; + if ( xrInputSource.targetRayMode !== 'tracked-pointer' || ! xrInputSource.gamepad || xrInputSource.hand ) return; fetchProfile( xrInputSource, this.path, DEFAULT_PROFILE ).then( ( { profile, assetPath } ) => { diff --git a/examples/misc_controls_transform.html b/examples/misc_controls_transform.html index b19805c8ff63ec..be16f880e08295 100644 --- a/examples/misc_controls_transform.html +++ b/examples/misc_controls_transform.html @@ -78,7 +78,6 @@ control = new TransformControls( currentCamera, renderer.domElement ); control.addEventListener( 'change', render ); - control.addEventListener( 'dragging-changed', function ( event ) { orbit.enabled = ! event.value; @@ -89,7 +88,9 @@ scene.add( mesh ); control.attach( mesh ); - scene.add( control ); + + const gizmo = control.getHelper(); + scene.add( gizmo ); window.addEventListener( 'resize', onWindowResize ); diff --git a/examples/misc_exporter_exr.html b/examples/misc_exporter_exr.html index ff19ba878d2ff1..af3ae4bc085b0c 100644 --- a/examples/misc_exporter_exr.html +++ b/examples/misc_exporter_exr.html @@ -178,7 +178,7 @@ } - function exportFile() { + async function exportFile() { let result, exportType, exportCompression; @@ -195,9 +195,9 @@ exportCompression = NO_COMPRESSION; if ( params.target == 'pmrem' ) - result = exporter.parse( renderer, renderTarget, { type: exportType, compression: exportCompression } ); + result = await exporter.parse( renderer, renderTarget, { type: exportType, compression: exportCompression } ); else - result = exporter.parse( dataTexture, { type: exportType, compression: exportCompression } ); + result = await exporter.parse( dataTexture, { type: exportType, compression: exportCompression } ); saveArrayBuffer( result, params.target + '.exr' ); diff --git a/examples/misc_exporter_gltf.html b/examples/misc_exporter_gltf.html index 13ed63341229c4..3e3ef06d519056 100644 --- a/examples/misc_exporter_gltf.html +++ b/examples/misc_exporter_gltf.html @@ -368,7 +368,13 @@ // --------------------------------------------------------------------- // Ortho camera // --------------------------------------------------------------------- - const cameraOrtho = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 0.1, 10 ); + + const height = 1000; // frustum height + const aspect = window.innerWidth / window.innerHeight; + + const cameraOrtho = new THREE.OrthographicCamera( - height * aspect, height * aspect, height, - height, 0, 2000 ); + cameraOrtho.position.set( 600, 400, 0 ); + cameraOrtho.lookAt( 0, 0, 0 ); scene1.add( cameraOrtho ); cameraOrtho.name = 'OrthographicCamera'; diff --git a/examples/models/fbx/mixamo.fbx b/examples/models/fbx/mixamo.fbx new file mode 100644 index 00000000000000..41653ea6128b42 Binary files /dev/null and b/examples/models/fbx/mixamo.fbx differ diff --git a/examples/models/gltf/readyplayer.me.glb b/examples/models/gltf/readyplayer.me.glb new file mode 100644 index 00000000000000..191f8035c711f0 Binary files /dev/null and b/examples/models/gltf/readyplayer.me.glb differ diff --git a/examples/screenshots/webgl_buffergeometry_compression.jpg b/examples/screenshots/webgl_buffergeometry_compression.jpg deleted file mode 100644 index 4da713d915df6a..00000000000000 Binary files a/examples/screenshots/webgl_buffergeometry_compression.jpg and /dev/null differ diff --git a/examples/screenshots/webgl_geometry_sdf.jpg b/examples/screenshots/webgl_geometry_sdf.jpg deleted file mode 100644 index 82d8696fd181dd..00000000000000 Binary files a/examples/screenshots/webgl_geometry_sdf.jpg and /dev/null differ diff --git a/examples/screenshots/webgl_lightprobe.jpg b/examples/screenshots/webgl_lightprobe.jpg index b4a9dab14ec3e5..0e7f57cb484eb0 100644 Binary files a/examples/screenshots/webgl_lightprobe.jpg and b/examples/screenshots/webgl_lightprobe.jpg differ diff --git a/examples/screenshots/webgl_loader_tilt.jpg b/examples/screenshots/webgl_loader_tilt.jpg deleted file mode 100644 index f0a5c2be70a076..00000000000000 Binary files a/examples/screenshots/webgl_loader_tilt.jpg and /dev/null differ diff --git a/examples/screenshots/webgl_postprocessing_advanced.jpg b/examples/screenshots/webgl_postprocessing_advanced.jpg index d09c919b94d150..f1de8899397e93 100644 Binary files a/examples/screenshots/webgl_postprocessing_advanced.jpg and b/examples/screenshots/webgl_postprocessing_advanced.jpg differ diff --git a/examples/screenshots/webgpu_animation_retargeting.jpg b/examples/screenshots/webgpu_animation_retargeting.jpg new file mode 100644 index 00000000000000..35fc6e84971680 Binary files /dev/null and b/examples/screenshots/webgpu_animation_retargeting.jpg differ diff --git a/examples/screenshots/webgpu_animation_retargeting_readyplayer.jpg b/examples/screenshots/webgpu_animation_retargeting_readyplayer.jpg new file mode 100644 index 00000000000000..2341bbcfd42135 Binary files /dev/null and b/examples/screenshots/webgpu_animation_retargeting_readyplayer.jpg differ diff --git a/examples/screenshots/webgpu_backdrop_water.jpg b/examples/screenshots/webgpu_backdrop_water.jpg index 768d7ad39e406d..2bc13bde83027f 100644 Binary files a/examples/screenshots/webgpu_backdrop_water.jpg and b/examples/screenshots/webgpu_backdrop_water.jpg differ diff --git a/examples/screenshots/webgpu_compute_birds.jpg b/examples/screenshots/webgpu_compute_birds.jpg index ce2d437e71cbda..44e34e91432dbc 100644 Binary files a/examples/screenshots/webgpu_compute_birds.jpg and b/examples/screenshots/webgpu_compute_birds.jpg differ diff --git a/examples/screenshots/webgpu_compute_sort_bitonic.jpg b/examples/screenshots/webgpu_compute_sort_bitonic.jpg new file mode 100644 index 00000000000000..a0a4d0c1c21099 Binary files /dev/null and b/examples/screenshots/webgpu_compute_sort_bitonic.jpg differ diff --git a/examples/screenshots/webgpu_compute_water.jpg b/examples/screenshots/webgpu_compute_water.jpg new file mode 100644 index 00000000000000..4c2aeb84539367 Binary files /dev/null and b/examples/screenshots/webgpu_compute_water.jpg differ diff --git a/examples/screenshots/webgpu_lensflares.jpg b/examples/screenshots/webgpu_lensflares.jpg new file mode 100644 index 00000000000000..c38d5e14a399ae Binary files /dev/null and b/examples/screenshots/webgpu_lensflares.jpg differ diff --git a/examples/screenshots/webgpu_lightprobe.jpg b/examples/screenshots/webgpu_lightprobe.jpg index 8a7a07577b2644..0f6b4c95bb5b6f 100644 Binary files a/examples/screenshots/webgpu_lightprobe.jpg and b/examples/screenshots/webgpu_lightprobe.jpg differ diff --git a/examples/screenshots/webgpu_lightprobe_cubecamera.jpg b/examples/screenshots/webgpu_lightprobe_cubecamera.jpg new file mode 100644 index 00000000000000..5d75a244773958 Binary files /dev/null and b/examples/screenshots/webgpu_lightprobe_cubecamera.jpg differ diff --git a/examples/screenshots/webgpu_lights_custom.jpg b/examples/screenshots/webgpu_lights_custom.jpg index fef4101a85d628..50a139f1332f5f 100644 Binary files a/examples/screenshots/webgpu_lights_custom.jpg and b/examples/screenshots/webgpu_lights_custom.jpg differ diff --git a/examples/screenshots/webgpu_materials_arrays.jpg b/examples/screenshots/webgpu_materials_arrays.jpg new file mode 100644 index 00000000000000..db7a27edfe60a1 Binary files /dev/null and b/examples/screenshots/webgpu_materials_arrays.jpg differ diff --git a/examples/screenshots/webgpu_materials_toon.jpg b/examples/screenshots/webgpu_materials_toon.jpg index 19483e386fd6c5..22bd79b5eaabc1 100644 Binary files a/examples/screenshots/webgpu_materials_toon.jpg and b/examples/screenshots/webgpu_materials_toon.jpg differ diff --git a/examples/screenshots/webgpu_modifier_curve.jpg b/examples/screenshots/webgpu_modifier_curve.jpg new file mode 100644 index 00000000000000..08490ac0598e33 Binary files /dev/null and b/examples/screenshots/webgpu_modifier_curve.jpg differ diff --git a/examples/screenshots/webgpu_shadowmap_vsm.jpg b/examples/screenshots/webgpu_shadowmap_vsm.jpg new file mode 100644 index 00000000000000..f0ee504b79781f Binary files /dev/null and b/examples/screenshots/webgpu_shadowmap_vsm.jpg differ diff --git a/examples/screenshots/webgpu_tonemapping.jpg b/examples/screenshots/webgpu_tonemapping.jpg new file mode 100644 index 00000000000000..69af06a32a44f1 Binary files /dev/null and b/examples/screenshots/webgpu_tonemapping.jpg differ diff --git a/examples/screenshots/webgpu_tsl_angular_slicing.jpg b/examples/screenshots/webgpu_tsl_angular_slicing.jpg index e99f032fe67d04..a1706e9de4a160 100644 Binary files a/examples/screenshots/webgpu_tsl_angular_slicing.jpg and b/examples/screenshots/webgpu_tsl_angular_slicing.jpg differ diff --git a/examples/screenshots/webgpu_tsl_raging_sea.jpg b/examples/screenshots/webgpu_tsl_raging_sea.jpg index e6377f719d5f2c..4a1a4ee31319f2 100644 Binary files a/examples/screenshots/webgpu_tsl_raging_sea.jpg and b/examples/screenshots/webgpu_tsl_raging_sea.jpg differ diff --git a/examples/screenshots/webgpu_tsl_vfx_linkedparticles.jpg b/examples/screenshots/webgpu_tsl_vfx_linkedparticles.jpg new file mode 100644 index 00000000000000..2060dda5823963 Binary files /dev/null and b/examples/screenshots/webgpu_tsl_vfx_linkedparticles.jpg differ diff --git a/examples/tags.json b/examples/tags.json index 0c457fd8bfbc79..b103ba8298fd06 100644 --- a/examples/tags.json +++ b/examples/tags.json @@ -119,6 +119,7 @@ "webgpu_compute_particles_rain": [ "gpgpu" ], "webgpu_compute_particles_snow_external": [ "gpgpu" ], "webgpu_compute_points": [ "gpgpu" ], + "webgpu_compute_sort_bitonic": [ "gpgpu" ], "webgpu_compute_texture": [ "gpgpu" ], "webgpu_compute_texture_pingpong": [ "gpgpu" ], "webgpu_depth_texture": [ "renderTarget" ], @@ -126,6 +127,7 @@ "webgpu_materials_lightmap": [ "shadow" ], "webgpu_materials_sss": [ "subsurface scattering", "derivatives", "translucency" ], "webgpu_materials_transmission": [ "alpha" ], + "webgpu_materials_arrays": [ "webgpu", "geometry", "groups", "array" ], "webgpu_mirror": [ "reflection" ], "webgpu_multiple_rendertargets": [ "mrt" ], "webgpu_multiple_rendertargets_readback": [ "mrt" ], @@ -143,6 +145,7 @@ "webgpu_refraction": [ "water" ], "webgpu_rtt": [ "renderTarget", "texture" ], "webgpu_sky": [ "sun" ], + "webgpu_tonemapping": [ "gltf" ], "webgpu_tsl_compute_attractors_particles": [ "gpgpu" ], "webgpu_ocean": [ "water" ] } diff --git a/examples/textures/tiltbrush/Light.webp b/examples/textures/tiltbrush/Light.webp deleted file mode 100644 index b72cf233654c72..00000000000000 Binary files a/examples/textures/tiltbrush/Light.webp and /dev/null differ diff --git a/examples/webgl_animation_skinning_ik.html b/examples/webgl_animation_skinning_ik.html index 90475be5bc4359..9fab7c04180af1 100644 --- a/examples/webgl_animation_skinning_ik.html +++ b/examples/webgl_animation_skinning_ik.html @@ -151,7 +151,7 @@ transformControls.showX = false; transformControls.space = 'world'; transformControls.attach( OOI.target_hand_l ); - scene.add( transformControls ); + scene.add( transformControls.getHelper() ); // disable orbitControls while using transformControls transformControls.addEventListener( 'mouseDown', () => orbitControls.enabled = false ); diff --git a/examples/webgl_buffergeometry_compression.html b/examples/webgl_buffergeometry_compression.html deleted file mode 100644 index 1822acd3b6ec90..00000000000000 --- a/examples/webgl_buffergeometry_compression.html +++ /dev/null @@ -1,273 +0,0 @@ - - - - three.js webgl - buffergeometry - compression - - - - - -
    - three.js - BufferGeometry Compression
    - Octahedron and Quantization encoding methods from Tarek Sherif -
    - - - - - - - diff --git a/examples/webgl_decals.html b/examples/webgl_decals.html index 0297ee9129fc50..b41090fc8ee0ff 100644 --- a/examples/webgl_decals.html +++ b/examples/webgl_decals.html @@ -187,8 +187,10 @@ mouseHelper.position.copy( p ); intersection.point.copy( p ); + const normalMatrix = new THREE.Matrix3().getNormalMatrix( mesh.matrixWorld ); + const n = intersects[ 0 ].face.normal.clone(); - n.transformDirection( mesh.matrixWorld ); + n.applyNormalMatrix( normalMatrix ); n.multiplyScalar( 10 ); n.add( intersects[ 0 ].point ); @@ -243,7 +245,7 @@ } ); scene.add( mesh ); - mesh.scale.set( 10, 10, 10 ); + mesh.scale.multiplyScalar( 10 ); } ); @@ -266,7 +268,8 @@ m.renderOrder = decals.length; // give decals a fixed render order decals.push( m ); - scene.add( m ); + + mesh.attach( m ); } @@ -274,7 +277,7 @@ decals.forEach( function ( d ) { - scene.remove( d ); + mesh.remove( d ); } ); diff --git a/examples/webgl_geometry_sdf.html b/examples/webgl_geometry_sdf.html deleted file mode 100644 index 6376535db1e81b..00000000000000 --- a/examples/webgl_geometry_sdf.html +++ /dev/null @@ -1,212 +0,0 @@ - - - - three.js webgl - SDF Geometry - - - - - -
    - three.js -SDF to Mesh-
    - a wrapper of Mikola Lysenko's Isosurface
    - Mandelbrot by EvilRyu
    -
    - - - - - - - diff --git a/examples/webgl_geometry_spline_editor.html b/examples/webgl_geometry_spline_editor.html index 9ec6fecd5064b0..89e4a78e011711 100644 --- a/examples/webgl_geometry_spline_editor.html +++ b/examples/webgl_geometry_spline_editor.html @@ -145,7 +145,7 @@ controls.enabled = ! event.value; } ); - scene.add( transformControl ); + scene.add( transformControl.getHelper() ); transformControl.addEventListener( 'objectChange', function () { diff --git a/examples/webgl_lightprobe.html b/examples/webgl_lightprobe.html index 16bc4fa6bc82f1..639aef31c4f13b 100644 --- a/examples/webgl_lightprobe.html +++ b/examples/webgl_lightprobe.html @@ -28,8 +28,11 @@ import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + import { LightProbeGenerator } from 'three/addons/lights/LightProbeGenerator.js'; + import { LightProbeHelper } from 'three/addons/helpers/LightProbeHelper.js'; + let mesh, renderer, scene, camera; let gui; @@ -99,6 +102,8 @@ scene.background = cubeTexture; lightProbe.copy( LightProbeGenerator.fromCubeTexture( cubeTexture ) ); + lightProbe.intensity = API.lightProbeIntensity; + lightProbe.position.set( - 10, 0, 0 ); // position not used in scene lighting calculations (helper honors the position, however) const geometry = new THREE.SphereGeometry( 5, 64, 32 ); //const geometry = new THREE.TorusKnotGeometry( 4, 1.5, 256, 32, 2, 3 ); @@ -115,6 +120,10 @@ mesh = new THREE.Mesh( geometry, material ); scene.add( mesh ); + // helper + const helper = new LightProbeHelper( lightProbe, 1 ); + scene.add( helper ); + render(); } ); diff --git a/examples/webgl_lightprobe_cubecamera.html b/examples/webgl_lightprobe_cubecamera.html index 3babcb51351ecf..765e0ff5bf3d5f 100644 --- a/examples/webgl_lightprobe_cubecamera.html +++ b/examples/webgl_lightprobe_cubecamera.html @@ -78,13 +78,15 @@ const urls = genCubeUrls( 'textures/cube/pisa/', '.png' ); - new THREE.CubeTextureLoader().load( urls, function ( cubeTexture ) { + new THREE.CubeTextureLoader().load( urls, async function ( cubeTexture ) { scene.background = cubeTexture; cubeCamera.update( renderer, scene ); - lightProbe.copy( LightProbeGenerator.fromCubeRenderTarget( renderer, cubeRenderTarget ) ); + const probe = await LightProbeGenerator.fromCubeRenderTarget( renderer, cubeRenderTarget ); + + lightProbe.copy( probe ); scene.add( new LightProbeHelper( lightProbe, 5 ) ); diff --git a/examples/webgl_lines_fat.html b/examples/webgl_lines_fat.html index ec52a35a40b9a4..64267185e65a25 100644 --- a/examples/webgl_lines_fat.html +++ b/examples/webgl_lines_fat.html @@ -17,7 +17,8 @@ { "imports": { "three": "../build/three.module.js", - "three/addons/": "./jsm/" + "three/addons/": "./jsm/", + "stats-gl": "https://cdn.jsdelivr.net/npm/stats-gl@2.2.8/dist/main.js" } } @@ -26,8 +27,7 @@ import * as THREE from 'three'; - import Stats from 'three/addons/libs/stats.module.js'; - import { GPUStatsPanel } from 'three/addons/utils/GPUStatsPanel.js'; + import Stats from 'stats-gl'; import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; @@ -39,7 +39,7 @@ let line, renderer, scene, camera, camera2, controls; let line1; let matLine, matLineBasic, matLineDashed; - let stats, gpuPanel; + let stats; let gui; // viewport @@ -138,13 +138,10 @@ window.addEventListener( 'resize', onWindowResize ); onWindowResize(); - stats = new Stats(); + stats = new Stats( { horizontal: false } ); + stats.init( renderer ); document.body.appendChild( stats.dom ); - gpuPanel = new GPUStatsPanel( renderer.getContext() ); - stats.addPanel( gpuPanel ); - stats.showPanel( 0 ); - initGui(); } @@ -174,9 +171,7 @@ controls.update(); - gpuPanel.startQuery(); renderer.render( scene, camera ); - gpuPanel.endQuery(); // inset scene diff --git a/examples/webgl_lines_fat_raycasting.html b/examples/webgl_lines_fat_raycasting.html index d779862cf511fd..38f72acb5dd2c8 100644 --- a/examples/webgl_lines_fat_raycasting.html +++ b/examples/webgl_lines_fat_raycasting.html @@ -17,7 +17,8 @@ { "imports": { "three": "../build/three.module.js", - "three/addons/": "./jsm/" + "three/addons/": "./jsm/", + "stats-gl": "https://cdn.jsdelivr.net/npm/stats-gl@2.2.8/dist/main.js" } } @@ -26,8 +27,7 @@ import * as THREE from 'three'; - import Stats from 'three/addons/libs/stats.module.js'; - import { GPUStatsPanel } from 'three/addons/utils/GPUStatsPanel.js'; + import Stats from 'stats-gl'; import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; @@ -40,7 +40,7 @@ let line, thresholdLine, segments, thresholdSegments; let renderer, scene, camera, controls; let sphereInter, sphereOnLine; - let stats, gpuPanel; + let stats; let gui; let clock; @@ -194,12 +194,10 @@ window.addEventListener( 'resize', onWindowResize ); onWindowResize(); - stats = new Stats(); + stats = new Stats( { horizontal: false } ); + stats.init( renderer ); document.body.appendChild( stats.dom ); - - gpuPanel = new GPUStatsPanel( renderer.getContext() ); - stats.addPanel( gpuPanel ); - stats.showPanel( 0 ); + initGui(); } @@ -268,9 +266,7 @@ } - gpuPanel.startQuery(); renderer.render( scene, camera ); - gpuPanel.endQuery(); stats.update(); diff --git a/examples/webgl_loader_tilt.html b/examples/webgl_loader_tilt.html deleted file mode 100644 index 1f499143ff4fa8..00000000000000 --- a/examples/webgl_loader_tilt.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - three.js webgl - tilt loader - - - - - -
    - three.js - tilt loader
    - TILTSPHERE by Rosie Summers -
    - - - - - - diff --git a/examples/webgl_modifier_curve.html b/examples/webgl_modifier_curve.html index 8e4dc45f880b63..4abc504b35bd40 100644 --- a/examples/webgl_modifier_curve.html +++ b/examples/webgl_modifier_curve.html @@ -191,7 +191,7 @@ const target = intersects[ 0 ].object; control.attach( target ); - scene.add( control ); + scene.add( control.getHelper() ); } diff --git a/examples/webgl_modifier_curve_instanced.html b/examples/webgl_modifier_curve_instanced.html index ac8e7fc035d7ef..36c98d8d646727 100644 --- a/examples/webgl_modifier_curve_instanced.html +++ b/examples/webgl_modifier_curve_instanced.html @@ -221,7 +221,7 @@ const target = intersects[ 0 ].object; control.attach( target ); - scene.add( control ); + scene.add( control.getHelper() ); } diff --git a/examples/webgl_postprocessing_advanced.html b/examples/webgl_postprocessing_advanced.html index 28ae562785d58f..ce9df31799b719 100644 --- a/examples/webgl_postprocessing_advanced.html +++ b/examples/webgl_postprocessing_advanced.html @@ -153,8 +153,8 @@ effectSepia.uniforms[ 'amount' ].value = 0.9; - effectVignette.uniforms[ 'offset' ].value = 0.95; - effectVignette.uniforms[ 'darkness' ].value = 1.6; + effectVignette.uniforms[ 'offset' ].value = 1.6; + effectVignette.uniforms[ 'darkness' ].value = 0.95; const effectBloom = new BloomPass( 0.5 ); const effectFilm = new FilmPass( 0.35 ); diff --git a/examples/webgl_postprocessing_ssaa.html b/examples/webgl_postprocessing_ssaa.html index 1a3140dd164fd6..b9eb45e8c14898 100644 --- a/examples/webgl_postprocessing_ssaa.html +++ b/examples/webgl_postprocessing_ssaa.html @@ -8,7 +8,7 @@
    - three.js - Unbiased Manual Supersamling Anti-Aliasing (SSAA) pass by Ben Houston

    + three.js - Unbiased Manual Supersampling Anti-Aliasing (SSAA) pass by Ben Houston

    This example shows how to unbias the rounding errors accumulated using high number of SSAA samples on a 8-bit per channel buffer.

    Turn off the "unbiased" feature to see the banding that results from accumulated rounding errors.
    diff --git a/examples/webgl_shadowmap_progressive.html b/examples/webgl_shadowmap_progressive.html index 795046abbfe8b9..e74c9cc08f7673 100644 --- a/examples/webgl_shadowmap_progressive.html +++ b/examples/webgl_shadowmap_progressive.html @@ -76,7 +76,7 @@ } ); control.attach( lightOrigin ); - scene.add( control ); + scene.add( control.getHelper() ); // create 8 directional lights to speed up the convergence for ( let l = 0; l < lightCount; l ++ ) { @@ -142,7 +142,7 @@ } ); control2.attach( object ); - scene.add( control2 ); + scene.add( control2.getHelper() ); const lightTarget = new THREE.Group(); lightTarget.position.set( 0, 20, 0 ); for ( let l = 0; l < dirLights.length; l ++ ) { diff --git a/examples/webgl_tonemapping.html b/examples/webgl_tonemapping.html index 36152be70693a6..99174aaf561d94 100644 --- a/examples/webgl_tonemapping.html +++ b/examples/webgl_tonemapping.html @@ -129,10 +129,11 @@ window.addEventListener( 'resize', onWindowResize ); gui = new GUI(); - const toneMappingFolder = gui.addFolder( 'tone mapping' ); + const toneMappingFolder = gui.addFolder( 'Tone Mapping' ); toneMappingFolder.add( params, 'toneMapping', Object.keys( toneMappingOptions ) ) + .name( 'type' ) .onChange( function () { updateGUI( toneMappingFolder ); @@ -142,7 +143,16 @@ } ); - const backgroundFolder = gui.addFolder( 'background' ); + guiExposure = toneMappingFolder.add( params, 'exposure', 0, 2 ) + + .onChange( function ( value ) { + + renderer.toneMappingExposure = value; + render(); + + } ); + + const backgroundFolder = gui.addFolder( 'Background' ); backgroundFolder.add( params, 'blurriness', 0, 1 ) @@ -170,23 +180,13 @@ function updateGUI( folder ) { - if ( guiExposure !== null ) { - - guiExposure.destroy(); - guiExposure = null; - - } - - if ( params.toneMapping !== 'None' ) { - - guiExposure = folder.add( params, 'exposure', 0, 2 ) + if ( params.toneMapping === 'None' ) { - .onChange( function () { + guiExposure.hide(); - renderer.toneMappingExposure = params.exposure; - render(); + } else { - } ); + guiExposure.show(); } diff --git a/examples/webgpu_animation_retargeting.html b/examples/webgpu_animation_retargeting.html new file mode 100644 index 00000000000000..64ee303c0b0177 --- /dev/null +++ b/examples/webgpu_animation_retargeting.html @@ -0,0 +1,301 @@ + + + three.js webgpu - animation retargeting + + + + + + +
    + three.js webgpu - animation retargeting +
    + + + + + + diff --git a/examples/webgpu_animation_retargeting_readyplayer.html b/examples/webgpu_animation_retargeting_readyplayer.html new file mode 100644 index 00000000000000..f70adcedd51698 --- /dev/null +++ b/examples/webgpu_animation_retargeting_readyplayer.html @@ -0,0 +1,210 @@ + + + three.js webgpu - animation retargeting + + + + + + +
    + three.js webgpu - animation retargeting
    + mixamo to readyplayer.me +
    + + + + + + diff --git a/examples/webgpu_backdrop.html b/examples/webgpu_backdrop.html index 272fd0dc845273..53142e3c16b5af 100644 --- a/examples/webgpu_backdrop.html +++ b/examples/webgpu_backdrop.html @@ -25,7 +25,7 @@ + + + + \ No newline at end of file diff --git a/examples/webgpu_compute_water.html b/examples/webgpu_compute_water.html new file mode 100644 index 00000000000000..d9686c56ca59e0 --- /dev/null +++ b/examples/webgpu_compute_water.html @@ -0,0 +1,505 @@ + + + + three.js webgpu - compute - water + + + + + + +
    + three.js - webgpu compute water
    + Move mouse to disturb water. +
    + + + + + + diff --git a/examples/webgpu_instance_mesh.html b/examples/webgpu_instance_mesh.html index 60cecb86234a94..de27f802d89465 100644 --- a/examples/webgpu_instance_mesh.html +++ b/examples/webgpu_instance_mesh.html @@ -69,7 +69,7 @@ // const gui = new GUI(); - gui.add( mesh, 'count', 0, count ); + gui.add( mesh, 'count', 1, count ); } ); diff --git a/examples/webgpu_lensflares.html b/examples/webgpu_lensflares.html new file mode 100644 index 00000000000000..7a824359e6fff0 --- /dev/null +++ b/examples/webgpu_lensflares.html @@ -0,0 +1,186 @@ + + + + three.js webgpu - lensflares + + + + + + +
    + three.js - lensflares
    + textures from ro.me
    + fly with WASD/RF/QE + mouse +
    + + + + + + + diff --git a/examples/webgpu_lightprobe.html b/examples/webgpu_lightprobe.html index c6b634e15d1079..139e3b8fd56e5b 100644 --- a/examples/webgpu_lightprobe.html +++ b/examples/webgpu_lightprobe.html @@ -29,8 +29,11 @@ import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + import { LightProbeGenerator } from 'three/addons/lights/LightProbeGenerator.js'; + import { LightProbeHelper } from 'three/addons/helpers/LightProbeHelperGPU.js'; + let mesh, renderer, scene, camera; let gui; @@ -100,6 +103,8 @@ scene.background = cubeTexture; lightProbe.copy( LightProbeGenerator.fromCubeTexture( cubeTexture ) ); + lightProbe.intensity = API.lightProbeIntensity; + lightProbe.position.set( - 10, 0, 0 ); // position not used in scene lighting calculations (helper honors the position, however) const geometry = new THREE.SphereGeometry( 5, 64, 32 ); //const geometry = new THREE.TorusKnotGeometry( 4, 1.5, 256, 32, 2, 3 ); @@ -116,6 +121,10 @@ mesh = new THREE.Mesh( geometry, material ); scene.add( mesh ); + // helper + const helper = new LightProbeHelper( lightProbe, 1 ); + scene.add( helper ); + } ); diff --git a/examples/webgpu_lightprobe_cubecamera.html b/examples/webgpu_lightprobe_cubecamera.html new file mode 100644 index 00000000000000..cf4c60fb37db04 --- /dev/null +++ b/examples/webgpu_lightprobe_cubecamera.html @@ -0,0 +1,125 @@ + + + + three.js webgpu - light probe from cubeCamera + + + + + + +
    + three.js webgpu - light probe from cubeCamera +
    + + + + + + + diff --git a/examples/webgpu_lights_custom.html b/examples/webgpu_lights_custom.html index 2f0a22aa4de897..9a295b15a8f8f1 100644 --- a/examples/webgpu_lights_custom.html +++ b/examples/webgpu_lights_custom.html @@ -50,21 +50,20 @@ camera.position.z = 1.5; scene = new THREE.Scene(); - scene.background = new THREE.Color( 0x222222 ); // lights - const sphereGeometry = new THREE.SphereGeometry( 0.01, 16, 8 ); + const sphereGeometry = new THREE.SphereGeometry( 0.02, 16, 8 ); const addLight = ( hexColor ) => { - const material = new THREE.MeshStandardNodeMaterial(); + const material = new THREE.NodeMaterial(); material.colorNode = color( hexColor ); material.lightsNode = lights(); // ignore scene lights const mesh = new THREE.Mesh( sphereGeometry, material ); - const light = new THREE.PointLight( hexColor, 0.1, 0.8 ); + const light = new THREE.PointLight( hexColor, 0.1, 1 ); light.add( mesh ); scene.add( light ); @@ -85,9 +84,9 @@ const points = []; - for ( let i = 0; i < 1_000_000; i ++ ) { + for ( let i = 0; i < 500_000; i ++ ) { - const point = new THREE.Vector3().random().subScalar( 0.5 ).multiplyScalar( 2 ); + const point = new THREE.Vector3().random().subScalar( 0.5 ).multiplyScalar( 3 ); points.push( point ); } @@ -138,7 +137,7 @@ function animate() { - const time = Date.now() * 0.0005; + const time = Date.now() * 0.001; const scale = .5; light1.position.x = Math.sin( time * 0.7 ) * scale; @@ -153,7 +152,7 @@ light3.position.y = Math.cos( time * 0.3 ) * scale; light3.position.z = Math.sin( time * 0.5 ) * scale; - scene.rotation.y = time * 0.6; + scene.rotation.y = time * 0.1; renderer.render( scene, camera ); diff --git a/examples/webgpu_materials.html b/examples/webgpu_materials.html index f95a754b2e8370..3604a9414a2f98 100644 --- a/examples/webgpu_materials.html +++ b/examples/webgpu_materials.html @@ -27,7 +27,7 @@ import * as THREE from 'three'; import * as TSL from 'three/tsl'; - import { Fn, wgslFn, positionLocal, scriptable, positionWorld, normalLocal, normalWorld, normalView, color, texture, uv, float, vec2, vec3, vec4, oscSine, triplanarTexture, viewportUV, js, string, global, Loop, cameraProjectionMatrix } from 'three/tsl'; + import { Fn, wgslFn, positionLocal, scriptable, positionWorld, normalLocal, normalWorld, normalView, color, texture, uv, float, vec2, vec3, vec4, oscSine, triplanarTexture, screenUV, js, string, global, Loop, cameraProjectionMatrix } from 'three/tsl'; import { TeapotGeometry } from 'three/addons/geometries/TeapotGeometry.js'; @@ -208,7 +208,7 @@ // Screen Projection Texture material = new THREE.MeshBasicNodeMaterial(); - material.colorNode = texture( uvTexture, viewportUV.flipY() ); + material.colorNode = texture( uvTexture, screenUV.flipY() ); materials.push( material ); // Loop @@ -398,10 +398,28 @@ } + function moduleToLib( module ) { + + const lib = {}; + + for ( const nodeElement of Object.values( module ) ) { + + if ( typeof nodeElement === 'function' && nodeElement.type !== undefined ) { + + lib[ nodeElement.type ] = nodeElement; + + } + + } + + return lib; + + } + function testSerialization( mesh ) { const json = mesh.toJSON(); - const loader = new THREE.NodeObjectLoader(); + const loader = new THREE.NodeObjectLoader().setNodes( moduleToLib( TSL ) ).setNodeMaterials( moduleToLib( THREE ) ); const serializedMesh = loader.parse( json ); serializedMesh.position.x = ( objects.length % 4 ) * 200 - 400; diff --git a/examples/webgpu_materials_arrays.html b/examples/webgpu_materials_arrays.html new file mode 100644 index 00000000000000..6e4b33a8ee782f --- /dev/null +++ b/examples/webgpu_materials_arrays.html @@ -0,0 +1,174 @@ + + + + three.js webgpu - materials arrays and geometry groups + + + + + + +
    + three.js - WebGPU Materials Arrays and Geometry Groups
    +
    + + + + + + + diff --git a/examples/webgpu_materials_toon.html b/examples/webgpu_materials_toon.html index 7d2f5173b15948..a0f3c72aaed4fa 100644 --- a/examples/webgpu_materials_toon.html +++ b/examples/webgpu_materials_toon.html @@ -24,6 +24,7 @@ + + + + diff --git a/examples/webgpu_mrt.html b/examples/webgpu_mrt.html index 8a8a5981cf1945..9b67a17c60df07 100644 --- a/examples/webgpu_mrt.html +++ b/examples/webgpu_mrt.html @@ -26,7 +26,7 @@ diff --git a/examples/webgpu_portal.html b/examples/webgpu_portal.html index 3eea886d0b2b71..361230cdd06c00 100644 --- a/examples/webgpu_portal.html +++ b/examples/webgpu_portal.html @@ -25,7 +25,7 @@ + + + + diff --git a/examples/webgpu_skinning.html b/examples/webgpu_skinning.html index d4bcea5e389887..5dc3d02edbb542 100644 --- a/examples/webgpu_skinning.html +++ b/examples/webgpu_skinning.html @@ -25,7 +25,7 @@ + + + + + diff --git a/examples/webgpu_tsl_angular_slicing.html b/examples/webgpu_tsl_angular_slicing.html index 1d45991294a450..2edb52b47acd6f 100644 --- a/examples/webgpu_tsl_angular_slicing.html +++ b/examples/webgpu_tsl_angular_slicing.html @@ -65,7 +65,7 @@ const directionalLight = new THREE.DirectionalLight( '#ffffff', 4 ); directionalLight.position.set( 6.25, 3, 4 ); directionalLight.castShadow = true; - directionalLight.shadow.mapSize.set( 1024, 1024 ); + directionalLight.shadow.mapSize.set( 2048, 2048 ); directionalLight.shadow.camera.near = 0.1; directionalLight.shadow.camera.far = 30; directionalLight.shadow.camera.top = 8; @@ -194,6 +194,7 @@ renderer = new THREE.WebGPURenderer( { antialias: true } ); renderer.toneMapping = THREE.ACESFilmicToneMapping; renderer.toneMappingExposure = 1; + renderer.shadowMap.enabled = true; renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setAnimationLoop( animate ); diff --git a/examples/webgpu_tsl_compute_attractors_particles.html b/examples/webgpu_tsl_compute_attractors_particles.html index 7f704a984aba3b..ad476d0d63a1f1 100644 --- a/examples/webgpu_tsl_compute_attractors_particles.html +++ b/examples/webgpu_tsl_compute_attractors_particles.html @@ -118,7 +118,7 @@ attractor.controls.attach( attractor.reference ); attractor.controls.visible = true; attractor.controls.enabled = attractor.controls.visible; - scene.add( attractor.controls ); + scene.add( attractor.controls.getHelper() ); attractor.controls.addEventListener( 'dragging-changed', ( event ) => { diff --git a/examples/webgpu_tsl_halftone.html b/examples/webgpu_tsl_halftone.html index a3aab938f70bea..b9068af2a4b25d 100644 --- a/examples/webgpu_tsl_halftone.html +++ b/examples/webgpu_tsl_halftone.html @@ -25,7 +25,7 @@ + + + + diff --git a/examples/webgpu_volume_perlin.html b/examples/webgpu_volume_perlin.html index 677cd262b2762b..25738f64de1603 100644 --- a/examples/webgpu_volume_perlin.html +++ b/examples/webgpu_volume_perlin.html @@ -89,7 +89,7 @@ const geometry = new THREE.BoxGeometry( 1, 1, 1 ); const material = new THREE.VolumeNodeMaterial( { - side: THREE.BackSide, + side: THREE.BackSide } ); material.base = new THREE.Color( 0x798aa0 ); @@ -103,7 +103,7 @@ If( mapValue.greaterThan( threshold ), () => { - const p = vec3().temp().assign( probe ).addAssign( 0.5 ); + const p = vec3( probe ).add( 0.5 ); finalColor.rgb.assign( map.normal( p ).mul( 0.5 ).add( probe.mul( 1.5 ).add( 0.25 ) ) ); finalColor.a.assign( 1 ); diff --git a/examples/webxr_xr_controls_transform.html b/examples/webxr_xr_controls_transform.html index 649a19835454d6..9451d13e92452f 100644 --- a/examples/webxr_xr_controls_transform.html +++ b/examples/webxr_xr_controls_transform.html @@ -162,7 +162,7 @@ controls = new TransformControls( camera, renderer.domElement ); controls.attach( group.children[ 0 ] ); - scene.add( controls ); + scene.add( controls.getHelper() ); // diff --git a/index.html b/index.html index 67b2d0961aa14b..9359cb0d61a960 100644 --- a/index.html +++ b/index.html @@ -27,7 +27,7 @@